PageRenderTime 63ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/toolboxes/fieldtrip/utilities/ft_checkdata.m

http://brainstream.googlecode.com/
MATLAB | 1926 lines | 1574 code | 121 blank | 231 comment | 249 complexity | a01e1dffd614d3e255fe5b37a270a4e7 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, LGPL-2.0, GPL-3.0, GPL-2.0, LGPL-2.1, LGPL-3.0, BSD-2-Clause

Large files files are truncated, but you can click here to view the full file

  1. function [data] = ft_checkdata(data, varargin)
  2. % FT_CHECKDATA checks the input data of the main FieldTrip functions, e.g. whether
  3. % the type of data strucure corresponds with the required data. If neccessary
  4. % and possible, this function will adjust the data structure to the input
  5. % requirements (e.g. change dimord, average over trials, convert inside from
  6. % index into logical).
  7. %
  8. % If the input data does NOT correspond to the requirements, this function
  9. % is supposed to give a elaborate warning message and if applicable point
  10. % the user to external documentation (link to website).
  11. %
  12. % Use as
  13. % [data] = ft_checkdata(data, ...)
  14. %
  15. % Optional input arguments should be specified as key-value pairs and can include
  16. % feedback = yes, no
  17. % datatype = raw, freq, timelock, comp, spike, source, volume, dip
  18. % dimord = any combination of time, freq, chan, refchan, rpt, subj, chancmb, rpttap, pos
  19. % senstype = ctf151, ctf275, ctf151_planar, ctf275_planar, neuromag122, neuromag306, bti148, bti248, bti248_planar, magnetometer, electrode
  20. % inside = logical, index
  21. % ismeg = yes, no
  22. % hastrials = yes, no
  23. % hasunits = yes, no
  24. % hassampleinfo = yes, no, ifmakessense
  25. % hascumtapcnt = yes, no (only applies to freq data)
  26. % hasdim = yes, no
  27. % hasdof = yes, no
  28. % cmbrepresentation = sparse, full (applies to covariance and cross-spectral density)
  29. % fsample = sampling frequency to use to go from SPIKE to RAW representation
  30. %
  31. % For some options you can specify multiple values, e.g.
  32. % [data] = ft_checkdata(data, 'senstype', {'ctf151', 'ctf275'}), e.g. in megrealign
  33. % [data] = ft_checkdata(data, 'datatype', {'timelock', 'freq'}), e.g. in sourceanalysis
  34. % Copyright (C) 2007-2009, Robert Oostenveld
  35. %
  36. % This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
  37. % for the documentation and details.
  38. %
  39. % FieldTrip is free software: you can redistribute it and/or modify
  40. % it under the terms of the GNU General Public License as published by
  41. % the Free Software Foundation, either version 3 of the License, or
  42. % (at your option) any later version.
  43. %
  44. % FieldTrip is distributed in the hope that it will be useful,
  45. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  46. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  47. % GNU General Public License for more details.
  48. %
  49. % You should have received a copy of the GNU General Public License
  50. % along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
  51. %
  52. % $Id: ft_checkdata.m 5033 2011-12-14 10:46:20Z roboos $
  53. % in case of an error this function could use dbstack for more detailled
  54. % user feedback
  55. %
  56. % this function should replace/encapsulate
  57. % fixdimord
  58. % fixinside
  59. % fixprecision
  60. % fixvolume
  61. % data2raw
  62. % raw2data
  63. % grid2transform
  64. % transform2grid
  65. % fourier2crsspctrm
  66. % freq2cumtapcnt
  67. % sensortype
  68. % time2offset
  69. % offset2time
  70. % fixsens -> this is kept a separate function because it should also be
  71. % called from other modules
  72. %
  73. % other potential uses for this function:
  74. % time -> offset in freqanalysis
  75. % average over trials
  76. % csd as matrix
  77. % get the optional input arguments
  78. feedback = ft_getopt(varargin, 'feedback', 'no');
  79. dtype = ft_getopt(varargin, 'datatype'); % should not conflict with the ft_datatype function
  80. dimord = ft_getopt(varargin, 'dimord');
  81. stype = ft_getopt(varargin, 'senstype'); % senstype is a function name which should not be masked
  82. ismeg = ft_getopt(varargin, 'ismeg');
  83. inside = ft_getopt(varargin, 'inside'); % can be 'logical' or 'index'
  84. hastrials = ft_getopt(varargin, 'hastrials');
  85. hasunits = ft_getopt(varargin, 'hasunits');
  86. hassampleinfo = ft_getopt(varargin, 'hassampleinfo', 'no');
  87. hasdimord = ft_getopt(varargin, 'hasdimord', 'no');
  88. hasdim = ft_getopt(varargin, 'hasdim');
  89. hascumtapcnt = ft_getopt(varargin, 'hascumtapcnt');
  90. hasdof = ft_getopt(varargin, 'hasdof', 'no');
  91. haspow = ft_getopt(varargin, 'haspow', 'no');
  92. cmbrepresentation = ft_getopt(varargin, 'cmbrepresentation');
  93. channelcmb = ft_getopt(varargin, 'channelcmb');
  94. sourcedimord = ft_getopt(varargin, 'sourcedimord');
  95. sourcerepresentation = ft_getopt(varargin, 'sourcerepresentation');
  96. fsample = ft_getopt(varargin, 'fsample');
  97. % check whether people are using deprecated stuff
  98. depHastrialdef = ft_getopt(varargin, 'hastrialdef');
  99. if (~isempty(depHastrialdef))
  100. warning_once('ft_checkdata option ''hastrialdef'' is deprecated; use ''hassampleinfo'' instead');
  101. hassampleinfo = depHastrialdef;
  102. end
  103. if (~isempty(ft_getopt(varargin, 'hasoffset')))
  104. warning_once('ft_checkdata option ''hasoffset'' has been removed and will be ignored');
  105. end
  106. % determine the type of input data
  107. % this can be raw, freq, timelock, comp, spike, source, volume, dip
  108. israw = ft_datatype(data, 'raw');
  109. isfreq = ft_datatype(data, 'freq');
  110. istimelock = ft_datatype(data, 'timelock');
  111. iscomp = ft_datatype(data, 'comp');
  112. isspike = ft_datatype(data, 'spike');
  113. isvolume = ft_datatype(data, 'volume');
  114. issource = ft_datatype(data, 'source');
  115. isdip = ft_datatype(data, 'dip');
  116. ismvar = ft_datatype(data, 'mvar');
  117. isfreqmvar = ft_datatype(data, 'freqmvar');
  118. ischan = ft_datatype(data, 'chan');
  119. % FIXME use the istrue function on ismeg and hasxxx options
  120. if ~isequal(feedback, 'no')
  121. if israw
  122. nchan = length(data.label);
  123. ntrial = length(data.trial);
  124. fprintf('the input is raw data with %d channels and %d trials\n', nchan, ntrial);
  125. elseif isfreq
  126. nchan = length(data.label);
  127. nfreq = length(data.freq);
  128. if isfield(data, 'time'), ntime = num2str(length(data.time)); else ntime = 'no'; end
  129. fprintf('the input is freq data with %d channels, %d frequencybins and %s timebins\n', nchan, nfreq, ntime);
  130. elseif istimelock
  131. nchan = length(data.label);
  132. ntime = length(data.time);
  133. fprintf('the input is timelock data with %d channels and %d timebins\n', nchan, ntime);
  134. elseif iscomp
  135. ncomp = length(data.label);
  136. nchan = length(data.topolabel);
  137. fprintf('the input is component data with %d components and %d original channels\n', ncomp, nchan);
  138. elseif isspike
  139. nchan = length(data.label);
  140. fprintf('the input is spike data with %d channels\n',nchan);
  141. elseif isvolume
  142. fprintf('the input is volume data with dimensions [%d %d %d]\n', data.dim(1), data.dim(2), data.dim(3));
  143. elseif issource
  144. nsource = size(data.pos, 1);
  145. fprintf('the input is source data with %d positions\n', nsource);
  146. elseif isdip
  147. fprintf('the input is dipole data\n');
  148. elseif ismvar
  149. fprintf('the input is mvar data\n');
  150. elseif isfreqmvar
  151. fprintf('the input is freqmvar data\n');
  152. elseif ischan
  153. nchan = length(data.label);
  154. fprintf('the input is chan data\n');
  155. end
  156. end % give feedback
  157. if issource && isvolume
  158. % it should be either one or the other: the choice here is to
  159. % represent it as volume description since that is simpler to handle
  160. % the conversion is done by remove the grid positions
  161. data = rmfield(data, 'pos');
  162. issource = false;
  163. end
  164. % the ft_datatype_XXX functions ensures the consistency of the XXX datatype
  165. % and provides a detailled description of the dataformat and its history
  166. if israw
  167. data = ft_datatype_raw(data, 'hassampleinfo', hassampleinfo);
  168. elseif isfreq
  169. data = ft_datatype_freq(data);
  170. elseif istimelock
  171. data = ft_datatype_timelock(data);
  172. elseif iscomp
  173. data = ft_datatype_comp(data);
  174. elseif isspike
  175. data = ft_datatype_spike(data);
  176. elseif isvolume
  177. data = ft_datatype_volume(data);
  178. elseif issource
  179. data = ft_datatype_source(data);
  180. elseif isdip
  181. data = ft_datatype_dip(data);
  182. elseif ismvar || isfreqmvar
  183. data = ft_datatype_mvar(data);
  184. end
  185. if ~isempty(dtype)
  186. if ~isa(dtype, 'cell')
  187. dtype = {dtype};
  188. end
  189. okflag = 0;
  190. for i=1:length(dtype)
  191. % check that the data matches with one or more of the required ft_datatypes
  192. switch dtype{i}
  193. case 'raw'
  194. okflag = okflag + israw;
  195. case 'freq'
  196. okflag = okflag + isfreq;
  197. case 'timelock'
  198. okflag = okflag + istimelock;
  199. case 'comp'
  200. okflag = okflag + iscomp;
  201. case 'spike'
  202. okflag = okflag + isspike;
  203. case 'volume'
  204. okflag = okflag + isvolume;
  205. case 'source'
  206. okflag = okflag + issource;
  207. case 'dip'
  208. okflag = okflag + isdip;
  209. case 'mvar'
  210. okflag = okflag + ismvar;
  211. case 'freqmvar'
  212. okflag = okflag + isfreqmvar;
  213. case 'chan'
  214. okflag = okflag + ischan;
  215. end % switch dtype
  216. end % for dtype
  217. if ~okflag
  218. % try to convert the data
  219. for iCell = 1:length(dtype)
  220. if isequal(dtype(iCell), {'source'}) && isvolume
  221. data = volume2source(data);
  222. isvolume = 0;
  223. issource = 1;
  224. okflag = 1;
  225. elseif isequal(dtype(iCell), {'volume'}) && issource
  226. data = source2volume(data);
  227. isvolume = 1;
  228. issource = 0;
  229. okflag = 1;
  230. elseif isequal(dtype(iCell), {'raw'}) && issource
  231. data = data2raw(data);
  232. issource = 0;
  233. israw = 1;
  234. okflag = 1;
  235. elseif isequal(dtype(iCell), {'raw'}) && istimelock
  236. data = timelock2raw(data);
  237. istimelock = 0;
  238. israw = 1;
  239. okflag = 1;
  240. elseif isequal(dtype(iCell), {'timelock'}) && israw
  241. data = raw2timelock(data);
  242. israw = 0;
  243. istimelock = 1;
  244. okflag = 1;
  245. elseif isequal(dtype(iCell), {'raw'}) && isfreq
  246. data = freq2raw(data);
  247. isfreq = 0;
  248. israw = 1;
  249. okflag = 1;
  250. elseif isequal(dtype(iCell), {'raw'}) && iscomp
  251. data = comp2raw(data);
  252. iscomp = 0;
  253. israw = 1;
  254. okflag = 1;
  255. elseif isequal(dtype(iCell), {'timelock'}) && iscomp
  256. data = comp2raw(data);
  257. data = raw2timelock(data);
  258. iscomp = 0;
  259. istimelock = 1;
  260. okflag = 1;
  261. elseif isequal(dtype(iCell), {'timelock'}) && ischan
  262. data = chan2timelock(data);
  263. ischan = 0;
  264. istimelock = 1;
  265. okflag = 1;
  266. elseif isequal(dtype(iCell), {'freq'}) && ischan
  267. data = chan2freq(data);
  268. ischan = 0;
  269. isfreq = 1;
  270. okflag = 1;
  271. elseif isequal(dtype(iCell), {'spike'}) && israw
  272. data = raw2spike(data);
  273. israw = 0;
  274. isspike = 1;
  275. okflag = 1;
  276. elseif isequal(dtype(iCell), {'raw'}) && isspike
  277. data = spike2raw(data,fsample);
  278. isspike = 0;
  279. israw = 1;
  280. okflag = 1;
  281. end
  282. end % for iCell
  283. end % if okflag
  284. if ~okflag
  285. % construct an error message
  286. if length(dtype)>1
  287. str = sprintf('%s, ', dtype{1:(end-2)});
  288. str = sprintf('%s%s or %s', str, dtype{end-1}, dtype{end});
  289. else
  290. str = dtype{1};
  291. end
  292. str = sprintf('This function requires %s data as input.', str);
  293. error(str);
  294. end % if okflag
  295. end
  296. if ~isempty(dimord)
  297. if ~isa(dimord, 'cell')
  298. dimord = {dimord};
  299. end
  300. if isfield(data, 'dimord')
  301. okflag = any(strcmp(data.dimord, dimord));
  302. else
  303. okflag = 0;
  304. end
  305. if ~okflag
  306. % construct an error message
  307. if length(dimord)>1
  308. str = sprintf('%s, ', dimord{1:(end-2)});
  309. str = sprintf('%s%s or %s', str, dimord{end-1}, dimord{end});
  310. else
  311. str = dimord{1};
  312. end
  313. str = sprintf('This function requires data with a dimord of %s.', str);
  314. error(str);
  315. end % if okflag
  316. end
  317. if ~isempty(stype)
  318. if ~isa(stype, 'cell')
  319. stype = {stype};
  320. end
  321. if isfield(data, 'grad') || isfield(data, 'elec')
  322. if any(strcmp(ft_senstype(data), stype));
  323. okflag = 1;
  324. else
  325. okflag = 0;
  326. end
  327. else
  328. okflag = 0;
  329. end
  330. if ~okflag
  331. % construct an error message
  332. if length(stype)>1
  333. str = sprintf('%s, ', stype{1:(end-2)});
  334. str = sprintf('%s%s or %s', str, stype{end-1}, stype{end});
  335. else
  336. str = stype{1};
  337. end
  338. str = sprintf('This function requires %s data as input, but you are giving %s data.', str, ft_senstype(data));
  339. error(str);
  340. end % if okflag
  341. end
  342. if ~isempty(ismeg)
  343. if isequal(ismeg, 'yes')
  344. okflag = isfield(data, 'grad');
  345. elseif isequal(ismeg, 'no')
  346. okflag = ~isfield(data, 'grad');
  347. end
  348. if ~okflag && isequal(ismeg, 'yes')
  349. error('This function requires MEG data with a ''grad'' field');
  350. elseif ~okflag && isequal(ismeg, 'no')
  351. error('This function should not be given MEG data with a ''grad'' field');
  352. end % if okflag
  353. end
  354. if ~isempty(inside)
  355. % TODO absorb the fixinside function into this code
  356. data = fixinside(data, inside);
  357. okflag = isfield(data, 'inside');
  358. if ~okflag
  359. % construct an error message
  360. error('This function requires data with an ''inside'' field.');
  361. end % if okflag
  362. end
  363. %if isvolume
  364. % % ensure consistent dimensions of the volumetric data
  365. % % reshape each of the volumes that is found into a 3D array
  366. % param = parameterselection('all', data);
  367. % dim = data.dim;
  368. % for i=1:length(param)
  369. % tmp = getsubfield(data, param{i});
  370. % tmp = reshape(tmp, dim);
  371. % data = setsubfield(data, param{i}, tmp);
  372. % end
  373. %end
  374. if isequal(hasunits, 'yes') && ~isfield(data, 'units')
  375. % calling convert_units with only the input data adds the units without converting
  376. data = ft_convert_units(data);
  377. end
  378. if issource || isvolume,
  379. % the following section is to make a dimord-consistent representation of
  380. % volume and source data, taking trials, time and frequency into account
  381. if isequal(hasdimord, 'yes') && (~isfield(data, 'dimord') || ~strcmp(data.dimord,sourcedimord))
  382. % determine the size of the data
  383. if isfield(data, 'dimord'),
  384. dimtok = tokenize(data.dimord, '_');
  385. if ~isempty(strmatch('time', dimtok)), Ntime = length(data.time); else Ntime = 1; end
  386. if ~isempty(strmatch('freq', dimtok)), Nfreq = length(data.freq); else Nfreq = 1; end
  387. else
  388. Nfreq = 1;
  389. Ntime = 1;
  390. end
  391. %convert old style source representation into new style
  392. if isfield(data, 'avg') && isfield(data.avg, 'mom') && (isfield(data, 'freq') || isfield(data, 'frequency')) && strcmp(sourcedimord, 'rpt_pos'),
  393. %frequency domain source representation convert to single trial power
  394. Npos = size(data.pos,1);
  395. Nrpt = size(data.cumtapcnt,1);
  396. tmpmom = zeros(Npos, size(data.avg.mom{data.inside(1)},2));
  397. tmpmom(data.inside,:) = cat(1,data.avg.mom{data.inside});
  398. tmppow = zeros(Npos, Nrpt);
  399. tapcnt = [0;cumsum(data.cumtapcnt)];
  400. for k = 1:Nrpt
  401. Ntap = tapcnt(k+1)-tapcnt(k);
  402. tmppow(data.inside,k) = sum(abs(tmpmom(data.inside,(tapcnt(k)+1):tapcnt(k+1))).^2,2)./Ntap;
  403. end
  404. data.pow = tmppow';
  405. data = rmfield(data, 'avg');
  406. if strcmp(inside, 'logical'),
  407. data = fixinside(data, 'logical');
  408. data.inside = repmat(data.inside(:)',[Nrpt 1]);
  409. end
  410. elseif isfield(data, 'avg') && isfield(data.avg, 'mom') && (isfield(data, 'freq') || isfield(data, 'frequency')) && strcmp(sourcedimord, 'rpttap_pos'),
  411. %frequency domain source representation convert to single taper fourier coefficients
  412. Npos = size(data.pos,1);
  413. Nrpt = sum(data.cumtapcnt);
  414. data.fourierspctrm = complex(zeros(Nrpt, Npos), zeros(Nrpt, Npos));
  415. data.fourierspctrm(:, data.inside) = transpose(cat(1, data.avg.mom{data.inside}));
  416. data = rmfield(data, 'avg');
  417. elseif isfield(data, 'avg') && isfield(data.avg, 'mom') && isfield(data, 'time') && strcmp(sourcedimord, 'pos_time'),
  418. Npos = size(data.pos,1);
  419. Nrpt = 1;
  420. tmpmom = zeros(Npos, size(data.avg.mom{data.inside(1)},2));
  421. tmpmom(data.inside,:) = cat(1,data.avg.mom{data.inside});
  422. data.mom = tmpmom;
  423. if isfield(data.avg, 'noise'),
  424. tmpnoise = data.avg.noise(:);
  425. data.noise = tmpnoise(:,ones(1,size(tmpmom,2)));
  426. end
  427. data = rmfield(data, 'avg');
  428. Ntime = length(data.time);
  429. elseif isfield(data, 'trial') && isfield(data.trial(1), 'mom') && isfield(data, 'time') && strcmp(sourcedimord, 'rpt_pos_time'),
  430. Npos = size(data.pos,1);
  431. Nrpt = length(data.trial);
  432. Ntime = length(data.time);
  433. tmpmom = zeros(Nrpt, Npos, Ntime);
  434. for k = 1:Nrpt
  435. tmpmom(k,data.inside,:) = cat(1,data.trial(k).mom{data.inside});
  436. end
  437. data = rmfield(data, 'trial');
  438. data.mom = tmpmom;
  439. elseif isfield(data, 'trial') && isstruct(data.trial)
  440. Nrpt = length(data.trial);
  441. else
  442. Nrpt = 1;
  443. end
  444. % start with an initial specification of the dimord and dim
  445. if (~isfield(data, 'dim') || ~isfield(data, 'dimord'))
  446. if issource
  447. % at least it should have a Nx3 pos
  448. data.dim = size(data.pos, 1);
  449. data.dimord = 'pos';
  450. elseif isvolume
  451. % at least it should have a 1x3 dim
  452. data.dim = data.dim;
  453. data.dimord = 'dim1_dim2_dim3';
  454. end
  455. end
  456. % add the additional dimensions
  457. if Nfreq>1
  458. data.dimord = [data.dimord '_freq'];
  459. data.dim = [data.dim Nfreq];
  460. end
  461. if Ntime>1
  462. data.dimord = [data.dimord '_time'];
  463. data.dim = [data.dim Ntime];
  464. end
  465. if Nrpt>1 && strcmp(sourcedimord, 'rpt_pos'),
  466. data.dimord = ['rpt_' data.dimord];
  467. data.dim = [Nrpt data.dim ];
  468. elseif Nrpt>1 && strcmp(sourcedimord, 'rpttap_pos'),
  469. data.dimord = ['rpttap_' data.dimord];
  470. data.dim = [Nrpt data.dim ];
  471. end
  472. % the nested trial structure is not compatible with dimord
  473. if isfield(data, 'trial') && isstruct(data.trial)
  474. param = fieldnames(data.trial);
  475. for i=1:length(param)
  476. if isa(data.trial(1).(param{i}), 'cell')
  477. concat = cell(data.dim(1), prod(data.dim(2:end)));
  478. else
  479. concat = zeros(data.dim(1), prod(data.dim(2:end)));
  480. end
  481. for j=1:length(data.trial)
  482. tmp = data.trial(j).(param{i});
  483. concat(j,:) = tmp(:);
  484. end % for each trial
  485. data.trial = rmfield(data.trial, param{i});
  486. data.(param{i}) = reshape(concat, data.dim);
  487. end % for each param
  488. data = rmfield(data, 'trial');
  489. end
  490. end
  491. % ensure consistent dimensions of the source reconstructed data
  492. % reshape each of the source reconstructed parameters
  493. if issource && isfield(data, 'dim') && prod(data.dim)==size(data.pos,1)
  494. dim = [prod(data.dim) 1];
  495. %elseif issource && any(~cellfun('isempty',strfind(fieldnames(data), 'dimord')))
  496. % dim = [size(data.pos,1) 1]; %sparsely represented source structure new style
  497. elseif isfield(data, 'dim'),
  498. dim = [data.dim 1];
  499. elseif issource && ~isfield(data, 'dimord')
  500. dim = [size(data.pos,1) 1];
  501. elseif isfield(data, 'dimord'),
  502. %HACK
  503. dimtok = tokenize(data.dimord, '_');
  504. for i=1:length(dimtok)
  505. if strcmp(dimtok(i), 'pos')
  506. dim(1,i) = size(getsubfield(data,dimtok{i}),1);
  507. elseif strcmp(dimtok(i), 'rpt')
  508. dim(1,i) = nan;
  509. else
  510. dim(1,i) = length(getsubfield(data,dimtok{i}));
  511. end
  512. end
  513. i = find(isnan(dim));
  514. if ~isempty(i)
  515. n = fieldnames(data);
  516. for ii=1:length(n)
  517. numels(1,ii) = numel(getfield(data,n{ii}));
  518. end
  519. nrpt = numels./prod(dim(setdiff(1:length(dim),i)));
  520. nrpt = nrpt(nrpt==round(nrpt));
  521. dim(i) = max(nrpt);
  522. end
  523. if numel(dim)==1, dim(1,2) = 1; end;
  524. end
  525. % these fields should not be reshaped
  526. exclude = {'cfg' 'fwhm' 'leadfield' 'q' 'rough'};
  527. if ~strcmp(inside, 'logical')
  528. % also exclude the inside/outside from being reshaped
  529. exclude = cat(2, exclude, {'inside' 'outside'});
  530. end
  531. param = setdiff(parameterselection('all', data), exclude);
  532. for i=1:length(param)
  533. if any(param{i}=='.')
  534. % the parameter is nested in a substructure, which can have multiple elements (e.g. source.trial(1).pow, source.trial(2).pow, ...)
  535. % loop over the substructure array and reshape for every element
  536. tok = tokenize(param{i}, '.');
  537. sub1 = tok{1}; % i.e. this would be 'trial'
  538. sub2 = tok{2}; % i.e. this would be 'pow'
  539. tmp1 = getfield(data, sub1);
  540. for j=1:numel(tmp1)
  541. tmp2 = getfield(tmp1(j), sub2);
  542. tmp2 = reshape(tmp2, dim);
  543. tmp1(j) = setfield(tmp1(j), sub2, tmp2);
  544. end
  545. data = setfield(data, sub1, tmp1);
  546. else
  547. tmp = getfield(data, param{i});
  548. tmp = reshape(tmp, dim);
  549. data = setfield(data, param{i}, tmp);
  550. end
  551. end
  552. end
  553. if isequal(hastrials, 'yes')
  554. okflag = isfield(data, 'trial');
  555. if ~okflag && isfield(data, 'dimord')
  556. % instead look in the dimord for rpt or subj
  557. okflag = ~isempty(strfind(data.dimord, 'rpt')) || ...
  558. ~isempty(strfind(data.dimord, 'rpttap')) || ...
  559. ~isempty(strfind(data.dimord, 'subj'));
  560. end
  561. if ~okflag
  562. error('This function requires data with a ''trial'' field');
  563. end % if okflag
  564. end
  565. if isequal(hassampleinfo, 'yes') || isequal(hassampleinfo, 'ifmakessense')
  566. data = fixsampleinfo(data);
  567. end
  568. if isequal(hasdim, 'yes') && ~isfield(data, 'dim')
  569. data.dim = pos2dim(data.pos);
  570. elseif isequal(hasdim, 'no') && isfield(data, 'dim')
  571. data = rmfield(data, 'dim');
  572. end % if hasdim
  573. if isequal(hascumtapcnt, 'yes') && ~isfield(data, 'cumtapcnt')
  574. error('This function requires data with a ''cumtapcnt'' field');
  575. elseif isequal(hascumtapcnt, 'no') && isfield(data, 'cumtapcnt')
  576. data = rmfield(data, 'cumtapcnt');
  577. end % if hascumtapcnt
  578. if isequal(hasdof, 'yes') && ~isfield(data, 'hasdof')
  579. error('This function requires data with a ''dof'' field');
  580. elseif isequal(hasdof, 'no') && isfield(data, 'hasdof')
  581. data = rmfield(data, 'cumtapcnt');
  582. end % if hasdof
  583. if ~isempty(cmbrepresentation)
  584. if istimelock
  585. data = fixcov(data, cmbrepresentation);
  586. elseif isfreq
  587. data = fixcsd(data, cmbrepresentation, channelcmb);
  588. elseif isfreqmvar
  589. data = fixcsd(data, cmbrepresentation, channelcmb);
  590. else
  591. error('This function requires data with a covariance, coherence or cross-spectrum');
  592. end
  593. end % cmbrepresentation
  594. if issource && ~isempty(sourcerepresentation)
  595. data = fixsource(data, 'type', sourcerepresentation);
  596. end
  597. if issource && ~strcmp(haspow, 'no')
  598. data = fixsource(data, 'type', sourcerepresentation, 'haspow', haspow);
  599. end
  600. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  601. % represent the covariance matrix in a particular manner
  602. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  603. function data = fixcov(data, desired)
  604. if isfield(data, 'cov') && ~isfield(data, 'labelcmb')
  605. current = 'full';
  606. elseif isfield(data, 'cov') && isfield(data, 'labelcmb')
  607. current = 'sparse';
  608. else
  609. error('Could not determine the current representation of the covariance matrix');
  610. end
  611. if isequal(current, desired)
  612. % nothing to do
  613. elseif strcmp(current, 'full') && strcmp(desired, 'sparse')
  614. % FIXME should be implemented
  615. error('not yet implemented');
  616. elseif strcmp(current, 'sparse') && strcmp(desired, 'full')
  617. % FIXME should be implemented
  618. error('not yet implemented');
  619. end
  620. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  621. % represent the cross-spectral density matrix in a particular manner
  622. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  623. function [data] = fixcsd(data, desired, channelcmb)
  624. % FIXCSD converts univariate frequency domain data (fourierspctrm) into a bivariate
  625. % representation (crsspctrm), or changes the representation of bivariate frequency
  626. % domain data (sparse/full/sparsewithpow, sparsewithpow only works for crsspctrm or
  627. % fourierspctrm)
  628. % Copyright (C) 2010, Jan-Mathijs Schoffelen, Robert Oostenveld
  629. if isfield(data, 'crsspctrm') && isfield(data, 'powspctrm')
  630. current = 'sparsewithpow';
  631. elseif isfield(data, 'powspctrm')
  632. current = 'sparsewithpow';
  633. elseif isfield(data, 'fourierspctrm') && ~isfield(data, 'labelcmb')
  634. current = 'fourier';
  635. elseif ~isfield(data, 'labelcmb')
  636. current = 'full';
  637. elseif isfield(data, 'labelcmb')
  638. current = 'sparse';
  639. else
  640. error('Could not determine the current representation of the %s matrix', param);
  641. end
  642. % first go from univariate fourier to the required bivariate representation
  643. if strcmp(current, 'fourier') && strcmp(desired, 'fourier')
  644. % nothing to do
  645. elseif strcmp(current, 'fourier') && strcmp(desired, 'sparsewithpow')
  646. dimtok = tokenize(data.dimord, '_');
  647. if ~isempty(strmatch('rpttap', dimtok)),
  648. nrpt = size(data.cumtapcnt,1);
  649. flag = 0;
  650. else
  651. nrpt = 1;
  652. flag = 1;
  653. end
  654. if ~isempty(strmatch('freq', dimtok)), nfrq=length(data.freq); else nfrq = 1; end
  655. if ~isempty(strmatch('time', dimtok)), ntim=length(data.time); else ntim = 1; end
  656. fastflag = all(data.cumtapcnt(:)==data.cumtapcnt(1));
  657. %create auto-spectra
  658. nchan = length(data.label);
  659. if fastflag
  660. % all trials have the same amount of tapers
  661. powspctrm = zeros(nrpt,nchan,nfrq,ntim);
  662. ntap = data.cumtapcnt(1);
  663. for p = 1:ntap
  664. powspctrm = powspctrm + abs(data.fourierspctrm(p:ntap:end,:,:,:,:)).^2;
  665. end
  666. powspctrm = powspctrm./ntap;
  667. else
  668. % different amount of tapers
  669. powspctrm = zeros(nrpt,nchan,nfrq,ntim)+i.*zeros(nrpt,nchan,nfrq,ntim);
  670. sumtapcnt = [0;cumsum(data.cumtapcnt(:))];
  671. for p = 1:nrpt
  672. indx = (sumtapcnt(p)+1):sumtapcnt(p+1);
  673. tmpdat = data.fourierspctrm(indx,:,:,:);
  674. powspctrm(p,:,:,:) = (sum(tmpdat.*conj(tmpdat),1))./data.cumtapcnt(p);
  675. end
  676. end
  677. %create cross-spectra
  678. if ~isempty(channelcmb),
  679. ncmb = size(channelcmb,1);
  680. cmbindx = zeros(ncmb,2);
  681. labelcmb = cell(ncmb,2);
  682. for k = 1:ncmb
  683. ch1 = find(strcmp(data.label, channelcmb(k,1)));
  684. ch2 = find(strcmp(data.label, channelcmb(k,2)));
  685. if ~isempty(ch1) && ~isempty(ch2),
  686. cmbindx(k,:) = [ch1 ch2];
  687. labelcmb(k,:) = data.label([ch1 ch2])';
  688. end
  689. end
  690. crsspctrm = zeros(nrpt,ncmb,nfrq,ntim)+i.*zeros(nrpt,ncmb,nfrq,ntim);
  691. if fastflag
  692. for p = 1:ntap
  693. tmpdat1 = data.fourierspctrm(p:ntap:end,cmbindx(:,1),:,:,:);
  694. tmpdat2 = data.fourierspctrm(p:ntap:end,cmbindx(:,2),:,:,:);
  695. crsspctrm = crsspctrm + tmpdat1.*conj(tmpdat2);
  696. end
  697. crsspctrm = crsspctrm./ntap;
  698. else
  699. for p = 1:nrpt
  700. indx = (sumtapcnt(p)+1):sumtapcnt(p+1);
  701. tmpdat1 = data.fourierspctrm(indx,cmbindx(:,1),:,:);
  702. tmpdat2 = data.fourierspctrm(indx,cmbindx(:,2),:,:);
  703. crsspctrm(p,:,:,:) = (sum(tmpdat1.*conj(tmpdat2),1))./data.cumtapcnt(p);
  704. end
  705. end
  706. data.crsspctrm = crsspctrm;
  707. data.labelcmb = labelcmb;
  708. end
  709. data.powspctrm = powspctrm;
  710. data = rmfield(data, 'fourierspctrm');
  711. if ntim>1,
  712. data.dimord = 'chan_freq_time';
  713. else
  714. data.dimord = 'chan_freq';
  715. end
  716. if nrpt>1,
  717. data.dimord = ['rpt_',data.dimord];
  718. end
  719. if flag, siz = size(data.crsspctrm); data.crsspctrm = reshape(data.crsspctrm, siz(2:end)); end
  720. elseif strcmp(current, 'fourier') && strcmp(desired, 'sparse')
  721. if isempty(channelcmb), error('no channel combinations are specified'); end
  722. dimtok = tokenize(data.dimord, '_');
  723. if ~isempty(strmatch('rpttap', dimtok)),
  724. nrpt = size(data.cumtapcnt,1);
  725. flag = 0;
  726. else
  727. nrpt = 1;
  728. flag = 1;
  729. end
  730. if ~isempty(strmatch('freq', dimtok)), nfrq=length(data.freq); else nfrq = 1; end
  731. if ~isempty(strmatch('time', dimtok)), ntim=length(data.time); else ntim = 1; end
  732. ncmb = size(channelcmb,1);
  733. cmbindx = zeros(ncmb,2);
  734. labelcmb = cell(ncmb,2);
  735. for k = 1:ncmb
  736. ch1 = find(strcmp(data.label, channelcmb(k,1)));
  737. ch2 = find(strcmp(data.label, channelcmb(k,2)));
  738. if ~isempty(ch1) && ~isempty(ch2),
  739. cmbindx(k,:) = [ch1 ch2];
  740. labelcmb(k,:) = data.label([ch1 ch2])';
  741. end
  742. end
  743. sumtapcnt = [0;cumsum(data.cumtapcnt(:))];
  744. fastflag = all(data.cumtapcnt(:)==data.cumtapcnt(1));
  745. if fastflag && nrpt>1
  746. ntap = data.cumtapcnt(1);
  747. % compute running sum across tapers
  748. siz = [size(data.fourierspctrm) 1];
  749. for p = 1:ntap
  750. indx = p:ntap:nrpt*ntap;
  751. if p==1.
  752. tmpc = zeros(numel(indx), size(cmbindx,1), siz(3), siz(4)) + ...
  753. 1i.*zeros(numel(indx), size(cmbindx,1), siz(3), siz(4));
  754. end
  755. for k = 1:size(cmbindx,1)
  756. tmpc(:,k,:,:) = data.fourierspctrm(indx,cmbindx(k,1),:,:).* ...
  757. conj(data.fourierspctrm(indx,cmbindx(k,2),:,:));
  758. end
  759. if p==1
  760. crsspctrm = tmpc;
  761. else
  762. crsspctrm = tmpc + crsspctrm;
  763. end
  764. end
  765. crsspctrm = crsspctrm./ntap;
  766. else
  767. crsspctrm = zeros(nrpt, ncmb, nfrq, ntim);
  768. for p = 1:nrpt
  769. indx = (sumtapcnt(p)+1):sumtapcnt(p+1);
  770. tmpdat1 = data.fourierspctrm(indx,cmbindx(:,1),:,:);
  771. tmpdat2 = data.fourierspctrm(indx,cmbindx(:,2),:,:);
  772. crsspctrm(p,:,:,:) = (sum(tmpdat1.*conj(tmpdat2),1))./data.cumtapcnt(p);
  773. end
  774. end
  775. data.crsspctrm = crsspctrm;
  776. data.labelcmb = labelcmb;
  777. data = rmfield(data, 'fourierspctrm');
  778. data = rmfield(data, 'label');
  779. if ntim>1,
  780. data.dimord = 'chan_freq_time';
  781. else
  782. data.dimord = 'chan_freq';
  783. end
  784. if nrpt>1,
  785. data.dimord = ['rpt_',data.dimord];
  786. end
  787. if flag, siz = size(data.crsspctrm); data.crsspctrm = reshape(data.crsspctrm, siz(2:end)); end
  788. elseif strcmp(current, 'fourier') && strcmp(desired, 'full')
  789. % this is how it is currently and the desired functionality of prepare_freq_matrices
  790. dimtok = tokenize(data.dimord, '_');
  791. if ~isempty(strmatch('rpttap', dimtok)),
  792. nrpt = size(data.cumtapcnt, 1);
  793. flag = 0;
  794. else
  795. nrpt = 1;
  796. flag = 1;
  797. end
  798. if ~isempty(strmatch('rpttap',dimtok)), nrpt=size(data.cumtapcnt, 1); else nrpt = 1; end
  799. if ~isempty(strmatch('freq', dimtok)), nfrq=length(data.freq); else nfrq = 1; end
  800. if ~isempty(strmatch('time', dimtok)), ntim=length(data.time); else ntim = 1; end
  801. if any(data.cumtapcnt(1,:) ~= data.cumtapcnt(1,1)), error('this only works when all frequencies have the same number of tapers'); end
  802. nchan = length(data.label);
  803. crsspctrm = zeros(nrpt,nchan,nchan,nfrq,ntim);
  804. sumtapcnt = [0;cumsum(data.cumtapcnt(:,1))];
  805. for k = 1:ntim
  806. for m = 1:nfrq
  807. for p = 1:nrpt
  808. %FIXME speed this up in the case that all trials have equal number of tapers
  809. indx = (sumtapcnt(p)+1):sumtapcnt(p+1);
  810. tmpdat = transpose(data.fourierspctrm(indx,:,m,k));
  811. crsspctrm(p,:,:,m,k) = (tmpdat*tmpdat')./data.cumtapcnt(p);
  812. clear tmpdat;
  813. end
  814. end
  815. end
  816. data.crsspctrm = crsspctrm;
  817. data = rmfield(data, 'fourierspctrm');
  818. if ntim>1,
  819. data.dimord = 'chan_chan_freq_time';
  820. else
  821. data.dimord = 'chan_chan_freq';
  822. end
  823. if nrpt>1,
  824. data.dimord = ['rpt_',data.dimord];
  825. end
  826. % remove first singleton dimension
  827. if flag || nrpt==1, siz = size(data.crsspctrm); data.crsspctrm = reshape(data.crsspctrm, siz(2:end)); end
  828. elseif strcmp(current, 'fourier') && strcmp(desired, 'fullfast'),
  829. dimtok = tokenize(data.dimord, '_');
  830. nrpt = size(data.fourierspctrm, 1);
  831. nchn = numel(data.label);
  832. nfrq = numel(data.freq);
  833. if ~isempty(strmatch('time', dimtok)), ntim=numel(data.time); else ntim = 1; end
  834. data.fourierspctrm = reshape(data.fourierspctrm, [nrpt nchn nfrq*ntim]);
  835. data.fourierspctrm(~isfinite(data.fourierspctrm)) = 0;
  836. crsspctrm = complex(zeros(nchn,nchn,nfrq*ntim));
  837. for k = 1:nfrq*ntim
  838. tmp = transpose(data.fourierspctrm(:,:,k));
  839. n = sum(tmp~=0,2);
  840. crsspctrm(:,:,k) = tmp*tmp'./n(1);
  841. end
  842. data = rmfield(data, 'fourierspctrm');
  843. data.crsspctrm = reshape(crsspctrm, [nchn nchn nfrq ntim]);
  844. if isfield(data, 'time'),
  845. data.dimord = 'chan_chan_freq_time';
  846. else
  847. data.dimord = 'chan_chan_freq';
  848. end
  849. if isfield(data, 'trialinfo'), data = rmfield(data, 'trialinfo'); end;
  850. if isfield(data, 'sampleinfo'), data = rmfield(data, 'sampleinfo'); end;
  851. if isfield(data, 'cumsumcnt'), data = rmfield(data, 'cumsumcnt'); end;
  852. if isfield(data, 'cumtapcnt'), data = rmfield(data, 'cumtapcnt'); end;
  853. end % convert to the requested bivariate representation
  854. % from one bivariate representation to another
  855. if isequal(current, desired)
  856. % nothing to do
  857. elseif (strcmp(current, 'full') && strcmp(desired, 'fourier')) || ...
  858. (strcmp(current, 'sparse') && strcmp(desired, 'fourier')) || ...
  859. (strcmp(current, 'sparsewithpow') && strcmp(desired, 'fourier'))
  860. % this is not possible
  861. error('converting the cross-spectrum into a Fourier representation is not possible');
  862. elseif strcmp(current, 'full') && strcmp(desired, 'sparsewithpow')
  863. error('not yet implemented');
  864. elseif strcmp(current, 'sparse') && strcmp(desired, 'sparsewithpow')
  865. % convert back to crsspctrm/powspctrm representation: useful for plotting functions etc
  866. indx = labelcmb2indx(data.labelcmb);
  867. autoindx = indx(indx(:,1)==indx(:,2), 1);
  868. cmbindx = setdiff([1:size(indx,1)]', autoindx);
  869. if strcmp(data.dimord(1:3), 'rpt')
  870. data.powspctrm = data.crsspctrm(:, autoindx, :, :);
  871. data.crsspctrm = data.crsspctrm(:, cmbindx, :, :);
  872. else
  873. data.powspctrm = data.crsspctrm(autoindx, :, :);
  874. data.crsspctrm = data.crsspctrm(cmbindx, :, :);
  875. end
  876. data.label = data.labelcmb(autoindx,1);
  877. data.labelcmb = data.labelcmb(cmbindx, :);
  878. if isempty(cmbindx)
  879. data = rmfield(data, 'crsspctrm');
  880. data = rmfield(data, 'labelcmb');
  881. end
  882. elseif strcmp(current, 'full') && strcmp(desired, 'sparse')
  883. dimtok = tokenize(data.dimord, '_');
  884. if ~isempty(strmatch('rpt', dimtok)), nrpt=size(data.cumtapcnt,1); else nrpt = 1; end
  885. if ~isempty(strmatch('freq', dimtok)), nfrq=numel(data.freq); else nfrq = 1; end
  886. if ~isempty(strmatch('time', dimtok)), ntim=numel(data.time); else ntim = 1; end
  887. nchan = length(data.label);
  888. ncmb = nchan*nchan;
  889. labelcmb = cell(ncmb, 2);
  890. cmbindx = zeros(nchan, nchan);
  891. k = 1;
  892. for j=1:nchan
  893. for m=1:nchan
  894. labelcmb{k, 1} = data.label{m};
  895. labelcmb{k, 2} = data.label{j};
  896. cmbindx(m,j) = k;
  897. k = k+1;
  898. end
  899. end
  900. % reshape all possible fields
  901. fn = fieldnames(data);
  902. for ii=1:numel(fn)
  903. if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim;
  904. if nrpt>1,
  905. data.(fn{ii}) = reshape(data.(fn{ii}), nrpt, ncmb, nfrq, ntim);
  906. else
  907. data.(fn{ii}) = reshape(data.(fn{ii}), ncmb, nfrq, ntim);
  908. end
  909. end
  910. end
  911. % remove obsolete fields
  912. data = rmfield(data, 'label');
  913. try, data = rmfield(data, 'dof'); end
  914. % replace updated fields
  915. data.labelcmb = labelcmb;
  916. if ntim>1,
  917. data.dimord = 'chancmb_freq_time';
  918. else
  919. data.dimord = 'chancmb_freq';
  920. end
  921. if nrpt>1,
  922. data.dimord = ['rpt_',data.dimord];
  923. end
  924. elseif strcmp(current, 'sparsewithpow') && strcmp(desired, 'sparse')
  925. % this representation for sparse data contains autospectra
  926. % as e.g. {'A' 'A'} in labelcmb
  927. if isfield(data, 'crsspctrm'),
  928. dimtok = tokenize(data.dimord, '_');
  929. catdim = match_str(dimtok, {'chan' 'chancmb'});
  930. data.crsspctrm = cat(catdim, data.powspctrm, data.crsspctrm);
  931. data.labelcmb = [data.label(:) data.label(:); data.labelcmb];
  932. data = rmfield(data, 'powspctrm');
  933. else
  934. data.crsspctrm = data.powspctrm;
  935. data.labelcmb = [data.label(:) data.label(:)];
  936. data = rmfield(data, 'powspctrm');
  937. end
  938. data = rmfield(data, 'label');
  939. elseif strcmp(current, 'sparse') && strcmp(desired, 'full')
  940. dimtok = tokenize(data.dimord, '_');
  941. if ~isempty(strmatch('rpt', dimtok)), nrpt=size(data.cumtapcnt,1); else nrpt = 1; end
  942. if ~isempty(strmatch('freq', dimtok)), nfrq=numel(data.freq); else nfrq = 1; end
  943. if ~isempty(strmatch('time', dimtok)), ntim=numel(data.time); else ntim = 1; end
  944. if ~isfield(data, 'label')
  945. % ensure that the bivariate spectral factorization results can be
  946. % processed. FIXME this is experimental and will not work if the user
  947. % did something weird before
  948. for k = 1:numel(data.labelcmb)
  949. tmp = tokenize(data.labelcmb{k}, '[');
  950. data.labelcmb{k} = tmp{1};
  951. end
  952. data.label = unique(data.labelcmb(:));
  953. end
  954. nchan = length(data.label);
  955. ncmb = size(data.labelcmb,1);
  956. cmbindx = zeros(nchan,nchan);
  957. for k = 1:size(data.labelcmb,1)
  958. ch1 = find(strcmp(data.label, data.labelcmb(k,1)));
  959. ch2 = find(strcmp(data.label, data.labelcmb(k,2)));
  960. if ~isempty(ch1) && ~isempty(ch2),
  961. cmbindx(ch1,ch2) = k;
  962. end
  963. end
  964. complete = all(cmbindx(:)~=0);
  965. fn = fieldnames(data);
  966. for ii=1:numel(fn)
  967. if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim;
  968. if nrpt==1,
  969. data.(fn{ii}) = reshape(data.(fn{ii}), [nrpt ncmb nfrq ntim]);
  970. end
  971. tmpall = nan(nrpt,nchan,nchan,nfrq,ntim);
  972. for j = 1:nrpt
  973. for k = 1:ntim
  974. for m = 1:nfrq
  975. tmpdat = nan(nchan,nchan);
  976. indx = find(cmbindx);
  977. if ~complete
  978. % this realizes the missing combinations to be represented as the
  979. % conjugate of the corresponding combination across the diagonal
  980. tmpdat(indx) = reshape(data.(fn{ii})(j,cmbindx(indx),m,k),[numel(indx) 1]);
  981. tmpdat = ctranspose(tmpdat);
  982. end
  983. tmpdat(indx) = reshape(data.(fn{ii})(j,cmbindx(indx),m,k),[numel(indx) 1]);
  984. tmpall(j,:,:,m,k) = tmpdat;
  985. end % for m
  986. end % for k
  987. end % for j
  988. % replace the data in the old representation with the new representation
  989. if nrpt>1,
  990. data.(fn{ii}) = tmpall;
  991. else
  992. data.(fn{ii}) = reshape(tmpall, [nchan nchan nfrq ntim]);
  993. end
  994. end % if numel
  995. end % for ii
  996. % remove obsolete fields
  997. try, data = rmfield(data, 'powspctrm'); end
  998. try, data = rmfield(data, 'labelcmb'); end
  999. try, data = rmfield(data, 'dof'); end
  1000. if ntim>1,
  1001. data.dimord = 'chan_chan_freq_time';
  1002. else
  1003. data.dimord = 'chan_chan_freq';
  1004. end
  1005. if nrpt>1,
  1006. data.dimord = ['rpt_',data.dimord];
  1007. end
  1008. elseif strcmp(current, 'sparse') && strcmp(desired, 'fullfast')
  1009. dimtok = tokenize(data.dimord, '_');
  1010. if ~isempty(strmatch('rpt', dimtok)), nrpt=size(data.cumtapcnt,1); else nrpt = 1; end
  1011. if ~isempty(strmatch('freq', dimtok)), nfrq=numel(data.freq); else nfrq = 1; end
  1012. if ~isempty(strmatch('time', dimtok)), ntim=numel(data.time); else ntim = 1; end
  1013. if ~isfield(data, 'label')
  1014. data.label = unique(data.labelcmb(:));
  1015. end
  1016. nchan = length(data.label);
  1017. ncmb = size(data.labelcmb,1);
  1018. cmbindx = zeros(nchan,nchan);
  1019. for k = 1:size(data.labelcmb,1)
  1020. ch1 = find(strcmp(data.label, data.labelcmb(k,1)));
  1021. ch2 = find(strcmp(data.label, data.labelcmb(k,2)));
  1022. if ~isempty(ch1) && ~isempty(ch2),
  1023. cmbindx(ch1,ch2) = k;
  1024. end
  1025. end
  1026. complete = all(cmbindx(:)~=0);
  1027. fn = fieldnames(data);
  1028. for ii=1:numel(fn)
  1029. if numel(data.(fn{ii})) == nrpt*ncmb*nfrq*ntim;
  1030. if nrpt==1,
  1031. data.(fn{ii}) = reshape(data.(fn{ii}), [nrpt ncmb nfrq ntim]);
  1032. end
  1033. tmpall = nan(nchan,nchan,nfrq,ntim);
  1034. for k = 1:ntim
  1035. for m = 1:nfrq
  1036. tmpdat = nan(nchan,nchan);
  1037. indx = find(cmbindx);
  1038. if ~complete
  1039. % this realizes the missing combinations to be represented as the
  1040. % conjugate of the corresponding combination across the diagonal
  1041. tmpdat(indx) = reshape(nanmean(data.(fn{ii})(:,cmbindx(indx),m,k)),[numel(indx) 1]);
  1042. tmpdat = ctranspose(tmpdat);
  1043. end
  1044. tmpdat(indx) = reshape(nanmean(data.(fn{ii})(:,cmbindx(indx),m,k)),[numel(indx) 1]);
  1045. tmpall(:,:,m,k) = tmpdat;
  1046. end % for m
  1047. end % for k
  1048. % replace the data in the old representation with the new representation
  1049. if nrpt>1,
  1050. data.(fn{ii}) = tmpall;
  1051. else
  1052. data.(fn{ii}) = reshape(tmpall, [nchan nchan nfrq ntim]);
  1053. end
  1054. end % if numel
  1055. end % for ii
  1056. % remove obsolete fields
  1057. try, data = rmfield(data, 'powspctrm'); end
  1058. try, data = rmfield(data, 'labelcmb'); end
  1059. try, data = rmfield(data, 'dof'); end
  1060. if ntim>1,
  1061. data.dimord = 'chan_chan_freq_time';
  1062. else
  1063. data.dimord = 'chan_chan_freq';
  1064. end
  1065. elseif strcmp(current, 'sparsewithpow') && strcmp(desired, 'full')
  1066. % this is how is currently done in prepare_freq_matrices
  1067. data = ft_checkdata(data, 'cmbrepresentation', 'sparse');
  1068. data = ft_checkdata(data, 'cmbrepresentation', 'full');
  1069. end
  1070. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1071. % convert to new source representation
  1072. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1073. function [output] = fixsource(input, varargin)
  1074. % FIXSOURCE converts old style source structures into new style source structures and the
  1075. % other way around
  1076. %
  1077. % Use as:
  1078. % fixsource(input, type)
  1079. % where input is a source structure,
  1080. %
  1081. % Typically, old style source structures contain
  1082. % avg.XXX or trial.XXX fields
  1083. %
  1084. % The new style source structure contains:
  1085. % source.pos
  1086. % source.dim (optional, if the list of positions describes a 3D volume
  1087. % source.XXX the old style subfields in avg/trial
  1088. % source.XXXdimord string how to interpret the respective XXX field:
  1089. % e.g. source.leadfield = cell(1,Npos), source.leadfielddimord = '{pos}_chan_ori'
  1090. % source.mom = cell(1,Npos), source.momdimord = '{pos}_ori_rpttap'
  1091. type = ft_getopt(varargin, 'type');
  1092. haspow = ft_getopt(varargin, 'haspow');
  1093. if isempty(type), type = 'old'; end
  1094. if isempty(haspow), haspow = 'no'; end
  1095. fnames = fieldnames(input);
  1096. tmp = cell2mat(strfind(fnames, 'dimord')); %get dimord like fields
  1097. if any(tmp>1),
  1098. current = 'new';
  1099. elseif any(tmp==1),
  1100. %don't know what to do yet data is JM's own invention
  1101. current = 'old';
  1102. else
  1103. current = 'old';
  1104. end
  1105. if strcmp(current, type),
  1106. %do nothing
  1107. output = input;
  1108. %return
  1109. elseif strcmp(current, 'old') && strcmp(type, 'new'),
  1110. %go from old to new
  1111. if isfield(input, 'avg'),
  1112. stuff = getfield(input, 'avg');
  1113. output = rmfield(input, 'avg');
  1114. elseif isfield(input, 'trial'),
  1115. stuff = getfield(input, 'trial');
  1116. output = rmfield(input, 'trial');
  1117. else
  1118. %this could occur later in the pipeline, e.g. when doing group statistics using individual subject
  1119. %descriptive statistics
  1120. error('the input does not contain an avg or trial field');
  1121. end
  1122. %-------------------------------------------------
  1123. %remove and rename the specified fields if present
  1124. removefields = {'xgrid';'ygrid';'zgrid';'method'};
  1125. renamefields = {'frequency' 'freq'; 'csdlabel' 'orilabel'};
  1126. fnames = fieldnames(output);
  1127. for k = 1:numel(fnames)
  1128. ix = strmatch(fnames{k}, removefields);
  1129. if ~isempty(ix),
  1130. output = rmfield(output, fnames{k});
  1131. end
  1132. ix = strmatch(fnames{k}, renamefields(:,1), 'exact');
  1133. if ~isempty(ix),
  1134. output = setfield(output, renamefields{ix,2}, ...
  1135. getfield(output, renamefields{ix,1}));
  1136. output = rmfield(output, fnames{k});
  1137. end
  1138. end
  1139. %----------------------------------------------------------------------
  1140. %put the stuff originally in avg or trial one level up in the structure
  1141. fnames = fieldnames(stuff(1));
  1142. npos = size(input.pos,1);
  1143. nrpt = numel(stuff);
  1144. for k = 1:numel(fnames)
  1145. if nrpt>1,
  1146. %multiple trials
  1147. %(or subjects FIXME not yet implemented, nor tested)
  1148. tmp = getfield(stuff(1), fnames{k});
  1149. siz = size(tmp);
  1150. if isfield(input, 'cumtapcnt') && strcmp(fnames{k}, 'mom')
  1151. %pcc based mom is orixrpttap
  1152. %tranpose to keep manageable
  1153. for kk = 1:numel(input.inside)
  1154. indx = input.inside(kk);
  1155. tmp{indx} = permute(tmp{indx}, [2 1 3]);
  1156. end
  1157. nrpttap = sum(input.cumtapcnt);
  1158. sizvox = [size(tmp{input.inside(1)}) 1];
  1159. sizvox = [nrpttap sizvox(2:end)];
  1160. elseif strcmp(fnames{k}, 'mom'),
  1161. %this is then probably not a frequency based mom
  1162. nrpttap = numel(stuff);
  1163. sizvox = [size(tmp{input.inside(1)}) 1];
  1164. sizvox = [nrpttap sizvox];
  1165. elseif iscell(tmp)
  1166. nrpttap = numel(stuff);
  1167. sizvox = [size(tmp{input.inside(1)}) 1];
  1168. sizvox = [nrpttap sizvox];
  1169. end
  1170. if siz(1) ~= npos && siz(2) ==npos,
  1171. tmp = transpose(tmp);
  1172. end
  1173. if iscell(tmp)
  1174. %allocate memory for cell-array
  1175. tmpall = cell(npos,1);
  1176. for n = 1:numel(input.inside)
  1177. tmpall{input.inside(n)} = zeros(sizvox);
  1178. end
  1179. else
  1180. %allocate memory for matrix
  1181. tmpall = zeros([npos nrpt siz(2:end)]);
  1182. end
  1183. cnt = 0;
  1184. for m = 1:nrpt
  1185. tmp = getfield(stuff(m), fnames{k});
  1186. siz = size(tmp);
  1187. if siz(1) ~= npos && siz(2) ==npos,
  1188. tmp = transpose(tmp);
  1189. end
  1190. if ~iscell(tmp),
  1191. tmpall(:,m,:,:,:) = tmp;
  1192. else
  1193. for n = 1:numel(input.inside)
  1194. indx = input.inside(n);
  1195. tmpdat = tmp{indx};
  1196. if isfield(input, 'cumtapcnt') && strcmp(fnames{k}, 'mom'),
  1197. if n==1, siz1 = size(tmpdat,2); end
  1198. else
  1199. if n==1, siz1 = 1; end
  1200. end
  1201. tmpall{indx}(cnt+[1:siz1],:,:,:,:) = tmpdat;
  1202. if n==numel(input.inside), cnt = cnt + siz1; end
  1203. end
  1204. end
  1205. end
  1206. output = setfield(output, fnames{k}, tmpall);
  1207. newdimord = createdimord(output, fnames{k}, 1);
  1208. if ~isempty(newdimord)
  1209. output = setfield(output, [fnames{k},'dimord'], newdimord);
  1210. end
  1211. else
  1212. tmp = getfield(stuff, fnames{k});
  1213. siz = size(tmp);
  1214. if isfield(input, 'cumtapcnt') && strcmp(fnames{k}, 'mom')
  1215. %pcc based mom is orixrpttap
  1216. %tranpose to keep manageable
  1217. for kk = 1:numel(input.inside)
  1218. indx = input.inside(kk);
  1219. tmp{indx} = permute(tmp{indx}, [2 1 3]);
  1220. end
  1221. end
  1222. if siz(1) ~= npos && siz(2) ==npos,
  1223. tmp = transpose(tmp);
  1224. end
  1225. output = setfield(output, fnames{k}, tmp);
  1226. newdimord = createdimord(output, fnames{k});
  1227. if ~isempty(newdimord)
  1228. output = setfield(output, [fnames{k},'dimord'], newdimord);
  1229. end
  1230. end
  1231. end
  1232. if isfield(output, 'csdlabel')
  1233. output = setfield(output, 'orilabel', getfield(output, 'csdlabel'));
  1234. output = rmfield(output, 'csdlabel');
  1235. end
  1236. if isfield(output, 'leadfield')
  1237. % add dimord to leadfield as well. since the leadfield is not in
  1238. % the original .avg or .trial field it has not yet been taken care of
  1239. output.leadfielddimord = createdimord(output, 'leadfield');
  1240. end
  1241. if isfield(output, 'ori')
  1242. % convert cell-array ori into matrix
  1243. ori = zeros(3,npos) + nan;
  1244. try,
  1245. ori(:,output.inside) = cat(2, output.ori{output.inside});
  1246. catch
  1247. %when oris are in wrong orientation (row rather than column)
  1248. for k = 1:numel(output.inside)
  1249. ori(:,output.inside(k)) = output.ori{output.inside(k)}';
  1250. end
  1251. end
  1252. output.ori = ori;
  1253. end
  1254. current = 'new';
  1255. elseif strcmp(current, 'new') && strcmp(type, 'old')
  1256. %go from new to old
  1257. error('not implemented yet');
  1258. end
  1259. if strcmp(current, 'new') && strcmp(haspow, 'yes'),
  1260. %----------------------------------------------
  1261. %convert mom into pow if requested and possible
  1262. convert = 0;
  1263. if isfield(output, 'mom') && size(output.mom{output.inside(1)},2)==1,
  1264. convert = 1;
  1265. else
  1266. warning('conversion from mom to pow is not possible, either because there is no mom in the data, or because the dimension of mom>1. in that case call ft_sourcedescriptives first with cfg.projectmom');
  1267. end
  1268. if isfield(output, 'cumtapcnt')
  1269. convert = 1 & convert;
  1270. else
  1271. warning('conversion from mom to pow will not be done, because cumtapcnt is missing');
  1272. end
  1273. if convert,
  1274. npos = size(output.pos,1);
  1275. nrpt = size(output.cumtapcnt,1);
  1276. tmpmom = cat(2,output.mom{output.inside});
  1277. tmppow = zeros(npos, nrpt);
  1278. tapcnt = [0;cumsum(output.cumtapcnt(:))];
  1279. for k = 1:nrpt
  1280. ntap = tapcnt(k+1)-tapcnt(k);
  1281. tmppow(output.inside,k) = sum(abs(tmpmom((tapcnt(k)+1):tapcnt(k+1),:)).^2,1)./ntap;
  1282. end
  1283. output.pow = tmppow;
  1284. output.powdimord = ['pos_rpt_freq'];
  1285. end
  1286. elseif strcmp(current, 'old') && strcmp(haspow, 'yes')
  1287. warning('construction of single trial power estimates is not implemented here using old style source representation');
  1288. end
  1289. %--------------------------------------------------------
  1290. function [dimord] = createdimord(output, fname, rptflag);
  1291. if nargin==2, rptflag = 0; end
  1292. tmp = getfield(output, fname);
  1293. dimord = '';
  1294. dimnum = 1;
  1295. hasori = isfield(output, 'ori'); %if not, this is probably singleton and not relevant at the end
  1296. if iscell(tmp) && (size(output.pos,1)==size(tmp,dimnum) || size(output.pos,1)==size(tmp,2))
  1297. dimord = [dimord,'{pos}'];
  1298. dimnum = dimnum + 1;
  1299. elseif ~iscell(tmp) && size(output.pos,1)==size(tmp,dimnum)
  1300. dimord = [dimord,'pos'];
  1301. dimnum = dimnum + 1;
  1302. end
  1303. switch fname
  1304. case 'cov'
  1305. if hasori, dimord = [dimord,'_ori_ori']; end;
  1306. case 'csd'
  1307. if hasori, dimord = [dimord,'_ori_ori']; end;
  1308. case 'csdlabel'
  1309. dimord = dimord;
  1310. case 'filter'
  1311. dimord = [dimord,'_ori_chan'];
  1312. case 'leadfield'
  1313. %if hasori,
  1314. dimord = [dimord,'_chan_ori'];
  1315. %else
  1316. % dimord = [dimord,'_chan'];
  1317. %end
  1318. case 'mom'
  1319. if isfield(output, 'cumtapcnt') && sum(output.cumtapcnt)==size(tmp{output.inside(1)},1)
  1320. if hasori,
  1321. dimord = [dimord,'_rpttap_ori'];
  1322. else
  1323. dimord = [dimord,'_rpttap'];
  1324. end
  1325. elsei

Large files files are truncated, but you can click here to view the full file