Skip to content

feat(sound, sspsir): SOUND and SSP-SIR forward-model denoisers (#32)#46

Open
snesmaeili wants to merge 4 commits into
mainfrom
feat/sound-sspsir-issue-32
Open

feat(sound, sspsir): SOUND and SSP-SIR forward-model denoisers (#32)#46
snesmaeili wants to merge 4 commits into
mainfrom
feat/sound-sspsir-issue-32

Conversation

@snesmaeili

Copy link
Copy Markdown
Contributor

Closes #32.

Adds Python ports of two leadfield-based M/EEG denoisers by Tuomas Mutanen,
previously available only in MATLAB (EEGLAB TESA / the Sound-Demo-Package), as
requested by @matteo-d-m. Both are sklearn-style fit/transform estimators
that work on MNE Raw/Epochs/Evoked objects or plain arrays.

What's included

  • mne_denoise.sound.SOUND (Mutanen et al., 2018) — automatic, robust noise
    suppression for EEG/MEG. SOUND iteratively estimates every sensor's noise
    amplitude by predicting it from all the other sensors through a forward model
    (a leave-one-channel-out minimum-norm estimate), then applies a Wiener filter
    that suppresses channel-specific noise while preserving field-consistent brain
    signal.
  • mne_denoise.sspsir.SSPSIR (Mutanen et al., 2016) — suppression of
    TMS-evoked muscle artifacts. It projects out the high-variance muscle-artifact
    subspace (SSP) and reconstructs the brain signal lost to that projection
    through the forward model (source-informed reconstruction). Supports automatic
    high-frequency artifact detection or a user-specified art_window, and an
    integer PC count or a variance fraction. This is conceptually SSP followed by
    the same reconstruction MNE exposes as proj=\"reconstruct\".
  • mne_denoise._leadfield.make_spherical_leadfield — builds a three-layer
    spherical lead field from the montage via MNE's forward solver
    (make_sphere_modelsetup_volume_source_spacemake_forward_solution)
    when no individual forward model is supplied. Both estimators also accept a
    custom mne.Forward.

Implementation notes

  • Reimplemented from the algorithms in the reference papers and the reference
    MATLAB (Sound-Demo-Package, tesa_sound.m, tesa_sspsir.m) — not copied —
    so the result is original BSD code. SOUND's cleaning operator is expressed in
    the efficient L Lᵀ form (no per-channel source-space products), which is
    numerically equivalent to the reference loop.
  • The spherical defaults match the originals (radii 81/85/88 mm, conductivities
    0.33 / 0.0066 / 0.33 S/m); for best results an individual mne.Forward should
    be supplied.

Tests

tests/test_leadfield.py, tests/test_sound.py, tests/test_sspsir.py
synthetic property tests (no MATLAB ground truth needed): the lead field spans
the sensor space and is average-referenced; SOUND flags and suppresses a
corrupted channel while preserving the others and converges; SSP-SIR removes an
injected muscle-like artifact (~variance drop) while preserving a dipolar brain
source (corr > 0.95); plus the array/forward paths and error cases. Full suite
green locally (545 passed, 11 skipped — the skips are the MATLAB parity tests).

Follow-up

  • A gallery example and an optional time-varying (artifact-window-weighted)
    SSP-SIR application mode can come in a follow-up; this PR ships the uniform
    operator, which is the cleanest and most predictable.

…oses #32)

Port two leadfield-based M/EEG denoisers by Tuomas Mutanen, previously
MATLAB-only, requested in issue #32.

- mne_denoise.sound.SOUND (Mutanen et al. 2018): automatic, robust noise
  suppression. Iteratively estimates each sensor's noise amplitude by
  predicting it from the other sensors through a forward model, then applies a
  Wiener filter preserving field-consistent signal.
- mne_denoise.sspsir.SSPSIR (Mutanen et al. 2016): suppresses TMS-evoked muscle
  artifacts by projecting out the high-variance artifact subspace and
  reconstructing the brain signal through the forward model (source-informed
  reconstruction), with automatic high-frequency detection or a manual window.
- mne_denoise._leadfield.make_spherical_leadfield builds a three-layer
  spherical lead field from the montage via MNE's forward solver when no
  individual forward model is supplied; both estimators also accept a custom
  mne.Forward.

Both follow the sklearn fit/transform API and work on Raw/Epochs/Evoked or
arrays. Reimplemented from the algorithms in the reference papers and the
Sound-Demo-Package / TESA MATLAB sources.
Add tests fitting SOUND and SSP-SIR on plain arrays with a supplied forward,
plus the channel-count mismatch and missing-positions error paths.
@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.02439% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.06%. Comparing base (c097b7d) to head (df85388).

Files with missing lines Patch % Lines
mne_denoise/sspsir/core.py 97.72% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #46      +/-   ##
==========================================
+ Coverage   95.93%   96.06%   +0.13%     
==========================================
  Files          41       46       +5     
  Lines        4599     4803     +204     
  Branches      849      872      +23     
==========================================
+ Hits         4412     4614     +202     
- Misses         88       89       +1     
- Partials       99      100       +1     
Flag Coverage Δ
unittests 96.06% <99.02%> (+0.13%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
mne_denoise/__init__.py 100.00% <100.00%> (ø)
mne_denoise/_leadfield.py 100.00% <100.00%> (ø)
mne_denoise/sound/__init__.py 100.00% <100.00%> (ø)
mne_denoise/sound/core.py 100.00% <100.00%> (ø)
mne_denoise/sspsir/__init__.py 100.00% <100.00%> (ø)
mne_denoise/sspsir/core.py 97.72% <97.72%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@snesmaeili snesmaeili requested a review from BabaSanfour June 10, 2026 08:05
…d outputs

compute_sound and compute_sspsir_operator were verified against the original
Mutanen MATLAB (SOUND.m, tesa_sspsir) to machine precision via Octave; Octave is
not in CI, so these regression tests lock the validated numerics in.
Reference parity (machine precision), SOUND noise-estimation correlation (0.98)
and SSP-SIR topography recovery (CC 0.95 / RE 32%, robust across M) reproducing
Mutanen et al. 2016/2018.
@snesmaeili

Copy link
Copy Markdown
Contributor Author

Validation against the original papers + reference MATLAB

I validated the SOUND and SSP-SIR reimplementations on the Alliance Fir cluster — GNU Octave 7.2 to run Mutanen's original MATLAB, and Python/MNE for the simulation studies. Full report + data: validation/sound_sspsir/.

1. Reference parity (correctness proof)

Identical inputs fed to the Python code and to the original MATLAB (SOUND.m, DDWiener.m, and the SSP-SIR core of tesa_sspsir.m) run under Octave — outputs agree to machine precision:

Quantity Python vs MATLAB rel-diff
SOUND noise sigma 2.1e-16
SOUND corrected data 8.0e-16
SSP-SIR cleaned data 3.9e-15

A golden-value regression test (tests/test_sound_sspsir_golden.py) pins this in CI, since Octave isn't available there.

2. Simulation reproduction

Metric This PR Paper
SOUND noise-estimation correlation (SNR=1, NCI=3) 0.980 ~0.98 — Mutanen 2018, Fig 3
SSP-SIR recovery (M=30) CC 0.953, 93% > 0.9, RE 32% CC 0.94-0.97, 84-94%, RE 21-36% — Mutanen 2016
SSP-SIR robustness across SIR truncation M CC 0.92-0.95 ~0.94
SSP-SIR uncleaned baseline CC 0.11 / RE 948% 0.17-0.23 / 700-1200%

SOUND validation
SSP-SIR validation

Caveat: the papers' real-data panels use private TMS-EEG/MEG recordings (HeadIT is defunct), so those exact figures can't be reproduced on identical data — the ground-truth simulations + the machine-precision parity are the rigorous substitute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add SOUND and SSP-SIR algorithms

1 participant