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

File: <base>/sources/mantas.lukosevicius_at_gmx.com/detectRrEvents15_grid.m (3,592 bytes)
function [events, val ] = detectRrEvents15_grid( y, rrPow )
%detectRrEvents14 detects fetal ECG R events form the indicator signal
% detectRrEvents14 + thick tail rrPdf from detectRrEvents0
% for PhysioNet 2013 challenge
% by Mantas Lukosevicius 2013

% if nargin < 2
%     rrPow = 1/100;
% end
% 
	% RR interval duration is assumed to have normal disribution 
	% from cinc_total_rr_hist.m: RR mean = 442.1759, std = 45.99
% 	rrMean = 442;
	rrStd = 46;
	% from cinc_total_75_rr_hist.m: RR mean = 424.8335, std = 83.6907 
	% from cinc_total_rr_hist_ign.m: RR mean = 423.8379, std = 39.867
	%  (has outliers up to ~5000 in A54)
	rrMean = 424;
%	rrStd = 40;
% 	rrStd = 83.7;
	
	% change of RR interval duration is assumed to have normal disribution 
	% from cinc_total_drr_hist.m: dRR mean = -0.06497, std = 18.8144
	%drrMean = 0;
	drrStd = 19;

	runLength = size( y, 2 );
	%yMean = mean(y);
		
	rrMin = 300;
	rrMax = 500; %550; % 2*rrMean; % ~0.9s


	drrMax = drrStd * 3;
	drrPdf = normpdf( -drrMax:drrMax, 0, drrStd )';
	drrPdf = drrPdf / max(drrPdf);

	% to regain the rythm once it's lost
% 	broadFactor = 0.17;
% 	broadPdf = ones(1, rrMax );
	
	broadFactor = 0.35;
	broadPdf = [2:2:(2*rrMean) (2*rrMean):-2:2]/(2*rrMean);

	% to keep the rithm
	rrPdf = normpdf( 1:(2*rrMean), rrMean, rrStd );
	rrPdf = rrPdf / max( rrPdf );
	
	rrPdf = ( rrPdf + broadPdf .* broadFactor) / (1+broadFactor);

	rrPdf = rrPdf(rrMin:rrMax)' .^ rrPow;% ( 1/100 );
		
	
	%% convolve with a peak of target signal
	
	% indicator width 5:
	peakWidth = 5; %should be odd and the same as for target
	peakCenter = (peakWidth-1)/2 + 1;
	peak = zeros(peakWidth,1);
	peak(1:peakCenter) = 1/peakCenter:1/peakCenter:1;
	peak(peakCenter:end) = 1:-1/peakCenter:1/peakCenter;
	peak = peak ./ sum(peak);
	
	yc = conv(peak,y);
	y = yc(peakCenter:end-peakCenter+1);

	%% find a probable sequence of RR events
 	y(y<0) = 0; % for multiplicative scores
	
	b = 1/6;% 1/4;% 1/8;% 1/10;% 1/5;% 1/3;% 1/2;%
	
	valOffset = rrMin-drrMax-1;
	
	val = zeros( rrMax+drrMax-valOffset, runLength ); % (lastRR, currentR)
	from = zeros( rrMax+drrMax-valOffset, runLength );
	valWind = zeros(rrMax-rrMin+1,1+2*drrMax);
	drrPdfM = (drrPdf * ones(1,rrMax-rrMin+1))';
	for i = 1:runLength
		if i < rrMin+1
			%valWind = valWind
			val(:,i) = y(i);
		else

			valWind(2:rrMax-rrMin+1,1:2*drrMax) = valWind(1:rrMax-rrMin,2:1+2*drrMax);
			valWind(1,:) = val(rrMin-valOffset-drrMax:rrMin-valOffset+drrMax,i-rrMin);
			
			if i < rrMax + 1
				valWind(i-rrMin:end,:) = y(i);
				rrRange = rrMin:i-1;
			else
				rrRange = rrMin:rrMax;
			end			
			
			%rrRange = rrMin:min(rrMax,i-1);
			rrIndices = -valOffset+drrMax + rrRange + size(val,1)*(i-1-rrRange);			
			valWind(1:length(rrRange),end) = val( rrIndices );
			
			[vs, fs] = max( valWind .* drrPdfM, [], 2 );
			val(rrMin-valOffset:rrMax-valOffset,i) = rrPdf .* y(i).^b .* vs.^(1-b);
			from(rrMin-valOffset:rrMax-valOffset,i) = (rrMin:rrMax)' + fs - (drrMax+1);
			
		end
	end
			
	% trace back
%  	[ w, j ] = max( val(:,runLength-rrMean-2*rrStd:runLength) );
% 	[ v, i ] = max( w );
 	[ w, i ] = max( val(:,runLength-rrMean-2*rrStd:runLength), [], 2 );
	% bias the last beat according to rrPdf
	%rrBias = b; % 1/6;
	%[ v, j ] = max( w' .* rrPdf( valOffset+1:end ).^rrBias );
	[ v, j ] = max( w );
	i = i(j) + runLength-rrMean-2*rrStd-1;
	j = j+valOffset;
	events = [];
	while i > 0 && j > 0 
		events = [i, events];
		i2 = i-j;
		j = from(j-valOffset,i);
		i = i2;
	end

end