fieldtrip artifact-rejection

Robert Oostenveld R.Oostenveld at FCDONDERS.RU.NL
Wed May 17 12:09:21 CEST 2006


Hi Markus,

I hope that you don't mind moving this thread over to the discussion
list, since other people also might be interested and/or want to
contribute.

On 16 May 2006, at 19:58, Markus Bauer wrote:
> I have started working on some EEG data today. I found the artifact
> rejection tools not totally satisfying for EEG data.
> In case you're interested I would be happy working on it, then we
> could discuss how to best do it.
> If you want to keep it like it is, I'll just make my own solution.

The artifact stuff is also not completely to my likings, so I am open
for suggestions (especially if you are willing to aid in implementing
the suggestions).

> Here are the major shortcomings, I have encountered:
> Particularly the lack of a (partial) rejection-tool for fixed
> amplitude thresholds makes life difficult and partial artifact
> rejection for EEG non-usable.

artifact_threshold already does this, but not for partial rejection.
It would be trivial to adapt it for partial artifacts.

> Often after muscle and EOG correction big spikes are remaining in
> the data, these cannot be taken care of, without doing total
> rejection of trial. I do not fully understand why such a function
> should be incompatible with partial rejection  - didn't understand
> your comment in the header (with min max) either.

which comment in which header? If you refer to artifact_threshold,
then see my previous comment that it could easily be enhanced for
partial rejection support.

> The artifact-markers in the EOG-routine are very often phase
> shifted with respect to the blink - such that the initial part of
> the blink is taken well care of (plus additional unaffected data),
> the later part is often not covered, even when specifying 0.15s or
> more. I have never seen the opposite case so far.

Could well be.

> I guess it has to do with the hilbert transform.

I don't think that that is the reason, I more expect it to be due to
a fast rising flank of the EOG followed by a slower falling flank.
But have not looked at enough experimental data myself to be sure.

> Since only a symmetric "artefact-padding" is allowed, data are
> often wasted/artefacts not taken well care of.

It would be fine with me to support both
    cfg.artfctdef.zvalue.artpadding  = val
and
    cfg.artfctdef.zvalue.artpadding  = [preval, postval]

This is also something that Marcel Bastiaansen suggested to me some
time ago.

> Also for EOG and muscle, the option for using absolute thresholds
> on the specially treated data could be helpful (with partial
> rejection), it has been taken out - is there a concrete reason ??

The old code for jump/eog/muscle was a mixture of combined z-values
over channels on one hand and plain thresholding of preprocessed data
on the other hand. Since the plain thresholding is also available in
artifact_threshold, I saw no reason to reimplement it in the new
functions. I want to prevent replicating functionality.

> I know that everybody can write their own custom functions, but I'm
> sure others will make same experiences.

Yes, I do prefer to improve the existing functions instead of
everyone writing their own.

> Another thing - I think it would be ideal to do the artifact
> rejection on all the conditions simultaneously to make sure that
> the same criteria are applied to the data of all conditions
> (particularly when only relative thresholds - zvalues - are used).
> Practically this would mean that one would use the artefact
> rejected cfg-structure - i.e. the result of rejectartifact - to
> later extract the conditions from those and then do preprocessing.

That is already possible in two ways, e.g. with two conditions one
could do this:

cfg1 = ...
cfg1 = definetrial(cfg1)
cfg2 = ...
cfg2 = definetrial(cfg1)

cfgall = ...
cfgall.trl = cat(2,cfg1.trl, cfg2.trl)  % combine all data segments
of interest
cfgall.artifact.eog = ...
cfgall = artifact_eog(cfgall)           % detect EOG artifacts in the
data segments of both conditions
cfgall.artifact.muscle = ...
cfgall = artifact_msucle(cfgall)        % detect Muscle artifacts in
the data segments of both conditions

cfg1.artifact = cfgall.artifact         % copy the detected artifacts
cfg1 = rejectartifact(cfg1)             % and reject the data
segments that overlap with an artifact
raw1 = preprocessing(cfg1);

cfg2.artifact = cfgall.artifact         % copy the detected artifacts
cfg2 = rejectartifact(cfg2)             % and reject the data
segments that overlap with an artifact
raw2 = preprocessing(cfg2);

The other way of realising this is by using recodeevent, which is
even more flexible. It might look like this

cfg1 = ...
cfg1 = definetrial(cfg1)
cfg2 = ...
cfg2 = definetrial(cfg1)
cfgall = ...
cfgall.trl = cat(2,cfg1.trl, cfg2.trl)  % alternatively you could use
only one trialfun for both

cfgall.artifact.eog = ...
cfgall = artifact_eog(cfgall)           % detect EOG artifacts in the
data segments of both conditions
cfgall.artifact.muscle = ...
cfgall = artifact_msucle(cfgall)        % detect Muscle artifacts in
the data segments of both conditions

cfgall = rejectartifact(cfgall)
rawall = preprocessing(cfgall)

cfg = ...
cfg.keeptrial = 'yes'
freqall = freqanalysis(cfg, rawall)

cfg = ...
cfg.output = 'eventvalue'
trigger = recodeevent(cfg, rawall)
sel1 = find(trigger==1);
sel2 = find(trigger==2);
freq1 = freqall;
freq1.powspctrm = freq1.powspctrm(sel1,:,:)
freq2 = freqall;
freq2.powspctrm = freq2.powspctrm(sel2,:,:)

Retrieving the match between the implicit events and the trial
segments could be done at various stages of the analysis, i.e. you
could even beam with singletrials and common filters for both
conditions, and sort the single trial estimates of power at the
source level after that.

> I have my own function that is capable of doing that, but since
> this may in principle be the appropriate way to do artefact
> rejection - I wonder whether you're interested in a more standard
> solution ??

I think that the desired functionality that you mention can be
achieved with only small modifications to fieldtrip. Please think
about it, and if you agree, then you could modify the
artifact_threshold function. Please also have a look at the attached
rejectvisual function (not yet released): it allows to reject trials
after they have been preprocessed, like in the BESA way that you once
suggested.

best regards,
Robert


-------------- next part --------------
A non-text attachment was scrubbed...
Name: rejectvisual.m
Type: application/octet-stream
Size: 6826 bytes
Desc: not available
URL: <http://mailman.science.ru.nl/pipermail/fieldtrip/attachments/20060517/890832f6/attachment-0001.obj>
-------------- next part --------------




More information about the fieldtrip mailing list