2 % REMOVE5060HZ removes line interference artifacts
3 % from biomedical signal data. Segmented data supported only
4 % with an FFT-based method.
14 % CHAN channel selection [
default: 0 (all)]
16 % HDR header structure (contains labels, sampling rate etc)
17 % Mode
'PCA',
'PCA 50' 50 Hz PCA/SVD filter
18 %
'NOTCH' 50 Hz FIR Notch filter, order=3
19 %
'FIT' fit and remove 50 Hz sine/cosine wave
20 %
'FFT' fft filter - cancels 50+-0.5 Hz in Frequency domain (
default)
21 %
'FFT3' fft filter - cancels also 3rd harmonic 50 and 150 Hz
22 %
'PCA 60' 60 Hz PCA/SVD filter
23 %
'NOTCH 60' 60 Hz FIR Notch filter, order=3
24 %
'FIT 60' fit and remove 60 Hz sine/cosine wave
25 %
'FFT 60' fft filter - cancels 60+-0.5 Hz in frequency domain
26 %
'FFT3 60' fft filter - cancels also 3rd harmonic 60 and 180 Hz
27 % outfile Name of file
for storing corrected data.
30 % s corrected signal data
31 % HDR header structure
34 % see also: REGRESS_EOG, EVENTCODES
40 % This program is free software; you can redistribute it and/or
41 % modify it under the terms of the GNU General Public License
42 % as published by the Free Software Foundation; either version 2
43 % of the License, or (at your option) any later version.
45 % This program is distributed in the hope that it will be useful,
46 % but WITHOUT ANY WARRANTY; without even the implied warranty of
47 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48 % GNU General Public License
for more details.
50 % You should have received a copy of the GNU General Public License
51 % along with
this program;
if not, write to the Free Software
52 % Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
54 % $Id:
remove5060hz.m 2905 2012-02-23 10:30:59Z schloegl $
55 % (C)2006,2009,2012 by Alois Schloegl <alois.schloegl@ist.ac.at>
56 % This is part of the BIOSIG-toolbox http:
62 if length(varargin)>1, arg2 = varargin{2}; end;
63 if length(varargin)>2, arg3 = varargin{3}; end;
66 k = strmatch(
'-o',varargin);
67 if k, outfile = varargin{k+1}; end;
80 [s,HDR] =
sload(arg1,CHAN);
82 elseif isnumeric(arg1) && isstruct(arg2)
95 NotchFreq = 50; %
default 50 Hz Notch
96 if strfind(upper(MODE),
'60')
101 if isfield(HDR,'EVENT')
102 segs = [1;HDR.EVENT.POS(HDR.EVENT.TYP==hex2dec('7ffe'));size(s,1)];
104 segs = [1;size(s,1)];
106 flagNoSegmentSupport = length(segs)>2;
109 if strfind(upper(MODE),'PCA') % strfind(upper(MODE),'SVD')
110 if flagNoSegmentSupport,
111 error('non-continous data is not supported by MODE=%s',MODE);
114 % fit and remove sine/cosine wave
115 % Assumption: stationarity of line interference
117 bw = 1; % bandwidth of 1 Hz
118 r = exp(-bw/HDR.SampleRate); % convert bandwidth into magnitude of poles
119 %B = real(r*poly(exp(i*2*pi/HDR.SampleRate*[NotchFreq:2*NotchFreq:HDR.SampleRate-NotchFreq])));
120 B = real(poly(r*exp(i*2*pi*NotchFreq/HDR.SampleRate*[1,-1])));
122 %%%%% identify 50/60 Hz component
123 [u,d,v] = svd(filtfilt(1,B,s),0); % s = u*d*v';
124 [tmp,ix] = max(diag(d));
126 %%%%% regress 50/60 Hz component
127 [R,S] =
regress_eog([s,u(:,ix)],1:size(s,2),size(s,2)+1); % regression on filtered component
128 s = S(:,1:size(s,2));
129 %[R2,s2] =
regress_eog(s,1:size(s,2),v(:,ix)); % regression on raw component
132 elseif ~isempty(strfind(upper(MODE),'FIT'))
133 if flagNoSegmentSupport,
134 error('non-continous data is not supported by MODE=%s',MODE);
137 % fit and remove sine/cosine wave
138 % Assumption: stationarity and locking of line and sampling frequency
139 t = [1:size(s,1)]'/HDR.SampleRate;
140 u = exp(j*2*pi*NotchFreq/HDR.SampleRate*[1:size(s,1)]');
145 elseif strfind(upper(MODE),'ICA')
147 %%%%% not implemented %%%%%
148 error('ICA method not implemented');
151 elseif ~isempty(strfind(upper(MODE),'NOTCH'))
152 if flagNoSegmentSupport,
153 error('non-continous data is not supported by MODE=%s',MODE);
156 if ~isempty(strfind(upper(MODE),'+'))
157 B = real(poly(exp(i*2*pi/HDR.SampleRate*[NotchFreq,HDR.SampleRate-NotchFreq])));
159 warning('NOTCH+ - mode is not recommended');
160 B = real(poly(exp(i*2*pi/HDR.SampleRate*[NotchFreq:2*NotchFreq:HDR.SampleRate-NotchFreq/2])));
162 s = filtfilt(B/sum(B),1,s);
165 elseif ~isempty(strfind(upper(MODE),'FFT'))
167 b = 1/2; % half bandwidth
169 for k=1:length(segs)-1,
170 %% support segmented data
171 u = fft(s(segs(k):segs(k+1)-1,:),[],1);
172 f = [0,segs(k+1)-segs(k)-1];
173 u((NotchFreq-b) < f & f < (NotchFreq+b),:) = 0;
174 u((NotchFreq-b) < (HDR.SampleRate-f) & (HDR.SampleRate-f) < (NotchFreq+b),:) = 0;
175 if ~isempty(strfind(upper(MODE),'FFT3'))
176 % cancel 3rd harmonic 150/180 Hz
177 u(3*(NotchFreq-b) < f & f < 3*(NotchFreq+b),:) = 0;
178 u(3*(NotchFreq-b) < (HDR.SampleRate-f) & (HDR.SampleRate-f) < 3*(NotchFreq+b),:) = 0;
180 s(segs(k):segs(k+1)-1,:) = real(ifft(u,[],1));
184 elseif ~isempty(strfind(upper(MODE),'USER-SPECIFIC')) && (abs(HDR.SampleRate-1000)<1e3),
186 B = load('49__51bs_2751pts_1000Hz.asc');
190 warning('unknown method: no correction applied.');
196 HDR.FileName = outfile;
203 HDR =
sopen(HDR,'w');