[FieldTrip] marking artifacts by channel + trial

Teresa Madsen braingirl at gmail.com
Fri Mar 3 23:31:04 CET 2017


Here's a rough sketch of my approach, with one custom function attached.
If you or others find it useful, maybe we can think about ways to
incorporate it into the FieldTrip code.  I've been working mostly with
scripts, but you've inspired me to work on functionizing the rest of it so
it's more shareable.

So, assuming raw multichannel data has been loaded into FieldTrip structure
'data' with unique trial identifiers in data.trialinfo...

for ch = 1:numel(data.label)
  %% pull out one channel at a time
  cfg = [];
  cfg.channel = data.label{ch};

  datch{ch} = ft_selectdata(cfg, data);

  %% identify large z-value artifacts and/or whatever else you might want

  cfg = [];
  cfg.artfctdef.zvalue.channel        = 'all';
  cfg.artfctdef.zvalue.cutoff         = 15;
  cfg.artfctdef.zvalue.trlpadding     = 0;
  cfg.artfctdef.zvalue.fltpadding     = 0;
  cfg.artfctdef.zvalue.artpadding     = 0.1;
  cfg.artfctdef.zvalue.rectify        = 'yes';

  [~, artifact.zvalue] = ft_artifact_zvalue([], datch{ch});

  %% replace artifacts with NaNs
  cfg = [];
  cfg.artfctdef.zvalue.artifact = artifact.zvalue;
  cfg.artfctdef.reject          = 'nan';

  datch{ch} = ft_rejectartifact(cfg,datch{ch});
end

%% re-merge channels
data = ft_appenddata([],datch);

%% mark uniform NaNs as artifacts when they occur across all channels
% and replace non-uniform NaNs (on some but not all channels) with zeroes,
saving times
[artifact,data,times] = artifact_nan2zero_TEM(data) % custom function, see
attached

%% reject artifacts by breaking into sub-trials
cfg = [];
cfg.artfctdef.nan2zero.artifact = artifact;
cfg.artfctdef.reject            = 'partial';

data = ft_rejectartifact(cfg,data);

%% identify real trials
trlinfo = unique(data.trialinfo,'rows','stable');

for tr = 1:size(trlinfo,1)

  %% calculate trial spectrogram

  cfg = [];

  cfg.trials = ismember(data.trialinfo, trlinfo(tr,:), 'rows');
  cfg.keeptrials = 'no';             % refers to sub-trials

  cfg.method     = 'mtmconvol';

  cfg.output     = 'powandcsd';

  cfg.foi = 2.^(0:0.1:log2(300));    % 83 freqs, log2 spaced, 1-300 Hz
  cfg.tapsmofrq  = cfg.foi/10;       % smooth by 10%
  cfg.t_ftimwin  = 2./cfg.tapsmofrq; % for 3 tapers (K=3), T=2/W
  cfg.toi        = '50%';
  cfg.pad        = 'nextpow2';


  freq = ft_freqanalysis(cfg,data);

  %% replace powspctrm & crsspctrum values with NaNs
  % where t_ftimwin (or wavlen for wavelets) overlaps with artifact
  for ch = 1:numel(freq.label)
    badt = [times{tr,ch}];
    if ~isempty(badt) && any(...
        badt > (min(freq.time) - max(freq.cfg.t_ftimwin)) & ...
        badt < (max(freq.time) + max(freq.cfg.t_ftimwin)))
      ci = find(any(strcmp(freq.label{ch}, freq.labelcmb)));
      for t = 1:numel(freq.time)
        for f = 1:numel(freq.freq)
          mint = freq.time(t) - freq.cfg.t_ftimwin(f);
          maxt = freq.time(t) + freq.cfg.t_ftimwin(f);
          if any(badt > mint & badt < maxt)
            freq.powspctrm(ch,f,t) = NaN;
            freq.crsspctrm(ci,f,t) = NaN;
          end
        end
      end
    end
  end

  %% save corrected output

  save(['trial' num2str(tr) 'mtmconvolTFA.mat'], 'freq', '-v7.3');
end



On Thu, Mar 2, 2017 at 9:55 AM, Tim Meehan <timeehan at gmail.com> wrote:

