Switch to unified view

a b/featurebased-approach/subfunctions/matchedQRS.m
1
function [qrs,ect_qrs] = matchedQRS(signal,templates,qrsref,btype)
2
% Matched filtering for QRS detection
3
%
4
%
5
%
6
% --
7
% ECG classification from single-lead segments using Deep Convolutional Neural 
8
% Networks and Feature-Based Approaches - December 2017
9
% 
10
% Released under the GNU General Public License
11
%
12
% Copyright (C) 2017  Fernando Andreotti, Oliver Carr
13
% University of Oxford, Insitute of Biomedical Engineering, CIBIM Lab - Oxford 2017
14
% fernando.andreotti@eng.ox.ac.uk
15
%
16
% 
17
% For more information visit: https://github.com/fernandoandreotti/cinc-challenge2017
18
% 
19
% Referencing this work
20
%
21
% Andreotti, F., Carr, O., Pimentel, M.A.F., Mahdi, A., & De Vos, M. (2017). 
22
% Comparing Feature Based Classifiers and Convolutional Neural Networks to Detect 
23
% Arrhythmia from Short Segments of ECG. In Computing in Cardiology. Rennes (France).
24
%
25
% Last updated : December 2017
26
% 
27
% This program is free software: you can redistribute it and/or modify
28
% it under the terms of the GNU General Public License as published by
29
% the Free Software Foundation, either version 3 of the License, or
30
% (at your option) any later version.
31
% 
32
% This program is distributed in the hope that it will be useful,
33
% but WITHOUT ANY WARRANTY; without even the implied warranty of
34
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35
% GNU General Public License for more details.
36
% 
37
% You should have received a copy of the GNU General Public License
38
% along with this program.  If not, see <http://www.gnu.org/licenses/>.
39
40
THRES = 0.7;  % correlation threshold, relative to priori knowledge on QRS
41
THRESgof = 0.4; % NMSE threshold
42
WIN = round(2*length(templates{1}));
43
qrs = cell(size(templates));
44
xcors = cell(size(templates));
45
ect_qrs = [];
46
%% Find new peaks by cross correlation
47
for i = 1:length(templates)
48
    padt = [templates{i}; zeros(length(signal)-length(templates{i}),1)];
49
    xcor = xcorr(padt,signal)/(norm(padt)*norm(signal));
50
    xcor = xcor(length(signal):-1:1); xcor = circshift(xcor,[round(length(templates{i})/2) 1]);
51
    xcor(xcor<0) = 0;
52
    thresh=nanmedian(THRES*xcor(qrsref));
53
    [~,qrstmp] = findpeaks(xcor,'MinPeakDistance',round(0.8*WIN),'MinPeakProminence',thresh);
54
%     qrstmp = sort([qrstmp; qrsref(btype == i)]); % Rescue previously detected abnomallies
55
%     qrstmp(diff(qrstmp)<WIN) = [];
56
    qrstmp(qrstmp<length(templates{i})/2|qrstmp>(length(signal)-length(templates{i})/2)) = []; % remove extremities
57
    segs = arrayfun(@(x) signal(x-floor(length(templates{i})/2):x+floor(length(templates{i})/2)),qrstmp,'UniformOutput',0);
58
    gof = cellfun(@(x)  1 - sum((x -templates{i}).^2)/sum((templates{i}-mean(templates{i})).^2),segs); % calculates goodness of fit for each beat agains template
59
    qrstmp = qrstmp(gof>THRESgof);
60
    qrs{i} = qrstmp;
61
    xcors{i} = xcor(qrstmp).*gof(gof>THRESgof);
62
    clear xcortmp qrstmp
63
end
64
65
%% Separate beats by type (avoid double peaks)
66
%== Removing peaks of low amplitude (likely noise)
67
% if length(templates) > 1
68
%     if 0.3*abs(median(signal(qrs{1}))) > abs(median(signal(qrs{2})))
69
%         qrs(2) = [];
70
%         templates(2) = [];
71
%     elseif 0.3*abs(median(signal(qrs{2}))) > abs(median(signal(qrs{1})))
72
%         qrs{1} = qrs{2};        
73
%         templates{1} = templates{2};
74
%         qrs(2) = [];
75
%         templates(2) = [];
76
%     end            
77
% end
78
79
%== Highest correlation/gof is kept.
80
if length(templates) > 1
81
        % matching closest indices
82
        if length(qrs{1}) > length(qrs{2})
83
            qrs1 = qrs{1};
84
            qrs2 = qrs{2};
85
        else
86
            qrs2 = qrs{1};
87
            qrs1 = qrs{2};
88
            tmp = xcors{1};
89
            xcors{1} =xcors{2};
90
            xcors{2} = tmp;
91
        end
92
                        
93
        [A,dist] = dsearchn(qrs1,qrs2);         % closest ref for each point in test qrs
94
        keepA = (dist<WIN);
95
        if any(keepA)
96
            tmpmat = [A(keepA) find(keepA)];
97
            [~,idx]=max([xcors{1}(tmpmat(:,1)), xcors{2}(tmpmat(:,2))],[],2);
98
            qrs1(tmpmat(idx ~= 1,1)) = [];
99
            qrs2(tmpmat(idx ~= 2,2)) = [];
100
        end
101
        if numel(qrs1)>numel(qrs2)
102
            qrs = qrs1;          
103
            ect_qrs = qrs2;
104
        else
105
            qrs = qrs2;          
106
            ect_qrs = qrs1;
107
        end
108
%     end
109
    
110
else
111
    qrs = qrs{1};
112
end
113
114