Noninvasive Fetal ECG: The PhysioNet/Computing in Cardiology Challenge 2013 1.0.0

File: <base>/sources/maurizio.varanini_at_ifc.cnr.it/A/FecgDetrFilt.m (5,265 bytes)
function Xd=FecgDetrFilt(X,fs,cName,graph,dbFlag)
% -------------------------------------------------------------------------------------------
%   ECG detrending
%
%  A baseline signal is estimated applying a low pass Butterworth filter 
%  in forward and backward direction.  The filter cut frequency is 3.17Hz. 
%  Each detrended signal is obtained as difference between the original signal 
%  and the estimated baseline. 
%  In case of residual artifacts due to fast baseline movements, median filtering is used.
%
%  function Xd=FecgDetrFilt(X,fs,cName,graph,dbFlag)
%
%  X      : signal matrix (one signal per column)
%  fs     : sampling frequency
%  cName  : record name
%  graf   : flag enabling figure drawing
%  dbFlag : flag enabling figure drawing for tuning and debugging
%
% -------------------------------------------------------------------------------------------
%   Maurizio Varanini, Clinical Physiology Institute, CNR, Pisa, Italy
%   For any comment or bug report, please send e-mail to: maurizio.varanini@ifc.cnr.it
% -------------------------------------------------------------------------------------------
% This program is free software; you can redistribute it and/or modify it under the terms
% of the GNU General Public License as published by the Free Software Foundation; either
% version 2 of the License, or (at your option) any later version.
%
% This program is distributed "as is" and "as available" in the hope that it will be useful,
% but WITHOUT ANY WARRANTY of any kind; without even the implied warranty of MERCHANTABILITY
% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
% -------------------------------------------------------------------------------------------

if(nargin<3), cName=''; end
if(nargin<4), graph=0; end
if(nargin<5), dbFlag=0; end
graphD= graph &dbFlag ;
graphSpt= graph &dbFlag ;

fprintf('\n --------------------------------------------------------- \n');
[progpath, progname] = fileparts(which(mfilename));
fprintf('Program: %s,   record name: %s\n', progname, cName);
%-------------------------------------------------------------
% recording duration
[ndt, ns]=size(X);
vtime= [1:ndt]/fs;
%-------------------------------------------------------------------------------
fmaxd=5;        % --> 3.17 Hz = filtfilt 3dB cut frequency
fmaxn = fmaxd/(fs/2);
[b,a]= butter(1,fmaxn,'low');
Xb=filtfilt(b,a,X);  %  estimated baseline

%  remove baseline from original ecg
Xd=X-Xb;
%-------------------------------------------------------------------------------
RRpmean=1.;
ww=fix(RRpmean*1.5*fs);   % wide windows  (many contain at least one QRS)
for is=1:ns
    x=Xd(:,is); n=length(x);
    [xmeaMi,xmeaMa] = meanMiMaSc(x,ww,8,8);
    thmima=1.3;
    xthmi=xmeaMi*thmima;    xthma=xmeaMa*thmima;
    if(graphD)
        figure, set(gcf,'Color','white');  hold on;
        plot(x,'b.-');
        plot(xmeaMi*ones(n,1),'m');
        plot(xmeaMa*ones(n,1),'m');
        plot(xthmi*ones(n,1),'r');
        plot(xthma*ones(n,1),'r');
        title(['EcgBaseline_atest:',' x(b), mi&ma (m), th (r)']);
    end
    
    iibadDetr=find(x<xthmi | xthma<x);
    % iibadDetr(find(diff(iibadDetr)>1*fs));
    if(length(iibadDetr)>1.3*fs)
        fprintf('Switching to median filtering,rec=%s, is=%d, bads=%d\n',cName, is, length(iibadDetr));
        wm=fix(0.26*fs); wm=2*floor(wm/2)+1;    %  window width
        Xb(:,is) = medfilt1mit(X(:,is),wm,1);
        x=X(:,is)-Xb(:,is);         % remove baseline from original ECG
        [xmeaMi,xmeaMa] = meanMiMaSc(x,ww,8,8);
        thmima=1.3;
        xthmi=xmeaMi*thmima;    xthma=xmeaMa*thmima;
        iinf=find(x<xthmi); x(iinf)=xthmi;
        isup=find(x>xthma); x(isup)=xthma;
        fmaxd=150;    fmaxn=fmaxd/(fs/2);  % Normalized cut-off frequency
        [b,a]= butter(1,fmaxn,'low');
        x=filtfilt(b,a,x);     %  low-pass filtered signal
        Xd(:,is)=x;
        if(graphSpt)
            figure; freqz(conv(b,b(end:-1:1)),conv(a,a(end:-1:1)),[0:0.005:2],fs);
        end
    end
end

if(graphSpt)
    for is=1:ns,
        figure, set(gcf,'Color','white');
        pwelch(X(:,is),[],[],[],fs);
        title('Original ECG Welch spectrum');
        shg
    end
end
if(graphSpt)
    for is=1:ns,
        figure, set(gcf,'Color','white');
        pwelch(Xd(:,is),[],[],[],fs);
        title('Detrended ECG Welch spectrum');
        shg
    end
end

if(graphD)
    figure, set(gcf,'Color','white');
    for is=1:ns,
        subplot(ns,1,is), hold on, plot(vtime,X(:,is),'r'), plot(vtime,Xb(:,is),'b');
        wgmimaV=mimaxscG(X(:,is),0,0,.1);
        ylim(wgmimaV);
        if(is~=ns), set(gca,'XTickLabel',''); end
        if(is==1), title('Original ECG (r) & estimated baseline(b)'); end
    end
    shg
end
if(graph)
    figure, set(gcf,'Color','white');
    for is=1:ns,
        subplot(ns,1,is), hold on, plot(vtime,X(:,is),'r'), plot(vtime,Xd(:,is),'b');
        wgmimaV=mimaxscG(Xd(:,is),0,0,.4);
        ylim(wgmimaV);
        if(is~=ns), set(gca,'XTickLabel',''); end
        if(is==1), title([cName,': original(r) & detrended(b) ECG']); end
    end
end
%if(dbFlag & learning) PlotSgnMrkNc(X', QRSa, fs, cName); end

end %== function ================================================================
%