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

File: <base>/sources/mhaghpanahi_at_gmail.com/FECG_extract_multichan.m (4,159 bytes)
function [Mout,Fout,corrcoef]=FECG_extract_multichan(Fin,fs,peaks,L)

[nleads,nsamples]=size(Fin);
phase = PhaseCalculation(peaks);     % phase calculation

JJ = find(peaks);
fm = fs./diff(JJ);          % heart-rate
w = mean(2*pi*fm);          % average heart-rate in rads.
wsd = std(2*pi*fm,1);       % heart-rate standard deviation in rads.


%%
% Pi-ICA analysis
[indep_comp,W,A] = PiCA([Fin -Fin],[peaks peaks]);

indep_comp = indep_comp(:,1:nsamples);
num_comp=size(indep_comp,1);


%%
% MECG Extraction

bins = 250; % number of phase bins
ECGsd= zeros(L,bins);
nk= zeros(1,L); % a vector indicating number of Gaussian kernels for each independent component
Q= (wsd)^2; % the process noise covariance matrix initialized with its first component. Note: size of Q changes in the for loop.
Wmean= w; % the process noise mean vector initialized with its first component. Note: size of Wmean changes in the for loop.

for comp_ind=1:L
    [ECGmean,ECGsd(comp_ind,:),meanphase] = MeanECGExtraction(indep_comp(comp_ind,:),phase,bins,1); % mean ECG extraction
    ECGsmooth=smooth(ECGmean,6,'moving')';
     
     test1=diff(ECGsmooth);
     test1=sign(test1);
     
     test2=filter([1 1],1,test1);
     gauss_ind=find(test2==0);
     lowchange=abs(diff(ECGsmooth(gauss_ind)))<1e-3; % ECGmean replaced by ECGsmooth 
     gauss_ind=setdiff(gauss_ind,gauss_ind(find(lowchange==1)));
     
    
    theta = meanphase(gauss_ind);
    alpha = 1.2*ECGsmooth(gauss_ind);% ECGmean replaced by ECGsmooth
    b = .04*ones(size(alpha));
    
    InitParams1= [alpha b theta];

    options = optimset('TolX',1e-4,'TolFun',1e-4,'MaxIter',100);
    OptimumParams = nlinfit(meanphase,ECGmean,@ECGModel,InitParams1,options);
    
%         Model = ECGModelError(OptimumParams,ECGmean,meanphase,1);
% 
%     figure;
%     plot(Model,'k','LineWidth',2);
%     hold on
%     plot(ECGmean,'r');
%     plot(ECGsmooth);
%     plot(gauss_ind,ECGsmooth(gauss_ind),'*');
    
    
 
% KF modeling and Parameter setting
    N = length(OptimumParams)/3;% number of Gaussian kernels
    nk(comp_ind)= N;
    subQ= [(.1*OptimumParams(1:N)).^2; (.05*ones(1,N)).^2; (.05*ones(1,N)).^2];
    Q=[Q zeros(size(Q,1),N*3); zeros(N*3, size(Q,2)) diag(subQ(:))]; 
    kp= reshape(OptimumParams,[],3)'; % Kernel parameters reshaped into a matrix. 1st row: alpha, 2nd row: b, 3rd row: theta
    kp= [1 0 0;0 0 1; 0 1 0]*kp; % Kernel parameters reshaped into a matrix. 1st row: alpha, 2nd row: theta, 3rd row: b
    Wmean= [Wmean; kp(:)];    
end

Y = [phase ; indep_comp(1:L,:)]; % Observation matrix
X0 = [-pi zeros(1,L)]'; % mean of the initial state
P0 = diag([(2*pi)^2; (10*max(abs(indep_comp(1:L,:)),[],2)).^2]);
Q=[Q zeros(size(Q,1),L); zeros(L, size(Q,2)) diag((.05*mean(ECGsd(:,1:round(bins/10)),2)).^2)];
R = [(w/fs).^2/12 zeros(1,L) ;zeros(L,1) diag((mean(ECGsd(:,1:round(bins/10)),2)).^2)];
Wmean= [Wmean; zeros(L,1)];
Vmean= zeros(L+1,1);

% Reserve space for estimates.
Xminus = zeros(size(X0,1),size(Y,2));
Xekf = zeros(size(X0,1),size(Y,2));
Pminus = zeros(size(X0,1),size(X0,1),size(Y,2));
Pekf = zeros(size(X0,1),size(X0,1),size(Y,2));

X= X0;
P= P0;

params={Wmean, nk, fs};

% Estimate with EKF
for k=1:size(Y,2)

   
   [X,P] = ekf_predict1(X,P,ekf_df_dx(X,params),Q,ekf_cost(X,params), ekf_df_dw(X,params));
   
    if(abs(X(1)-Y(1,k)) > pi)
       X(1) = Y(1,k);
    end 
   
   Xminus(:,k)   = X;
   Pminus(:,:,k) = P;
   
   [X,P] = ekf_update1(X,P,Y(:,k),eye(L+1),R);
   Xekf(:,k)   = X;
   Pekf(:,:,k) = P;
     
end



[Xeks,Peks] = ekf_smooth1(Xekf,Pekf,Xminus,Pminus,@ekf_df_dx,params);

indep_comp_cleaned= indep_comp(1:L,:)-Xeks(2:L+1,:);
MECG_comp_cleaned= Xeks(2:L+1,:);



%%
% Inverse Periodic-ICA

FICA=[indep_comp_cleaned;indep_comp(L+1:4,:)];
MICA=[MECG_comp_cleaned;zeros(num_comp-L,nsamples)];
Fout=A*FICA; 
Mout=A*MICA;

corrcoef = zeros(4,1);
for i=1:4
    xx=dualSample(Fout(i,:),peaks,phase);
    corrcoef(i)=mean(xx.*Fout(i,1:length(xx)))/sqrt(mean(xx.^2)*mean(Fout(i,1:length(xx)).^2));
end

end