TEAP (Toolbox for Emotion Analysis using Physiological Signals) doc
get_regress_eog.m
Go to the documentation of this file.
1 function [h0, s00] = get_regress_eog(fn,Mode)
2 % GET_REGRESS_EOG tries to obtain the regression coefficients
3 % for EOG correction. According to [1], some extra recordings
4 % with large eye movements (i.e. EOG artifacts) are needed.
5 % GET_REGRESS_EOG tries to identify this data.
6 %
7 % hdr = get_regress_eog(file)
8 % hdr = get_regress_eog(file, Mode)
9 %
10 % INPUT:
11 % file filename which should be corrected.
12 % usually, the eye movements are stored in a different file.
13 % Some lab-specific heuristics is used to identify the file with the eye movements.
14 % Mode 'REG' [default] regression with one or two bipolar EOG channels [1]
15 % 'REG+CAR' regression and common average reference
16 % removes 2 bipolar + averaged monopolar EOG
17 % 'REG+PCA' regression and PCA,
18 % removes 3 "EOG" components
19 % 'REG+ICA' regression + ICA [3]
20 % removes 3 "EOG" components
21 % 'PCA-k' removes the k-largest PCA components, k must be a positive integer
22 % 'ICA-k' removes the k-largest ICA components [3], k must be a positive integer
23 % others like 'NGCA-k','TDSEP-k','TDSEP3-k','TDSEP1','FFDIAG'
24 % 'msec' same as PCA-3, modified (without averaging) MSEC method [2]
25 % 'bf-' beamformer, assume zero-activity reference electrode
26 % 'bf+' beamformer, take into account activity of reference electrode
27 % 'Hurst' ICA components selected by the method of[5]
28 % 'Joyce2004' [6]
29 % 'Barbati2004' [7]
30 % 'Meinecke2002' [8]
31 %
32 % The following modifiers can be combined with any of the above
33 % 'FILT###-###Hz' filtering between ### and ### Hz. ### must be numeric
34 % 'Fs=###Hz' downsampling to ### Hz, ### must be numeric
35 % 'x' 2nd player of season2 data
36 %
37 % OUTPUT:
38 % hdr.REGRESS.r0 correction coefficients
39 %
40 % The EOG correction will be applied to the channels CHAN with any of these commands:
41 % HDR = sopen(file,'r',hdr.REGRESS.r0(:,CHAN)); [s,HDR]=sread(HDR); HDR=sclose(HDR);
42 % [s,HDR] = sload(file,hdr.REGRESS.r0(:,CHAN));
43 % [s,HDR] = sload(file,CHAN,'EOG_CORRECTION','ON');
44 %
45 % See also: SLOAD, IDENTIFY_EOG_CHANNELS, BV2BIOSIG_EVENTS, REGRESS_EOG
46 %
47 % Reference(s):
48 % [1] Schlogl A, Keinrath C, Zimmermann D, Scherer R, Leeb R, Pfurtscheller G.
49 % A fully automated correction method of EOG artifacts in EEG recordings.
50 % Clin Neurophysiol. 2007 Jan;118(1):98-104. Epub 2006 Nov 7.
51 % http://dx.doi.org/10.1016/j.clinph.2006.09.003
52 % http://pub.ist.ac.at/~schloegl/publications/schloegl2007eog.pdf
53 % [2] Berg P, Scherg M.
54 % A multiple source approach to the correction of eye artifacts.
55 % Electroencephalogr Clin Neurophysiol. 1994 Mar;90(3):229-41.
56 % [3] JADE algorithm, Jean-François Cardoso.
57 % [4] Boudet S., Peyrodie L., P Gallois, C Vasseur,
58 % Filtering by optimal projectsion and application to automatic artifact removal from EEG
59 % Signal Processing 87 (2007) 1987-1992.
60 % [5] Vorobyov and Cichocki (2002)
61 % Blind noise reduction for multisensory signals using ICA and subspace
62 % filtering, with application to EEG analysis.
63 % Biol Cybern. 2002 Apr;86(4):293-303.
64 % [6] C.A. Joyce, I.F. Gorodnitsky, M.Kutas
65 % Automated removal of eye movement and blink artifats from EEG data using blind component separation.
66 % Psychobiology, 41 (2004), 313-325
67 % [7] Barbati et al (2004)
68 % [8] Frank Meinecke, Andreas Ziehe, Motoaki Kawanabe, and Klaus-Robert Müller.
69 % A Resampling Approach to Estimate the Stability of One-Dimensional or Multidimensional Independent Components.
70 % IEEE Transactions on Biomedical Engineering, 49(12):1514-1525, 2002.
71 % [9] Blanchard G., Kawanabe M., Sugiyama M., Spokoiny V., Muller K.-R. (2006).
72 % In search of non-gaussian components of a high-dimensional distribution.
73 % Journal of Machine Learning Research 7, 247-282.
74 % [10] Kawanabe M., Sugiyama M., Blanchard G, Müller K.-R. (2007)
75 % A new algorithm of non-Gaussian component analysis with radial kernel functions
76 % Annals of the Institute of Statistical Mathematics, 59(1):2007
77 % [11] K.H. Ting, P.C.W. Fung, C.Q.Chang, F.H.Z.Chan
78 % automatec correction of artifact from single-trial event-related potentials bz blind separation using second order statistics only.
79 % Medical Engineering & Physics, 28, 780-794 (2006)
80 
81 % $Id: get_regress_eog.m 2649 2011-03-09 09:52:44Z schloegl $
82 % Copyright (C) 2006,2007 by Alois Schloegl
83 % This is part of the BIOSIG-toolbox http://biosig.sf.net/
84 
85 % This library is free software; you can redistribute it and/or
86 % modify it under the terms of the GNU Library General Public
87 % License as published by the Free Software Foundation; either
88 % Version 2 of the License, or (at your option) any later version.
89 
90  % extract information from BBCI data for EOG correction
91  if nargin<3,
92  CHAN = 0 ;
93  end;
94  if nargin<2,
95  Mode = '';
96  end;
97 
98  [p,f,e] = fileparts(fn);
99 
100  %%%=== search for eye-movement recordings (in order to obtain clean EOG artifacts) ===%%%
101  % an heuristic approach is to support lab-specific standards
102  % currently, the convention of the GrazBCI and the BBCI Lab are supported
103 
104  f0 = dir(fullfile(p,['arte*',e])); % BBCI files
105  LAB_ID = 'BBCI';
106  if length(f0)>1,
107  % hack to ignore "arte*eog_mono" data
108  ix = regexp(strvcat({f0.name}),'eog_mono');
109  for k=1:length(ix)
110  if ix{k},
111  f0(k) = [];
112  end;
113  end;
114  end;
115 
116  if 0,
117  elseif length(f0)==1,
118  feog = fullfile(p,f0.name);
119  LAB_ID = 'BBCI';
120  else
121  f0 = dir(fullfile(p,'EOG/*.gdf')); % Graz BCI files
122  LAB_ID = 'GrazBCI';
123  if length(f0)==1,
124  feog = fullfile(p,'EOG',f0.name);
125  else
126  f0 = dir(fullfile(p,'*03.bkr')); % Graz BCI files
127  if length(f0)==0,
128  f0 = dir(fullfile(p,'*12.bkr')); % Graz BCI files
129  end;
130  if length(f0)==1,
131  feog = fullfile(p,f0.name);
132  eegchan = 1:22;
133  end
134  LAB_ID = 'Graz22';
135  end;
136  end
137 
138  if length(f0)<1,
139  feog = fn;
140  fprintf('error: no artefact file found. Use specified file.\n');
141  end
142  if length(f0)>1,
143  fprintf('error: more than one artefact file found!\n');
144  {f0.name}
145  return;
146  end;
147 
148  % load eye movement calibration data
149  [s00,h0] = sload(feog);
150  s0 = s00;
151 
152  FLAG.SEASON2DATA_PLAYER2 = 0;
153  if strcmp(LAB_ID,'BBCI'),
154  if ~isempty(strfind(Mode,'x')) %%%% this is a hack for the SEASON2DATASET
155  FLAG.SEASON2DATA_PLAYER2 = 1;
156  end;
157 
158  % resting EEG with eyes open
159  ix = find([h0.EVENT.TYP==hex2dec('0114')] | [h0.EVENT.TYP==hex2dec('0115')]);
160  r00 = [];
161  for k=1:length(ix),
162  r00 = [r00; s00(h0.EVENT.POS(ix(k))+(0:h0.EVENT.DUR(ix(k))),:)];
163  end;
164 
165 
166  % find eye movements in BBCI recordings
167  tmp = bitand(2^15-1,h0.EVENT.TYP);
168  tmp = find((tmp > hex2dec('0430')) & (tmp<=hex2dec('0439')));
169  ix1 = min(tmp);
170  ix2 = max(tmp);
171 
172  % extract segment with large eye movements/EOG artifacts
173  s00 = s00(h0.EVENT.POS(ix1):h0.EVENT.POS(ix2)+h0.EVENT.DUR(ix2),:);
174 
175  if size(s00,1)<h0.SampleRate*10,
176  fprintf(2,'WARNING GET_REGRESS_EOG: in %s no eye movements identified\n',h0.FileName);
177  end;
178 
179  elseif strcmp(LAB_ID,'Graz22'),
180  f0 = dir(fullfile(p,'*02.bkr')); % Graz BCI files
181  if length(f0)==0,
182  f0 = dir(fullfile(p,'*11.bkr')); % Graz BCI files
183  end;
184  if length(f0)==1,
185  feog = fullfile(p,f0.name);
186  end
187  [r00,h0r] = sload(feog);
188 
189  else
190  r00 = [];
191  end;
192  FLAG.HURST = ~isempty(strfind(Mode,'HURST')); % Vorobyov and Cichocki (2002)
193  FLAG.AFOP = ~isempty(strfind(Mode,'AFOP')); % Boudet et al 2007
194  FLAG.FOP = ~FLAG.AFOP & ~isempty(strfind(Mode,'FOP')); % Boudet et al 2007
195  FLAG.TDSEP1 = ~isempty(strfind(Mode,'TDSEP1'));
196  FLAG.TDSEP2 = ~isempty(strfind(Mode,'TDSEP2'));
197  FLAG.FFDIAG = ~isempty(strfind(Mode,'FFDIAG'));
198  FLAG.Joyce = ~isempty(strfind(Mode,'JOYCE'));
199  FLAG.Barbati = ~isempty(strfind(Mode,'BARBATI'));
200  FLAG.Meinecke = ~isempty(strfind(Mode,'MEINECKE'));
201 
202  ix = strfind(Mode,'NGCA-');
203  FLAG.NGCA = ~isempty(ix);
204  if FLAG.NGCA,
205  FLAG.NGCA = str2double(strtok(Mode(ix+5:end),' '));
206  end;
207 
208  ix = strfind(Mode,'TDSEP3-');
209  FLAG.TDSEP3 = ~isempty(ix);
210  if FLAG.TDSEP3,
211  FLAG.TDSEP3 = str2double(strtok(Mode(ix+7:end),' '));
212  end;
213 
214  ix = strfind(Mode,'TDSEP-');
215  FLAG.TDSEP = ~isempty(ix);
216  if FLAG.TDSEP,
217  FLAG.TDSEP = str2double(strtok(Mode(ix+6:end),' '));
218  end;
219 
220  ix = strfind(Mode,'ICA-');
221  FLAG.ICA = ~isempty(ix);
222  if FLAG.ICA,
223  FLAG.ICA = str2double(strtok(Mode(ix+4:end),' '));
224  end;
225  ix = strfind(Mode,'PCA-');
226  FLAG.PCA = ~isempty(ix);
227  if FLAG.PCA,
228  FLAG.PCA = str2double(strtok(Mode(ix+4:end),' '));
229  end;
230  if ~isempty(strfind(upper(Mode),'MSEC'));
231  FLAG.PCA = 3;
232  end;
233 
234  FLAG.REG = ~isempty(strfind(upper(Mode),'REG'));
235 
236  % downsampling
237  ix1 = strfind(upper(Mode),'FS=');
238  if ~isempty(ix1),
239  ix2 = strfind(upper(Mode(ix1:end)),'HZ');
240  Fs = Mode(ix1+3:ix1+ix2-2);
241  Fs = str2double(Fs);
242  if length(Fs)==1 & isfinite(Fs),
243  s00 = rs(s00,h0.SampleRate,Fs);
244  h0.SampleRate = Fs;
245  else
246  fprintf(2,'Warning GET_REGRESS_EOG: Fs="%s" could not be decoded. No filter is applied\n',tmp);
247  end;
248  end;
249 
250  % filter data
251  ix1 = strfind(Mode,'FILT');
252  if ~isempty(ix1),
253  ix2 = strfind(upper(Mode(ix1:end)),'HZ');
254  tmp = Mode(ix1+4:ix1+ix2-2);
255  tmp((tmp=='-')|(tmp=='='))=' ';
256  B = str2double(tmp);
257  if (length(B)==2) & all(isfinite(B))
258  FLAG.Filter = B;
259  tmp = center(s00,1); tmp(isnan(tmp)) = 0;
260  tmp = fft(tmp); f=[0:size(s00,1)-1]*h0.SampleRate/size(s00,1);
261  w = ((f>B(1)) & (f<B(2))) | ((f>h0.SampleRate-B(2)) & (f<h0.SampleRate-B(1)));
262  tmp(~w,:) = 0;
263  s00 = real(ifft(tmp));
264  clear tmp;
265  else
266  fprintf(2,'Warning GET_REGRESS_EOG: Filter="%s" could not be decoded. No filter is applied\n',tmp);
267  end;
268  end;
269 
270  %%%%% define EEG and EOG channels %%%%%
271  CHANTYP = repmat(' ',h0.NS,1);
272  CHANTYP([(h0.LeadIdCode>=996) & (h0.LeadIdCode<=1302)])='E'; % EEG
273  if strcmp(LAB_ID, 'Graz22');
274  CHANTYP(1:22)='E';
275  end;
276  eogchan = identify_eog_channels(h0);
277  CHANTYP(any(eogchan,2)) = 'O'; % EOG
278  if FLAG.SEASON2DATA_PLAYER2,
279  CHANTYP = CHANTYP([65:128,1:64]);
280  eogchan = eogchan([65:128,1:64],:);
281  end;
282 
283  if isempty(strfind(upper(Mode),'MSEC1'))
284  % MSEC,MSEC2 [default]
285  CHAN = find((CHANTYP=='E') | (CHANTYP=='O'));
286  else % MSEC1
287  CHAN = find(CHANTYP=='E');
288  end;
289  chan = CHAN;
290  nc = length(CHAN);
291 
292  %%%%% identify EOG components %%%%%
293  if 0,
294 
295  elseif FLAG.AFOP,
296  error('Mode AFOP not supported');
297 
298  elseif FLAG.FOP,
299  % Optimal Projection (Boudet et al, 2007)
300  chan = find(CHANTYP=='E' | CHANTYP=='O');
301 
302  RES.FOP.w = [];
303  [P,D] = eig(covm(r00(:,chan),'D'),covm(s00(:,chan),'D'));
304  TH = 0.3; % Boudet et al. 2007, p 1989.
305  eogchan = sparse(chan,1:length(chan),1,h0.NS,length(chan))*P(:,diag(D)<TH);
306  if size(eogchan,2)>5,
307  eogchan=eogchan(:,1:5);
308  end;
309  RES.FOP.w = eogchan;
310 
311  elseif ~isempty(strfind(Mode,'bf-'))
312  % beamformer approach
313  T = load('EOG_DIPOLS3'); % load lead field matrix
314  T.Label = T.sa.clab_electrodes;
315  T = leadidcodexyz(T);
316  V = zeros(h0.NS,3);
317  for k=find(h0.LeadIdCode)',
318  ix = find(T.LeadIdCode==h0.LeadIdCode(k));
319  if length(ix),
320  V(k,:) = T.v(ix,4:6);
321  end;
322  end;
323  eogchan = pinv(V)';
324  if FLAG.SEASON2DATA_PLAYER2,
325  eogchan = eogchan([h0.NS/2+1:h0.NS,1:h0.NS/2],:);
326  end;
327 
328  elseif ~isempty(strfind(Mode,'bf+'))
329  % beamformer approach
330  T = load('EOG_DIPOLS3'); % load lead field matrix
331  T.Label = T.sa.clab_electrodes;
332  T = leadidcodexyz(T);
333  V = zeros(h0.NS,3);
334  for k=find(h0.LeadIdCode)',
335  ix = find(T.LeadIdCode==h0.LeadIdCode(k));
336  if length(ix),
337  V(k,:) = T.v(ix,4:6);
338  end;
339  end;
340  R = eye(64);
341  R(1:54,1:54)=R(1:54,1:54)-1/54;
342  eogchan = [R*pinv(V(1:64,:))';zeros(64,3)];
343  if FLAG.SEASON2DATA_PLAYER2,
344  eogchan = eogchan([h0.NS/2+1:h0.NS,1:h0.NS/2],:);
345  end;
346 
347  elseif FLAG.Meinecke,
348  CHAN = find(CHANTYP=='E');
349  chan = sparse(CHAN,1:length(CHAN),1,h0.NS,length(CHAN));
350  r = [chan,eogchan]; % CAR and bipolar EOG
351  tmp = s00*r;
352  tmp = tmp(~any(isnan(tmp),2),:);
353 
354 % opt.verbose: 0 = no progress reports
355 % 1 = progress reports (default)
356 % 2 = progress reports and plot
357 % opt.title: string containing title of the data set
358 % opt.B: Bootstrap size (default B=100)
359 % opt.sel: time lag values for TDSEP
360 
361  opt.verbose = 0;
362  opt.title = 'BSS resampling';
363  opt.B = 10;
364  opt.sel = 0:round(.15*h0.SampleRate)
365  if ~isempty(strfind(upper(Mode),'JADE'));
366  alg = 'jade';
367  else
368  alg = 'tdsep';
369  end;
370 
371  ica = ica_resamp(tmp',alg,opt)
372 
373 % ica.x: the given mixtures
374 % ica.A: the estimated mixing matrix
375 % ica.s: the estimated source signals
376 % ica.S: the separability matrix
377 % ica.perm: permutation of the estimated sources that makes the
378 % block structure visible
379 
380 
381  ochan = pinv(ica.A)';
382  eogchan = r*ochan;
383 
384 
385  elseif ~isempty(strfind(Mode,'JOYCE'))
386  CHAN = find(CHANTYP=='E');
387  chan = sparse(CHAN,1:length(CHAN),1,h0.NS,length(CHAN));
388  r = [chan,eogchan]; % mono and bipolar EOG
389  tmp = s00(~any(isnan(s00),2),:);
390 
391  sel = round(.15*h0.SampleRate);
392  meth = 'TDSEP0';
393  W1 = bss(zscore(tmp*[chan, eogchan]),meth,[],sel);
394  W2 = bss(zscore(tmp*[chan,-eogchan]),meth,[],sel);
395 
396  % step 2
397  c1 = corrcoef(tmp*[chan, eogchan]*W1,tmp*[chan, -eogchan]*W2);
398  [sel2,ix]=find(c1 < -0.5);
399 
400  % step 3
401  c2 = corrcoef(s00*eogchan,s00*[chan, eogchan]*W1);
402  sel3 = find(any(abs(c2)>.3));
403 
404  % step 4
405  c3 = rms(diff(zscore(s00*[chan, eogchan])*W1(:,sel3),[],1));
406  sel4 = find(c3 < 0.2 * 500 / h0.SampleRate);
407  %sel2',sel3,sel4,
408  sel = unique([sel2(:)',sel3(sel4)]);
409  FLAG.Joyce.C1 = c1;
410  FLAG.Joyce.C2 = c2;
411  FLAG.Joyce.C3 = c3;
412 
413  eogchan = [chan, eogchan]*W1(:,sel);
414 
415  elseif ~isempty(strfind(Mode,'KIERKELS'))
416  [t,r]=strtok(Mode);
417  [meth]=strtok(r);
418 
419  eegchan = find(CHANTYP=='E');
420  eogchan = find(CHANTYP=='O');
421  chan = [eegchan(:);eogchan(:)];
422  tmp = s00(:,chan);
423  tmp = tmp(~any(isnan(tmp),2),:);
424 
425  sel = round([0,1,2,3,5,10,20]/250*h0.SampleRate);
426  W = bss(tmp,meth,[],sel);
427  A = inv(W);
428  r = corrcoef(s00(:,chan)*W,s00(:,eogchan));
429  sel = any(r>0.7, 2);
430  eogchan = sparse(chan,1:length(chan),1,h0.NS,length(chan)) * W * A(:,sel);
431 
432 
433  elseif ~isempty(strfind(Mode,'TING'))
434  eegchan = find(CHANTYP=='E');
435  eogchan = find(CHANTYP=='O');
436  chan = [eegchan(:);eogchan(:)];
437  tmp = s00(:,chan);
438  tmp = tmp(~any(isnan(tmp),2),:);
439 
440  sel = round(.15*h0.SampleRate);
441  meth= 'TDSEP0';
442  W = bss(tmp,meth,[],sel);
443  A = inv(W);
444 
445  c1 = max(abs(tmp),[],1) * max(abs(A),[],2);
446  up = chan(length(eegchan)+1);
447  lo = chan(length(eegchan)+2);
448  le = chan(end-1);
449  ri = chan(end);
450  c2 = abs(A(:,up)-A(:,lo)) - max(max(A(:,1:length(eegchan))));
451  c3 = abs(A(:,le)-A(:,ri)) - max(max(A(:,1:length(eegchan))));
452 
453  sel=zeros(1,3);
454  [tmp,sel(1)]=max(c1);
455  [tmp,sel(2)]=max(c2);
456  [tmp,sel(3)]=max(c3);
457  sel=unique(sel);
458  %find(c1>100),find(c2>0),find(c3>0),
459  sel=[find(c1>100),find(c2>0),find(c3>0)]
460  eogchan = sparse(chan,1:length(chan),1,h0.NS,length(chan)) * W * A(:,sel);
461 
462 
463  elseif (FLAG.PCA>0) | (FLAG.ICA>0) | (FLAG.NGCA>0) | (FLAG.TDSEP>0) |(FLAG.TDSEP1>0) | (FLAG.TDSEP2>0) | (FLAG.TDSEP3>0) | (FLAG.HURST) | (FLAG.FFDIAG),
464  % identify channels used for PCA
465 
466  if FLAG.PCA,
467  chan = sparse(chan,1:nc,1,h0.NS,nc)*(eye(nc) - 1/nc); % Common Average Reference (CAR)
468  r = [chan,eogchan]; % CAR and bipolar EOG
469  tmp = s00*r;
470  tmp = tmp(~any(isnan(tmp),2),:);
471 
472  [u,s,ochan] = svds(tmp, FLAG.PCA); % get k (i.e. FLAG.PCA) largests PCA's
473  eogchan = r*ochan;
474  RES.PCA.w = eogchan;
475 
476  elseif FLAG.ICA,
477  chan = sparse(chan,1:nc,1,h0.NS,nc)*(eye(nc) - 1/nc); % Common Average Reference (CAR)
478  r = [chan,eogchan]; % CAR and bipolar EOG
479  tmp = s00*r;
480  tmp = tmp(~any(isnan(tmp),2),:);
481 
482  [A] = jade(tmp', FLAG.ICA); % get k (i.e. FLAG.PCA) largests PCA's
483  ochan = pinv(A)';
484  eogchan = r*ochan;
485 
486  elseif FLAG.HURST,
487  chan = sparse(chan,1:nc,1,h0.NS,nc)*(eye(nc) - 1/nc); % Common Average Reference (CAR)
488  r = [chan,eogchan]; % CAR and bipolar EOG
489  tmp = s00*r;
490  tmp = tmp(~any(isnan(tmp),2),:);
491 
492  A = jade(tmp', min(20,size(tmp,1)));
493  U = pinv(A)';
494  H = hurst(s0*r*U)*log(2) % account for c=1/2
495  ix = find((H>=.58) & (H<=0.64));
496  eogchan = r*U(:,ix);
497  h0.HURST = H;
498 
499  elseif FLAG.NGCA, % NonGaussian Component Analysis
500  % full rank required
501  par.nbng = FLAG.NGCA;
502  chan = sparse(chan,1:nc,1,h0.NS,nc);
503  tmp = s00*chan;
504  tmp = tmp(~any(isnan(tmp),2),:);
505  [ngmatrix, projdata, signalmatrix] = NGCA(tmp',par);
506  eogchan = chan*ngmatrix;
507 
508  elseif FLAG.FFDIAG, %
509  chan = sparse(chan,1:nc,1,h0.NS,nc);
510  tmp = s00*chan;
511  tmp = tmp(~any(isnan(tmp),2),:);
512 
513  sel = 0:round(.15*h0.SampleRate);
514  C= zeros(nc,nc,length(sel));
515  for k= 1:length(sel)
516  C(:,:,k)= tdCorr(tmp', sel(k));
517  end
518  [W,d] = ffdiag2(C);
519  W = (W./repmat(sqrt(sum(W.*W,2)),1,nc))';
520  [tmp,ix]=sort(-rms(s00*chan*W,1));
521  eogchan = chan*W(:,ix(1:3));
522 
523  elseif FLAG.TDSEP, %
524  chan = sparse(chan,1:nc,1,h0.NS,nc)*(eye(nc) - 1/nc); % Common Average Reference (CAR)
525  tmp = s00*chan;
526  tmp = tmp(~any(isnan(tmp),2),:);
527 
528  sel = round([0,1,2,3,5,10,20]/256*h0.SampleRate);
529  %%% DO NOT USE
530  [W,d] = tdsep(tmp',sel);
531  eogchan = chan*W(1:3,:)';
532 
533  elseif FLAG.BSS, %
534  chan1= sparse(chan,1:nc,1,h0.NS,nc);
535  tmp = s00*chan1;
536  tmp = tmp(~any(isnan(tmp),2),:);
537  sel = 0:round(.15*h0.SampleRate);
538  W = bss(tmp',alg,[],sel);
539 
540  %%% select 1st 3 components %%%
541  eogchan = chan*W(1:3,:)';
542 
543  %%% select 3 components with minumum angle to b0 %%%
544  [h0.REGRESS, s01] = regress_eog(s00,chan,eogchan);
545  iW = inv(W);
546  for k = 1:size(W,2),
547  phi(k) = subspace(h0.REGRESS.b0(2:3,:)',iW(:,k));
548  end;
549  [phi,ix] = sort(phi);
550  eogchan = chan1*W(ix(1:3),:)';
551 
552  elseif FLAG.TDSEP1, %
553  chan1= sparse(chan,1:nc,1,h0.NS,nc);
554  tmp = s00*chan1;
555  tmp = tmp(~any(isnan(tmp),2),:);
556  sel = 0:round(.15*h0.SampleRate);
557  W = tdsep0(tmp',sel);
558  iW = inv(W);
559  [h0.REGRESS, s01] = regress_eog(s00,chan,eogchan);
560 
561  for k = 1:size(W,2),
562  phi(k) = subspace(h0.REGRESS.b0(2:3,:)',iW(:,k));
563  end;
564  [phi,ix] = sort(phi);
565  eogchan = chan1*W(ix(1:3),:)';
566 
567  elseif FLAG.TDSEP2, %
568  chan1= sparse(chan,1:nc,1,h0.NS,nc);
569  tmp = s00*chan1;
570  tmp = tmp(~any(isnan(tmp),2),:);
571  sel = 0:round(.15*h0.SampleRate);
572  W = tdsep0(tmp',sel);
573  iW = inv(W);
574  [h0.REGRESS, s01] = regress_eog(s00,chan,eogchan);
575 
576  c = [];
577  ix = [];
578  P = eye(length(chan));
579  for k0 = 1:3,
580  for k = 1:size(W,2),
581  phi(k) = subspace(P*h0.REGRESS.b0(2:3,:)',P*iW(:,k));
582  end;
583  [sp,ix(k0)] = min(phi);
584  w = iW(:,ix);
585  c = [c,iW(:,ix)];
586  P = P*[eye(nc)-w*inv(w'*w)*w'];
587  end;
588  eogchan = chan1*W(ix,:)';
589 
590  elseif FLAG.TDSEP3, %
591  % full rank required
592  chan = sparse(chan,1:nc,1,h0.NS,nc);
593  r = [chan,eogchan]; % CAR and bipolar EOG
594  tmp = s00*chan;
595  tmp = tmp(~any(isnan(tmp),2),:);
596 
597  sel = round([0,1,2,3,5,10,20]/256*h0.SampleRate);
598  [y,W,d] = tdsep3(tmp',sel);
599  eogchan = chan*W(1:3,:)';
600  end;
601 
602 
603  elseif FLAG.REG, %REGRESSION
604  % define xEOG channels
605  FLAG.REG = 1;
606  if ~isempty(strfind(upper(Mode),'REG+CAR1'));
607  eogchan = [eogchan,any(eogchan,2)];
608  elseif ~isempty(strfind(upper(Mode),'REG+CAR2'));
609  eogchan = [eogchan,double([CHANTYP=='O']/sum(CHANTYP=='O')-[CHANTYP>' ']/sum(CHANTYP>' '))];
610  end;
611  end;
612 
613  % remove EOG channels for list of corrected channels
614  % chan = 1:h0.NS;
615  chan = find(CHANTYP=='E');
616  % regression analysis - compute correction coefficients.
617  [h0.REGRESS, s01] = regress_eog(s00,chan,eogchan);
618  h0.REGRESS.FLAG = FLAG;
619 
620  %%%%% post-regression improvement
621  if length(Mode)>6,
622  if ~isempty(strfind(Mode([1:4,6,7]),'REG+CA'))
623  % select EEG and EOG channels and do CAR
624  echan = find(CHANTYP>' ');
625  nc = length(echan);
626  echan = sparse(echan,1:nc,1,h0.NS,nc)*(eye(nc) - 1/nc); % Common Average Reference (CAR)
627 
628  tmp = strtok(Mode);
629  nc = str2double(tmp(8:end));
630  if isempty(nc) | isnan(nc),
631  nc = 1;
632  else
633  end;
634  tmp = center(s01,1)*echan;
635  tmp = tmp(~any(isnan(tmp),2),:);
636  if ~isempty(strfind(Mode,'REG+PCA'))
637  % get largest PCA's
638  [u,s,zeog] = svds(tmp, nc);
639  elseif ~isempty(strfind(Mode,'REG+ICA'))
640  %%% ICA: identify one component
641  [A,s] = jade(tmp',nc);
642  zeog = pinv(A)';
643  else
644  fprintf(2,'Mode %s not supported - regression is used only.\n',Mode);
645  return;
646  end;
647 
648  w = sparse([eogchan,h0.REGRESS.r0*echan*zeog]);
649 %rank(full(w))
650 w(isnan(w))=0;
651 h0.REGRESS.r0,
652 %rank(full(w))
653  [h0.REGRESS,s01] = regress_eog(s00,chan,w);
654  end
655  end
656  h0.REGRESS.FLAG = FLAG;
657 
658 
659  %%% quantifying the noise
get_regress_eog
function get_regress_eog(in fn, in Mode)
sclose
function sclose(in HDR)
sload
function sload(in FILENAME, in varargin)
identify_eog_channels
function identify_eog_channels(in fn, in x)
regress_eog
function regress_eog(in D, in ny, in nx)
sopen
function sopen(in arg1, in PERMISSION, in CHAN, in MODE, in arg5, in arg6)
str2double
function str2double(in s, in cdelim, in rdelim, in ddelim)
rs
function rs(in y1, in T, in f2)
leadidcodexyz
function leadidcodexyz(in arg1)
sread
function sread(in HDR, in NoS, in StartPos)