spm_eeg_artefact.m 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. function D = spm_eeg_artefact(S)
  2. % Simple artefact detection, optionally with robust averaging
  3. % FORMAT D = spm_eeg_artefact(S)
  4. %
  5. % S - input structure
  6. %
  7. % fields of S:
  8. % S.mode 'reject' [default]: reject bad channels and trials
  9. % 'mark': scan the data and create events marking the
  10. % artefacts
  11. % S.D - MEEG object or filename of M/EEG mat-file
  12. % S.badchanthresh - fraction of trials (or time) with artefacts above
  13. % which a channel is declared as bad [default: 0.2]
  14. %
  15. % S.append - 1 [default]: append new markings to existing ones
  16. % 0: overwrite existing markings
  17. % S.methods - structure array with configuration parameters for
  18. % artefact detection plugins
  19. % S.prefix - prefix for the output file [default: 'a']
  20. %
  21. % Output:
  22. % D - MEEG object (also written on disk)
  23. %__________________________________________________________________________
  24. %
  25. % This is a modular function for which plugins can be developed to detect
  26. % artefacts with any algorithm.
  27. % The name of a plugin function should start with 'spm_eeg_artefact_'.
  28. % Several plugins are already implemented annd they can be used as
  29. % templates for new plugins:
  30. %
  31. % peak2peak - thresholds peak-to-peak amplitude
  32. % (spm_eeg_artefact_peak2peak)
  33. %
  34. % jump - thresholds the difference between adjacent samples
  35. % (spm_eeg_artefact_jump)
  36. %
  37. % flat - detects flat segments in the data
  38. % (spm_eeg_artefact_flat)
  39. %__________________________________________________________________________
  40. % Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging
  41. % Vladimir Litvak
  42. % $Id: spm_eeg_artefact.m 7132 2017-07-10 16:22:58Z guillaume $
  43. SVNrev = '$Rev: 7132 $';
  44. %-Startup
  45. %--------------------------------------------------------------------------
  46. spm('FnBanner', mfilename, SVNrev);
  47. spm('FigName','M/EEG artefact detection'); spm('Pointer','Watch');
  48. if ~isfield(S, 'mode'), S.mode = 'reject'; end
  49. if ~isfield(S, 'badchanthresh'), S.badchanthresh = 0.2; end
  50. if ~isfield(S, 'append'), S.append = true; end
  51. if ~isfield(S, 'prefix'), S.prefix = 'a'; end
  52. %-Get MEEG object
  53. %--------------------------------------------------------------------------
  54. D = spm_eeg_load(S.D);
  55. if isequal(S.mode, 'reject')
  56. if isequal(D.type, 'continuous')
  57. error('Artefact rejection can only be applied to epoched data.');
  58. end
  59. %-Create a copy of the dataset
  60. %----------------------------------------------------------------------
  61. D = copy(D, [S.prefix D.fname]);
  62. %-Run the artefact detection routines
  63. %----------------------------------------------------------------------
  64. bad = zeros(D.nchannels, D.ntrials);
  65. for i = 1:numel(S.methods)
  66. chanind = D.selectchannels(S.methods(i).channels);
  67. if S.append
  68. chanind = setdiff(chanind, D.badchannels);
  69. end
  70. if ~isempty(chanind)
  71. S1 = S.methods(i).settings;
  72. if isempty(S1)
  73. S1 = [];
  74. end
  75. S1.mode = S.mode;
  76. S1.D = D;
  77. S1.chanind = chanind;
  78. bad = bad | feval(['spm_eeg_artefact_' S.methods(i).fun], S1);
  79. end
  80. end
  81. %-Classify MEEG channels as bad if the fraction of bad trials exceeds threshold
  82. %------------------------------------------------------------------------------
  83. badchanind = intersect(find(mean(bad, 2)>S.badchanthresh), indchantype(D, 'MEEG'));
  84. badchanind = union(badchanind, D.badchannels);
  85. goodchanind = setdiff(1:D.nchannels, badchanind);
  86. %-Classify trials as bad if they have artefacts in good M/EEG channels
  87. %-or in non-M/EEG channels
  88. %----------------------------------------------------------------------
  89. badtrialind = find(any(bad(goodchanind, :), 1));
  90. %-Update and save new dataset
  91. %----------------------------------------------------------------------
  92. if ~S.append
  93. D = badtrials(D, ':', 0);
  94. D = badchannels(D, ':', 0);
  95. end
  96. D = badtrials(D, badtrialind, 1);
  97. D = badchannels(D, badchanind, ones(size(badchanind)));
  98. %-Report on command line
  99. %----------------------------------------------------------------------
  100. fprintf('%d rejected trials: %s\n', length(badtrialind), num2str(badtrialind));
  101. elseif isequal(S.mode, 'mark')
  102. %-Create a copy of the dataset
  103. %----------------------------------------------------------------------
  104. D = copy(D, [S.prefix D.fname]);
  105. %-Run the artefact detection routines
  106. %----------------------------------------------------------------------
  107. for i = 1:numel(S.methods)
  108. chanind = setdiff(D.selectchannels(S.methods(i).channels), D.badchannels);
  109. if ~isempty(chanind)
  110. S1 = S.methods(i).settings;
  111. if isempty(S1)
  112. S1 = [];
  113. end
  114. S1.mode = S.mode;
  115. S1.D = D;
  116. S1.badchanthresh = S.badchanthresh;
  117. S1.append = S.append;
  118. S1.chanind = chanind;
  119. D = feval(['spm_eeg_artefact_' S.methods(i).fun], S1);
  120. end
  121. end
  122. meegind = D.indchantype({'MEEG', 'LFP'});
  123. bad = squeeze(mean(mean(badsamples(D, meegind, ':', ':'), 2), 3)) > S.badchanthresh;
  124. badchanind = meegind(bad);
  125. %-Update and save new dataset
  126. %----------------------------------------------------------------------
  127. D = badchannels(D, badchanind, 1);
  128. else
  129. error('Invalid mode specification.');
  130. end
  131. if isempty(badchanind)
  132. fprintf('There are no bad channels.\n');
  133. else
  134. lbl = D.chanlabels(badchanind);
  135. if ~iscell(lbl), lbl = {lbl}; end
  136. fprintf('%d bad channels: %s\n', numel(lbl), sprintf('%s ', lbl{:}));
  137. end
  138. D = D.history(mfilename, S);
  139. save(D);
  140. %-Cleanup
  141. %--------------------------------------------------------------------------
  142. fprintf('%-40s: %30s\n','Completed',spm('time')); %-#
  143. spm('FigName','M/EEG artefact detection: done'); spm('Pointer','Arrow');