spm_eeg_average.m 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. function D = spm_eeg_average(S)
  2. % Average each channel over trials or trial types
  3. % FORMAT D = spm_eeg_average(S)
  4. %
  5. % S - optional input struct
  6. % fields of S:
  7. % D - MEEG object or filename of M/EEG mat-file with epoched data
  8. % S.robust - (optional) - use robust averaging
  9. % .savew - save the weights in an additional dataset
  10. % .bycondition - compute the weights by condition (1,
  11. % default) or from all trials (0)
  12. % .ks - offset of the weighting function (default: 3)
  13. % S.prefix - prefix for the output file (default - 'm')
  14. %
  15. % Output:
  16. % D - MEEG object (also written on disk)
  17. %__________________________________________________________________________
  18. % Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging
  19. % Stefan Kiebel
  20. % $Id: spm_eeg_average.m 7125 2017-06-23 09:49:29Z guillaume $
  21. SVNrev = '$Rev: 7125 $';
  22. %-Startup
  23. %--------------------------------------------------------------------------
  24. spm('FnBanner', mfilename, SVNrev);
  25. spm('FigName','M/EEG averaging'); spm('Pointer','Watch');
  26. %-Get input parameters
  27. %--------------------------------------------------------------------------
  28. if ~isfield(S, 'prefix'), S.prefix = 'm'; end
  29. if ~isfield(S, 'robust'), S.robust = 0; end
  30. %-Configure robust averaging
  31. %--------------------------------------------------------------------------
  32. if isstruct(S.robust)
  33. if ~isfield(S.robust, 'savew'), S.robust.savew = 0; end
  34. if ~isfield(S.robust, 'bycondition'), S.robust.bycondition = 0; end
  35. if ~isfield(S.robust, 'ks'), S.robust.ks = 3; end
  36. if ~isfield(S.robust, 'removebad'), S.robust.removebad = 0; end
  37. robust = 1;
  38. savew = S.robust.savew;
  39. bycondition = S.robust.bycondition;
  40. ks = S.robust.ks;
  41. removebad = S.robust.removebad;
  42. else
  43. robust = 0;
  44. end
  45. %-Get MEEG object
  46. %--------------------------------------------------------------------------
  47. D = spm_eeg_load(S.D);
  48. montage_ind = D.montage('getindex');
  49. D = D.montage('switch', 0);
  50. %-Check that there is any good data available
  51. %--------------------------------------------------------------------------
  52. if ntrials(D)==0 || isempty(indtrial(D, D.condlist, 'GOOD'))
  53. warning('No good trials for averaging were found. Nothing to do.');
  54. return;
  55. end
  56. %-Redirect to Time-Frequency averaging if necessary
  57. %--------------------------------------------------------------------------
  58. if strncmpi(D.transformtype,'TF',2) % TF and TFphase
  59. D = spm_eeg_average_TF(S);
  60. return
  61. end
  62. %-Generate new MEEG object with new files
  63. %--------------------------------------------------------------------------
  64. Dnew = clone(D, [S.prefix fname(D)], [D.nchannels D.nsamples D.nconditions]);
  65. Dnew = type(Dnew, 'evoked');
  66. if robust && savew
  67. Dw = clone(D, ['W' fname(D)]);
  68. end
  69. %-Do the averaging
  70. %--------------------------------------------------------------------------
  71. cl = D.condlist;
  72. ni = zeros(1, D.nconditions);
  73. for i = 1:D.nconditions
  74. w = indtrial(D, deblank(cl{i}), 'GOOD');
  75. ni(i) = length(w);
  76. if ni(i) == 0
  77. warning('%s: No trials for trial type %d', D.fname, cl{i});
  78. end
  79. end
  80. goodtrials = indtrial(D, cl, 'GOOD');
  81. chanind = D.indchantype({'MEEG', 'LFP'});
  82. if prod(size(D))*8 < spm('memory')
  83. %-Average everything at once if there is enough memory
  84. %======================================================================
  85. spm_progress_bar('Init', D.nconditions, 'Averages done');
  86. if D.nconditions > 100, Ibar = floor(linspace(1, D.nconditions, 100));
  87. else Ibar = 1:D.nconditions; end
  88. if robust && ~bycondition
  89. W1 = ones(D.nchannels, D.nsamples, length(goodtrials));
  90. Y = D(chanind, :, goodtrials);
  91. if removebad
  92. bad = badsamples(D, chanind, ':', goodtrials);
  93. Y(bad) = NaN;
  94. end
  95. [Y, W2] = spm_robust_average(Y, 3, ks);
  96. W1(chanind, :, :) = W2;
  97. if savew
  98. Dw(:, :, goodtrials) = W1;
  99. end
  100. W = zeros(size(D));
  101. W(:, :, goodtrials) = W1;
  102. end
  103. for i = 1:D.nconditions
  104. w = indtrial(D, deblank(cl{i}), 'GOOD');
  105. if isempty(w)
  106. continue;
  107. end
  108. if ~robust
  109. Dnew(:, :, i) = mean(D(:, :, w), 3);
  110. else
  111. if bycondition
  112. W = ones(D.nchannels, D.nsamples, length(w));
  113. Y = D(chanind, :, w);
  114. if removebad
  115. bad = badsamples(D, chanind, ':', w);
  116. Y(bad) = NaN;
  117. end
  118. [Y, W1] = spm_robust_average(Y, 3, ks);
  119. W(chanind, :, :) = W1;
  120. Dnew(chanind, :, i) = Y;
  121. if length(chanind)<D.nchannels
  122. Dnew(setdiff(1:D.nchannels, chanind), :, i) = mean(D(setdiff(1:D.nchannels, chanind), :, w), 3);
  123. end
  124. if savew
  125. Dw(:, :, w) = W;
  126. end
  127. else
  128. X = D(:, :, w);
  129. X(isnan(X)) = 0;
  130. Dnew(:, :, i) = ...
  131. sum(W(:, :, w).*X, 3)./sum(W(:, :, w), 3);
  132. end
  133. end
  134. if ismember(i, Ibar), spm_progress_bar('Set', i); end
  135. end % for i = 1:D.nconditions
  136. else
  137. %-Averaging by channel
  138. %======================================================================
  139. spm_progress_bar('Init', D.nchannels, 'Channels completed');
  140. if D.nchannels > 100, Ibar = floor(linspace(1, D.nchannels, 100));
  141. else Ibar = [1:D.nchannels]; end
  142. for j = 1:D.nchannels
  143. if robust && ~bycondition
  144. if ismember(j, chanind)
  145. Y = D(j, :, goodtrials);
  146. if removebad
  147. bad = badsamples(D, j, ':', goodtrials);
  148. Y(bad) = NaN;
  149. end
  150. [Y, W1] = spm_robust_average(Y, 3, ks);
  151. W = zeros([1 D.nsamples D.ntrials]);
  152. W(1, :, goodtrials) = W1;
  153. else
  154. W1 = ones(1, D.nsamples, length(goodtrials));
  155. end
  156. if savew
  157. Dw(j, :, goodtrials) = W1;
  158. end
  159. end
  160. for i = 1:D.nconditions
  161. w = indtrial(D, deblank(cl{i}), 'GOOD');
  162. if isempty(w)
  163. continue;
  164. end
  165. if ~robust || ~ismember(j, chanind)
  166. Dnew(j, :, i) = mean(D(j, :, w), 3);
  167. else
  168. if bycondition
  169. Y = D(j, :, w);
  170. if removebad
  171. bad = badsamples(D, j, ':', w);
  172. Y(bad) = NaN;
  173. end
  174. [Y, W] = spm_robust_average(Y, 3, ks);
  175. Dnew(j, :, i) = Y;
  176. if savew
  177. Dw(j, :, w) = W;
  178. end
  179. else
  180. X = D(j, :, w);
  181. X(isnan(X)) = 0;
  182. Dnew(j, :, i) = ...
  183. sum(W(1, :, w).*X, 3)./sum(W(1, :, w), 3);
  184. end
  185. end
  186. end % for i = 1:D.nconditions
  187. if ismember(j, Ibar), spm_progress_bar('Set', j); end
  188. end
  189. end
  190. spm_progress_bar('Clear');
  191. %-Update some header information
  192. %--------------------------------------------------------------------------
  193. Dnew = conditions(Dnew, ':', cl);
  194. Dnew = repl(Dnew, ':', ni);
  195. Dnew = montage(Dnew, 'switch', montage_ind);
  196. %-Display averaging statistics
  197. %--------------------------------------------------------------------------
  198. fprintf('%s: Number of replications per contrast:\n', Dnew.fname); %-#
  199. for i = 1:D.nconditions
  200. fprintf(' average %s: %d trials\n', cl{i}, ni(i)); %-#
  201. end
  202. if robust
  203. disp('Robust averaging might have introduced high frequencies in the data. It is advised to re-apply low-pass filter.');
  204. end
  205. %-Save new evoked M/EEG dataset
  206. %--------------------------------------------------------------------------
  207. Dnew = Dnew.history(mfilename, S);
  208. save(Dnew);
  209. if robust && savew
  210. Dw = Dw.history(mfilename, S);
  211. save(Dw);
  212. end
  213. D = Dnew;
  214. %-Cleanup
  215. %--------------------------------------------------------------------------
  216. fprintf('%-40s: %30s\n','Completed',spm('time')); %-#
  217. spm('FigName','M/EEG averaging: done'); spm('Pointer','Arrow');