Skip to content

Speed up notch filter spectrum fit - #14114

Merged
larsoner merged 6 commits into
mne-tools:mainfrom
cbrnr:spectrum-fit
Jul 30, 2026
Merged

Speed up notch filter spectrum fit#14114
larsoner merged 6 commits into
mne-tools:mainfrom
cbrnr:spectrum-fit

Conversation

@cbrnr

@cbrnr cbrnr commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Adding @cache to _get_window_thresh results in a speedup of ~1.85x on my machine (15.48s vs. 8.37s) in the following benchmark:

from pathlib import Path
from time import perf_counter

import numpy as np

import mne
from mne.datasets import sample

mne.set_log_level("WARNING")

fname = Path(sample.data_path()) / "MEG" / "sample" / "sample_audvis_raw.fif"

raw = mne.io.read_raw_fif(fname, preload=True)
raw.crop(tmin=0, tmax=60)

start = perf_counter()
raw.notch_filter(freqs=np.arange(50, 251, 50), method="spectrum_fit")
elapsed = perf_counter() - start
print(f"{elapsed=:.3f}s")

@cbrnr
cbrnr requested review from agramfort and larsoner as code owners July 30, 2026 10:17

@larsoner larsoner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small potential ideas for the future work, but not blockers I think

Comment on lines +277 to +278
# compute FFTs in one batch (faster than looping over tapers but uses more memory)
x_mt = rfft(x[..., np.newaxis, :] * dpss, n=n_fft, axis=-1)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point we might want to make this conditional on the size. If you have like a 2GB file this is going to be painful, and doing it in chunks would be much less so (and not much slower).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll revert this then - it turns out for the notch filter use case, it always receives a single channel anyway, but this could affect other call sites which I didn't think of.

Comment thread mne/filter.py
return xf


@cache

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe better here would be a lru_cache with a maxsize (100?) to prevent it growing without bound. But here the risk is probably low in practice so okay to stay as is (maybe fix next time someone is working in the file)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, I'll do that in a follow-up PR. The risk is minimal in practice, but better to be safe. I'll just use the default of maxsize=128.

@larsoner
larsoner merged commit d58b117 into mne-tools:main Jul 30, 2026
29 checks passed
@larsoner

Copy link
Copy Markdown
Member

Thanks @cbrnr !

@cbrnr
cbrnr deleted the spectrum-fit branch July 31, 2026 05:25
@cbrnr cbrnr mentioned this pull request Jul 31, 2026
larsoner added a commit to larsoner/mne-python that referenced this pull request Aug 4, 2026
* upstream/main: (35 commits)
  Fix bug with coreg scaling (mne-tools#14132)
  MAINT: Update code credit (mne-tools#14131)
  Fix bugs with dark mode panels (mne-tools#14109)
  Improve code credit workflow (mne-tools#14120)
  Align _AbstractRenderer.tube with the PyVista implementation (mne-tools#14125)
  Assign instead of compare when marking explicit zeros in spatio_temporal_dist_adjacency (mne-tools#14124)
  MAINT: Update pre-commit hook versions (mne-tools#14122)
  MAINT: Update dependency specifiers (mne-tools#14121)
  fix: correct typo in comment (mne-tools#14117)
  [dependabot]: Bump the actions group with 2 updates (mne-tools#14123)
  Fix` read_raw_eyelink()` failure when recording blocks are empty or starting with empty values (mne-tools#13571)
  ENH: Add `event_key` parameter to `read_raw_egi` for MFF event metadata (mne-tools#14086)
  fix for scipy sparse deprecations (mne-tools#14118)
  Fix notch spectrum fit (mne-tools#14116)
  Speed up notch filter spectrum fit (mne-tools#14114)
  fix MNE-RT links and update roadmap (mne-tools#14096)
  Clarify `docdict["filter_length_notch"]` (mne-tools#14113)
  Refactor test_plot_alignment_basic() (mne-tools#13472)
  BUG: Cleanup cHPI filtering using smooth interpolation (mne-tools#14112)
  Use redirector app (mne-tools#14111)
  ...

# Conflicts:
#	mne/tests/test_filter.py
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.

2 participants