mne-tools / mne-python

MNE: Magnetoencephalography (MEG) and Electroencephalography (EEG) in Python
https://mne.tools
BSD 3-Clause "New" or "Revised" License
2.73k stars 1.32k forks source link

[Question] remove EOG / ECG artifacts from EEG signal #3757

Closed ppasler closed 7 years ago

ppasler commented 8 years ago

Hi there,

I tried to run the tutorial Compute ICA on MEG data and remove artifacts with my own data.

I have several problems with it:

Any tips or hints will be appreciated - tanks in advance, paul

This is how I load my own data:

def createInfo(filePath):
    with open(filePath, 'rb') as f:
        ch_names = f.readline().strip().split(",")
    ch_types = ["eeg"] * len(ch_names)
    sfreq = 128
    montage = mne.channels.read_montage("standard_1020")
    info = mne.create_info(ch_names, sfreq, ch_types, montage)
    return info

def createRawObject(filePath):
    info = createInfo(filePath)
    data = np.swapaxes(np.delete(np.genfromtxt(filePath, dtype=float, delimiter=","), 0, 0),0,1)
    return mne.io.RawArray(data, info)

filePath = "test_data.txt"
raw = createRawObject(filePath)
raw.filter(1, 45, n_jobs=1, l_trans_bandwidth=0.5, h_trans_bandwidth=0.5,
           filter_length='10s', phase='zero-double')

test_data.txt

mmagnuski commented 8 years ago
ppasler commented 8 years ago

Hey @mmagnuski, thanks for clearing things a bit.

  1. I will try to figure out a good threshold.
  2. I don't have a ecg channel. I thought create_ecg_epochs creates a synthetic channel, but the documentation sais ...a synthetic ECG channel is created from cross channel average. Synthetic channel can only be created from ‘meg’ channels. As I only have EEG channels, this will not work.
  3. Thanks for the link, I missed this one...

Do you have a tip which EEG channels are useful to create "synthetic" EOG / ECG channels?

mmagnuski commented 8 years ago

No tips for ECG, sorry - I've always been spotting these components (and some others such as muscle artifacts) by myself - I never trusted automatic methods enough. For EOG - you can use for example the difference between left and right frontal channels, but detecting blinks and eye movements is where template-matching methods (see corrmap) work really well.

ppasler commented 8 years ago

Thanks, I will work through the corrmap example with my data. I will record an ECG for my next data acquisition and try to remove EMG with inertial motion sensors. So the only "problem" is the EOG.

Just a few comments to the Artifact Correction with ICA tutorial (I am using v0.14.dev0).

1) I throws deprecation warnings in plot_artifacts_correction_ica.py:33 Multiple deprecated filter parameters were used:

2) With Windows you also get

