TEAP (Toolbox for Emotion Analysis using Physiological Signals) doc
remove5060hz.m
Go to the documentation of this file.
1 function [s,HDR] = remove5060hz(varargin)
2 % REMOVE5060HZ removes line interference artifacts
3 % from biomedical signal data. Segmented data supported only
4 % with an FFT-based method.
5 %
6 % [s,HDR] = remove5060hz(fn, Mode)
7 % [s,HDR] = remove5060hz(fn, CHAN, Mode)
8 % [s,HDR] = remove5060hz(s, HDR, Mode)
9 % remove5060hz(..., '-o',outfile)
10 %
11 %
12 % INPUT:
13 % fn biosignal file
14 % CHAN channel selection [default: 0 (all)]
15 % s signal data
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.
28 %
29 % OUTPUT:
30 % s corrected signal data
31 % HDR header structure
32 %
33 %
34 % see also: REGRESS_EOG, EVENTCODES
35 %
36 % Reference(s):
37 %
38 
39 
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.
44 %
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.
49 %
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.
53 
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://biosig.sf.net/
57 
58 MODE = [];
59 
60 arg2 = []; arg3=[];
61 arg1 = varargin{1};
62 if length(varargin)>1, arg2 = varargin{2}; end;
63 if length(varargin)>2, arg3 = varargin{3}; end;
64 
65 outfile = [];
66 k = strmatch('-o',varargin);
67 if k, outfile = varargin{k+1}; end;
68 
69 if ischar(arg1),
70  CHAN = 0;
71  if (nargin>1)
72  if ischar(arg2)
73  MODE = arg2;
74  CHAN = 0;
75  else
76  MODE = '50';
77  CHAN = arg2;
78  end;
79  end;
80  [s,HDR] = sload(arg1,CHAN);
81 
82 elseif isnumeric(arg1) && isstruct(arg2)
83  s = arg1;
84  HDR = arg2;
85  if (nargin>2)
86  MODE = arg3;
87  end;
88 
89 end
90 
91 if isempty(MODE)
92  MODE = 'FFT';
93 end;
94 
95 NotchFreq = 50; % default 50 Hz Notch
96 if strfind(upper(MODE),'60')
97  NotchFreq = 60;
98 end;
99 
100 
101 if isfield(HDR,'EVENT')
102  segs = [1;HDR.EVENT.POS(HDR.EVENT.TYP==hex2dec('7ffe'));size(s,1)];
103 else
104  segs = [1;size(s,1)];
105 end;
106 flagNoSegmentSupport = length(segs)>2;
107 
108 
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);
112  end;
113 
114  % fit and remove sine/cosine wave
115  % Assumption: stationarity of line interference
116 
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])));
121 
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));
125 
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
130 
131 
132 elseif ~isempty(strfind(upper(MODE),'FIT'))
133  if flagNoSegmentSupport,
134  error('non-continous data is not supported by MODE=%s',MODE);
135  end;
136 
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)]');
141  A = covm(u,s);
142  s = s - 2*real(u*A);
143 
144 
145 elseif strfind(upper(MODE),'ICA')
146 
147  %%%%% not implemented %%%%%
148  error('ICA method not implemented');
149 
150 
151 elseif ~isempty(strfind(upper(MODE),'NOTCH'))
152  if flagNoSegmentSupport,
153  error('non-continous data is not supported by MODE=%s',MODE);
154  end;
155 
156  if ~isempty(strfind(upper(MODE),'+'))
157  B = real(poly(exp(i*2*pi/HDR.SampleRate*[NotchFreq,HDR.SampleRate-NotchFreq])));
158  else
159  warning('NOTCH+ - mode is not recommended');
160  B = real(poly(exp(i*2*pi/HDR.SampleRate*[NotchFreq:2*NotchFreq:HDR.SampleRate-NotchFreq/2])));
161  end;
162  s = filtfilt(B/sum(B),1,s);
163 
164 
165 elseif ~isempty(strfind(upper(MODE),'FFT'))
166  % cancel 50/60 Hz
167  b = 1/2; % half bandwidth
168 
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;
179  end;
180  s(segs(k):segs(k+1)-1,:) = real(ifft(u,[],1));
181  end;
182 
183 
184 elseif ~isempty(strfind(upper(MODE),'USER-SPECIFIC')) && (abs(HDR.SampleRate-1000)<1e3),
185  % Sebastians filter
186  B = load('49__51bs_2751pts_1000Hz.asc');
187  s = filtfilt(B,1,s);
188 
189 else
190  warning('unknown method: no correction applied.');
191 
192 end;
193 
194 
195 if ~isempty(outfile)
196  HDR.FileName = outfile;
197  HDR.TYPE = 'GDF';
198  HDR.VERSION = 3;
199  HDR.GDFTYP(:) = 16;
200  try,
201  mexSSAVE(HDR,s);
202  catch
203  HDR = sopen(HDR,'w');
204  HDR = swrite(HDR,s);
205  HDR = sclose(HDR);
206  end;
207 end;
208 
209 
sclose
function sclose(in HDR)
sload
function sload(in FILENAME, in varargin)
swrite
function swrite(in HDR, in data)
remove5060hz
function remove5060hz(in varargin)
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)