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