|
a |
|
b/rddata.m |
|
|
1 |
% This programm reads ECG data which are saved in format 212. |
|
|
2 |
% (e.g., 100.dat from MIT-BIH-DB, cu01.dat from CU-DB,...) |
|
|
3 |
% The data are displayed in a figure together with the annotations. |
|
|
4 |
% The annotations are saved in the vector ANNOT, the corresponding |
|
|
5 |
% times (in seconds) are saved in the vector ATRTIME. |
|
|
6 |
% The annotations are saved as numbers, the meaning of the numbers can |
|
|
7 |
% be found in the codetable "ecgcodes.h" available at www.physionet.org. |
|
|
8 |
% |
|
|
9 |
% ANNOT only contains the most important information, which is displayed |
|
|
10 |
% with the program rdann (available on www.physionet.org) in the 3rd row. |
|
|
11 |
% The 4th to 6th row are not saved in ANNOT. |
|
|
12 |
% |
|
|
13 |
% |
|
|
14 |
% created on Feb. 27, 2003 by |
|
|
15 |
% Robert Tratnig (Vorarlberg University of Applied Sciences) |
|
|
16 |
% (email: rtratnig@gmx.at), |
|
|
17 |
% |
|
|
18 |
% algorithm is based on a program written by |
|
|
19 |
% Klaus Rheinberger (University of Innsbruck) |
|
|
20 |
% (email: klaus.rheinberger@uibk.ac.at) |
|
|
21 |
% |
|
|
22 |
%------------------------------------------------------------------------- |
|
|
23 |
clc; clear all; |
|
|
24 |
|
|
|
25 |
%------ SPECIFY DATA ------------------------------------------------------ |
|
|
26 |
%------ 指定数据文件 ------------------------------------------------------- |
|
|
27 |
PATH= 'F:\MATLAB\MIT-BIH'; % 指定数据的储存路径 |
|
|
28 |
HEADERFILE= '100.hea'; % .hea 格式,头文件,可用记事本打开 |
|
|
29 |
ATRFILE= '100.atr'; % .atr 格式,属性文件,数据格式为二进制数 |
|
|
30 |
DATAFILE='100.dat'; % .dat ¸ñʽ£¬ECG Êý¾Ý |
|
|
31 |
SAMPLES2READ=1800; % 指定需要读入的样本数 |
|
|
32 |
% 若.dat文件中存储有两个通道的信号: |
|
|
33 |
% 则读入 2*SAMPLES2READ 个数据 |
|
|
34 |
|
|
|
35 |
%------ LOAD HEADER DATA -------------------------------------------------- |
|
|
36 |
%------ 读入头文件数据 ----------------------------------------------------- |
|
|
37 |
% |
|
|
38 |
% 示例:用记事本打开的117.hea 文件的数据 |
|
|
39 |
% |
|
|
40 |
% 117 2 360 650000 |
|
|
41 |
% 117.dat 212 200 11 1024 839 31170 0 MLII |
|
|
42 |
% 117.dat 212 200 11 1024 930 28083 0 V2 |
|
|
43 |
% # 69 M 950 654 x2 |
|
|
44 |
% # None |
|
|
45 |
% |
|
|
46 |
%------------------------------------------------------------------------- |
|
|
47 |
fprintf(1,'\\n$> WORKING ON %s ...\n', HEADERFILE); % 在Matlab命令行窗口提示当前工作状态 |
|
|
48 |
% |
|
|
49 |
% 【注】函数 fprintf 的功能将格式化的数据写入到指定文件中。 |
|
|
50 |
% ±í´ïʽ£ºcount = fprintf(fid,format,A,...) |
|
|
51 |
% 在字符串'format'的控制下,将矩阵A的实数数据进行格式化,并写入到文件对象fid中。该函数返回所写入数据的字节数 count。 |
|
|
52 |
% fid 是通过函数 fopen 获得的整型文件标识符。fid=1,表示标准输出(即输出到屏幕显示);fid=2,表示标准偏差。 |
|
|
53 |
% |
|
|
54 |
signalh= fullfile(PATH, HEADERFILE); % 通过函数 fullfile 获得头文件的完整路径 |
|
|
55 |
fid1=fopen(signalh,'r'); % 打开头文件,其标识符为 fid1 ,属性为'r'--“只读” |
|
|
56 |
z= fgetl(fid1); % 读取头文件的第一行数据,字符串格式 |
|
|
57 |
A= sscanf(z, '%*s %d %d %d',[1,3]); % 按照格式 '%*s %d %d %d' 转换数据并存入矩阵 A 中 |
|
|
58 |
nosig= A(1); % 信号通道数目 |
|
|
59 |
sfreq=A(2); % 数据采样频率 |
|
|
60 |
clear A; % 清空矩阵 A ,准备获取下一行数据 |
|
|
61 |
for k=1:nosig % 读取每个通道信号的数据信息 |
|
|
62 |
z= fgetl(fid1); |
|
|
63 |
A= sscanf(z, '%*s %d %d %d %d %d',[1,5]); |
|
|
64 |
dformat(k)= A(1); % 信号格式; 这里只允许为 212 格式 |
|
|
65 |
gain(k)= A(2); % 每 mV 包含的整数个数 |
|
|
66 |
bitres(k)= A(3); % 采样精度(位分辨率) |
|
|
67 |
zerovalue(k)= A(4); % ECG 信号零点相应的整数值 |
|
|
68 |
firstvalue(k)= A(5); % 信号的第一个整数值 (用于偏差测试) |
|
|
69 |
end; |
|
|
70 |
fclose(fid1); |
|
|
71 |
clear A; |
|
|
72 |
|
|
|
73 |
%------ LOAD BINARY DATA -------------------------------------------------- |
|
|
74 |
%------ 读取 ECG 信号二值数据 ---------------------------------------------- |
|
|
75 |
% |
|
|
76 |
if dformat~= [212,212], error('this script does not apply binary formats different to 212.'); end; |
|
|
77 |
signald= fullfile(PATH, DATAFILE); % 读入 212 格式的 ECG 信号数据 |
|
|
78 |
fid2=fopen(signald,'r'); |
|
|
79 |
A= fread(fid2, [3, SAMPLES2READ], 'uint8')'; % matrix with 3 rows, each 8 bits long, = 2*12bit |
|
|
80 |
fclose(fid2); |
|
|
81 |
% 通过一系列的移位(bitshift)、位与(bitand)运算,将信号由二值数据转换为十进制数 |
|
|
82 |
M2H= bitshift(A(:,2), -4); %字节向右移四位,即取字节的高四位 |
|
|
83 |
M1H= bitand(A(:,2), 15); %取字节的低四位 |
|
|
84 |
PRL=bitshift(bitand(A(:,2),8),9); % sign-bit 取出字节低四位中最高位,向右移九位 |
|
|
85 |
PRR=bitshift(bitand(A(:,2),128),5); % sign-bit 取出字节高四位中最高位,向右移五位 |
|
|
86 |
M( : , 1)= bitshift(M1H,8)+ A(:,1)-PRL; |
|
|
87 |
M( : , 2)= bitshift(M2H,8)+ A(:,3)-PRR; |
|
|
88 |
if M(1,:) ~= firstvalue, error('inconsistency in the first bit values'); end; |
|
|
89 |
switch nosig |
|
|
90 |
case 2 |
|
|
91 |
M( : , 1)= (M( : , 1)- zerovalue(1))/gain(1); |
|
|
92 |
M( : , 2)= (M( : , 2)- zerovalue(2))/gain(2); |
|
|
93 |
TIME=(0:(SAMPLES2READ-1))/sfreq; |
|
|
94 |
case 1 |
|
|
95 |
M( : , 1)= (M( : , 1)- zerovalue(1)); |
|
|
96 |
M( : , 2)= (M( : , 2)- zerovalue(1)); |
|
|
97 |
M=M'; |
|
|
98 |
M(1)=[]; |
|
|
99 |
sM=size(M); |
|
|
100 |
sM=sM(2)+1; |
|
|
101 |
M(sM)=0; |
|
|
102 |
M=M'; |
|
|
103 |
M=M/gain(1); |
|
|
104 |
TIME=(0:2*(SAMPLES2READ)-1)/sfreq; |
|
|
105 |
otherwise % this case did not appear up to now! |
|
|
106 |
% here M has to be sorted!!! |
|
|
107 |
disp('Sorting algorithm for more than 2 signals not programmed yet!'); |
|
|
108 |
end; |
|
|
109 |
clear A M1H M2H PRR PRL; |
|
|
110 |
fprintf(1,'\\n$> LOADING DATA FINISHED \n'); |
|
|
111 |
|
|
|
112 |
%------ LOAD ATTRIBUTES DATA ---------------------------------------------- |
|
|
113 |
atrd= fullfile(PATH, ATRFILE); % attribute file with annotation data |
|
|
114 |
fid3=fopen(atrd,'r'); |
|
|
115 |
A= fread(fid3, [2, inf], 'uint8')'; |
|
|
116 |
fclose(fid3); |
|
|
117 |
ATRTIME=[]; |
|
|
118 |
ANNOT=[]; |
|
|
119 |
sa=size(A); |
|
|
120 |
saa=sa(1); |
|
|
121 |
i=1; |
|
|
122 |
while i<=saa |
|
|
123 |
annoth=bitshift(A(i,2),-2); |
|
|
124 |
if annoth==59 |
|
|
125 |
ANNOT=[ANNOT;bitshift(A(i+3,2),-2)]; |
|
|
126 |
ATRTIME=[ATRTIME;A(i+2,1)+bitshift(A(i+2,2),8)+... |
|
|
127 |
bitshift(A(i+1,1),16)+bitshift(A(i+1,2),24)]; |
|
|
128 |
i=i+3; |
|
|
129 |
elseif annoth==60 |
|
|
130 |
% nothing to do! |
|
|
131 |
elseif annoth==61 |
|
|
132 |
% nothing to do! |
|
|
133 |
elseif annoth==62 |
|
|
134 |
% nothing to do! |
|
|
135 |
elseif annoth==63 |
|
|
136 |
hilfe=bitshift(bitand(A(i,2),3),8)+A(i,1); |
|
|
137 |
hilfe=hilfe+mod(hilfe,2); |
|
|
138 |
i=i+hilfe/2; |
|
|
139 |
else |
|
|
140 |
ATRTIME=[ATRTIME;bitshift(bitand(A(i,2),3),8)+A(i,1)]; |
|
|
141 |
ANNOT=[ANNOT;bitshift(A(i,2),-2)]; |
|
|
142 |
end; |
|
|
143 |
i=i+1; |
|
|
144 |
end; |
|
|
145 |
ANNOT(length(ANNOT))=[]; % last line = EOF (=0) |
|
|
146 |
ATRTIME(length(ATRTIME))=[]; % last line = EOF |
|
|
147 |
clear A; |
|
|
148 |
ATRTIME= (cumsum(ATRTIME))/sfreq; |
|
|
149 |
ind= find(ATRTIME <= TIME(end)); |
|
|
150 |
ATRTIMED= ATRTIME(ind); |
|
|
151 |
ANNOT=round(ANNOT); |
|
|
152 |
ANNOTD= ANNOT(ind); |
|
|
153 |
|
|
|
154 |
%------ DISPLAY DATA ------------------------------------------------------ |
|
|
155 |
figure(1); clf, box on, hold on |
|
|
156 |
plot(TIME, M(:,1),'r'); |
|
|
157 |
if nosig==2 |
|
|
158 |
plot(TIME, M(:,2),'b'); |
|
|
159 |
end; |
|
|
160 |
for k=1:length(ATRTIMED) |
|
|
161 |
text(ATRTIMED(k),0,num2str(ANNOTD(k))); |
|
|
162 |
end; |
|
|
163 |
xlim([TIME(1), TIME(end)]); |
|
|
164 |
xlabel('Time / s'); ylabel('Voltage / mV'); |
|
|
165 |
string=['ECG signal ',DATAFILE]; |
|
|
166 |
title(string); |
|
|
167 |
fprintf(1,'\\n$> DISPLAYING DATA FINISHED \n'); |
|
|
168 |
|
|
|
169 |
% ------------------------------------------------------------------------- |
|
|
170 |
fprintf(1,'\\n$> ALL FINISHED \n'); |