spm_eeg_convert.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. function D = spm_eeg_convert(S)
  2. % Convert various M/EEG formats to SPM12 format
  3. % FORMAT D = spm_eeg_convert(S)
  4. % S - string (filename) or struct (see below)
  5. %
  6. % If S is a struct it can have the optional following fields:
  7. % S.dataset - file name
  8. % S.mode - 'header' - only convert the header without reading data
  9. % 'continuous' - convert data as continuous
  10. % 'epoched' - convert data as epoched (requires data that is
  11. % already epoched or a trial definition in S.trl).
  12. % S.timewin - for continuous mode [start end] of data segment in sec (all if empty)
  13. % - for epoched mode time window in PST ms
  14. % S.outfile - output file name (default 'spmeeg_' + input)
  15. % S.channels - 'all' - convert all channels
  16. % or cell array of labels
  17. % For epoched mode:
  18. %
  19. % S.trl - [N x 3] trl matrix or name of the trial definition file
  20. % containing 'trl' variable with such a matrix
  21. % S.conditionlabels- labels for the trials in the data [default: 'Undefined']
  22. %
  23. % or
  24. %
  25. % S.trialdef - structure array for trial definition with fields
  26. % S.trialdef.conditionlabel - string label for the condition
  27. % S.trialdef.eventtype - string
  28. % S.trialdef.eventvalue - string, numeric or empty
  29. %
  30. %
  31. % S.inputformat - data type (optional) to force the use of specific data
  32. % reader
  33. % S.eventpadding - the additional time period around each trial for which
  34. % the events are saved with the trial (to let the user
  35. % keep and use for analysis events which are outside
  36. % trial borders), in seconds. [default: 0]
  37. % S.blocksize - size of blocks used internally to split large files
  38. % [default: ~100Mb]
  39. % S.checkboundary - 1 - check if there are breaks in the file and do not
  40. % read across those breaks [default]
  41. % 0 - ignore breaks (not recommended).
  42. % S.saveorigheader - 1 - save original data header with the dataset
  43. % 0 - do not keep the original header [default]
  44. %
  45. % % D - MEEG object (also written on disk)
  46. %__________________________________________________________________________
  47. % Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging
  48. % Vladimir Litvak
  49. % $Id: spm_eeg_convert.m 7451 2018-10-17 14:48:56Z vladimir $
  50. SVNrev = '$Rev: 7451 $';
  51. %-Startup
  52. %--------------------------------------------------------------------------
  53. spm('FnBanner', mfilename, SVNrev);
  54. spm('FigName','M/EEG convert'); spm('Pointer', 'Watch');
  55. if ischar(S)
  56. temp = S;
  57. S = [];
  58. S.dataset = temp;
  59. end
  60. if ~isfield(S, 'dataset')
  61. error('Dataset must be specified.');
  62. end
  63. if ~isfield(S, 'outfile'), S.outfile = ['spmeeg_' spm_file(S.dataset,'basename')]; end
  64. if ~isfield(S, 'channels'), S.channels = 'all'; end
  65. if ~isfield(S, 'timewin'), S.timewin = []; end
  66. if ~isfield(S, 'blocksize'), S.blocksize = 3276800; end %100 Mb
  67. if ~isfield(S, 'checkboundary'), S.checkboundary = 1; end
  68. if ~isfield(S, 'eventpadding'), S.eventpadding = 0; end
  69. if ~isfield(S, 'saveorigheader'), S.saveorigheader = 0; end
  70. if ~isfield(S, 'conditionlabels'), S.conditionlabels = 'Undefined' ; end
  71. if ~isfield(S, 'inputformat'), S.inputformat = [] ; end
  72. if ~iscell(S.conditionlabels)
  73. S.conditionlabels = {S.conditionlabels};
  74. end
  75. if ~isfield(S, 'mode') || ~isequal(S.mode, 'header')
  76. % The header is read here in a recursive call and the above if avoids reading
  77. % it twice which might be expensive for some formats
  78. S1 = [];
  79. S1.mode = 'header';
  80. S1.dataset = S.dataset;
  81. S1.outfile = S.outfile;
  82. S1.inputformat = S.inputformat;
  83. Dhdr = spm_eeg_convert(S1);
  84. hdr = Dhdr.hdr;
  85. event = Dhdr.events;
  86. eventsamples = Dhdr.events(':', 'samples');
  87. else
  88. %--------- Read and check header
  89. hdr = ft_read_header(S.dataset, 'headerformat', S.inputformat);
  90. if isfield(hdr, 'label')
  91. [unique_label,junk,ind] = unique(hdr.label);
  92. if length(unique_label) ~= length(hdr.label)
  93. warning(['Data file contains several channels with ',...
  94. 'the same name. These channels cannot be processed and will be disregarded']);
  95. % This finds the repeating labels and removes all their occurences
  96. sortind = sort(ind);
  97. [junk,ind2] = setdiff(hdr.label, unique_label(sortind(diff(sortind)==0)));
  98. hdr.label = hdr.label(ind2);
  99. hdr.nChans = length(hdr.label);
  100. end
  101. end
  102. %--------- Read and prepare events
  103. try
  104. event = ft_read_event(S.dataset, 'detectflank', 'both', 'eventformat', S.inputformat);
  105. if ~isempty(strmatch('UPPT001', hdr.label))
  106. % This is s somewhat ugly fix to the specific problem with event
  107. % coding in FIL CTF. It can also be useful for other CTF systems where the
  108. % pulses in the event channel go downwards.
  109. fil_ctf_events = ft_read_event(S.dataset, 'detectflank', 'down', 'type', 'UPPT001', 'trigshift', -1, 'eventformat', S.inputformat);
  110. if ~isempty(fil_ctf_events)
  111. [fil_ctf_events(:).type] = deal('FIL_UPPT001_down');
  112. event = cat(1, event(:), fil_ctf_events(:));
  113. end
  114. end
  115. if ~isempty(strmatch('UPPT002', hdr.label))
  116. % This is s somewhat ugly fix to the specific problem with event
  117. % coding in FIL CTF. It can also be useful for other CTF systems where the
  118. % pulses in the event channel go downwards.
  119. fil_ctf_events = ft_read_event(S.dataset, 'detectflank', 'down', 'type', 'UPPT002', 'trigshift', -1, 'eventformat', S.inputformat);
  120. if ~isempty(fil_ctf_events)
  121. [fil_ctf_events(:).type] = deal('FIL_UPPT002_down');
  122. event = cat(1, event(:), fil_ctf_events(:));
  123. end
  124. end
  125. % This is another FIL-specific fix that will hopefully not affect other sites
  126. if isfield(hdr, 'orig') && isfield(hdr.orig, 'VERSION') && isequal(uint8(hdr.orig.VERSION),uint8([255 'BIOSEMI']))
  127. ind = strcmp('STATUS', {event(:).type});
  128. val = [event(ind).value];
  129. if ~isempty(val)
  130. bytes = dec2bin(val);
  131. bytes = bytes(:, end-7:end);
  132. % This is a very specific criterion that assumes that
  133. % trigger code 1 is always used.
  134. if ~ismember('00000001', bytes, 'rows') && ismember('10000000', bytes, 'rows')
  135. bytes = fliplr(bytes);
  136. end
  137. nval = bin2dec(bytes);
  138. if (sum(val(:)>nval(:))/length(val))>0.5
  139. nval = num2cell(nval);
  140. [event(ind).value] = deal(nval{:});
  141. end
  142. end
  143. end
  144. catch
  145. warning(['Could not read events from file ' S.dataset]);
  146. event = [];
  147. end
  148. % Replace samples with time
  149. if numel(event)>0
  150. for i = 1:numel(event)
  151. event(i).time = event(i).sample./hdr.Fs;
  152. end
  153. end
  154. end
  155. if ~isfield(S, 'mode')
  156. if (hdr.nTrials == 1)
  157. S.mode = 'continuous';
  158. else
  159. S.mode = 'epoched';
  160. end
  161. end
  162. %--------- Start making the header
  163. D = [];
  164. D.Fsample = hdr.Fs;
  165. %--------- Select channels
  166. if ~strcmp(S.channels, 'all') %Dhdr should be available in this case
  167. chansel = selectchannels(Dhdr, S.channels);
  168. else
  169. if isfield(hdr, 'nChans')
  170. chansel = 1:hdr.nChans;
  171. else
  172. chansel = 1:length(hdr.label);
  173. end
  174. end
  175. nchan = length(chansel);
  176. D.channels = repmat(struct('bad', 0), 1, nchan);
  177. if isfield(hdr, 'label')
  178. [D.channels(:).label] = deal(hdr.label{chansel});
  179. end
  180. %--------- Preparations specific to reading mode (continuous/epoched)
  181. if ismember(S.mode, {'continuous', 'header'})
  182. if isempty(S.timewin)
  183. if hdr.nTrials == 1
  184. segmentbounds = [1 hdr.nSamples];
  185. elseif ~S.checkboundary || isequal(S.mode, 'header')
  186. segmentbounds = [1 hdr.nSamples*hdr.nTrials];
  187. else
  188. error('The data cannot be read without ignoring trial borders');
  189. end
  190. timewindow = segmentbounds./D.Fsample;
  191. else
  192. timewindow = S.timewin;
  193. segmentbounds = round(timewindow.*D.Fsample);
  194. segmentbounds(1) = max(segmentbounds(1), 1);
  195. end
  196. %--------- Sort events and put in the trial
  197. if ~isempty(event)
  198. try
  199. event = rmfield(event, {'offset', 'sample'});
  200. end
  201. event = select_events(event, ...
  202. [timewindow(1)-S.eventpadding timewindow(2)+S.eventpadding]);
  203. end
  204. D.trials.label = S.conditionlabels{1};
  205. D.trials.events = event;
  206. D.trials.onset = timewindow(1);
  207. %--------- Break too long segments into blocks
  208. nblocksamples = floor(S.blocksize/nchan);
  209. nsampl = diff(segmentbounds)+1;
  210. trl = segmentbounds(1):nblocksamples:segmentbounds(2);
  211. if (trl(end)==segmentbounds(2))
  212. trl = trl(1:(end-1));
  213. end
  214. trl = [trl(:) [trl(2:end)-1 segmentbounds(2)]'];
  215. ntrial = size(trl, 1);
  216. readbytrials = 0;
  217. D.timeOnset = (trl(1,1)-1)./hdr.Fs;
  218. D.Nsamples = nsampl;
  219. else % Read by trials
  220. if isfield(S, 'trl') || isfield(S, 'trialdef')
  221. if isfield(S, 'trl')
  222. if ischar(S.trl)
  223. trl = getfield(load(S.trl, 'trl'), 'trl');
  224. conditionlabels = getfield(load(S.trl, 'conditionlabels'), 'conditionlabels');
  225. else
  226. trl = S.trl;
  227. conditionlabels = S.conditionlabels;
  228. end
  229. else
  230. S1 = [];
  231. S1.D = Dhdr;
  232. S1.timewin = S.timewin;
  233. S1.trialdef = S.trialdef;
  234. S1.reviewtrials = 0;
  235. S1.save = 0;
  236. [trl, conditionlabels] = spm_eeg_definetrial(S1);
  237. end
  238. trl = double(trl);
  239. if size(trl, 2) >= 3
  240. D.timeOnset = unique(trl(:, 3))./D.Fsample;
  241. trl = trl(:, 1:2);
  242. else
  243. D.timeOnset = 0;
  244. end
  245. if length(D.timeOnset) > 1
  246. error('All trials should have identical baseline');
  247. end
  248. if ~iscell(conditionlabels)
  249. conditionlabels = {conditionlabels};
  250. end
  251. if numel(conditionlabels) == 1
  252. conditionlabels = repmat(conditionlabels, 1, size(trl, 1));
  253. end
  254. readbytrials = 0;
  255. else
  256. try
  257. trialind = sort([strmatch('trial', {event.type}, 'exact'), ...
  258. strmatch('average', {event.type}, 'exact')]);
  259. trl = [eventsamples(trialind).sample];
  260. trl = double(trl(:));
  261. trl = [trl trl+double([event(trialind).duration]')-1];
  262. try
  263. offset = unique([event(trialind).offset]);
  264. catch
  265. offset = [];
  266. end
  267. if length(offset) == 1 && offset~=0
  268. D.timeOnset = offset/D.Fsample;
  269. else
  270. D.timeOnset = -hdr.nSamplesPre/hdr.Fs;
  271. end
  272. conditionlabels = {};
  273. for i = 1:length(trialind)
  274. if isempty(event(trialind(i)).value)
  275. conditionlabels{i} = S.conditionlabels{1};
  276. else
  277. if all(ischar(event(trialind(i)).value))
  278. conditionlabels{i} = event(trialind(i)).value;
  279. else
  280. conditionlabels{i} = num2str(event(trialind(i)).value);
  281. end
  282. end
  283. end
  284. if hdr.nTrials>1 && size(trl, 1)~=hdr.nTrials
  285. warning('Mismatch between trial definition in events and in data. Ignoring events');
  286. readbytrials = 1;
  287. else
  288. readbytrials = 0;
  289. end
  290. event = event(setdiff(1:numel(event), trialind));
  291. catch
  292. if hdr.nTrials == 1
  293. error('Could not define trials based on data. Use continuous option or trial definition file.');
  294. else
  295. readbytrials = 1;
  296. end
  297. end
  298. end
  299. if readbytrials
  300. nsampl = hdr.nSamples;
  301. ntrial = hdr.nTrials;
  302. trl = zeros(ntrial, 2);
  303. if exist('conditionlabels', 'var') ~= 1 || length(conditionlabels) ~= ntrial
  304. conditionlabels = repmat(S.conditionlabels, 1, ntrial);
  305. end
  306. else
  307. nsampl = unique(diff(trl, [], 2))+1;
  308. if length(nsampl) > 1
  309. error('All trials should have identical lengths');
  310. end
  311. inbounds = (trl(:,1)>=1 & trl(:, 2)<=hdr.nSamples*hdr.nTrials)';
  312. rejected = find(~inbounds);
  313. if ~isempty(rejected)
  314. trl = trl(inbounds, :);
  315. conditionlabels = conditionlabels(inbounds);
  316. warning([S.dataset ': Trials ' num2str(rejected) ' not read - out of bounds']);
  317. end
  318. ntrial = size(trl, 1);
  319. if ntrial == 0
  320. warning([S.dataset ': No trials to read. Bailing out.']);
  321. D = [];
  322. return;
  323. end
  324. end
  325. D.Nsamples = nsampl;
  326. if isfield(event, 'sample')
  327. event = rmfield(event, 'sample');
  328. end
  329. end
  330. %--------- Prepare for reading the data
  331. outpath = spm_file(S.outfile,'fpath');
  332. outfile = spm_file(S.outfile,'basename');
  333. if isempty(outfile), outfile = 'spmeeg'; end
  334. D.path = outpath;
  335. D.fname = [outfile '.mat'];
  336. if ~isequal(S.mode, 'header')
  337. % These are the units used for channel data in SPM
  338. chanunit = units(Dhdr, chansel);
  339. chanunit(strcmp('T', chanunit)) = {'fT'};
  340. chanunit(strcmp('T/m', chanunit)) = {'fT/mm'};
  341. chanunit(strcmp('V', chanunit)) = {'uV'};
  342. if isequal(S.mode, 'continuous')
  343. D.data = file_array(fullfile(D.path, [outfile '.dat']), [nchan nsampl], 'float32-le');
  344. else
  345. D.data = file_array(fullfile(D.path, [outfile '.dat']), [nchan nsampl ntrial], 'float32-le');
  346. end
  347. % physically initialise file
  348. initialise(D.data);
  349. spm_progress_bar('Init', ntrial, 'reading and converting'); drawnow;
  350. if ntrial > 100, Ibar = floor(linspace(1, ntrial,100));
  351. else Ibar = 1:ntrial; end
  352. %--------- Read the data
  353. offset = 1;
  354. for i = 1:ntrial
  355. spm_progress_bar('Set','ylabel','reading...');
  356. if readbytrials
  357. dat = ft_read_data(S.dataset,'header', hdr, 'begtrial', i, 'endtrial', i,...
  358. 'chanindx', chansel, 'chanunit', chanunit, 'checkboundary', S.checkboundary, 'dataformat', S.inputformat);
  359. else
  360. dat = ft_read_data(S.dataset,'header', hdr, 'begsample', trl(i, 1), 'endsample', trl(i, 2),...
  361. 'chanindx', chansel, 'chanunit', chanunit, 'checkboundary', S.checkboundary, 'dataformat', S.inputformat);
  362. end
  363. % Sometimes ft_read_data returns sparse output
  364. dat = full(dat);
  365. spm_progress_bar('Set','ylabel','writing...');
  366. switch S.mode
  367. case 'continuous'
  368. nblocksamples = size(dat,2);
  369. D.data(:, offset:(offset+nblocksamples-1)) = dat;
  370. offset = offset+nblocksamples;
  371. case 'epoched'
  372. D.data(:, :, i) = dat;
  373. D.trials(i).label = conditionlabels{i};
  374. D.trials(i).onset = trl(i, 1)./D.Fsample;
  375. D.trials(i).events = select_events(event, ...
  376. [ trl(i, 1)./D.Fsample-S.eventpadding trl(i, 2)./D.Fsample+S.eventpadding]);
  377. end
  378. if ismember(i, Ibar)
  379. spm_progress_bar('Set', i);
  380. end
  381. end
  382. spm_progress_bar('Clear');
  383. else
  384. D.data = [];
  385. end
  386. % Specify sensor positions and fiducials
  387. if isfield(hdr, 'grad')
  388. D.sensors.meg = hdr.grad;
  389. end
  390. if isfield(hdr, 'elec')
  391. elec = hdr.elec;
  392. else
  393. try
  394. elec = ft_read_sens(S.dataset, 'fileformat', S.inputformat);
  395. % It might be that read_sens will return the grad for MEG datasets
  396. if any(ismember({'ori', 'coilori', 'coilpos'}, fieldnames(elec)))
  397. elec = [];
  398. end
  399. catch
  400. elec = [];
  401. end
  402. end
  403. if ~isempty(elec)
  404. D.sensors.eeg = elec;
  405. else
  406. sw = warning('off','backtrace');
  407. warning('Could not obtain electrode locations automatically.');
  408. warning(sw);
  409. end
  410. try
  411. D.fiducials = ft_convert_units(ft_read_headshape(S.dataset, 'fileformat', S.inputformat), 'mm');
  412. catch
  413. sw = warning('off','backtrace');
  414. warning('Could not obtain fiducials automatically.');
  415. warning(sw);
  416. end
  417. %--------- Create meeg object
  418. D = meeg(D);
  419. % history
  420. D = D.history('spm_eeg_convert', S);
  421. if isfield(hdr, 'orig')
  422. if S.saveorigheader
  423. D.origheader = hdr.orig;
  424. end
  425. % Uses fileio function to get the information about channel types stored in
  426. % the original header.
  427. origchantypes = ft_chantype(hdr);
  428. [sel1, sel2] = spm_match_str(D.chanlabels, hdr.label);
  429. origchantypes = origchantypes(sel2);
  430. if length(strmatch('unknown', origchantypes, 'exact')) ~= numel(origchantypes)
  431. D.origchantypes = struct([]);
  432. D.origchantypes(1).label = hdr.label(sel2);
  433. D.origchantypes(1).type = origchantypes;
  434. end
  435. end
  436. S1 = [];
  437. S1.task = 'defaulttype';
  438. S1.D = D;
  439. S1.updatehistory = 0;
  440. D = spm_eeg_prep(S1);
  441. % Assign default EEG sensor positions if possible
  442. if ~isempty(strmatch('EEG', D.chantype, 'exact'))
  443. if isempty(D.sensors('EEG'))
  444. S1 = [];
  445. S1.task = 'defaulteegsens';
  446. S1.updatehistory = 0;
  447. S1.D = D;
  448. D = spm_eeg_prep(S1);
  449. else
  450. S1 = [];
  451. S1.task = 'project3D';
  452. S1.modality = 'EEG';
  453. S1.updatehistory = 0;
  454. S1.D = D;
  455. D = spm_eeg_prep(S1);
  456. end
  457. end
  458. % Create 2D positions for MEG
  459. % by projecting the 3D positions to 2D
  460. if ~isempty(strmatch('MEG', D.chantype)) && ~isempty(D.sensors('MEG'))
  461. S1 = [];
  462. S1.task = 'project3D';
  463. S1.modality = 'MEG';
  464. S1.updatehistory = 0;
  465. S1.D = D;
  466. D = spm_eeg_prep(S1);
  467. end
  468. % If channel units are available, store them.
  469. if isequal(S.mode, 'header')
  470. [sel1, sel2] = spm_match_str(D.chanlabels, hdr.label);
  471. D = units(D, sel1, hdr.chanunit(sel2));
  472. else
  473. D = units(D, ':', chanunit);
  474. end
  475. % The conditions will later be sorted in the original order they were defined.
  476. if isfield(S, 'trialdef')
  477. D = condlist(D, {S.trialdef(:).conditionlabel});
  478. end
  479. % This is for the recursive call to work properly
  480. if isequal(S.mode, 'header')
  481. D.hdr = hdr;
  482. end
  483. if ~isequal(S.mode, 'header')
  484. save(D);
  485. end
  486. %-Cleanup
  487. %--------------------------------------------------------------------------
  488. fprintf('%-40s: %30s\n','Completed',spm('time')); %-#
  489. spm('FigName','M/EEG convert: done'); spm('Pointer', 'Arrow');
  490. %==========================================================================
  491. % select_events
  492. %==========================================================================
  493. function event = select_events(event, timeseg)
  494. % Utility function to select events according to time segment
  495. % FORMAT event = select_events(event, timeseg)
  496. if iscell(event)
  497. event = event{1};
  498. end
  499. if ~isempty(event)
  500. [time,ind] = sort([event(:).time]);
  501. selectind = ind(time>=timeseg(1) & time<=timeseg(2));
  502. event = event(selectind);
  503. end