> Hi Teresa,
>
> Thanks for the reply. I'll take a look at your example if you don't mind
> sharing. Thanks!
>
> Tim
>
> On Thu, Mar 2, 2017 at 9:53 AM, Teresa Madsen <braingirl at gmail.com> wrote:
>
>> No, not really.  The only way I've found to do that is to loop through my
>> artifact rejection process on each trial individually, then merge them back
>> together with NaNs filling in where there are artifacts, but then that
>> breaks every form of analysis I want to do.  :-P
>>
>> I wonder if it would work to fill in the artifacts with 0s instead of
>> NaNs....I might play with that.  Let me know if you're interested in some
>> example code.
>>
>> ~Teresa
>>
>>
>> On Wed, Mar 1, 2017 at 3:55 PM, Tim Meehan <timeehan at gmail.com> wrote:
>>
>>> Hello All,
>>>
>>> When performing visual artifact rejection, I want to be able to mark
>>> artifacts that occur during some specific trials and only on some specific
>>> channels. In the tutorials I see only ways to mark bad channels (i.e.
>>> across all trials) or bad trials (i.e. across all channels). Does FieldTrip
>>> handle marking artifacts restricted to some channel/trial combination?
>>>
>>> Thanks,
>>> Tim
>>>
>>> _______________________________________________
>>> fieldtrip mailing list
>>> fieldtrip at donders.ru.nl
>>> https://mailman.science.ru.nl/mailman/listinfo/fieldtrip
>>>
>>
>>
>>
>> --
>> Teresa E. Madsen, PhD
>> Research Technical Specialist:  *in vivo *electrophysiology & data
>> analysis
>> Division of Behavioral Neuroscience and Psychiatric Disorders
>> Yerkes National Primate Research Center
>> Emory University
>> Rainnie Lab, NSB 5233
>> 954 Gatewood Rd. NE
>> Atlanta, GA 30329
>> (770) 296-9119
>> braingirl at gmail.com
>> https://www.linkedin.com/in/temadsen
>>
>> _______________________________________________
>> fieldtrip mailing list
>> fieldtrip at donders.ru.nl
>> https://mailman.science.ru.nl/mailman/listinfo/fieldtrip
>>
>
>
> _______________________________________________
> fieldtrip mailing list
> fieldtrip at donders.ru.nl
> https://mailman.science.ru.nl/mailman/listinfo/fieldtrip
>



-- 
Teresa E. Madsen, PhD
Research Technical Specialist:  *in vivo *electrophysiology & data analysis
Division of Behavioral Neuroscience and Psychiatric Disorders
Yerkes National Primate Research Center
Emory University
Rainnie Lab, NSB 5233
954 Gatewood Rd. NE
Atlanta, GA 30329
(770) 296-9119
braingirl at gmail.com
https://www.linkedin.com/in/temadsen
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.science.ru.nl/pipermail/fieldtrip/attachments/20170303/ecd1e7f3/attachment-0001.html>
-------------- next part --------------
function [artifact,data,times] = artifact_nan2zero_TEM(data)
% ARTIFACT_NAN2ZERO_TEM marks NaNs that occur uniformly across all channels
%   as artifacts, taking FT format data structure & returning the same
%   format as ft_artifact_xxx, for input to ft_rejectartifact.  Non-uniform
%   NaNs (those not present on all channels) are replaced with 0s to avoid
%   breaking analysis functions.  Also returns times of replaced NaNs by
%   trial & channel, so they can be changed back to NaNs in freq output.
%
% written 3/2/17 by Teresa E. Madsen

artifact = [];
times = cell(numel(data.trial), numel(data.label));

for tr = 1:numel(data.trial)
  % find NaNs to mark as artifacts (present uniformly across all channels)
  trlnan = isnan(data.trial{tr});   % identify NaNs by channel & timepoint
  allnan = all(trlnan,1);   % need to specify dim in case of single channel
  
  % find, save timepoints, & replace non-uniform NaNs (not on all chs) w/ 0
  replacenan = trlnan & repmat(~allnan,size(trlnan,1),1);
  for ch = 1:numel(data.label)
    times{tr,ch} = data.time{tr}(replacenan(ch,:));  % ID before replacing
  end
  data.trial{tr}(replacenan) = 0;   % replace these w/ 0s
  
  if any(allnan)
    % determine the file sample #s for this trial
    trsamp = data.sampleinfo(tr,1):data.sampleinfo(tr,2);
    
    while any(allnan)
      % start from the end so sample #s don't shift
      endnan = find(allnan,1,'last');
      allnan = allnan(1:endnan);  % remove any non-NaNs after this
      
      % find last non-NaN before the NaNs
      beforenan = find(~allnan,1,'last');
      
      if isempty(beforenan)   % if no more non-NaNs
        begnan = 1;
        allnan = false;   % while loop ends
      else  % still more to remove - while loop continues
        begnan = beforenan + 1;
        allnan = allnan(1:beforenan);  % remove the identified NaNs
      end
      
      % identify file sample #s that correspond to beginning and end of
      % this chunk of NaNs and append to artifact
      artifact = [artifact; trsamp(begnan) trsamp(endnan)]; %#ok<AGROW>
    end   % while any(tnan)
  end   % if any(tnan)
end   % for tr = 1:numel(data.trial)

end


More information about the fieldtrip mailing list