Noninvasive Fetal ECG: The PhysioNet/Computing in Cardiology Challenge 2013 1.0.0
(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