Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# simple makefile to simplify repetetive build env management tasks under posix
# caution: testing won't work on windows, see README
PYTHON ?= python
PYTESTS ?= py.test
PYTESTS ?= pytest
CTAGS ?= ctags
CODESPELL_SKIPS ?= "*.html,*.fif,*.eve,*.gz,*.tgz,*.zip,*.mat,*.stc,*.label,*.w,*.bz2,*.annot,*.sulc,*.log,*.local-copy,*.orig_avg,*.inflated_avg,*.gii,*.pyc,*.doctree,*.pickle,*.inv,*.png,*.edf,*.touch,*.thickness,*.nofix,*.volume,*.defect_borders,*.mgh,lh.*,rh.*,COR-*,FreeSurferColorLUT.txt,*.examples,.xdebug_mris_calc,bad.segments,BadChannels,*.hist,empty_file,*.orig,*.js,*.map,*.ipynb,searchindex.dat"
CODESPELL_DIRS ?= meegkit/ examples/
Expand Down Expand Up @@ -85,21 +85,21 @@ install-dev:

# Tests
# =============================================================================
test: in
test:
rm -f .coverage
$(PYTESTS) -m 'not ultraslowtest' meegkit
$(PYTESTS) -m 'not ultraslowtest'

test-verbose: in
test-verbose:
rm -f .coverage
$(PYTESTS) -m 'not ultraslowtest' meegkit --verbose
$(PYTESTS) -m 'not ultraslowtest' --verbose

test-fast: in
test-fast:
rm -f .coverage
$(PYTESTS) -m 'not slowtest' meegkit
$(PYTESTS) -m 'not slowtest'

test-full: in
test-full:
rm -f .coverage
$(PYTESTS) meegkit
$(PYTESTS)

.PHONY: init test

Expand Down
3 changes: 2 additions & 1 deletion meegkit/asr.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,8 @@ def asr_calibrate(X, sfreq, cutoff=5, blocksize=100, win_len=0.5,
sig = np.zeros(nc)
for ichan in reversed(range(nc)):
mu[ichan], sig[ichan], alpha, beta = fit_eeg_distribution(
rms[ichan], min_clean_fraction, max_dropout_fraction)
rms[ichan], min_clean_fraction, max_dropout_fraction,
step_sizes=[0.01, 0.01])

T = np.dot(np.diag(mu + cutoff * sig), V.T)
logging.debug("[ASR] Calibration done.")
Expand Down
2 changes: 1 addition & 1 deletion meegkit/utils/asr.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@


def fit_eeg_distribution(X, min_clean_fraction=0.25, max_dropout_fraction=0.1,
fit_quantiles=[0.022, 0.6], step_sizes=[0.0220, 0.6000],
fit_quantiles=[0.022, 0.6], step_sizes=[0.01, 0.01],
shape_range=SHAPE_RANGE):
"""Estimate the mean and SD of clean EEG from contaminated data.

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ filterwarnings = [
addopts = """
--color=yes
--durations 10
--noplots
"""

[tool.coverage.run]
Expand Down
33 changes: 33 additions & 0 deletions tests/test_asr.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,39 @@ def test_clean_windows_offset_phase_drift():
assert abs(int(offsets_raw[-1]) - int(offsets_truncated[-1])) >= 10


def test_fit_eeg_distribution_default_step_sizes():
"""Default step_sizes matches the documented [0.01, 0.01].

The old default [0.022, 0.6] (copied from fit_quantiles) collapses the
grid search, so callers that omit step_sizes get a degenerate fit.
"""
raw = np.load(os.path.join(THIS_FOLDER, "data", "eeg_raw.npy"))
sfreq = 250

# windowed-RMS vector for one channel, as asr_calibrate builds it
# internally (full recording so there are enough windows to matter)
N = int(np.round(0.5 * sfreq))
step = int(np.round(N * (1 - 0.66)))
x = raw[0]
offsets = np.arange(0, len(x) - N, step).astype(int)
csum = np.zeros(len(x) + 1)
np.cumsum(x ** 2, out=csum[1:])
rms = np.sqrt((csum[offsets + N] - csum[offsets]) / N)

mu_default, sig_default, _, _ = fit_eeg_distribution(rms)
mu_explicit, sig_explicit, _, _ = fit_eeg_distribution(
rms, step_sizes=[0.01, 0.01])

# default must match the documented [0.01, 0.01] grid
np.testing.assert_allclose(mu_default, mu_explicit, rtol=1e-9)
np.testing.assert_allclose(sig_default, sig_explicit, rtol=1e-9)

# the old [0.022, 0.6] default is degenerate -> materially different fit
mu_old, sig_old, _, _ = fit_eeg_distribution(rms, step_sizes=[0.022, 0.6])
assert not np.allclose(mu_old, mu_explicit, rtol=1e-9)
assert not np.allclose(sig_old, sig_explicit, rtol=1e-9)


if __name__ == "__main__":
pytest.main([__file__])
# test_yulewalk(250, True)
Expand Down
Loading