methlabUZH / automagic

Automagic
GNU General Public License v3.0
89 stars 32 forks source link

Problem with reference channel when calling PREP #46

Closed ramBrain closed 2 years ago

ramBrain commented 3 years ago

Dear developers,

I have found a possible issue in the way the pipeline handles the reference channel when PREP is called.

If a reference channel is specified, there is a first attempt to remove it in preprocess.m (around line 169). However in performPrep.m there is a second attempt to remove the reference channel (line 61), which assumes that the current list of channel indices goes from 1 to the current number of channels. If for instance my reference channel is 48 (i.e. Cz in Biosemi 64), and this channel was already removed in preprocess.m, in performPrep.m channels indices will be [1 2 3 … 63]. This vector will include a channel indexed as 48, which will be removed again. Through this attempt, an EEG channel is wrongly assigned as EOG, since there is an attempt to define EOG channels without testing whether there is any EOG channel as input, and this causes errors at later stages of the pipeline.

I think I found a possible fix to this issue, which consists of:

• \preprocessing\performPrep.m: I commented any attempt to deal with the reference channel, including line 61 and where ‘referenceChannels’, ‘evaluationChannels’ and ‘reference’ for the prepPipeline.m are defined.

• In the same function, I made the definition of EOG channels more robust by first testing whether there is any as input. This results in:

if ~isempty(EOG_in.data)
    eog_chans = setdiff(1: EEG_in.nbchan + EOG_in.nbchan, eeg_chans); %#ok<NASGU>
else
    eog_chans=[];
end

• \preprocessing\preprocess.m: line 400, I am not sure why there is an attempt again to remove the reference channel at this point of the pipeline. I replaced EEG.automagic.autoBadChans = setdiff(removedChans, EEGSystem.refChan.idx) with:

% Write back output
if ~isempty(EEGSystem.refChan) 
%     EEG.automagic.autoBadChans = setdiff(removedChans, EEGSystem.refChan.idx);
    removedChans(removedChans > EEGSystem.refChan.idx)=removedChans(removedChans > EEGSystem.refChan.idx)+1;
    EEG.automagic.autoBadChans = removedChans;
else
    EEG.automagic.autoBadChans = removedChans;
end

This fix was needed as when reintroducing the reference channel, in the data viewer the blue lines and the red stars on the bad channels with index higher than the reference were shifted negatively by 1.

I tested the pipeline with PREP, ZapLine, filters and ICLabel, and seems to work smoothly. I did not test with any possible combination of methods to see whether there is any unexpected error associated with my fixes.

What do you think about my changes? Please let me know if any of these looks wrong, “dangerous” or whether I am ignoring any aspect that might make this changes incompatible with other parts of the pipeline.

Many thanks for considering my comments.

Ramtin

ksgfan commented 3 years ago

Hi Ramtin

that is also a bug and this error occurs when the reference is not the last channel in EEG.chanlocs. I tested your code and it works well. Thanks for fixing that!

Best, Dawid

ramBrain commented 3 years ago

Hi Dawid,

I worked with the EGI system in the past, and I thought indeed that you could have been "blind" to this bug as reference is the last channel on that system.

Thank you! Ramtin

ramBrain commented 3 years ago

Hi Dawid,

I apologise, but there is a little inaccuracy in my fix. Specifically, when reitroducing the reference channel it should be:

% Write back output
if ~isempty(EEGSystem.refChan) 
%     EEG.automagic.autoBadChans = setdiff(removedChans, EEGSystem.refChan.idx);
    removedChans(removedChans >= EEGSystem.refChan.idx)=removedChans(removedChans >= EEGSystem.refChan.idx)+1;
    EEG.automagic.autoBadChans = removedChans;
else
    EEG.automagic.autoBadChans = removedChans;
end

I.E. the test should be >= rather than only >.

Otherwise, let's suppose that 48 is the reference channel and it is removed before preprocessing; if the new channel 48 (i.e. former 49) is deemed as bad, it will not be correctly selected.

It happened luckily with one of my dataset, so I could notice it!