-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Validated new algorithm for ICA MEG reference channel method #7212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
… correlation thesholds instead of Z score
|
do we have an MNE dataset that allows to illustrate the benefit of this code in an example? |
larsoner
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for datasets, it looks like we use gradient compensation with this dataset:
raw_fname = op.join(data_path, 'MEG', 'bst_resting',
'subj002_spontaneous_20111102_01_AUX.ds')
Can you see if there are some artifacts that can be removed with your method?
If not, maybe one of the other brainstorm datasets?
|
Regarding datasets, I've tried all of the brainstorm, as well as the BTI Phantom. Unfortunately, they're all too clean. There may be an inherent selection bias problem, here: The method focusses on intermittent external noise which isn't corrected by fixed weights solutions, but presumably a dataset which has such intermittent noise would be considered not suitable as an example dataset. |
agramfort
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be really nice to have an example to show how to use this from raw data. Worse case can we use a simulation if we don't have an adapted public dataset we can use?
mne/preprocessing/ica.py
Outdated
| stop=None, l_freq=None, h_freq=None, | ||
| reject_by_annotation=True, verbose=None): | ||
| stop=None, l_freq=None, h_freq=None, method='together', | ||
| reject_by_annotation=True, bad_measure="zscore", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bad_measure -> measure? function already has bads in its name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. Should I also extend this option to EOG and ECG?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to do it for consistency
|
I'll see what I can do with simulated data. There should be a good solution there, somewhere... |
…arameter expanded to EOG/ECG
Codecov Report
@@ Coverage Diff @@
## master #7212 +/- ##
==========================================
- Coverage 89.77% 89.76% -0.02%
==========================================
Files 445 445
Lines 79873 79897 +24
Branches 12773 12781 +8
==========================================
+ Hits 71703 71716 +13
- Misses 5372 5379 +7
- Partials 2798 2802 +4 |
|
Hopefully these cover all the issues in review. The example should follow in a few days. |
|
Artemis data has a reference array that we are currently not using (certainly not effectively) that might be useful for an example. There is 1 second hpi phantom run in the
hpis are at 140hz, 150hz, 160hz everything else is 'noise'. @jshanna100 if that looks promising, I may be able to find subject who I can share, either offline or via some |
|
@jshanna100 any chance to get to this in the next week or two to make it into the 0.20 release? |
|
Possibly within two weeks, definitely not in one. Sorry, a bunch of deadlines with work threw me off track here! |
|
@larsoner @agramfort doing simulations of external noise that also manifest in the reference channels will require also making small modifications to forward and simulate. I already did these a while ago for doing the simulations I needed to validate the methods. They are contained in the refsim branch on my MNE fork. Should we go forward with this? Alternatively, we have a real MEG dataset that demonstrates the technique very well. I'm not sure how conservative you are with adding new datasets... |
Real data would be nicer than simulations I think. You could take your data file and crop it to some suitable length (30 sec? 60 sec?) to demonstrate the method's utility, then we add it as a new |
|
Here is an example of what's needed at the MNE end: |
|
Let me know what you think. The dataset is unfortunately fairly large at around 90MB - also the two full ICA decompositions that run in the example do not get done so quickly. I spent some time trying to get it down as much as I could, but the "together" algorithm does not seem to function well with very short stretches of data. I was able to reduce it by a lot however by downsampling to 100Hz, and throwing out every other magnetometer. |
Have you tried |
and This is going to be our longest-running example, and memory > 1.5 GB is typically problematic because it can cause CircleCI to crash on a full run. Okay if I take a look and see if there is some way to speed it up? and |
mne/preprocessing/ica.py
Outdated
| Method to use to identify reference channel related components. | ||
| Defaults to "together." See notes. | ||
|
|
||
| .. versionadded:: 0.20 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update version
| measure : {'zscore', "cor"} | ||
| Which method to use for finding outliers. "zscore" (default) is | ||
| the iterated Z-scoring method, and "cor" is an absolute raw | ||
| correlation threshold with a range of 0 to 1. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
versionadded
|
One of the two ICA decompositions is actually superfluous, so that now nearly cuts it in half. Picard does not converge, even with the default number of iterations. Presently I have it set at the default "fastica." Feel free to have a go at speeding it up. |
|
Style run failed |
|
Hmm. It's passing on my side. What could be causing the discrepancy? |
| # external magnetic noise | ||
| ref_comps = ica_ref.get_sources(raw_sep) | ||
| for c in ref_comps.ch_names: # they need to have REF_ prefix to be recognised | ||
| ref_comps.rename_channels({c:"REF_" + c}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example this is definitely E231 missing whitespace after :
Did you forget to push? Does make flake actually run on your machine?
I see |
|
Oh, sorry, I see now I forgot to stage the new plot_find_ref_artifacts.py. Here it comes... |
|
I can't push commits because edits by maintainers are not allowed. I also can't seem to open a PR to your repo for some reason, so you can cherry-pick this if you want |
|
That's about a five-fold speed up on my machine. |
|
@jshanna100 in the future you can do: And it would have preserved the history instead of the lines becoming yours. Not a problem here really but can be useful / easier than manual copy-paste + commit of the changes. |
mne/preprocessing/ica.py
Outdated
| ---------- | ||
| .. footbibliography:: | ||
|
|
||
| .. versionadded:: 0.18 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
versionadded should stay in Notes section, not move to References
.circleci/config.yml
Outdated
| python -c "import mne; print(mne.datasets.limo.data_path(subject=1, update_path=True))"; | ||
| fi; | ||
| if [[ $(cat $FNAME | grep -x ".*datasets.*megref_noise.*" | wc -l) -gt 0 ]]; then | ||
| python -c "import mne; print(mne.datasets.megref_noise.data_path(update_path=True))"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two lines must be wrong because CircleCI has the download status:
Looks like megref_noise -> refmeg_noise
Can you check the output and see if it's otherwise how you want it to look?
The topomaps look a bit crazy but that's a separate plotting bug I think (feel free to open an issue), not something you changed here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first plot now looks more cramped than it did before, but I could live with it. Otherwise it seems fine.
I noticed the topomaps as well. My guess is that this is somehow related to throwing out every other channel to reduce the size of the dataset.
larsoner
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks reasonable to me. @drammock do you want to look?
| year = {1989} | ||
| } | ||
|
|
||
| @article{HannaEtAl2020, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs DOI
| .. _ex-megnoise_processing: | ||
|
|
||
| ==================================== | ||
| Find MEG reference channel artefacts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throughout the rest of the docstrings / documentation we use the "artifact" spelling variant (not "artefact"); please change to be consistent.
|
|
||
| Use ICA decompositions of MEG reference channels to remove intermittent noise. | ||
|
|
||
| Many MEG systems have an array of reference channels which are used to remove |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Many MEG systems have an array of reference channels which are used to remove | |
| Many MEG systems have an array of reference channels which are used to detect |
| Use ICA decompositions of MEG reference channels to remove intermittent noise. | ||
|
|
||
| Many MEG systems have an array of reference channels which are used to remove | ||
| external magnetic noise. However, standard removal techniques often fail when |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| external magnetic noise. However, standard removal techniques often fail when | |
| external magnetic noise. However, standard techniques that use reference | |
| channels to remove noise from standard channels often fail when |
|
|
||
| Many MEG systems have an array of reference channels which are used to remove | ||
| external magnetic noise. However, standard removal techniques often fail when | ||
| noise is intermittent. This technique often succeeds where the standard |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| noise is intermittent. This technique often succeeds where the standard | |
| noise is intermittent. The technique described here (using ICA on the reference | |
| channels) often succeeds where the standard |
mne/preprocessing/ica.py
Outdated
| is similar to an EOG/ECG, with reference components replacing the | ||
| EOG/ECG channels. Recommended procedure is to perform ICA separately | ||
| on reference channels, extract them using .get_sources(), and then | ||
| append them to the inst using .add_channels(), preferably with the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| append them to the inst using .add_channels(), preferably with the | |
| append them to the inst using :meth:`~mne.io.Raw.add_channels`, | |
| preferably with the |
mne/preprocessing/ica.py
Outdated
| EOG/ECG channels. Recommended procedure is to perform ICA separately | ||
| on reference channels, extract them using .get_sources(), and then | ||
| append them to the inst using .add_channels(), preferably with the | ||
| prefix REF_ICA so that they can be automatically detected. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| prefix REF_ICA so that they can be automatically detected. | |
| prefix ``REF_ICA`` so that they can be automatically detected. |
mne/preprocessing/ica.py
Outdated
| prefix REF_ICA so that they can be automatically detected. | ||
|
|
||
| Thresholding in both cases is based on adaptive z-scoring: | ||
| The above threshold components will be masked and the z-score will be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| The above threshold components will be masked and the z-score will be | |
| The above-threshold components will be masked and the z-score will be |
mne/preprocessing/ica.py
Outdated
| recomputed until no supra-threshold component remains. | ||
|
|
||
| Validation and further documentation for this technique can be found | ||
| in :footcite:`HannaEtAl2020` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| in :footcite:`HannaEtAl2020` | |
| in :footcite:`HannaEtAl2020`. |
mne/preprocessing/ica.py
Outdated
| If True, data annotated as bad will be omitted. Defaults to True. | ||
|
|
||
| .. versionadded:: 0.14.0 | ||
| measure : {'zscore', "cor"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| measure : {'zscore', "cor"} | |
| measure : 'zscore' | 'cor' |
|
Thanks @drammock, the raw.plot in particular looks much better now. |
|
CircleCI failure is unrelated. Last idea: |
|
Coverage actually looks okay so I think we can ignore that one, too |
|
Commit updated on |
|
I'm away from my computer for the day. I've tried again enabling contributions. If it works, feel free to try any changes. Otherwise I'll add the plot tomorrow. |
Does not seem to work unfortunately |
|
I opened #7810, will merge if CIs come back happy and everything looks okay. Thanks in advance @jshanna100 ! |
This revists the use of ICA decompositions on reference channel data to remove noise from the main channels. This was first implemented in #5807. Adding a 2nd algorithm was discussed in #5959, but ultimately postponed until the method was validated. A validation using simulations has now been successfully carried out, and the results will be published shortly in the Journal of Neuroscience Methods (preprint: https://arxiv.org/abs/2001.03397).
This PR has the following changes: