Describe the issue:
preProcess/get_whitening_matrix.m (line 48; identical in v2.0.2, v2.5.2, v3.0.2):
while ibatch<=Nbatch
...
CC = CC + (datr' * datr)/NT;
ibatch = ibatch + ops.nSkipCov;
end
CC = CC / ceil((Nbatch-1)/ops.nSkipCov);
The loop visits floor((Nbatch-1)/nSkipCov) + 1 batches; the normalizer is ceil((Nbatch-1)/nSkipCov). Whenever nSkipCov divides Nbatch-1 exactly these differ by one, and the covariance is inflated by (m+1)/m with m = (Nbatch-1)/nSkipCov. Since Wrot ~ C^(-1/2), the whitened data are then uniformly scaled by sqrt(m/(m+1)), and every threshold expressed in whitened units (ops.Th, ops.spkTh) becomes effectively sqrt((m+1)/m) harder. With the default nSkipCov = 25:
| Nbatch |
duration @30 kHz |
covariance |
effective thresholds |
| 26 |
~57 s |
x2.00 |
x1.414 |
| 51 |
~1.9 min |
x1.50 |
x1.225 |
| 251 |
~9.5 min |
x1.10 |
x1.049 |
| 1651 |
~62 min |
x1.015 |
x1.008 |
One in 25 possible batch counts is affected, so adding ~2 s of recording can discontinuously change detection behavior; the bias is material for short recordings and negligible for hour-long ones.
Kilosort 4 already fixed this by counting loop iterations (kilosort/preprocessing.py::get_whitening_matrix, variable k).
Suggested one-line fix (either):
CC = CC / (floor((Nbatch-1)/ops.nSkipCov) + 1);
or count iterations in the loop as KS4 does.
Arithmetic + whitening-scale demonstration: https://github.com/cindykrafft/research-software-audit/blob/main/audits/kilosort/verify/km3_nskipcov.py
Context: found while auditing the Kilosort versions used by 60 papers in six high-impact journals (2021–2026); 41 of them pin KS2/2.5/3.
Generated by Claude Code
Describe the issue:
preProcess/get_whitening_matrix.m(line 48; identical in v2.0.2, v2.5.2, v3.0.2):The loop visits
floor((Nbatch-1)/nSkipCov) + 1batches; the normalizer isceil((Nbatch-1)/nSkipCov). WhenevernSkipCovdividesNbatch-1exactly these differ by one, and the covariance is inflated by(m+1)/mwithm = (Nbatch-1)/nSkipCov. SinceWrot ~ C^(-1/2), the whitened data are then uniformly scaled bysqrt(m/(m+1)), and every threshold expressed in whitened units (ops.Th,ops.spkTh) becomes effectivelysqrt((m+1)/m)harder. With the defaultnSkipCov = 25:One in 25 possible batch counts is affected, so adding ~2 s of recording can discontinuously change detection behavior; the bias is material for short recordings and negligible for hour-long ones.
Kilosort 4 already fixed this by counting loop iterations (
kilosort/preprocessing.py::get_whitening_matrix, variablek).Suggested one-line fix (either):
or count iterations in the loop as KS4 does.
Arithmetic + whitening-scale demonstration: https://github.com/cindykrafft/research-software-audit/blob/main/audits/kilosort/verify/km3_nskipcov.py
Context: found while auditing the Kilosort versions used by 60 papers in six high-impact journals (2021–2026); 41 of them pin KS2/2.5/3.
Generated by Claude Code