PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/trunk/examples/toolboxes/fieldtrip/ft_artifact_zvalue.m

http://brainstream.googlecode.com/
MATLAB | 361 lines | 172 code | 27 blank | 162 comment | 38 complexity | 59c974695b1c15c0689fc5c2a7254a9a 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
  1. function [cfg, artifact] = ft_artifact_zvalue(cfg,data)
  2. % FT_ARTIFACT_ZVALUE reads the interesting segments of data from file and
  3. % identifies artifacts by means of thresholding the z-transformed value
  4. % of the preprocessed raw data. Depending on the preprocessing options,
  5. % this method will be sensitive to EOG, muscle or jump artifacts.
  6. % This procedure only works on continuously recorded data.
  7. %
  8. % Use as
  9. % [cfg, artifact] = ft_artifact_zvalue(cfg)
  10. % or
  11. % [cfg, artifact] = ft_artifact_zvalue(cfg, data)
  12. %
  13. % The output argument "artifact" is a Nx2 matrix comparable to the
  14. % "trl" matrix of FT_DEFINETRIAL. The first column of which specifying the
  15. % beginsamples of an artifact period, the second column contains the
  16. % endsamples of the artifactperiods.
  17. %
  18. % If you are calling FT_ARTIFACT_ZVALUE with only the configuration as first
  19. % input argument and the data still has to be read from file, you should
  20. % specify:
  21. % cfg.headerfile
  22. % cfg.headerfile
  23. % cfg.datafile
  24. % cfg.datatype
  25. %
  26. % If you are calling FT_ARTIFACT_ZVALUE with also the second input argument
  27. % "data", then that should contain data that was already read from file in
  28. % a call to FT_PREPROCESSING.
  29. %
  30. % The required configuration settings are:
  31. % cfg.trl
  32. % cfg.artfctdef.zvalue.channel
  33. % cfg.artfctdef.zvalue.cutoff
  34. % cfg.artfctdef.zvalue.trlpadding
  35. % cfg.artfctdef.zvalue.fltpadding
  36. % cfg.artfctdef.zvalue.artpadding
  37. % cfg.continuous
  38. %
  39. % Configuration settings related to the preprocessing of the data are
  40. % cfg.artfctdef.zvalue.lpfilter = 'no' or 'yes' lowpass filter
  41. % cfg.artfctdef.zvalue.hpfilter = 'no' or 'yes' highpass filter
  42. % cfg.artfctdef.zvalue.bpfilter = 'no' or 'yes' bandpass filter
  43. % cfg.artfctdef.zvalue.lnfilter = 'no' or 'yes' line noise removal using notch filter
  44. % cfg.artfctdef.zvalue.dftfilter = 'no' or 'yes' line noise removal using discrete fourier transform
  45. % cfg.artfctdef.zvalue.medianfilter = 'no' or 'yes' jump preserving median filter
  46. % cfg.artfctdef.zvalue.lpfreq = lowpass frequency in Hz
  47. % cfg.artfctdef.zvalue.hpfreq = highpass frequency in Hz
  48. % cfg.artfctdef.zvalue.bpfreq = bandpass frequency range, specified as [low high] in Hz
  49. % cfg.artfctdef.zvalue.lnfreq = line noise frequency in Hz, default 50Hz
  50. % cfg.artfctdef.zvalue.lpfiltord = lowpass filter order
  51. % cfg.artfctdef.zvalue.hpfiltord = highpass filter order
  52. % cfg.artfctdef.zvalue.bpfiltord = bandpass filter order
  53. % cfg.artfctdef.zvalue.lnfiltord = line noise notch filter order
  54. % cfg.artfctdef.zvalue.medianfiltord = length of median filter
  55. % cfg.artfctdef.zvalue.lpfilttype = digital filter type, 'but' (default) or 'fir'
  56. % cfg.artfctdef.zvalue.hpfilttype = digital filter type, 'but' (default) or 'fir'
  57. % cfg.artfctdef.zvalue.bpfilttype = digital filter type, 'but' (default) or 'fir'
  58. % cfg.artfctdef.zvalue.detrend = 'no' or 'yes'
  59. % cfg.artfctdef.zvalue.blc = 'no' or 'yes'
  60. % cfg.artfctdef.zvalue.blcwindow = [begin end] in seconds, the default is the complete trial
  61. % cfg.artfctdef.zvalue.hilbert = 'no' or 'yes'
  62. % cfg.artfctdef.zvalue.rectify = 'no' or 'yes'
  63. %
  64. % See also FT_REJECTARTIFACT
  65. % Copyright (c) 2003-2005, Jan-Mathijs Schoffelen, Robert Oostenveld
  66. %
  67. % This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
  68. % for the documentation and details.
  69. %
  70. % FieldTrip is free software: you can redistribute it and/or modify
  71. % it under the terms of the GNU General Public License as published by
  72. % the Free Software Foundation, either version 3 of the License, or
  73. % (at your option) any later version.
  74. %
  75. % FieldTrip is distributed in the hope that it will be useful,
  76. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  77. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  78. % GNU General Public License for more details.
  79. %
  80. % You should have received a copy of the GNU General Public License
  81. % along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
  82. %
  83. % $Id: ft_artifact_zvalue.m 1038 2010-05-05 15:48:52Z timeng $
  84. fieldtripdefs
  85. % set default rejection parameters
  86. if ~isfield(cfg,'artfctdef'), cfg.artfctdef = []; end
  87. if ~isfield(cfg.artfctdef,'zvalue'), cfg.artfctdef.zvalue = []; end
  88. if ~isfield(cfg, 'headerformat'), cfg.headerformat = []; end
  89. if ~isfield(cfg, 'dataformat'), cfg.dataformat = []; end
  90. % for backward compatibility
  91. if isfield(cfg.artfctdef.zvalue,'sgn')
  92. cfg.artfctdef.zvalue.channel = cfg.artfctdef.zvalue.sgn;
  93. cfg.artfctdef.zvalue = rmfield(cfg.artfctdef.zvalue, 'sgn');
  94. end
  95. if isfield(cfg.artfctdef.zvalue, 'artifact')
  96. fprintf('zvalue artifact detection has already been done, retaining artifacts\n');
  97. artifact = cfg.artfctdef.zvalue.artifact;
  98. return
  99. end
  100. if ~isfield(cfg.artfctdef.zvalue,'channel'), cfg.artfctdef.zvalue.channel = {}; end
  101. if ~isfield(cfg.artfctdef.zvalue,'trlpadding'), cfg.artfctdef.zvalue.trlpadding = 0; end
  102. if ~isfield(cfg.artfctdef.zvalue,'artpadding'), cfg.artfctdef.zvalue.artpadding = 0; end
  103. if ~isfield(cfg.artfctdef.zvalue,'fltpadding'), cfg.artfctdef.zvalue.fltpadding = 0; end
  104. if ~isfield(cfg.artfctdef.zvalue,'feedback'), cfg.artfctdef.zvalue.feedback = 'no'; end
  105. if ~isfield(cfg.artfctdef.zvalue,'cumulative'), cfg.artfctdef.zvalue.cumulative = 'yes'; end
  106. thresholdsum = strcmp(cfg.artfctdef.zvalue.cumulative, 'yes');
  107. if nargin > 1
  108. % data given as input
  109. isfetch = 1;
  110. hdr = fetch_header(data);
  111. elseif nargin == 1
  112. % only cfg given
  113. isfetch = 0;
  114. hdr = ft_read_header(cfg.headerfile, 'headerformat', cfg.headerformat);
  115. end
  116. % set default cfg.continuous
  117. if ~isfield(cfg, 'continuous')
  118. if hdr.nTrials==1
  119. cfg.continuous = 'yes';
  120. else
  121. cfg.continuous = 'no';
  122. end
  123. end
  124. trl = cfg.trl;
  125. trlpadding = round(cfg.artfctdef.zvalue.trlpadding*hdr.Fs);
  126. fltpadding = round(cfg.artfctdef.zvalue.fltpadding*hdr.Fs);
  127. artpadding = round(cfg.artfctdef.zvalue.artpadding*hdr.Fs);
  128. trl(:,1) = trl(:,1) - trlpadding; % pad the trial with some samples, in order to detect
  129. trl(:,2) = trl(:,2) + trlpadding; % artifacts at the edges of the relevant trials.
  130. trl(:,3) = nan; % the offset is not correct any more
  131. trllength = trl(:,2) - trl(:,1) + 1; % length of each trial
  132. numtrl = size(trl,1);
  133. cfg.artfctdef.zvalue.trl = trl; % remember where we are going to look for artifacts
  134. cfg.artfctdef.zvalue.channel = ft_channelselection(cfg.artfctdef.zvalue.channel, hdr.label);
  135. sgnind = match_str(hdr.label, cfg.artfctdef.zvalue.channel);
  136. numsgn = length(sgnind);
  137. if numsgn<1
  138. error('no channels selected');
  139. else
  140. fprintf('searching for artifacts in %d channels\n', numsgn);
  141. end
  142. % read the data and apply preprocessing options
  143. sumval = zeros(numsgn, 1);
  144. sumsqr = zeros(numsgn, 1);
  145. numsmp = zeros(numsgn, 1);
  146. fprintf('searching trials');
  147. for trlop = 1:numtrl
  148. fprintf('.');
  149. if isfetch
  150. dat{trlop} = fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no'));
  151. else
  152. dat{trlop} = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind, 'checkboundary', strcmp(cfg.continuous,'no'), 'dataformat', cfg.dataformat);
  153. end
  154. dat{trlop} = preproc(dat{trlop}, cfg.artfctdef.zvalue.channel, hdr.Fs, cfg.artfctdef.zvalue, [], fltpadding, fltpadding);
  155. % accumulate the sum and the sum-of-squares
  156. sumval = sumval + sum(dat{trlop},2);
  157. sumsqr = sumsqr + sum(dat{trlop}.^2,2);
  158. numsmp = numsmp + size(dat{trlop},2);
  159. end % for trlop
  160. % compute the average and the standard deviation
  161. datavg = sumval./numsmp;
  162. datstd = sqrt(sumsqr./numsmp - (sumval./numsmp).^2);
  163. for trlop = 1:numtrl
  164. % initialize some matrices
  165. zmax{trlop} = -inf + zeros(1,size(dat{trlop},2));
  166. zsum{trlop} = zeros(1,size(dat{trlop},2));
  167. zindx{trlop} = zeros(1,size(dat{trlop},2));
  168. nsmp = size(dat{trlop},2);
  169. zdata = (dat{trlop} - datavg(:,ones(1,nsmp)))./datstd(:,ones(1,nsmp)); % convert the filtered data to z-values
  170. zsum{trlop} = sum(zdata,1); % accumulate the z-values over channels
  171. [zmax{trlop},ind] = max(zdata,[],1); % find the maximum z-value and remember it
  172. zindx{trlop} = sgnind(ind); % also remember the channel number that has the largest z-value
  173. % This alternative code does the same, but it is much slower
  174. % for i=1:size(zmax{trlop},2)
  175. % if zdata{trlop}(i)>zmax{trlop}(i)
  176. % % update the maximum value and channel index
  177. % zmax{trlop}(i) = zdata{trlop}(i);
  178. % zindx{trlop}(i) = sgnind(sgnlop);
  179. % end
  180. % end
  181. end % for trlop
  182. %for sgnlop=1:numsgn
  183. % % read the data and apply preprocessing options
  184. % sumval = 0;
  185. % sumsqr = 0;
  186. % numsmp = 0;
  187. % fprintf('searching channel %s ', cfg.artfctdef.zvalue.channel{sgnlop});
  188. % for trlop = 1:numtrl
  189. % fprintf('.');
  190. % if isfetch
  191. % dat{trlop} = fetch_data(data, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind(sgnlop), 'checkboundary', strcmp(cfg.continuous,'no'));
  192. % else
  193. % dat{trlop} = read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1)-fltpadding, 'endsample', trl(trlop,2)+fltpadding, 'chanindx', sgnind(sgnlop), 'checkboundary', strcmp(cfg.continuous,'no'));
  194. % end
  195. % dat{trlop} = preproc(dat{trlop}, cfg.artfctdef.zvalue.channel(sgnlop), hdr.Fs, cfg.artfctdef.zvalue, [], fltpadding, fltpadding);
  196. % % accumulate the sum and the sum-of-squares
  197. % sumval = sumval + sum(dat{trlop},2);
  198. % sumsqr = sumsqr + sum(dat{trlop}.^2,2);
  199. % numsmp = numsmp + size(dat{trlop},2);
  200. % end % for trlop
  201. %
  202. % % compute the average and the standard deviation
  203. % datavg = sumval./numsmp;
  204. % datstd = sqrt(sumsqr./numsmp - (sumval./numsmp).^2);
  205. %
  206. % for trlop = 1:numtrl
  207. % if sgnlop==1
  208. % % initialize some matrices
  209. % zdata{trlop} = zeros(size(dat{trlop}));
  210. % zmax{trlop} = -inf + zeros(size(dat{trlop}));
  211. % zsum{trlop} = zeros(size(dat{trlop}));
  212. % zindx{trlop} = zeros(size(dat{trlop}));
  213. % end
  214. % zdata{trlop} = (dat{trlop} - datavg)./datstd; % convert the filtered data to z-values
  215. % zsum{trlop} = zsum{trlop} + zdata{trlop}; % accumulate the z-values over channels
  216. % zmax{trlop} = max(zmax{trlop}, zdata{trlop}); % find the maximum z-value and remember it
  217. % zindx{trlop}(zmax{trlop}==zdata{trlop}) = sgnind(sgnlop); % also remember the channel number that has the largest z-value
  218. %
  219. % % This alternative code does the same, but it is much slower
  220. % % for i=1:size(zmax{trlop},2)
  221. % % if zdata{trlop}(i)>zmax{trlop}(i)
  222. % % % update the maximum value and channel index
  223. % % zmax{trlop}(i) = zdata{trlop}(i);
  224. % % zindx{trlop}(i) = sgnind(sgnlop);
  225. % % end
  226. % % end
  227. % end
  228. % fprintf('\n');
  229. %end % for sgnlop
  230. for trlop = 1:numtrl
  231. zsum{trlop} = zsum{trlop} ./ sqrt(numsgn);
  232. end
  233. if strcmp(cfg.artfctdef.zvalue.feedback, 'yes')
  234. % give graphical feedback and allow the user to modify the threshold
  235. interactiveloop = 1;
  236. while interactiveloop
  237. h = figure;
  238. hold on
  239. for trlop=1:numtrl
  240. xval = trl(trlop,1):trl(trlop,2);
  241. if thresholdsum,
  242. yval = zsum{trlop};
  243. else
  244. yval = zmax{trlop};
  245. end
  246. plot(xval, yval, 'b-');
  247. dum = yval<=cfg.artfctdef.zvalue.cutoff;
  248. yval(dum) = nan;
  249. plot(xval, yval, 'r-');
  250. end
  251. hline(cfg.artfctdef.zvalue.cutoff, 'color', 'r', 'linestyle', ':');
  252. xlabel('sample number');
  253. ylabel('cumulative z-value');
  254. [response, interactiveloop] = smartinput('\nwould you like to page through the data [y/N]? ', 'n');
  255. artval = {};
  256. for trlop=1:numtrl
  257. if thresholdsum,
  258. % threshold the accumulated z-values
  259. artval{trlop} = zsum{trlop}>cfg.artfctdef.zvalue.cutoff;
  260. else
  261. % threshold the max z-values
  262. artval{trlop} = zmax{trlop}>cfg.artfctdef.zvalue.cutoff;
  263. end
  264. % pad the artifacts
  265. artbeg = find(diff([0 artval{trlop}])== 1);
  266. artend = find(diff([artval{trlop} 0])==-1);
  267. artbeg = artbeg - artpadding;
  268. artend = artend + artpadding;
  269. artbeg(artbeg<1) = 1;
  270. artend(artend>length(artval{trlop})) = length(artval{trlop});
  271. for artlop=1:length(artbeg)
  272. artval{trlop}(artbeg(artlop):artend(artlop)) = 1;
  273. end
  274. end
  275. % show the z-values, the artifacts and a selection of the original data
  276. if interactiveloop
  277. if nargin==1,
  278. if ~thresholdsum, zsum = zmax; end;
  279. artifact_viewer(cfg, cfg.artfctdef.zvalue, zsum, artval, zindx);
  280. cfg.artfctdef.zvalue.cutoff = smartinput(sprintf('\ngive new cutoff value, or press enter to accept current value [%g]: ', cfg.artfctdef.zvalue.cutoff), cfg.artfctdef.zvalue.cutoff);
  281. else
  282. if ~thresholdsum, zsum = zmax; end;
  283. artifact_viewer(cfg, cfg.artfctdef.zvalue, zsum, artval, zindx, data);
  284. cfg.artfctdef.zvalue.cutoff = smartinput(sprintf('\ngive new cutoff value, or press enter to accept current value [%g]: ', cfg.artfctdef.zvalue.cutoff), cfg.artfctdef.zvalue.cutoff);
  285. end
  286. end
  287. if ishandle(h), close(h), end;
  288. end % interactiveloop
  289. else
  290. % this code snippet is the same as above, but without the plotting
  291. artval = {};
  292. for trlop=1:numtrl
  293. if thresholdsum,
  294. % threshold the accumulated z-values
  295. artval{trlop} = zsum{trlop}>cfg.artfctdef.zvalue.cutoff;
  296. else
  297. % threshold the max z-values
  298. artval{trlop} = zmax{trlop}>cfg.artfctdef.zvalue.cutoff;
  299. end
  300. % pad the artifacts
  301. artbeg = find(diff([0 artval{trlop}])== 1);
  302. artend = find(diff([artval{trlop} 0])==-1);
  303. artbeg = artbeg - artpadding;
  304. artend = artend + artpadding;
  305. artbeg(artbeg<1) = 1;
  306. artend(artend>length(artval{trlop})) = length(artval{trlop});
  307. for artlop=1:length(artbeg)
  308. artval{trlop}(artbeg(artlop):artend(artlop)) = 1;
  309. end
  310. end
  311. end % feedback
  312. % convert to one long vector
  313. dum = zeros(1,max(trl(:,2)));
  314. for trlop=1:numtrl
  315. dum(trl(trlop,1):trl(trlop,2)) = artval{trlop};
  316. end
  317. artval = dum;
  318. % find the padded artifacts and put them in a Nx2 trl-like matrix
  319. artbeg = find(diff([0 artval])== 1);
  320. artend = find(diff([artval 0])==-1);
  321. artifact = [artbeg(:) artend(:)];
  322. % remember the artifacts that were found
  323. cfg.artfctdef.zvalue.artifact = artifact;
  324. fprintf('detected %d artifacts\n', size(artifact,1));
  325. % add version information to the configuration
  326. try
  327. % get the full name of the function
  328. cfg.artfctdef.zvalue.version.name = mfilename('fullpath');
  329. catch
  330. % required for compatibility with Matlab versions prior to release 13 (6.5)
  331. [st, i] = dbstack;
  332. cfg.artfctdef.zvalue.version.name = st(i);
  333. end
  334. cfg.artfctdef.zvalue.version.id = '$Id: ft_artifact_zvalue.m 1038 2010-05-05 15:48:52Z timeng $';