From a016f878914c7b22a082b93da41b9ec97c1b1e8a Mon Sep 17 00:00:00 2001 From: skjerns <14980558+skjerns@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:23:57 +0100 Subject: [PATCH 01/13] Add more information to eSSS in examples and docsstring --- doc/references.bib | 11 ++++++++++ mne/utils/docs.py | 5 ++++- .../preprocessing/60_maxwell_filtering_sss.py | 21 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/doc/references.bib b/doc/references.bib index 3b7ddf6dc04..12d63458bd1 100644 --- a/doc/references.bib +++ b/doc/references.bib @@ -813,6 +813,17 @@ @book{Heiman2002 year = {2002} } +@ARTICLE{HelleEtAl2021, + author={Helle, Liisa and Nenonen, Jukka and Larson, Eric and Simola, Juha and Parkkonen, Lauri and Taulu, Samu}, + journal={IEEE Transactions on Biomedical Engineering}, + title={Extended Signal-Space Separation Method for Improved Interference Suppression in MEG}, + year={2021}, + volume={68}, + number={7}, + pages={2211-2221}, + doi={10.1109/TBME.2020.3040373} +} + @article{HippEtAl2011, author = {Hipp, Joerg F. and Engel, Andreas K. and Siegel, Markus}, doi = {10.1016/j.neuron.2010.12.027}, diff --git a/mne/utils/docs.py b/mne/utils/docs.py index fe1bc00d5ef..b9536693030 100644 --- a/mne/utils/docs.py +++ b/mne/utils/docs.py @@ -1559,7 +1559,10 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): docdict["extended_proj_maxwell"] = """ extended_proj : list The empty-room projection vectors used to extend the external - SSS basis (i.e., use eSSS). + SSS basis (i.e., use eSSS). You can use any SSP projectors that contain + pure noise of the structure that you expect in your signal, e.g. by + proj = mne.compute_proj_raw(raw_noise.pick('meg'), n_grad=3, n_mag=3, + meg="separate") .. versionadded:: 0.21 """ diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index 73c0bd5a73f..bb24b5560dc 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -307,6 +307,27 @@ # :func:`~mne.preprocessing.maxwell_filter` for details. # # +# extended SSS (eSSS) +# ^^^^^^^^^^^^^^^^^^ +# +# Extended SSS (eSSS) is a variant of SSS that improves suppression of external +# interference especially, when the “ideal” external model is not perfect +# (e.g., because of small calibration/geometry errors). It does this by +# extending the *external* part of the SSS model with interference patterns +# learned from a separate empty-room recording :footcite:`HelleEtAl2021`. +# +# Practical notes: +# - Keep the number of added components small (the ~8 in the original paper); +# adding too many can worsen numerical conditioning and increase noise. +# - Prefer empty-room data from the same session/environment. +# - eSSS can be combined with tSSS (“teSSS”, i.e. setting `st_duration=X`). +# - you can get projectsion from an empty room recording via +# proj = mne.compute_proj_raw(noise_raw.pick('meg'), n_grad=3, n_mag=3, +# meg="separate") +# You can enabme eSSS by setting ``extended_proj=proj`` in +# :func:`~mne.preprocessing.maxwell_filter`. +# +# # Movement compensation # ^^^^^^^^^^^^^^^^^^^^^ # From 5669888d635049565f132974df9dc2a48f747b8f Mon Sep 17 00:00:00 2001 From: skjerns <14980558+skjerns@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:29:13 +0100 Subject: [PATCH 02/13] improve wording --- mne/utils/docs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mne/utils/docs.py b/mne/utils/docs.py index b9536693030..ea7e06b7405 100644 --- a/mne/utils/docs.py +++ b/mne/utils/docs.py @@ -1559,10 +1559,10 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): docdict["extended_proj_maxwell"] = """ extended_proj : list The empty-room projection vectors used to extend the external - SSS basis (i.e., use eSSS). You can use any SSP projectors that contain - pure noise of the structure that you expect in your signal, e.g. by - proj = mne.compute_proj_raw(raw_noise.pick('meg'), n_grad=3, n_mag=3, - meg="separate") + SSS basis (i.e., use eSSS). You can use any SSP projections that contain + pure *external* noise that you expect to be present in your signal e.g. by + `proj = mne.compute_proj_raw(raw_empty_room.pick('meg'), n_grad=3, n_mag=3, + meg="separate")` .. versionadded:: 0.21 """ From 865d732cde0f02645348e9da114a54ddee87d2af Mon Sep 17 00:00:00 2001 From: skjerns <14980558+skjerns@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:31:39 +0100 Subject: [PATCH 03/13] improve wording --- mne/utils/docs.py | 6 ++++-- tutorials/preprocessing/60_maxwell_filtering_sss.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mne/utils/docs.py b/mne/utils/docs.py index ea7e06b7405..5e7a37dbdff 100644 --- a/mne/utils/docs.py +++ b/mne/utils/docs.py @@ -1560,9 +1560,11 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): extended_proj : list The empty-room projection vectors used to extend the external SSS basis (i.e., use eSSS). You can use any SSP projections that contain - pure *external* noise that you expect to be present in your signal e.g. by + pure *external* noise that you expect to be present in your signal. + Typically, this should be the case during an empty room recording. Get the + projections e.g. by calling `proj = mne.compute_proj_raw(raw_empty_room.pick('meg'), n_grad=3, n_mag=3, - meg="separate")` + meg="combined")` .. versionadded:: 0.21 """ diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index bb24b5560dc..b15e1088ba3 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -323,7 +323,7 @@ # - eSSS can be combined with tSSS (“teSSS”, i.e. setting `st_duration=X`). # - you can get projectsion from an empty room recording via # proj = mne.compute_proj_raw(noise_raw.pick('meg'), n_grad=3, n_mag=3, -# meg="separate") +# meg="combined") # You can enabme eSSS by setting ``extended_proj=proj`` in # :func:`~mne.preprocessing.maxwell_filter`. # From 1352675cdab20f55f889f75bd2925994a7cc8666 Mon Sep 17 00:00:00 2001 From: skjerns <14980558+skjerns@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:37:22 +0100 Subject: [PATCH 04/13] add towncrier rst --- doc/changes/dev/13591.other.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/dev/13591.other.rst diff --git a/doc/changes/dev/13591.other.rst b/doc/changes/dev/13591.other.rst new file mode 100644 index 00000000000..20831356a0a --- /dev/null +++ b/doc/changes/dev/13591.other.rst @@ -0,0 +1 @@ +Documentation improvement for eSSS in docstring :func:`mne.preprocessing.maxwell_filter` and in the MaxFilter example by `Simon Kern`_. From 03f6947341d850dcd83c59176693f7cf476343b1 Mon Sep 17 00:00:00 2001 From: skjerns <14980558+skjerns@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:55:18 +0100 Subject: [PATCH 05/13] fix formatting error --- tutorials/preprocessing/60_maxwell_filtering_sss.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index b15e1088ba3..af500e1cb07 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -320,11 +320,11 @@ # - Keep the number of added components small (the ~8 in the original paper); # adding too many can worsen numerical conditioning and increase noise. # - Prefer empty-room data from the same session/environment. -# - eSSS can be combined with tSSS (“teSSS”, i.e. setting `st_duration=X`). +# - eSSS can be combined with tSSS (“teSSS”, i.e. setting ``st_duration=X``). # - you can get projectsion from an empty room recording via -# proj = mne.compute_proj_raw(noise_raw.pick('meg'), n_grad=3, n_mag=3, -# meg="combined") -# You can enabme eSSS by setting ``extended_proj=proj`` in +# ``proj = mne.compute_proj_raw(noise_raw.pick('meg'), n_grad=3, n_mag=3, +# meg="combined")`` +# You can enable eSSS by setting ``extended_proj=proj`` in # :func:`~mne.preprocessing.maxwell_filter`. # # From e1773954ca03773f6c939763b68a301a6480d457 Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Wed, 14 Jan 2026 09:22:59 -0500 Subject: [PATCH 06/13] Apply suggestions from code review [skip azp] [skip actions] --- mne/utils/docs.py | 8 +++++--- tutorials/preprocessing/60_maxwell_filtering_sss.py | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/mne/utils/docs.py b/mne/utils/docs.py index 5e7a37dbdff..2adb6d12375 100644 --- a/mne/utils/docs.py +++ b/mne/utils/docs.py @@ -1562,9 +1562,11 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): SSS basis (i.e., use eSSS). You can use any SSP projections that contain pure *external* noise that you expect to be present in your signal. Typically, this should be the case during an empty room recording. Get the - projections e.g. by calling - `proj = mne.compute_proj_raw(raw_empty_room.pick('meg'), n_grad=3, n_mag=3, - meg="combined")` + projections e.g. by calling:: + + proj = mne.compute_proj_raw( + raw_empty_room.pick('meg'), n_grad=3, n_mag=3, meg="combined" + ) .. versionadded:: 0.21 """ diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index af500e1cb07..ce4c328dd5b 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -307,7 +307,7 @@ # :func:`~mne.preprocessing.maxwell_filter` for details. # # -# extended SSS (eSSS) +# Extended SSS (eSSS) # ^^^^^^^^^^^^^^^^^^ # # Extended SSS (eSSS) is a variant of SSS that improves suppression of external @@ -322,8 +322,11 @@ # - Prefer empty-room data from the same session/environment. # - eSSS can be combined with tSSS (“teSSS”, i.e. setting ``st_duration=X``). # - you can get projectsion from an empty room recording via -# ``proj = mne.compute_proj_raw(noise_raw.pick('meg'), n_grad=3, n_mag=3, -# meg="combined")`` +# :func:`mne.compute_proj_raw` like:: +# +# proj = mne.compute_proj_raw( +# noise_raw, n_grad=3, n_mag=3, n_eeg=0, meg="combined", +# ) # You can enable eSSS by setting ``extended_proj=proj`` in # :func:`~mne.preprocessing.maxwell_filter`. # From 5678d39562ba319d1cb19546d3759f870fa21911 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:23:18 +0000 Subject: [PATCH 07/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tutorials/preprocessing/60_maxwell_filtering_sss.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index ce4c328dd5b..d08c8c892ef 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -323,7 +323,7 @@ # - eSSS can be combined with tSSS (“teSSS”, i.e. setting ``st_duration=X``). # - you can get projectsion from an empty room recording via # :func:`mne.compute_proj_raw` like:: -# +# # proj = mne.compute_proj_raw( # noise_raw, n_grad=3, n_mag=3, n_eeg=0, meg="combined", # ) From 6e1f7a40ae52438113be2e4e62d084b6fe8e37b1 Mon Sep 17 00:00:00 2001 From: Simon Kern <14980558+skjerns@users.noreply.github.com> Date: Wed, 14 Jan 2026 17:37:41 +0100 Subject: [PATCH 08/13] Add teSSS example link Added external example link for teSSS with movement compensation. --- tutorials/preprocessing/60_maxwell_filtering_sss.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index d08c8c892ef..03895e559ed 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -330,6 +330,10 @@ # You can enable eSSS by setting ``extended_proj=proj`` in # :func:`~mne.preprocessing.maxwell_filter`. # +# An external example using spatiotemporal extended SSS (teSSS) with movement +# compensation can be found at +# `github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG`_. +# # # Movement compensation # ^^^^^^^^^^^^^^^^^^^^^ @@ -401,5 +405,6 @@ # # # .. LINKS -# +# # .. _spherical harmonics: https://en.wikipedia.org/wiki/Spherical_harmonics +# .. _github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG: https://github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG/blob/8dbe1594c8f69486aee5395b3f4fcaef5484f95b/pipeline.py#L118-L147 From f91399b8206f655f9da3afbf939ce4fca7f1851b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 16:37:59 +0000 Subject: [PATCH 09/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tutorials/preprocessing/60_maxwell_filtering_sss.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index 03895e559ed..ad4b8af47d0 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -331,7 +331,7 @@ # :func:`~mne.preprocessing.maxwell_filter`. # # An external example using spatiotemporal extended SSS (teSSS) with movement -# compensation can be found at +# compensation can be found at # `github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG`_. # # @@ -405,6 +405,6 @@ # # # .. LINKS -# +# # .. _spherical harmonics: https://en.wikipedia.org/wiki/Spherical_harmonics # .. _github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG: https://github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG/blob/8dbe1594c8f69486aee5395b3f4fcaef5484f95b/pipeline.py#L118-L147 From 70705589b7865b15db4eda75b475d1eee3db06cb Mon Sep 17 00:00:00 2001 From: Simon Kern <14980558+skjerns@users.noreply.github.com> Date: Wed, 14 Jan 2026 17:41:44 +0100 Subject: [PATCH 10/13] update link --- tutorials/preprocessing/60_maxwell_filtering_sss.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index ad4b8af47d0..32af2a5311b 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -407,4 +407,4 @@ # .. LINKS # # .. _spherical harmonics: https://en.wikipedia.org/wiki/Spherical_harmonics -# .. _github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG: https://github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG/blob/8dbe1594c8f69486aee5395b3f4fcaef5484f95b/pipeline.py#L118-L147 +# .. _github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG: https://github.com/ilabsbrainteam/2022-Best-Practices-Infant-MEG/blob/c62019b4d37a20f0c82420b73595ea241b892a17/pipeline.py#L119-L147 From 6272b9a1f414bd0273fbc593b1a73522a58d1f98 Mon Sep 17 00:00:00 2001 From: skjerns <14980558+skjerns@users.noreply.github.com> Date: Thu, 15 Jan 2026 11:10:11 +0100 Subject: [PATCH 11/13] fix sphinx errors --- tutorials/preprocessing/60_maxwell_filtering_sss.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index 32af2a5311b..e2fc980c68c 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -308,7 +308,7 @@ # # # Extended SSS (eSSS) -# ^^^^^^^^^^^^^^^^^^ +# ^^^^^^^^^^^^^^^^^^^ # # Extended SSS (eSSS) is a variant of SSS that improves suppression of external # interference especially, when the “ideal” external model is not perfect @@ -322,11 +322,13 @@ # - Prefer empty-room data from the same session/environment. # - eSSS can be combined with tSSS (“teSSS”, i.e. setting ``st_duration=X``). # - you can get projectsion from an empty room recording via +# # :func:`mne.compute_proj_raw` like:: # # proj = mne.compute_proj_raw( # noise_raw, n_grad=3, n_mag=3, n_eeg=0, meg="combined", # ) +# # You can enable eSSS by setting ``extended_proj=proj`` in # :func:`~mne.preprocessing.maxwell_filter`. # From eb8ecc4ea13f0ae1ffa92b4d5579c7a9ff0cc1f6 Mon Sep 17 00:00:00 2001 From: skjerns <14980558+skjerns@users.noreply.github.com> Date: Thu, 15 Jan 2026 13:05:44 +0100 Subject: [PATCH 12/13] try to fix sphinx errors --- tutorials/preprocessing/60_maxwell_filtering_sss.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index e2fc980c68c..670294d7178 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -321,8 +321,7 @@ # adding too many can worsen numerical conditioning and increase noise. # - Prefer empty-room data from the same session/environment. # - eSSS can be combined with tSSS (“teSSS”, i.e. setting ``st_duration=X``). -# - you can get projectsion from an empty room recording via -# +# - You can get projections from an empty room recording via # :func:`mne.compute_proj_raw` like:: # # proj = mne.compute_proj_raw( From a84070ecf4c6664caff1bf8f86faf50440dd7de6 Mon Sep 17 00:00:00 2001 From: Simon Kern <14980558+skjerns@users.noreply.github.com> Date: Fri, 16 Jan 2026 09:43:27 +0100 Subject: [PATCH 13/13] add blank line to appease the sphinx --- tutorials/preprocessing/60_maxwell_filtering_sss.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index 670294d7178..70d18dcde6a 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -317,6 +317,7 @@ # learned from a separate empty-room recording :footcite:`HelleEtAl2021`. # # Practical notes: +# # - Keep the number of added components small (the ~8 in the original paper); # adding too many can worsen numerical conditioning and increase noise. # - Prefer empty-room data from the same session/environment.