raise ImportError('[joblib] Attempting to do parallel computing '
ImportError: [joblib] Attempting to do parallel computing without protecting your import on a system that does not support forking. To use parallel-computing in a script, you must protect your main loop using "if __name__ == '__main__'". Please see the joblib documentation on Parallel for more information

As the error says, this can be solved by putting the whole code in a method and calling it with

def tutorial():
    # code

if __name__ == '__main__':
    tutorial()
dengemann commented 8 years ago

Do you have a tip which EEG channels are useful to create "synthetic" EOG / ECG channels?

Hi there, this should probably be changed to give a more informative error message for EEG only inputs. Currently we extract the ECG by averaging magnetometers if we find any. This of course only works if you have MEG.

On Fri, Nov 11, 2016 at 10:05 AM ppasler notifications@github.com wrote:

Hey @mmagnuski https://github.com/mmagnuski, thanks for clearing things a bit.

  1. I will try to figure out a good threshold.
  2. I don't have a ecg channel. I thought create_ecg_epochs creates a synthetic channel, but the documentation sais ...a synthetic ECG channel is created from cross channel average. Synthetic channel can only be created from ‘meg’ channels. As I only have EEG channels, this will not work.
  3. Thanks for the link, I missed this one...

Do you have a tip which EEG channels are useful to create "synthetic" EOG / ECG channels?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mne-tools/mne-python/issues/3757#issuecomment-259912954, or mute the thread https://github.com/notifications/unsubscribe-auth/AB0fis54EewF97CtA4-jeVyNer6zR_Cnks5q9C_egaJpZM4Kutn4 .

mmagnuski commented 8 years ago

1) these are messages from 0.13 indicating change in filter defaults, they will be removed in 0.14, so no worries. :) 2) this is a known issue with multiprocessing on windows. I never had it in jupyter (notebook/console) - only in standalone scripts IIRC. Apart from if __name__ == '__main__': you can also set all n_jobs arguments to 1 (then no multiprocessing is performed so you don't get this error).

ppasler commented 8 years ago

@dengemann thanks for clearing this. I am just curious, why does the synthetic EOG / ECG channel (= estimating EOG / ECG from MEG?) only works with MEG, shouldn't it be also possible with an EEG? I thought I read somewhere, that this is also done with EEG signals.

@mmagnuski

  1. alright, after releasing 0.14 this the tutorial might be adjusted?
  2. The error message gives the hint needed to fix this on windows, so this is fine. Although this isn't a mne problem, you might insert it to your documentation?
ppasler commented 7 years ago

Hi @mmagnuski, I've been working through the Corrmap Tutorial. Although the headline says "What if we don’t have an EOG channel?", an EOG channel is used as reference. How can I choose my template without a reference EOG?

icas = [reference_ica] + icas_from_other_data
template = (0, eog_inds[0])

fig_template, fig_detected = corrmap(icas, template=template, label="blinks",
                                     show=True, threshold=.8, ch_type='mag')

There's a comment about the topmaps above this headline Component properties ica.plot_components() # can you spot some potential bad guys? I can't spot the bad guys, could anyone explain where they are and why?

Thanks in advance

ppasler commented 7 years ago

I tried several index combinations as template and this combination serves the following plot. I am not very familiar with topo maps and the whole corrmap procedure. Can anyone explain the plots to me? corrmap_plot

jona-sassenhagen commented 7 years ago

@ppasler, where are you getting the channel locations from?

ppasler commented 7 years ago

@jona-sassenhagen which channel locations do you mean?

Maybe you mean this: I ran through every possible tuple combination for the template

 for i in range(len(icas)):
    for j in range(n_components):
        template = (i, j)
        fig_template, fig_detected = corrmap(icas, template=template, label="blinks",
                                         show=False, ch_type='eeg', verbose=True)

And got two types of message:

If the first one appeared, I thought this could work.

jona-sassenhagen commented 7 years ago

I mean, where are you getting your montage from when importing the raw files?

Also, you can use ica.plot_properties to see which components look like blinks.

mmagnuski commented 7 years ago

@ppasler

How can I choose my template without a reference EOG?

As @jona-sassenhagen suggests, look at your topomaps and component properties. I would suggest using the interactive mode explained in the tutorial (plot_components with passing your raw/epochs to inst arg) - then you see the topomaps but can also click them for properties panel (this only works in interactive matplotlib mode ie. not in inline mode). Eyeblink component will look different in EEG and MEG - in EEG it should be a clear blob around the eyes: similar to this. But you can also have eye movement components: similar to this. I've had an infographic for student with different component types (including heart and muscle artifacts) - I can try to dig it up tomorrow. But then - in real life the components (especially those not eye-related) are usually not that clear and obvious as those shown in examples and guides. 😃

If you have suggestions for the tutorial to be easier to follow/understand - please share them.

mmagnuski commented 7 years ago

BTW - depending on whether your montage is correct and your coverage as sparse as your topomap suggests - the components you found through corrmap may be even a single bad channel - notice that the interpolation can play tricks on your eyes if the coverage is sparse. Another possibility is that your subjects blink with their ears ;)

jona-sassenhagen commented 7 years ago

I have a hunch he could be falling prey to #3755

mmagnuski commented 7 years ago

It's probable (that's the ear-blink hypothesis :) ) @ppasler - one more clarification - do not check all possible templates for corrmap, first find one that is definitely an eye-blink / eye-movement and than use this one ic as template.

ppasler commented 7 years ago

Thanks guys, your answer cleared many things :) The images helped and I would appreciate any further information (especially made for noobs). To exclude #3755 I could install the bugfix branch and try it again?

I'll have a look at the interactive mode and record some "clear blinks" to have a reference (Maybe also some with ear-blinks...). Good hint with the bad channels, I'll check that first.

After getting my stuff to work, I will suggest some things that were unclear for me in the tutorial.

ppasler commented 7 years ago

If I understood this right, this is a good plot (with location near the eyes). Is this saying, that subj. 0 has its eog artefacts in IC 0; Subj.1 in IC 2 and so on? corrmap_plot_2

