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

File: <base>/sources/mantas.lukosevicius_at_gmx.com/MECGcancellation2.m (2,777 bytes)
function residual = MECGcancellation(peaks,ECG,fs) %,nbCycles)
% MECG cancellation algorithm inspired from [1].
%
% inputs:
%   fs: sampling frequency
%   nbCycles: number of cycles on which to build the mean MECG template
%   ECG: matrix of abdominal ECG channels.
%   peaks: MQRS markers in seconds. Each marker corresponds to the
%   position of a MQRS.
%
% output:
%   residual: residual containing the FECG.
%
% Author: Joachim Behar - IPMG Oxford (joachim.behar@eng.ox.ac.uk)
% Last updated: 03_02_2013
%
% [1] Martens S et al. A robust fetal ECG detection method for
% abdominal recordings. Physiol. Meas. (2007) 28(4) 373�388
% 
% Last updated 2013.04.27 by Mantas Lukosevicius

% ---- constants ----
%if nargin < 4
%	r = size(peaks,2);
% else
% 	r                   = nbCycles;
% end
Pstart              = 0.25*fs-1;
Tstop               = 0.45*fs;
N                   = length(peaks);       % number of MECG QRS
ecgLength			= length(ECG);
ECG_temp            = zeros(1,ecgLength);

% ---- ECG template ----
templateStart = 1;
while templateStart < N && peaks(templateStart)-Pstart < 1
	templateStart = templateStart+1;
end
templateEnd = N;
while templateEnd >= templateStart && peaks(templateEnd)+Tstop > ecgLength
	templateEnd = templateEnd-1;
end
	
ECG_last_r_cycles   = zeros(0.7*fs,templateEnd-templateStart+1);

for i=templateStart:templateEnd
    peak_nb = peaks(i); 
    ECG_last_r_cycles(:,i) = ECG(peak_nb-Pstart:peak_nb+Tstop)';
end
ECG_mean = mean(ECG_last_r_cycles,2);

% ---- MECG cancellation ----
% ---- MECG cancellation ----
M  = zeros (0.7*fs,3);
M(1:0.2*fs,1)           = ECG_mean(1:Pstart-0.05*fs+1);
M(0.2*fs+1:0.3*fs,2)    = ECG_mean(Pstart-0.05*fs+2:Pstart+0.05*fs+1);
M(0.3*fs+1:end,3)       = ECG_mean(Pstart+2+0.05*fs:Pstart+1+Tstop);
for i=1:N
	%TODO: handle end cases
	if peaks(i)>Pstart
		Pstart_ = Pstart;
		if ecgLength-peaks(i) >= Tstop
			Tstop_ = Tstop;
			M_ = M;
		else
			Tstop_ = ecgLength-peaks(i);
			M_ = M(1:0.7*fs-(Tstop-Tstop_),:);
			if all(M_(:,3)==0)
				M_ = M_(:,1:2);
			end
		end
	else
		Pstart_ = peaks(i)-1;
		Tstop_ = Tstop;
		M_ = M(Pstart-Pstart_+1:end,:);
		if all(M_(:,1)==0)
			M_ = M_(:,2:3);
		end
	end
	
	
	%M_ = M(Pstart-Pstart_+1:0.7*fs-(Tstop-Tstop_),:);
	
	a = (M_'*M_)\M_'*ECG(peaks(i)-Pstart_:peaks(i)+Tstop_)';
% 	if ~any(isnan(a))
% 		ECG_temp(peaks(i)-Pstart_:peaks(i)+Tstop_) = ...
% 		a(1)*M_(:,1)'+a(2)*M_(:,2)'+a(3)*M_(:,3)';		
% 	end

	if length(a) == 3
		ECG_temp(peaks(i)-Pstart_:peaks(i)+Tstop_) = a(1)*M_(:,1)'+a(2)*M_(:,2)'+a(3)*M_(:,3)';		
	else
		ECG_temp(peaks(i)-Pstart_:peaks(i)+Tstop_) = a(1)*M_(:,1)'+a(2)*M_(:,2)';	
	end


end
% compute residual
residual = ECG - ECG_temp;
end