Repository: mne-tools/mne-python

Issue:
maxwell_filter does not remove MEG projectors
Hi
The mne.preprocessing.maxwell_filter function does not remove the initial Acquisition MEG projectors from the data like the Elekta MaxFilter does. Could this be implemented?

Thanks,
Maggie



Discussion:
Yeah, we should get rid of the MEG projectors in `info` when applying `maxwell_filter`. I can take care of it this week.


Resolving patch:
diff --git a/mne/epochs.py b/mne/epochs.py
--- a/mne/epochs.py
+++ b/mne/epochs.py
@@ -2749,7 +2749,8 @@ def average_movements(epochs, head_pos=None, orig_sfreq=None, picks=None,
     from .preprocessing.maxwell import (_trans_sss_basis, _reset_meg_bads,
                                         _check_usable, _col_norm_pinv,
                                         _get_n_moments, _get_mf_picks,
-                                        _prep_mf_coils, _check_destination)
+                                        _prep_mf_coils, _check_destination,
+                                        _remove_meg_projs)
     if pos is not None:
         head_pos = pos
         warnings.warn('pos has been replaced by head_pos and will be removed '
@@ -2856,5 +2857,6 @@ def average_movements(epochs, head_pos=None, orig_sfreq=None, picks=None,
         data[meg_picks] = np.dot(mapping, data[good_picks])
     evoked = epochs._evoked_from_epoch_data(
         data, info_to, picks, count, 'average')
+    _remove_meg_projs(evoked)  # remove MEG projectors, they won't apply now
     logger.info('Created Evoked dataset from %s epochs' % (count,))
     return (evoked, mapping) if return_mapping else evoked
diff --git a/mne/preprocessing/maxwell.py b/mne/preprocessing/maxwell.py
--- a/mne/preprocessing/maxwell.py
+++ b/mne/preprocessing/maxwell.py
@@ -255,6 +255,7 @@ def maxwell_filter(raw, origin='auto', int_order=8, ext_order=3,
     raw_sss, pos_picks = _copy_preload_add_channels(
         raw, add_channels=head_pos[0] is not None)
     del raw
+    _remove_meg_projs(raw_sss)  # remove MEG projectors, they won't apply now
     info, times = raw_sss.info, raw_sss.times
     meg_picks, mag_picks, grad_picks, good_picks, coil_scale, mag_or_fine = \
         _get_mf_picks(info, int_order, ext_order, ignore_ref, mag_scale=100.)
@@ -454,6 +455,17 @@ def maxwell_filter(raw, origin='auto', int_order=8, ext_order=3,
     return raw_sss
 
 
+def _remove_meg_projs(inst):
+    """Helper to remove inplace existing MEG projectors (assumes inactive)"""
+    meg_picks = pick_types(inst.info, meg=True, exclude=[])
+    meg_channels = [inst.ch_names[pi] for pi in meg_picks]
+    non_meg_proj = list()
+    for proj in inst.info['projs']:
+        if not any(c in meg_channels for c in proj['data']['col_names']):
+            non_meg_proj.append(proj)
+    inst.add_proj(non_meg_proj, remove_existing=True)
+
+
 def _check_destination(destination, info, head_frame):
     """Helper to triage our reconstruction trans"""
     if destination is None:


Test patch:
diff --git a/mne/preprocessing/tests/test_maxwell.py b/mne/preprocessing/tests/test_maxwell.py
--- a/mne/preprocessing/tests/test_maxwell.py
+++ b/mne/preprocessing/tests/test_maxwell.py
@@ -354,8 +354,11 @@ def test_basic():
     assert_equal(_get_n_moments([int_order, ext_order]).sum(), nbases)
 
     # Test SSS computation at the standard head origin
+    assert_equal(len(raw.info['projs']), 12)  # 11 MEG projs + 1 AVG EEG
     raw_sss = maxwell_filter(raw, origin=mf_head_origin, regularize=None,
                              bad_condition='ignore')
+    assert_equal(len(raw_sss.info['projs']), 1)  # avg EEG
+    assert_equal(raw_sss.info['projs'][0]['desc'], 'Average EEG reference')
     assert_meg_snr(raw_sss, Raw(sss_std_fname), 200., 1000.)
     py_cal = raw_sss.info['proc_history'][0]['max_info']['sss_cal']
     assert_equal(len(py_cal), 0)