jona-sassenhagen commented 7 years ago

Possibly - the electrode sampling is very sparse - check plot_properties on one of the components and look at the time course.

ppasler commented 7 years ago

@jona-sassenhagen as far as I can tell, #3755 had no effect to the topo maps.

ppasler commented 7 years ago

@mmagnuski I'm not 100% done yet, but here's a thing that would help me in the tutorial. I stumbled over the comment in line 72 (can you spot some potential bad guys?). Maybe it would go to far to explain where and why there are bad guys, but it would help me understand what we are looking for. For example something as explained here Prototypical EEG Artifact Independent Components. Maybe explaining topomaps is an extra tutorial.

Furthermore a glossary would be nice, where some general and mne specific terms are shortly explained. But I am aware, that you guys can't explain the whole meg / eeg processing from scratch.

jona-sassenhagen commented 7 years ago

I'm not sure MNE must provide an explanation of when and how to use an algorithm. CORRMAP is described in a paper, which we reference. Similarly, ICA components and ICA correction are described in countless papers. You should certainly read these papers over the MNE API docs.

ppasler commented 7 years ago

@jona-sassenhagen I do that and will read some more. But as you have tutorials, I just note the things that were unclear to me. Don't take it as a command, but as a proposal :)

I agree that working through the tutorials won't prevent from reading other literature. It's just that the entry to the whole topic might be a bit easier.

mmagnuski commented 7 years ago

I definitelly agree there should be some explanation to why some components are bad and examples of prototypical artifact IC's. It just wasn't easy to do previously (IC's were not sorted by explained variance) - but currently still will not work perfectly - ICA is undeterministic, so the order of IC (even when sorted) can change from run to run a bit and all the tutorials/docs are created dynamically. Maybe we should just link to some other page that shows the prototypical IC's (at least just for now)? BTW - is there support for more static docs (mne manual seems to work this way)?

ppasler commented 7 years ago

Hey @mmagnuski, I've recorded some EEG Signals with blinks every 5 seconds. I was really surprised how clear they appear in the signal (picture shows AF3 sensor): blink_af3

The source plot of the recorded template ICA shows clearly the blinks in IC 0. blink_ica Does anyone know what IC 3 could be? It does not look like the others

blink_match So I used this as template for the corrmap algorithm. I had to use a threshold of 0.85 to match with all subjects. Is this enough?

Now I exclude the found ICs, call get_source and the blink artifact should be gone?

jona-sassenhagen commented 7 years ago

Try ica.plot_properties(inst, picks=...) to investigate specific components.

I had to use a threshold of 0.85 to match with all subjects. Is this enough?

See what your data looks like using this correction. Did you catch all blink activity?

call get_source

raw_cleaned = ica.apply(inst, exclude=ica.labels_["your_labels"])

ppasler commented 7 years ago

@jona-sassenhagen Thank you!

I think it worked (for my template recording), the humps are gone :) blink_before_after

Do anyone know what IC 3 could be (picture from my previous comment)? It does not look like the others.

jona-sassenhagen commented 7 years ago

Do anyone know what IC 3 could be (picture from my previous comment)? It does not look like the others.

Try ica.plot_properties(inst, picks=...) to investigate specific components.

ppasler commented 7 years ago

I not familiar with IC patterns and the properties did not provide any useful information to me. I just thought this "saw-tooth" pattern is somehow known.

ppasler commented 7 years ago

@mmagnuski @dengemann @jona-sassenhagen thanks for the support, this was good and motivating starting point for me.

As I am done with finding at least one artifact. I have some improvements for the tutorial.

Last question here: Could the IC 3 be a pulse artifact? blink_ica

jona-sassenhagen commented 7 years ago

Is the data from a dry EEG?

I agree, the ICA tutorial should show how to get to cleaned data, and what it looks like compared to contaminated data.

@mmagnuski maybe you're bored right now ...

ppasler commented 7 years ago

@jona-sassenhagen what do you mean by "dry EEG"? It is a 14-channel EEG, without extra ECG or EOG sensors.

mmagnuski commented 7 years ago

@jona-sassenhagen not really bored now :grin: (although being back to Poland the lack of sun is even more painful :cloud_with_snow: :cloud: ). I'll try to take a closer look into it in not so distant future (along with other mne todos that I have gathered lately).