Improve SNIRF Sampling Rate Estimation by Replacing Rounding with Pre… #13195
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Overview
This PR improves the robustness of sampling rate extraction from SNIRF files by replacing a potentially unsafe .round() operation with a more reliable np.allclose() check. This change ensures compatibility with high-precision data and avoids unintended misclassification of uniformly-sampled data as jittered.
Problem
In _extract_sampling_rate(), the existing implementation uses:
python
Copy
Edit
uniq_periods = np.unique(periods.round(decimals=4))
This approach may incorrectly group near-equal values due to rounding, leading to false positives when detecting jitter.
Solution
This PR:
Replaces the rounding + uniqueness check with np.allclose(periods, mean_period, rtol=1e-6)
Retains jitter detection logic with improved precision
Keeps the warning message for users when jitter exceeds 1% threshold
Benefits
Better support for high-resolution SNIRF datasets
More accurate sampling rate detection
Fewer false warnings about jitter
Cleaner code and better alignment with scientific precision standards
🔬 Test Strategy
Although the function is part of a data I/O pipeline, the following unit tests are proposed:
✅ New Tests:
Test Perfectly Uniform Sampling
Input: Linearly spaced time_data
Expected: No warning, correct sampling rate
Test Sampling With Very Small Precision Jitter
Input: time_data with tiny noise added (below 1% jitter)
Expected: Sampling rate computed, info logged, no warning raised
Test Clearly Jittered Data
Input: time_data with jitter > 1%
Expected: Sampling rate computed, warning raised
✅ Example Test Snippet (using pytest + mne.utils._logging.catch_logging):
python
Copy
Edit
import numpy as np
from mne.io import read_raw_snirf
from mne.utils._logging import catch_logging
def test_uniform_sampling_rate_extraction():
class DummyDat:
def get(self, path):
if path == "nirs/data1/time":
return np.linspace(0, 10, 1001)
def test_jitter_warning(caplog):
class DummyDat:
def get(self, path):
if path == "nirs/data1/time":
t = np.linspace(0, 10, 1001)
t[500] += 0.02 # Introduce artificial jitter
return t