spm_eeg_grandmean.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. function Do = spm_eeg_grandmean(S)
  2. % Average over multiple M/EEG data sets
  3. % FORMAT Do = spm_eeg_grandmean(S)
  4. %
  5. % S - struct (optional)
  6. % fields of S:
  7. % D - filenames (char matrix) of M/EEG MAT-files containing
  8. % epoched data
  9. % weighted - average weighted by number of replications in inputs (1)
  10. % or not (0) [default: 0]
  11. % outfile - name of the output file [default: 'grand_mean']
  12. %
  13. % Output:
  14. % Do - EEG data struct, result files are saved in the same
  15. % directory as first input file.
  16. %__________________________________________________________________________
  17. %
  18. % spm_eeg_grandmean averages data over multiple files. The data must have
  19. % the same trialtype numbering and sampling rate. This function can be used
  20. % for grand mean averaging, i.e. computing the average over multiple
  21. % subjects. Missing event types and bad channels are taken into account
  22. % properly. The output is written to a user-specified new file. The default
  23. % name is the same name as the first selected input file, but prefixed with
  24. % a 'g'. The output file is written to the current working directory.
  25. %__________________________________________________________________________
  26. % Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging
  27. % Stefan Kiebel
  28. % $Id: spm_eeg_grandmean.m 7139 2017-07-24 10:54:11Z guillaume $
  29. SVNrev = '$Rev: 7139 $';
  30. %-Startup
  31. %--------------------------------------------------------------------------
  32. spm('FnBanner', mfilename, SVNrev);
  33. spm('FigName','M/EEG Grand Mean'); spm('Pointer','Watch');
  34. if ~isfield(S, 'weighted'), S.weighted = 0; end
  35. if ~isfield(S, 'outfile'), S.outfile = 'grand_mean'; end
  36. %-Load MEEG data
  37. %--------------------------------------------------------------------------
  38. D = S.D;
  39. if ischar(D)
  40. F = cell(1,size(D,1));
  41. try
  42. for i = 1:size(D, 1)
  43. F{i} = spm_eeg_load(deblank(D(i, :)));
  44. end
  45. D = F;
  46. catch
  47. error('Trouble reading files.');
  48. end
  49. end
  50. Nfiles = length(D);
  51. %-Check dimension of the data files
  52. %--------------------------------------------------------------------------
  53. estr = '';
  54. for i = 1:Nfiles
  55. flist = [];
  56. if ~strcmp(D{i}.type, 'evoked')
  57. flist = [flist ' ' D{i}.fname];
  58. end
  59. if ~isempty(flist)
  60. estr = ['The files' flist ' do not contain averaged (evoked) data.'];
  61. end
  62. end
  63. % This applies to # of channels, # of samples, # of conditions, sampling
  64. % rate, and # of frequencies (if time-frequency data).
  65. nc = zeros(Nfiles,1);
  66. ns = zeros(Nfiles,1);
  67. fs = zeros(Nfiles,1);
  68. ne = zeros(Nfiles,1);
  69. if strncmp(D{1}.transformtype, 'TF',2)
  70. nf = zeros(Nfiles,1);
  71. end
  72. megsens = [];
  73. eegsens = [];
  74. fid = [];
  75. for i = 1:Nfiles
  76. nc(i) = D{i}.nchannels;
  77. ns(i) = D{i}.nsamples;
  78. fs(i) = D{i}.fsample;
  79. ne(i) = D{i}.nconditions;
  80. if strncmp(D{1}.transformtype, 'TF',2)
  81. nf(i) = D{i}.nfrequencies;
  82. end
  83. if ~isempty(D{i}.sensors('MEG')) || ~isempty(D{i}.sensors('EEG'))
  84. D{i} = check(D{i}, '3d');
  85. end
  86. if ~isempty(D{i}.sensors('MEG'))
  87. megsens = spm_cat_struct(megsens, D{i}.sensors('MEG'));
  88. end
  89. if ~isempty(D{i}.sensors('EEG'))
  90. eegsens = spm_cat_struct(eegsens, D{i}.sensors('EEG'));
  91. end
  92. if ~isempty(megsens) || ~isempty(eegsens)
  93. fid = spm_cat_struct(fid, D{i}.fiducials);
  94. end
  95. end
  96. unc = unique(nc);
  97. if length(unc)~=1
  98. ind = zeros(Nfiles,1);
  99. fna = cell(length(unc),1);
  100. for i=1:Nfiles
  101. ind(i) = find(unc==nc(i));
  102. fna{ind(i)} = [fna{ind(i)},'-',D{i}.fname,'\n'];
  103. end
  104. fprintf('\n')
  105. for i=1:length(unc)
  106. fprintf(['\nThose files have ',num2str(unc(i)),' channels:\n',...
  107. fna{i}])
  108. end
  109. estr = [estr,'Data don''t have the same number of channels.\n'];
  110. end
  111. uns = unique(ns);
  112. if length(uns)~=1
  113. ind = zeros(Nfiles,1);
  114. fna = cell(length(uns),1);
  115. for i=1:Nfiles
  116. ind(i) = find(uns==ns(i));
  117. fna{ind(i)} = [fna{ind(i)},'-',D{i}.fname,'\n'];
  118. end
  119. fprintf('\n')
  120. for i=1:length(uns)
  121. fprintf(['\nThose files have ',num2str(uns(i)),' time points:\n',...
  122. fna{i}])
  123. end
  124. estr = [estr,'Data don''t have the same number of time points.\n'];
  125. end
  126. ufs = unique(fs);
  127. if length(ufs)~=1
  128. ind = zeros(Nfiles,1);
  129. fna = cell(length(ufs),1);
  130. for i=1:Nfiles
  131. ind(i) = find(ufs==fs(i));
  132. fna{ind(i)} = [fna{ind(i)},'-',D{i}.fname,'\n'];
  133. end
  134. fprintf('\n')
  135. for i=1:length(ufs)
  136. fprintf(['\nThose files have a sampling rate of ',num2str(ufs(i)),' Hz:\n',...
  137. fna{i}])
  138. end
  139. estr = [estr,'Data don''t have the same sampling rate.\n'];
  140. end
  141. une = unique(ne);
  142. if length(une)~=1
  143. ind = zeros(Nfiles,1);
  144. fna = cell(length(une),1);
  145. for i=1:Nfiles
  146. ind(i) = find(une==ne(i));
  147. fna{ind(i)} = [fna{ind(i)},'-',D{i}.fname,'\n'];
  148. end
  149. fprintf('\n')
  150. for i=1:length(unc)
  151. fprintf(['\nThose files have ',num2str(une(i)),' conditions:\n',...
  152. fna{i}])
  153. end
  154. %estr = [estr,'Data don''t have the same number of conditions.\n'];
  155. end
  156. if strncmp(D{1}.transformtype, 'TF',2)
  157. unf = unique(nf);
  158. if length(unf)~=1
  159. ind = zeros(Nfiles,1);
  160. fna = cell(length(unf),1);
  161. for i=1:Nfiles
  162. ind(i) = find(unf==nf(i));
  163. fna{ind(i)} = [fna{ind(i)},'-',D{i}.fname,'\n'];
  164. end
  165. fprintf('\n')
  166. for i=1:length(unf)
  167. fprintf(['\nThose files have ',num2str(unf(i)),' frequency bins:\n',...
  168. fna{i}])
  169. end
  170. estr = [estr,'Data don''t have the same number of frequency bins.\n'];
  171. end
  172. end
  173. % send message error (if any)
  174. if ~isempty(estr)
  175. error(estr)
  176. else
  177. fprintf('Ok: All data files have the same dimensions.\n')
  178. end
  179. %-Initialise output
  180. %--------------------------------------------------------------------------
  181. Do = D{1};
  182. % how many different trial types and bad channels
  183. types = {};
  184. for i = 1:Nfiles
  185. types = unique([types, D{i}.condlist]);
  186. end
  187. % The order of the conditions will be consistent with the first file
  188. [sel1, sel2] = spm_match_str(D{1}.condlist, types);
  189. sel2 = sel2(:)';
  190. types = types([sel2, setdiff(1:length(types), sel2)]);
  191. Ntypes = numel(types);
  192. % how many repetitons per trial type
  193. nrepl = zeros(Nfiles, Ntypes);
  194. for i = 1:Nfiles
  195. for j = 1:numel(types)
  196. ind = D{i}.indtrial(types{j});
  197. if ~isempty(ind)
  198. nrepl(i, j) = D{i}.repl(ind);
  199. end
  200. end
  201. end
  202. if ~S.weighted
  203. nrepl = ones(Nfiles, Ntypes);
  204. end
  205. % generate new meeg object with new filenames
  206. if strncmp(D{1}.transformtype, 'TF',2)
  207. Do = clone(Do, S.outfile, [Do.nchannels Do.nfrequencies Do.nsamples Ntypes]);
  208. else
  209. Do = clone(Do, S.outfile, [Do.nchannels Do.nsamples Ntypes]);
  210. end
  211. % for determining bad channels of the grandmean
  212. w = zeros(Do.nchannels, Ntypes);
  213. badchans = cellfun(@badchannels, D, 'UniformOutput', 0);
  214. trialinds = cellfun(@(x) x.indtrial(types, 'GOOD'), D, 'UniformOutput', 0);
  215. %-Do the averaging
  216. %--------------------------------------------------------------------------
  217. spm_progress_bar('Init', Ntypes, 'responses averaged');
  218. if Ntypes > 100, Ibar = floor(linspace(1, Ntypes, 100));
  219. else Ibar = [1:Ntypes]; end
  220. if strncmp(D{1}.transformtype, 'TF',2)
  221. for i = 1:Ntypes
  222. d = zeros(D{1}.nchannels, D{1}.nfrequencies, D{1}.nsamples);
  223. for j = 1:D{1}.nchannels
  224. for k = 1:Nfiles
  225. if ~any(badchans{k}==j)
  226. ind = trialinds{k}(i);
  227. if ~isempty(ind)
  228. d(j, :, :) = d(j, :, :) + nrepl(k, i)*D{k}(j, :, :, ind);
  229. w(j, i) = w(j, i) + nrepl(k, i);
  230. end
  231. end
  232. end
  233. if w(j, i) > 0
  234. d(j, :, :) = d(j, :, :)/w(j, i);
  235. end
  236. end
  237. Do(1:Do.nchannels, 1:Do.nfrequencies, 1:Do.nsamples, i) = d;
  238. if any(Ibar==i), spm_progress_bar('Set', i); end
  239. end
  240. else
  241. for i = 1:Ntypes
  242. d = zeros(D{1}.nchannels, D{1}.nsamples);
  243. for j = 1:D{1}.nchannels
  244. for k = 1:Nfiles
  245. if ~any(badchans{k}==j)
  246. ind = trialinds{k}(i);
  247. if ~isempty(ind)
  248. d(j, :) = d(j, :) + nrepl(k, i)*D{k}(j, :, ind);
  249. w(j, i) = w(j, i) + nrepl(k, i);
  250. end
  251. end
  252. end
  253. if w(j, i) > 0
  254. d(j, :) = d(j, :)/w(j, i);
  255. end
  256. end
  257. Do(1:Do.nchannels, 1:Do.nsamples, i) = d;
  258. if any(Ibar==i), spm_progress_bar('Set', i); end
  259. end
  260. end
  261. spm_progress_bar('Clear');
  262. %-Average sensor locations
  263. %--------------------------------------------------------------------------
  264. nograph = spm('CmdLine');
  265. h = [];
  266. Ntrials = sum(nrepl, 2);
  267. if ~isempty(megsens)
  268. if ~nograph, spm_figure('GetWin','Graphics');clf; end
  269. if ~isempty(eegsens)
  270. if ~nograph, h = subplot(2, 1, 1); end
  271. aeegsens = ft_average_sens(eegsens, 'weights', Ntrials, 'feedback', h);
  272. Do = sensors(Do, 'EEG', aeegsens);
  273. if ~nograph, h = subplot(2, 1, 2); end
  274. else
  275. if ~nograph, h = axes; end
  276. end
  277. [amegsens,afid] = ft_average_sens(megsens, 'fiducials', fid, 'weights', Ntrials, 'feedback', h);
  278. Do = sensors(Do, 'MEG', amegsens);
  279. Do = fiducials(Do, afid);
  280. elseif ~isempty(eegsens)
  281. if ~nograph
  282. spm_figure('GetWin','Graphics');clf;
  283. h = axes;
  284. end
  285. [aeegsens,afid] = ft_average_sens(eegsens, 'fiducials', fid, 'weights', Ntrials, 'feedback', h);
  286. Do = sensors(Do, 'EEG', aeegsens);
  287. Do = fiducials(Do, afid);
  288. end
  289. %-Save Grand Mean to disk
  290. %--------------------------------------------------------------------------
  291. Do = type(Do, 'evoked');
  292. nrepl = sum(nrepl, 1);
  293. Do = badchannels(Do, ':', ~any(w, 2));
  294. Do = conditions(Do, ':', types);
  295. Do = repl(Do, ':', nrepl);
  296. Do = badtrials(Do, ':', 0);
  297. Do = trialonset(Do, ':', []);
  298. Do = trialtag(Do, ':', []);
  299. Do = Do.history('spm_eeg_grandmean', S, 'reset');
  300. save(Do);
  301. %-Cleanup
  302. %--------------------------------------------------------------------------
  303. spm('FigName','M/EEG Grand Mean: done'); spm('Pointer','Arrow');