spm_eeg_tf.m 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. function [Dtf, Dtph] = spm_eeg_tf(S)
  2. % Compute instantaneous power and phase in peri-stimulus time and frequency
  3. % FORMAT [Dtf, Dtph] = spm_eeg_tf(S)
  4. %
  5. % S - input structure
  6. %
  7. % fields of S:
  8. % S.D - MEEG object or filename of M/EEG mat-file with
  9. %
  10. % S.channels - cell array of channel names. Can include generic
  11. % wildcards: 'All', 'EEG', 'MEG' etc.
  12. %
  13. % S.frequencies - vector of frequencies of interest
  14. %
  15. % S.timewin - time window of interest in PST in ms.
  16. %
  17. % S.method - name for the spectral estimation to use. This
  18. % corresponds to the name of a plug-in function that comes
  19. % after 'spm_eeg_specest_' prefix.
  20. % S.settings - plug-in specific settings
  21. %
  22. % S.phase - also save phase dataset (1) or not (0)
  23. % phase dataset cannot be computed for some
  24. % spectral estimation methods
  25. % S.prefix - prefix added before the standard prefix (tf_ or tph_)
  26. %
  27. % Output:
  28. % Dtf - M/EEG object with power (also written on disk)
  29. % Dtph - M/EEG object with phase (also written on disk)
  30. %__________________________________________________________________________
  31. % This is a modular function for which plugins can be developed implementing
  32. % specific spectral estimation methods. There are 3 basic plugins presently
  33. % implemented and they can be used as templates for new plugins.
  34. % The name of a plugin function should start with 'spm_eeg_specest_'
  35. %
  36. % morlet (spm_eeg_specest_morlet) - Morlet wavelet transform
  37. %
  38. % hilbert (spm_eeg_specest_hilbert) - filtering + Hilbert transform
  39. %
  40. % ft_mtmconvol (spm_eeg_specest_mtmconvol) - Fieldtrip implementation
  41. % of multi-taper spectral
  42. % analysis
  43. %__________________________________________________________________________
  44. % Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging
  45. % Vladimir Litvak
  46. % $Id: spm_eeg_tf.m 7449 2018-10-16 13:52:04Z vladimir $
  47. SVNrev = '$Rev: 7449 $';
  48. %-Startup
  49. %--------------------------------------------------------------------------
  50. spm('FnBanner', mfilename, SVNrev);
  51. spm('FigName','M/EEG Time-Frequency'); spm('Pointer','Watch');
  52. %-Configure the analysis
  53. %--------------------------------------------------------------------------
  54. if ~isfield(S, 'channels'), S.channels = 'all'; end
  55. if ~isfield(S, 'timewin'), S.timewin = [-Inf Inf]; end
  56. if ~isfield(S, 'phase'), S.phase = 0; end
  57. if ~isfield(S, 'prefix'), S.prefix = ''; end
  58. if ~isfield(S, 'frequencies') || isempty(S.frequencies)
  59. S.frequencies = 1:48;
  60. end
  61. if ~isfield(S, 'method')
  62. S.method = 'morlet';
  63. S.settings = [];
  64. end
  65. D = spm_eeg_load(S.D);
  66. chanind = D.selectchannels(S.channels);
  67. if isempty(chanind)
  68. error('No channels selected.');
  69. end
  70. if isfield(S, 'settings')
  71. S1 = S.settings;
  72. else
  73. S1 = [];
  74. end
  75. timeind = D.indsample(1e-3*min(S.timewin)):D.indsample(1e-3*max(S.timewin));
  76. % remove uninetended non-uniformities in the frequency axis
  77. frequencies = S.frequencies;
  78. if length(frequencies)>1
  79. df = unique(diff(frequencies));
  80. if length(df) == 1 || (max(diff(df))/mean(df))<0.1
  81. df = mean(diff(frequencies));
  82. frequencies = (0:(length(frequencies)-1))*df + frequencies(1);
  83. end
  84. end
  85. S1.frequencies = frequencies;
  86. if ~isequal(D.type, 'continuous')
  87. %-Run the analysis on all trials
  88. %--------------------------------------------------------------------------
  89. spm_progress_bar('Init', D.ntrials, 'trials done');
  90. if D.ntrials > 100, Ibar = floor(linspace(1, D.ntrials, 100));
  91. else Ibar = 1:D.ntrials; end
  92. for k = 1:D.ntrials
  93. spm_progress_bar('Set','ylabel','reading and computing...');
  94. trial = feval(['spm_eeg_specest_' S.method], S1, D(chanind, timeind, k), D.time(timeind));
  95. if k == 1
  96. spm_progress_bar('Set','ylabel','initialising output...');
  97. if isfield(trial, 'fourier')
  98. outdata = trial.fourier;
  99. else
  100. outdata = trial.pow;
  101. end
  102. Nchannels = size(outdata, 1);
  103. Nfrequencies = size(outdata, 2);
  104. Nsamples = size(outdata, 3);
  105. %-Generate output datasets
  106. %--------------------------------------------------------------------------
  107. Dtf = clone(D, [S.prefix 'tf_' D.fname], [Nchannels Nfrequencies Nsamples D.ntrials], 0, 1);
  108. Dtf = Dtf.frequencies(':', trial.freq);
  109. Dtf = timeonset(Dtf, trial.time(1));
  110. Dtf = fsample(Dtf, 1/diff(trial.time(1:2)));
  111. Dtf = transformtype(Dtf, 'TF');
  112. Dtf = chanlabels(Dtf, 1:Nchannels, D.chanlabels(chanind));
  113. Dtf = badchannels(Dtf, 1:Nchannels, D.badchannels(chanind));
  114. Dtf = chantype(Dtf, 1:Nchannels, D.chantype(chanind));
  115. Dtf = coor2D(Dtf, 1:Nchannels, coor2D(D,chanind));
  116. if S.phase && isfield(trial, 'fourier')
  117. Dtph = clone(Dtf, [S.prefix 'tph_' D.fname]);
  118. Dtph = transformtype(Dtph, 'TFphase');
  119. else
  120. if ~isfield(trial, 'fourier')
  121. warning('Phase cannot be estimated with the requested method. Estimating power only.');
  122. end
  123. Dtph = [];
  124. end
  125. end
  126. spm_progress_bar('Set','ylabel','writing...');
  127. if isfield(trial, 'fourier')
  128. Dtf(:, :, :, k) = trial.fourier.*conj(trial.fourier);
  129. if S.phase
  130. Dtph(:, :, :, k) = angle(trial.fourier);
  131. end
  132. elseif isfield(trial, 'pow')
  133. Dtf(:, :, :, k) = trial.pow;
  134. else
  135. error('The plug-in returned unexpected output');
  136. end
  137. if ismember(k, Ibar), spm_progress_bar('Set', k); end
  138. end
  139. spm_progress_bar('Clear');
  140. else % by channel for continuous data
  141. Nchannels = length(chanind);
  142. spm_progress_bar('Init', Nchannels , 'channels done');
  143. if Nchannels > 100, Ibar = floor(linspace(1, Nchannels, 100));
  144. else Ibar = 1:Nchannels; end
  145. for k = 1:Nchannels
  146. spm_progress_bar('Set','ylabel','reading and computing...');
  147. trial = feval(['spm_eeg_specest_' S.method], S1, D(chanind(k), timeind), D.time(timeind));
  148. if k == 1
  149. spm_progress_bar('Set','ylabel','initialising output...');
  150. if isfield(trial, 'fourier')
  151. outdata = trial.fourier;
  152. else
  153. outdata = trial.pow;
  154. end
  155. Nfrequencies = size(outdata, 2);
  156. Nsamples = size(outdata, 3);
  157. %-Generate output datasets
  158. %--------------------------------------------------------------------------
  159. Dtf = clone(D, [S.prefix 'tf_' D.fname], [Nchannels Nfrequencies Nsamples 1]);
  160. Dtf = Dtf.frequencies(':', trial.freq);
  161. Dtf = timeonset(Dtf, trial.time(1));
  162. Dtf = fsample(Dtf, 1/diff(trial.time(1:2)));
  163. Dtf = transformtype(Dtf, 'TF');
  164. Dtf = chanlabels(Dtf, 1:Nchannels, D.chanlabels(chanind));
  165. Dtf = badchannels(Dtf, 1:Nchannels, D.badchannels(chanind));
  166. Dtf = chantype(Dtf, 1:Nchannels, D.chantype(chanind));
  167. Dtf = coor2D(Dtf, 1:Nchannels, coor2D(D,chanind));
  168. ev = Dtf.events;
  169. if ~isempty(ev)
  170. ev = ev([ev.time]>=Dtf.time(1) & [ev.time]<=Dtf.time(end));
  171. Dtf = events(Dtf, 1, ev);
  172. end
  173. if S.phase && isfield(trial, 'fourier')
  174. Dtph = clone(Dtf, [S.prefix 'tph_' D.fname]);
  175. Dtph = transformtype(Dtph, 'TFphase');
  176. else
  177. if ~isfield(trial, 'fourier')
  178. warning('Phase cannot be estimated with the requested method. Estimating power only.');
  179. end
  180. Dtph = [];
  181. end
  182. end
  183. spm_progress_bar('Set','ylabel','writing...');
  184. if isfield(trial, 'fourier')
  185. Dtf(k, :, :, 1) = trial.fourier.*conj(trial.fourier);
  186. if S.phase
  187. Dtph(k, :, :, 1) = angle(trial.fourier);
  188. end
  189. elseif isfield(trial, 'pow')
  190. Dtf(k, :, :, 1) = trial.pow;
  191. else
  192. error('The plug-in returned unexpected output');
  193. end
  194. if ismember(k, Ibar), spm_progress_bar('Set', k); end
  195. end
  196. spm_progress_bar('Clear');
  197. end
  198. %-Save new M/EEG dataset(s)
  199. %--------------------------------------------------------------------------
  200. Dtf = Dtf.history('spm_eeg_tf', S);
  201. save(Dtf);
  202. if ~isempty(Dtph)
  203. Dtph = Dtph.history('spm_eeg_tf', S);
  204. save(Dtph);
  205. end
  206. %-Cleanup
  207. %--------------------------------------------------------------------------
  208. fprintf('%-40s: %30s\n','Completed',spm('time')); %-#
  209. spm('FigName','M/EEG Time Frequency: done'); spm('Pointer','Arrow');