0001 function [x,w,ww]=nt_star(x,thresh,closest,depth)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 nt_greetings;
0016
0017 PCA_THRESH=10^-15;
0018 NSMOOTH=10;
0019 MINPROP=0.3;
0020 NITER=3;
0021 VERBOSE=1;
0022
0023 if nargin<1; error; end
0024 if nargin<2 || isempty(thresh); thresh=1; end
0025 if nargin<3; closest=[]; end
0026 if ~isempty(closest)&&size(closest,1)~=size(x,2);
0027 error('closest array should have as many rows as channels of x');
0028 end
0029 if nargin<4 || isempty(depth); depth=1; end
0030
0031 if nargout==0
0032 [y,w,ww]=nt_star(x,thresh,closest,depth);
0033 disp([mean(w(:)), mean(ww(:))])
0034 figure(1); clf;
0035 subplot 311; plot(x);
0036 subplot 312; plot(y);
0037 subplot 313; plot(w, '.-'); ylim([0 1.1]);
0038 clear x w ww
0039 return
0040 end
0041
0042
0043 [nsample,nchan,~]=size(x);
0044 x=nt_unfold(x);
0045
0046 p0=nt_wpwr(x);
0047 mn=mean(x);
0048 x=nt_demean(x);
0049 nn=sqrt(mean(x.^2));
0050 x=nt_normcol(x);
0051 p00=nt_wpwr(x);
0052
0053
0054 iNan=find(all(isnan(x)));
0055 iZero=find(all(x==0));
0056 x(:,iNan)=randn(size(x,1),numel(iNan));
0057 x(:,iZero)=randn(size(x,1),numel(iZero));
0058
0059 x=nt_demean(x);
0060 c0=nt_cov(x);
0061
0062
0063 Find time intervals where at least one channel is excentric --> w==0.
0064
0065
0066 iIter=NITER;
0067 while iIter>0
0068
0069
0070 w=ones(size(x,1),1);
0071 for iChan=1:nchan
0072
0073
0074 if ~isempty(closest);
0075 oChan=closest(iChan,:);
0076 else
0077 oChan=setdiff(1:nchan,iChan);
0078 end
0079 oChan(oChan>nchan)=[];
0080
0081
0082 [topcs,eigenvalues]=nt_pcarot(c0(oChan,oChan));
0083 idx=find(eigenvalues/max(eigenvalues) > PCA_THRESH);
0084 topcs=topcs(:,idx);
0085
0086
0087 b=c0(iChan,oChan)*topcs/(topcs'*c0(oChan,oChan)*topcs);
0088 y=x(:,oChan)*(topcs*b');
0089 dx=abs(y-x(:,iChan));
0090 dx=dx+eps;
0091
0092 d=dx/mean(dx(find(w)));
0093 if NSMOOTH>0;
0094 d=filtfilt(ones(NSMOOTH,1)/NSMOOTH,1,d);
0095 end
0096
0097 d=d/thresh;
0098 w=min(w,(d<1));
0099
0100 end
0101
0102 prop=mean(w);
0103 if VERBOSE>0; disp(['proportion artifact free: ', num2str(prop)]); end
0104
0105 if iIter==NITER && prop<MINPROP
0106 thresh=thresh*1.1;
0107 if VERBOSE>0; disp(['Warning: nt_star increasing threshold to ', num2str(thresh)]); end
0108 w=ones(size(w));
0109 else
0110 iIter=iIter-1;
0111 end
0112
0113 x=nt_demean(x,w);
0114 c0=nt_cov(x,[],w);
0115 end
0116
0117
0118 We now know which part contains channel-specific artifacts (w==0 for artifact part),
0119 and we have an estimate of the covariance matrix of the artifact-free part.
0120
0121
0122
0123 Find which channel is most excentric at each time point.
0124 Here we use an excentricity measure based on the absolute value of the signal,
0125 rather than the difference between signal and projection.
0126
0127
0128 xx=abs(x);
0129 xx=bsxfun(@times,xx, 1 ./ sqrt(mean(xx(find(w),:).^2)));
0130 if NSMOOTH>0;
0131 xx=filtfilt(ones(NSMOOTH,1)/NSMOOTH,1,xx);
0132 end
0133 [~,rank]=sort(xx','descend');
0134 rank=rank';
0135 rank(find(w),:)=0;
0136
0137 depth=min(depth,nchan-1);
0138 ww=ones(size(x));
0139 for iDepth=1:depth
0140
0141
0142 Fix each channel by projecting on other channels.
0143
0144
0145 iFixed=nchan;
0146 nFixed=0;
0147 for iChan=1:nchan
0148
0149 bad_samples=find(iChan==rank(:,iDepth));
0150 if iDepth ~=1;
0151 bad_samples(find(xx(bad_samples,iChan)<thresh)) =[];
0152 end
0153
0154 nFixed=nFixed+numel(bad_samples);
0155 if isempty(bad_samples);
0156 iFixed=iFixed-1;
0157 continue;
0158 end
0159 ww(bad_samples,iChan)=0;
0160
0161
0162 if ~isempty(closest);
0163 oChan=closest(iChan,:);
0164 else
0165 oChan=setdiff(1:nchan,iChan);
0166 end
0167 oChan(oChan>nchan)=[];
0168
0169
0170 [topcs,eigenvalues]=nt_pcarot(c0(oChan,oChan));
0171 idx=find(eigenvalues/max(eigenvalues) > PCA_THRESH);
0172 topcs=topcs(:,idx);
0173
0174
0175 b=c0(iChan,oChan)*topcs/(topcs'*c0(oChan,oChan)*topcs);
0176 y=x(bad_samples,oChan)*(topcs*b');
0177
0178 x(bad_samples,iChan)=y(:);
0179
0180 end
0181
0182 if VERBOSE>0;
0183 disp(['depth: ', num2str(iDepth), ', n fixed channels: ',num2str(iFixed),...
0184 ', n fixed samples: ', num2str(nFixed), ', ratio: ',num2str(nt_wpwr(x)/p00)]);
0185 end
0186 end
0187
0188 x=nt_demean(x);
0189 x=bsxfun(@times,x,nn);
0190 x=bsxfun(@plus,x,mn);
0191
0192 x=nt_fold(x,nsample);
0193 w=nt_fold(w,nsample);
0194 ww=nt_fold(ww,nsample);
0195
0196
0197
0198
0199 x(:,iNan)=nan;
0200 x(:,iZero)=0;
0201
0202 if VERBOSE>0; disp(['power ratio: ', num2str(nt_wpwr(x)/p0)]); end