a b/featurebased-approach/subfunctions/get_poincare.m
1
function feat=get_poincare(QRS,fs)
2
% Obtain poincare plots for HRV analysis
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
i=1;
41
% Set the bins for the histogram
42
edges{1}=0:100:2000;     % <----------- SET BINS
43
edges{2}=-1000:100:1000; % <----------- SET BINS
44
45
% Get the RR interval series from the QRS detection
46
RR=diff(QRS./fs)*1000;
47
48
% If there are less than 5 r peaks, enter NaN instead of finding
49
% histogram
50
51
% Find the difference in RR interval series
52
dRR=diff(RR);
53
54
RR2=RR(2:end);
55
X=[RR2,dRR];
56
57
x_mid=median(RR2);
58
y_mid=median(dRR);
59
60
r=[50,100,200,300]; % <--------- SET NUMBER AND VALUES OF RADIUS (IF >4 CHANGE ALL FEATURE INDICES)
61
for j=1:4    
62
    ang=0:0.01:2*pi; 
63
    xc1=r(j)*cos(ang)+x_mid;
64
    yc1=r(j)*sin(ang)+y_mid;   
65
    
66
    in = inpolygon(RR2,dRR,xc1,yc1);
67
    
68
    % Features 1-4: Percentage of points inside circle (centred on median)
69
    feat(i,j)=sum(in)/length(in);
