|
a |
|
b/DS_test.m |
|
|
1 |
%% 参考rddata.m,用于QRS波一次性全数据库评估; |
|
|
2 |
%------------------------------------------------------------------------- |
|
|
3 |
clc; clear all;tic, |
|
|
4 |
Name_whole=[100,101,102,103,104,105,106,107,108,109,111,112,113,114,115,... |
|
|
5 |
116,117,118,119,121,122,123,124,200,201,202,203,205,207,208,209,... |
|
|
6 |
210,212,213,214,215,217,219,220,221,222,223,228,230,231,232,233,234]; |
|
|
7 |
INFO=[];fs=360; |
|
|
8 |
for na=1:48 |
|
|
9 |
|
|
|
10 |
%------ SPECIFY DATA ------------------------------------------------------ |
|
|
11 |
%------ 指定数据文件 ------------------------------------------------------- |
|
|
12 |
|
|
|
13 |
Name=num2str(Name_whole(na)); |
|
|
14 |
PATH= 'F:\MATLAB\MIT-BIH'; % 指定数据的储存路径 |
|
|
15 |
HEADERFILE=strcat(Name, '.hea');% .hea 格式,头文件,可用记事本打开 |
|
|
16 |
ATRFILE=strcat(Name, '.atr'); % .atr 格式,属性文件,数据格式为二进制数 |
|
|
17 |
DATAFILE=strcat(Name, '.dat');% .dat ¸ñʽ£¬ECG Êý¾Ý |
|
|
18 |
SAMPLES2READ=650000; % 指定需要读入的样本数 |
|
|
19 |
% 若.dat文件中存储有两个通道的信号: |
|
|
20 |
% 则读入 2*SAMPLES2READ 个数据 |
|
|
21 |
|
|
|
22 |
%------ LOAD HEADER DATA -------------------------------------------------- |
|
|
23 |
%------ 读入头文件数据 ----------------------------------------------------- |
|
|
24 |
% |
|
|
25 |
% 示例:用记事本打开的117.hea 文件的数据 |
|
|
26 |
% |
|
|
27 |
% 117 2 360 650000 |
|
|
28 |
% 117.dat 212 200 11 1024 839 31170 0 MLII |
|
|
29 |
% 117.dat 212 200 11 1024 930 28083 0 V2 |
|
|
30 |
% # 69 M 950 654 x2 |
|
|
31 |
% # None |
|
|
32 |
% |
|
|
33 |
%------------------------------------------------------------------------- |
|
|
34 |
fprintf(1,'\\n$> WORKING ON %s ...\n', HEADERFILE); % 在Matlab命令行窗口提示当前工作状态 |
|
|
35 |
% |
|
|
36 |
% 【注】函数 fprintf 的功能将格式化的数据写入到指定文件中。 |
|
|
37 |
% ±í´ïʽ£ºcount = fprintf(fid,format,A,...) |
|
|
38 |
% 在字符串'format'的控制下,将矩阵A的实数数据进行格式化,并写入到文件对象fid中。该函数返回所写入数据的字节数 count。 |
|
|
39 |
% fid 是通过函数 fopen 获得的整型文件标识符。fid=1,表示标准输出(即输出到屏幕显示);fid=2,表示标准偏差。 |
|
|
40 |
% |
|
|
41 |
signalh= fullfile(PATH, HEADERFILE); % 通过函数 fullfile 获得头文件的完整路径 |
|
|
42 |
fid1=fopen(signalh,'r'); % 打开头文件,其标识符为 fid1 ,属性为'r'--“只读” |
|
|
43 |
z= fgetl(fid1); % 读取头文件的第一行数据,字符串格式 |
|
|
44 |
A= sscanf(z, '%*s %d %d %d',[1,3]); % 按照格式 '%*s %d %d %d' 转换数据并存入矩阵 A 中 |
|
|
45 |
nosig= A(1); % 信号通道数目 |
|
|
46 |
sfreq=A(2); % 数据采样频率 |
|
|
47 |
clear A; % 清空矩阵 A ,准备获取下一行数据 |
|
|
48 |
for k=1:nosig % 读取每个通道信号的数据信息 |
|
|
49 |
z= fgetl(fid1); |
|
|
50 |
A= sscanf(z, '%*s %d %d %d %d %d',[1,5]); |
|
|
51 |
dformat(k)= A(1); % 信号格式; 这里只允许为 212 格式 |
|
|
52 |
gain(k)= A(2); % 每 mV 包含的整数个数 |
|
|
53 |
bitres(k)= A(3); % 采样精度(位分辨率) |
|
|
54 |
zerovalue(k)= A(4); % ECG 信号零点相应的整数值 |
|
|
55 |
firstvalue(k)= A(5); % 信号的第一个整数值 (用于偏差测试) |
|
|
56 |
end; |
|
|
57 |
fclose(fid1); |
|
|
58 |
clear A; |
|
|
59 |
|
|
|
60 |
%------ LOAD BINARY DATA -------------------------------------------------- |
|
|
61 |
%------ 读取 ECG 信号二值数据 ---------------------------------------------- |
|
|
62 |
% |
|
|
63 |
if dformat~= [212,212], error('this script does not apply binary formats different to 212.'); end; |
|
|
64 |
signald= fullfile(PATH, DATAFILE); % 读入 212 格式的 ECG 信号数据 |
|
|
65 |
fid2=fopen(signald,'r'); |
|
|
66 |
A= fread(fid2, [3, SAMPLES2READ], 'uint8')'; % matrix with 3 rows, each 8 bits long, = 2*12bit |
|
|
67 |
fclose(fid2); |
|
|
68 |
% 通过一系列的移位(bitshift)、位与(bitand)运算,将信号由二值数据转换为十进制数 |
|
|
69 |
M2H= bitshift(A(:,2), -4); %字节向右移四位,即取字节的高四位 |
|
|
70 |
M1H= bitand(A(:,2), 15); %取字节的低四位 |
|
|
71 |
PRL=bitshift(bitand(A(:,2),8),9); % sign-bit 取出字节低四位中最高位,向右移九位 |
|
|
72 |
PRR=bitshift(bitand(A(:,2),128),5); % sign-bit 取出字节高四位中最高位,向右移五位 |
|
|
73 |
M( : , 1)= bitshift(M1H,8)+ A(:,1)-PRL; |
|
|
74 |
M( : , 2)= bitshift(M2H,8)+ A(:,3)-PRR; |
|
|
75 |
if M(1,:) ~= firstvalue, error('inconsistency in the first bit values'); end; |
|
|
76 |
switch nosig |
|
|
77 |
case 2 |
|
|
78 |
M( : , 1)= (M( : , 1)- zerovalue(1))/gain(1); |
|
|
79 |
M( : , 2)= (M( : , 2)- zerovalue(2))/gain(2); |
|
|
80 |
TIME=(0:(SAMPLES2READ-1))/sfreq; |
|
|
81 |
case 1 |
|
|
82 |
M( : , 1)= (M( : , 1)- zerovalue(1)); |
|
|
83 |
M( : , 2)= (M( : , 2)- zerovalue(1)); |
|
|
84 |
M=M'; |
|
|
85 |
M(1)=[]; |
|
|
86 |
sM=size(M); |
|
|
87 |
sM=sM(2)+1; |
|
|
88 |
M(sM)=0; |
|
|
89 |
M=M'; |
|
|
90 |
M=M/gain(1); |
|
|
91 |
TIME=(0:2*(SAMPLES2READ)-1)/sfreq; |
|
|
92 |
otherwise % this case did not appear up to now! |
|
|
93 |
% here M has to be sorted!!! |
|
|
94 |
disp('Sorting algorithm for more than 2 signals not programmed yet!'); |
|
|
95 |
end; |
|
|
96 |
clear A M1H M2H PRR PRL; |
|
|
97 |
fprintf(1,'\\n$> LOADING DATA FINISHED \n'); |
|
|
98 |
|
|
|
99 |
%------ LOAD ATTRIBUTES DATA ---------------------------------------------- |
|
|
100 |
atrd= fullfile(PATH, ATRFILE); % attribute file with annotation data |
|
|
101 |
fid3=fopen(atrd,'r'); |
|
|
102 |
A= fread(fid3, [2, inf], 'uint8')'; |
|
|
103 |
fclose(fid3); |
|
|
104 |
ATRTIME=[]; |
|
|
105 |
ANNOT=[]; |
|
|
106 |
sa=size(A); |
|
|
107 |
saa=sa(1); |
|
|
108 |
i=1; |
|
|
109 |
while i<=saa |
|
|
110 |
annoth=bitshift(A(i,2),-2); |
|
|
111 |
if annoth==59 |
|
|
112 |
ANNOT=[ANNOT;bitshift(A(i+3,2),-2)]; |
|
|
113 |
ATRTIME=[ATRTIME;A(i+2,1)+bitshift(A(i+2,2),8)+... |
|
|
114 |
bitshift(A(i+1,1),16)+bitshift(A(i+1,2),24)]; |
|
|
115 |
i=i+3; |
|
|
116 |
elseif annoth==60 |
|
|
117 |
% nothing to do! |
|
|
118 |
elseif annoth==61 |
|
|
119 |
% nothing to do! |
|
|
120 |
elseif annoth==62 |
|
|
121 |
% nothing to do! |
|
|
122 |
elseif annoth==63 |
|
|
123 |
hilfe=bitshift(bitand(A(i,2),3),8)+A(i,1); |
|
|
124 |
hilfe=hilfe+mod(hilfe,2); |
|
|
125 |
i=i+hilfe/2; |
|
|
126 |
else |
|
|
127 |
ATRTIME=[ATRTIME;bitshift(bitand(A(i,2),3),8)+A(i,1)]; |
|
|
128 |
ANNOT=[ANNOT;bitshift(A(i,2),-2)]; |
|
|
129 |
end; |
|
|
130 |
i=i+1; |
|
|
131 |
end; |
|
|
132 |
ANNOT(length(ANNOT))=[]; % last line = EOF (=0) |
|
|
133 |
ATRTIME(length(ATRTIME))=[]; % last line = EOF |
|
|
134 |
clear A; |
|
|
135 |
ATRTIME= (cumsum(ATRTIME))/sfreq; |
|
|
136 |
ind= find(ATRTIME <= TIME(end)); |
|
|
137 |
ATRTIMED= ATRTIME(ind); |
|
|
138 |
ANNOT=round(ANNOT); |
|
|
139 |
ANNOTD= ANNOT(ind); |
|
|
140 |
|
|
|
141 |
%------ DISPLAY DATA ------------------------------------------------------ |
|
|
142 |
%{ |
|
|
143 |
figure(1); clf, box on, hold on |
|
|
144 |
plot(TIME, M(:,1),'r'); |
|
|
145 |
if nosig==2 |
|
|
146 |
plot(TIME, M(:,2),'b'); |
|
|
147 |
end; |
|
|
148 |
for k=1:length(ATRTIMED) |
|
|
149 |
text(ATRTIMED(k),0,num2str(ANNOTD(k))); |
|
|
150 |
end; |
|
|
151 |
xlim([TIME(1), TIME(end)]); |
|
|
152 |
xlabel('Time / s'); ylabel('Voltage / mV'); |
|
|
153 |
string=['ECG signal ',DATAFILE]; |
|
|
154 |
title(string); |
|
|
155 |
fprintf(1,'\\n$> DISPLAYING DATA FINISHED \n'); |
|
|
156 |
%} |
|
|
157 |
% ------------------------------------------------------------------------- |
|
|
158 |
fprintf(1,'\\n$> ALL FINISHED \n'); |
|
|
159 |
|
|
|
160 |
%% --------------------------------------------------------------- |
|
|
161 |
s=M(:,1); |
|
|
162 |
ecg_i=s'; |
|
|
163 |
%% |
|
|
164 |
[QRS_amp,QRS_ind] = DS_detect(ecg_i,0); % µ÷ÓÃQRS²¨¼ì²âËã·¨£» |
|
|
165 |
%% |
|
|
166 |
Nt=size(QRS_ind,2); |
|
|
167 |
R_TIME=ATRTIMED(ANNOTD~=14 & ANNOTD~=16 & ANNOTD~=18 & ANNOTD~=19 & ANNOTD~=20 & ANNOTD~=21 & ANNOTD~=22 & ... |
|
|
168 |
ANNOTD~=23 & ANNOTD~=24 & ANNOTD~=27 & ANNOTD~=28 & ANNOTD~=29 & ANNOTD~=30 & ... |
|
|
169 |
ANNOTD~=32 & ANNOTD~=33 & ANNOTD~=37 & ANNOTD~=39 & ANNOTD~=40); |
|
|
170 |
REF_ind=round(R_TIME'.*fs); |
|
|
171 |
Nr=size(REF_ind,2); |
|
|
172 |
if Nt>Nr |
|
|
173 |
typ=0; |
|
|
174 |
else |
|
|
175 |
typ=1; |
|
|
176 |
end |
|
|
177 |
TP=0;FP=0;FN=0; |
|
|
178 |
if typ==0 |
|
|
179 |
QRS_ind_buf=[]; |
|
|
180 |
for n=1:Nr |
|
|
181 |
ref=REF_ind(n); |
|
|
182 |
for m=1:Nt |
|
|
183 |
if abs(ref-QRS_ind(m))<=0.15*fs |
|
|
184 |
QRS_ind_buf=[QRS_ind_buf QRS_ind(m)]; |
|
|
185 |
TP=TP+1; |
|
|
186 |
break; |
|
|
187 |
end |
|
|
188 |
end |
|
|
189 |
if m==Nt&&abs(ref-QRS_ind(Nt))>0.15*fs |
|
|
190 |
FN=FN+1; |
|
|
191 |
end |
|
|
192 |
end |
|
|
193 |
FP=Nt-size(QRS_ind_buf,2); |
|
|
194 |
else |
|
|
195 |
REF_ind_buf=[]; |
|
|
196 |
for n=1:Nt |
|
|
197 |
qrs=QRS_ind(n); |
|
|
198 |
for m=1:Nr |
|
|
199 |
if abs(qrs-REF_ind(m))<=0.15*fs |
|
|
200 |
REF_ind_buf=[REF_ind_buf REF_ind(m)]; |
|
|
201 |
TP=TP+1; |
|
|
202 |
break; |
|
|
203 |
end |
|
|
204 |
end |
|
|
205 |
if m==Nr&&abs(qrs-REF_ind(Nr))>0.15*fs |
|
|
206 |
FP=FP+1; |
|
|
207 |
end |
|
|
208 |
end |
|
|
209 |
FN=Nr-size(REF_ind_buf,2); |
|
|
210 |
end |
|
|
211 |
Se=TP/(TP+FN);Pp=TP/(TP+FP); |
|
|
212 |
info=[Name_whole(na),Nr,TP,FP,FN,Se,Pp]; |
|
|
213 |
INFO=[INFO;info]; |
|
|
214 |
end |
|
|
215 |
final=[0,sum(INFO(:,2)),sum(INFO(:,3)),sum(INFO(:,4)),sum(INFO(:,5)),... |
|
|
216 |
0,0]; |
|
|
217 |
final(6)=final(3)/(final(3)+final(5)); |
|
|
218 |
final(7)=final(3)/(final(3)+final(4)); |
|
|
219 |
INFO=[INFO;final]; |
|
|
220 |
toc |