ECG-Kit 1.0

File: <base>/common/bxb.m (3,592 bytes)
%% (Internal) Compares two heartbeat series and produce the confusion matrix as result
%   
%   [C, TP_ann_idx, TP_det_idx, FN_idx, FP_idx] = bxb( ann, test_qrs_idx, heasig, strDBformat)
% 
% Arguments:
% 
%      + ann: the string
% 
%      + test_qrs_idx: size of the target string.
% 
%      + heasig: "left" "right" "center"
% 
%      + strDBformat: the string
% 
% Output:
% 
%      + C: the confusion matrix.
% 
%      + TP_ann_idx, TP_det_idx, FN_idx, FP_idx: the indexes of the true
%      positive (TP), false negative (FN) and FP within test_qrs_idx
% 
% Example:
% 
% See also ECGtask_QRS_detection
% 
% Author: Mariano Llamedo Soria llamedom@electron.frba.utn.edu.ar
% Version: 0.1 beta
% Last update: 14/5/2014
% Birthdate  : 21/4/2015
% Copyright 2008-2015
% 
function [C, TP_ann_idx, TP_det_idx, FN_idx, FP_idx] = bxb( ann, test_qrs_idx, heasig, strDBformat)

% constants
win_in_samples = round(0.15*heasig.freq);


if( nargin < 4 || isempty(strDBformat) )
    strDBformat = 'MIT';
end

if( isstruct(test_qrs_idx) && isfield(ann, 'time') )
    test_qrs_idx = test_qrs_idx.time;
end

%filtramos las anotaciones que son latidos
if( isfield(ann, 'anntyp') )
    ann = AnnotationFilterConvert(ann, strDBformat, 'AAMI');
end


% AHA database special case: just annotated a small part of each recording.
if( strcmpi(strDBformat, 'AHA') )
    test_qrs_idx = test_qrs_idx(test_qrs_idx >= (ann.time(1) - win_in_samples) & test_qrs_idx <= (ann.time(end) + win_in_samples));
end


[test_qrs_idx, test_qrs_idx2] = sort(test_qrs_idx);

%find matchs now
lRefBeats = length(ann.time);
lDetectedBeats = length(test_qrs_idx);
Ref_idx = 1;
TP_idx = [];
FN_idx = [];

while( Ref_idx <= lRefBeats )
    
    beat_distance = abs( ann.time(Ref_idx) - test_qrs_idx);
    close_beats_idx = find( beat_distance <= win_in_samples );
    
    if( ~isempty(close_beats_idx) )
        
        lclose_beats = length(close_beats_idx);
        
        if( lclose_beats == 1  )
            %matched beat
            TP_idx = [TP_idx; Ref_idx test_qrs_idx2(close_beats_idx)];
        
        elseif( lclose_beats > 1  )
            %several beats close to the true beat.
            [~, closest_beat_idx] = sort( beat_distance(close_beats_idx) );
            
            if( beat_distance(close_beats_idx(closest_beat_idx(1))) ~= beat_distance(close_beats_idx(closest_beat_idx(2))) )
                %choose the closest
                TP_idx = [TP_idx; Ref_idx test_qrs_idx2(close_beats_idx(closest_beat_idx(1))) ];
            else
                %choose the first happened match 
                if( test_qrs_idx(close_beats_idx(closest_beat_idx(1))) <= test_qrs_idx(close_beats_idx(closest_beat_idx(1))) )
                    TP_idx = [TP_idx; Ref_idx test_qrs_idx2(close_beats_idx(closest_beat_idx(1))) ];
                else
                    TP_idx = [TP_idx; Ref_idx test_qrs_idx2(close_beats_idx(closest_beat_idx(2))) ];
                end
            end
            
        end
    else
        %beat missed
        FN_idx = [FN_idx; Ref_idx];
    end
    
    Ref_idx = Ref_idx + 1;
    
end

%build the beat index references.
if( isempty(TP_idx) )
    TP_ann_idx = [];
    TP_det_idx = [];
else
    TP_ann_idx = TP_idx(:,1);
    TP_det_idx = TP_idx(:,2);
end

FP_idx = setdiff(1:lDetectedBeats, TP_det_idx);

%build the confusion matrix.
C = [ length(TP_ann_idx), length(FN_idx); length(FP_idx), 0 ];

if(nargout == 0)
        %pretty print performance
        
end