70
end
71
% Features 5-8: median and iqr of x and y coordinates
72
feat(i,5)=x_mid;
73
feat(i,6)=y_mid;
74
feat(i,7)=iqr(RR2);
75
feat(i,8)=iqr(dRR);
76
77
[N,~]=hist3(X,'Edges',edges);
78
[N2,~]=hist3([x_mid,y_mid],'Edges',edges);
79
[row,col]=find(N2);
80
81
% Features 9-14: Bins with at least 1 and greater than 1 values (and
82
% normalised)
83
feat(i,9)=sum(sum(N>0));
84
feat(i,10)=sum(sum(N>1));
85
feat(i,11)=sum(sum(N>0))/length(RR);
86
feat(i,12)=sum(sum(N>1))/length(RR);
87
feat(i,13)=sum(sum(N>0))/sum(RR);
88
feat(i,14)=sum(sum(N>1))/sum(RR);
89
90
[a1,a2]=meshgrid(1:length(edges{1}),1:length(edges{2}));
91
C = sqrt((a1-row).^2+(a2-col).^2)<=3; % <-----------------SET THIS RADIUS
92
93
M=N;
94
M(C)=0;
95
96
% Features 15-20: Bins with at least 1 and greater than 1 values (and
97
% normalised) excluding centre circle
98
feat(i,15)=sum(sum(M>0));
99
feat(i,16)=sum(sum(M>1));
100
feat(i,17)=sum(sum(M>0))/length(RR);
101
feat(i,18)=sum(sum(M>1))/length(RR);
102
feat(i,19)=sum(sum(M>0))/sum(RR);
103
feat(i,20)=sum(sum(M>1))/sum(RR);
104
105
k = boundary(RR2,dRR);
106
107
A = polyarea(RR2(k),dRR(k));
108
% Features 21-23: Minimum area enclosing all points (normalised)
109
feat(i,21)=A;
110
feat(i,22)=A/length(RR);
111
feat(i,23)=A/sum(RR);
112
113
k2 = boundary(RR2,dRR,0);
114
A2 = polyarea(RR2(k2),dRR(k2));
115
116
% Features 24-26: Minimum convex area enclosing all points (normalised)
117
feat(i,24)=A2;
118
feat(i,25)=A2/length(RR);
119
feat(i,26)=A2/sum(RR);
120
121
% Features 27-29: Perimeter of minimum area
122
feat(i,27)=sqrt(sum(diff(RR2(k)).^2+diff(dRR(k)).^2));
123
feat(i,28)=feat(i,27)/length(RR);
124
feat(i,29)=feat(i,27)/sum(RR);
125
126
% Features 30-32: Perimeter of minimum area
127
feat(i,30)=sqrt(sum(diff(RR2(k)).^2+diff(dRR(k)).^2));
128
feat(i,31)=feat(i,27)/length(RR);
129
feat(i,32)=feat(i,27)/sum(RR);
130
131
% Features 33-35: Average distance to centre
132
feat(i,33)=mean(sqrt((RR2-x_mid).^2+(dRR-y_mid).^2));
133
feat(i,34)=feat(i,33)/length(RR);
134
feat(i,35)=feat(i,33)/sum(RR);
135
136
B = bsxfun(@minus,X(:,1)',X(:,1)) + ...
137
    bsxfun(@minus,X(:,2)',X(:,2));
138
B=B.^2;
139
B(1:length(B)+1:numel(B)) = Inf;
140
minB=min(B);
141
% Features 36-38: Average distance to nearest point
142
feat(i,36)=mean(minB);
143
feat(i,37)=feat(i,36)/length(RR);
144
feat(i,38)=feat(i,36)/sum(RR);
145
146
% Features 39-41: Distance to next point
147
feat(i,39)=sqrt(sum(diff(RR2).^2+diff(dRR).^2));
148
feat(i,40)=feat(i,39)/length(RR);
149
feat(i,41)=feat(i,39)/sum(RR);
150
151
[idx,Cent,sumd] = kmeans(X,4);
152
Dist=pdist(Cent);
153
154
% Features 42-46: Cluster distances
155
feat(i,42)=max(Dist);
156
feat(i,43)=min(Dist);
157
feat(i,44)=mean(Dist);
158
feat(i,45)=std(Dist);
159
feat(i,46)=median(Dist);
160
161
vertA2=[RR2(k2),dRR(k2)];
162
DistA2=pdist(vertA2);
163
% Features 47-49: Area major minor axes
164
feat(i,47)=max(DistA2);
165
166
% Features 50-55: Smaller percentage in circle (for other rhythms)
167
r2=[3,5,10,20,30,40]; % <--------- SET NUMBER AND VALUES OF RADIUS (IF >4 CHANGE ALL FEATURE INDICES)
168
for j=1:6
169
    ang=0:0.01:2*pi;
170
    xc1=r2(j)*cos(ang)+x_mid;
171
    yc1=r2(j)*sin(ang)+y_mid;
172
    
173
    in = inpolygon(RR2,dRR,xc1,yc1);
174
    feat(i,47+j)=sum(in)/length(in);
175
end
176
177
178
P=[RR2(k2),dRR(k2)];
179
[A , c] = MinVolEllipse(P', 0.1);
180
[U Q V]=svd(A);
181
r1=1/sqrt(Q(1,1));
182
r2=1/sqrt(Q(2,2));
183
theta=acos(V(1,1));
184
% Features 56-61: Ellipse features
185
feat(i,54)=c(1);
186
feat(i,55)=c(2);
187
feat(i,56)=r1;
188
feat(i,57)=r2;
189
feat(i,58)=r1/r2;
190
feat(i,59)=theta;
191
192
% features 62-68: Number of clusters
193
thresh_dist=[100,200,300,400,500,750,1000];
194
for th=1:length(thresh_dist)
195
    if max(Dist)<thresh_dist(th)
196
        clust=1;
197
    elseif min(Dist)>thresh_dist(th)
198
        clust=4;
199
    else
200
        indD=Dist<thresh_dist(th);
201
        group1=1;
202
        group2=2;
203
        group3=3;
204
        group4=4;
205
        if indD(1)==1
206
            group1=[group1, 2];
207
            group2=[];
208
        end
209
        if indD(2)==1
210
            group1=[group1, 3];
211
            group3=[];
212
        end
213
        if indD(3)==1
214
            group1=[group1, 4];
215
            group4=[];
216
        end
217
        if indD(4)==1 && indD(1)==1
218
            group1=[group1, 3];
219
            group3=[];
220
        end
221
        if indD(4)==1 && indD(1)==0
222
            group2=[group2, 3];
223
            group3=[];
224
        end
225
        if indD(5)==1 && indD(1)==1
226
            group1=[group1, 4];
227
            group4=[];
228
        end
229
        if indD(5)==1 && indD(1)==0
230
            group2=[group2, 4];
231
            group4=[];
232
        end
233
        if indD(6)==1 && indD(2)==1
234
            group1=[group1, 4];
235
            group4=[];
236
        end
237
        if indD(6)==1 && indD(1)==0 && indD(4)==1
238
            group2=[group2, 4];
239
            group4=[];
240
        end
241
        if indD(6)==1 && indD(1)==0 && indD(4)==0
242
            group3=[group3, 4];
243
            group4=[];
244
        end
245
        clust=1;
246
        if ~isempty(group2)
247
            clust=clust+1;
248
        end
249
        if ~isempty(group3)
250
            clust=clust+1;
251
        end
252
        if ~isempty(group4)
253
            clust=clust+1;
254
        end
255
    end
256
    feat(i,59+th)=clust;
257
end
258
259
260