|
a |
|
b/DS_detect.m |
|
|
1 |
function [QRS_amp,QRS_ind] = DS_detect( ecg_i,gr ) |
|
|
2 |
%% function [QRS_amp,QRS_ind]=DS_detect(ecg_i,gr) |
|
|
3 |
%% 输入 |
|
|
4 |
% ecg_i : 原信号,一维向量 |
|
|
5 |
% gr : 绘图与否,0:不绘图,1:绘图 |
|
|
6 |
%% 输出 |
|
|
7 |
% QRS_amp:QRS波振幅. |
|
|
8 |
% QRS_ind:QRS波索引. |
|
|
9 |
% 绘制图像. |
|
|
10 |
%% 作者:刘文涵(WHliu@whu.edu.cn) |
|
|
11 |
%% 版本:1.1 |
|
|
12 |
%% 04-24-2018 |
|
|
13 |
%% 代码: |
|
|
14 |
if nargin < 2 |
|
|
15 |
gr = 1; |
|
|
16 |
if nargin<1 |
|
|
17 |
error('The algorithm need a input:ecg_i.'); |
|
|
18 |
end |
|
|
19 |
end |
|
|
20 |
if ~isvector(ecg_i) |
|
|
21 |
error('ecg_i must be a row or column vector.'); |
|
|
22 |
end |
|
|
23 |
fs=360; |
|
|
24 |
if size(ecg_i,2)<round(1.5*fs)+1 |
|
|
25 |
error('The algorithm need a longer input.'); |
|
|
26 |
end |
|
|
27 |
tic, |
|
|
28 |
s=ecg_i; |
|
|
29 |
N=size(s,2); |
|
|
30 |
ECG=s; |
|
|
31 |
FIR_c1=[0.0041,0.0053,0.0068,0.0080,0.0081,0.0058,-0.0000,-0.0097,-0.0226,... |
|
|
32 |
-0.0370,-0.0498,-0.0577,-0.0576,-0.0477,-0.0278,0,0.0318,0.0625,0.0867,... |
|
|
33 |
0.1000,0.1000,0.0867,0.0625,0.0318,0,-0.0278,-0.0477,-0.0576,-0.0577,... |
|
|
34 |
-0.0498,-0.0370,-0.0226,-0.0097,-0.0000,0.0058,0.0081,0.0080,0.0068,... |
|
|
35 |
0.0053,0.0041]; % 使用fdatool设计并导出的滤波器系数,带通FIR,15~25Hz,详情使用fdatool打开DS1.fda查看 |
|
|
36 |
FIR_c2=[0.0070,0.0094,0.0162,0.0269,0.0405,0.0555,0.0703,0.0833,0.0928,... |
|
|
37 |
0.0979,0.0979,0.0928,0.0833,0.0703,0.0555,0.0405,0.0269,0.0162,0.0094,... |
|
|
38 |
0.0070]; % 使用fdatool设计并导出的滤波器系数,低通FIR,截止频率5Hz,详情使用fdatool打开DS2.fda查看 |
|
|
39 |
|
|
|
40 |
l1=size(FIR_c1,2); |
|
|
41 |
ECG_l=[ones(1,l1)*ECG(1) ECG ones(1,l1)*ECG(N)]; % 数据点延拓,防止滤波边缘效应; |
|
|
42 |
ECG=filter(FIR_c1,1,ECG_l); % 使用filter滤波; |
|
|
43 |
ECG=ECG((l1+1):(N+l1)); % 前面延拓了数据点,这里截取有用的部分; |
|
|
44 |
|
|
|
45 |
%% 双斜率处理 |
|
|
46 |
a=round(0.015*fs); % 两侧目标区间0.015~0.060s; |
|
|
47 |
b=round(0.060*fs); |
|
|
48 |
Ns=N-2*b; % 确保在不超过信号长度; |
|
|
49 |
S_l=zeros(1,b-a+1); |
|
|
50 |
S_r=zeros(1,b-a+1); |
|
|
51 |
S_dmax=zeros(1,Ns); |
|
|
52 |
for i=1:Ns % 对每个点双斜率处理; |
|
|
53 |
for k=a:b |
|
|
54 |
S_l(k-a+1)=(ECG(i+b)-ECG(i+b-k))./k; |
|
|
55 |
S_r(k-a+1)=(ECG(i+b)-ECG(i+b+k))./k; |
|
|
56 |
end |
|
|
57 |
S_lmax=max(S_l); |
|
|
58 |
S_lmin=min(S_l); |
|
|
59 |
S_rmax=max(S_r); |
|
|
60 |
S_rmin=min(S_r); |
|
|
61 |
C1=S_rmax-S_lmin; |
|
|
62 |
C2=S_lmax-S_rmin; |
|
|
63 |
S_dmax(i)=max([C1 C2]); |
|
|
64 |
end |
|
|
65 |
|
|
|
66 |
%% 再次进行低通滤波,思路与上述带通滤波一致 |
|
|
67 |
l2=size(FIR_c2,2); |
|
|
68 |
S_dmaxl=[ones(1,l2)*S_dmax(1) S_dmax ones(1,l2)*S_dmax(Ns)]; |
|
|
69 |
S_dmaxt=filter(FIR_c2,1,S_dmaxl); |
|
|
70 |
S_dmaxt=S_dmaxt((l2+1):(Ns+l2)); |
|
|
71 |
|
|
|
72 |
%% 滑动窗口积分 |
|
|
73 |
w=8;wd=7; |
|
|
74 |
d_l=[zeros(1,w) S_dmaxt zeros(1,w)]; % 零延拓,确保所有的点都可以进行窗口积分 |
|
|
75 |
m=zeros(1,Ns); |
|
|
76 |
for n=(w+1):(Ns+w) % 滑动窗口; |
|
|
77 |
m(n-w)=sum(d_l(n-w:n+w)); % 积分; |
|
|
78 |
end |
|
|
79 |
m_l=[ones(1,wd)*m(1) m ones(1,wd)*m(Ns)]; |
|
|
80 |
|
|
|
81 |
%% 双阈值检测与动态变化 |
|
|
82 |
QRS_buf1=[]; % 存储检测到的QRS波索引 |
|
|
83 |
AMP_buf1=[]; % 存储最近检测到的8个QRS波对应特征信号的波峰值 |
|
|
84 |
thr_init0=0.4;thr_lim0=0.23; |
|
|
85 |
thr_init1=0.6;thr_lim1=0.3; %% 阈值变化的初始值和下限设置 |
|
|
86 |
en=-1; % 标记波峰检出情况,高于高阈值--1,高低阈值之间--0,未检出-- -1 |
|
|
87 |
thr0=thr_init0; |
|
|
88 |
thr1=thr_init1; |
|
|
89 |
thr1_buf=[]; % 阈值缓存,记录阈值变化情况; |
|
|
90 |
thr0_buf=[]; |
|
|
91 |
for j=8:Ns |
|
|
92 |
t=1; |
|
|
93 |
cri=1; |
|
|
94 |
while t<=wd&&cri>0 % 检测候选波峰; |
|
|
95 |
cri=((m_l(j)-m_l(j-t))>0)&&(m_l(j)-m_l(j+t)>0); |
|
|
96 |
t=t+1; |
|
|
97 |
end |
|
|
98 |
if t==wd+1 |
|
|
99 |
N1=size(QRS_buf1,2); %N1:已经检测到的QRS波个数 |
|
|
100 |
if m_l(j)>thr1 % 高于高阈值时的处理 |
|
|
101 |
if N1<2 % N1小于2时直接存储; |
|
|
102 |
QRS_buf1=[QRS_buf1 (j-wd)]; % j-wd 减去了滑动窗口积分带来的延迟; |
|
|
103 |
AMP_buf1=[AMP_buf1 m_l(j)]; |
|
|
104 |
en=1; |
|
|
105 |
else |
|
|
106 |
dist=j-wd-QRS_buf1(N1); |
|
|
107 |
if dist>0.24*fs % 检测波峰距离; |
|
|
108 |
QRS_buf1=[QRS_buf1 (j-wd)]; |
|
|
109 |
AMP_buf1=[AMP_buf1 m_l(j)]; |
|
|
110 |
en=1; |
|
|
111 |
else |
|
|
112 |
if m_l(j)>AMP_buf1(end) % 不应期处理 |
|
|
113 |
QRS_buf1(end)=j-wd; |
|
|
114 |
AMP_buf1(end)=m_l(j); |
|
|
115 |
en=1; |
|
|
116 |
end |
|
|
117 |
end |
|
|
118 |
end |
|
|
119 |
|
|
|
120 |
else % 特征峰值低于高阈值 |
|
|
121 |
|
|
|
122 |
if N1<2&&m_l(j)>thr0 % 特征峰值在两阈值之间 |
|
|
123 |
QRS_buf1=[QRS_buf1 (j-wd)]; |
|
|
124 |
AMP_buf1=[AMP_buf1 m_l(j)]; |
|
|
125 |
en=0; |
|
|
126 |
else |
|
|
127 |
if m_l(j)>thr0 % 特征峰值在两阈值之间 |
|
|
128 |
dist_m=mean(diff(QRS_buf1)); |
|
|
129 |
dist=j-wd-QRS_buf1(N1); |
|
|
130 |
if dist>0.24*fs && dist>0.5*dist_m % 不应期检测,并且,波峰要距离足够远(> 平均距离的一半) |
|
|
131 |
QRS_buf1=[QRS_buf1 (j-wd)]; |
|
|
132 |
AMP_buf1=[AMP_buf1 m_l(j)]; |
|
|
133 |
en=0; |
|
|
134 |
else |
|
|
135 |
if m_l(j)>AMP_buf1(end) |
|
|
136 |
QRS_buf1(end)=j-wd; |
|
|
137 |
AMP_buf1(end)=m_l(j); |
|
|
138 |
en=0; |
|
|
139 |
end |
|
|
140 |
end |
|
|
141 |
else |
|
|
142 |
en=-1; |
|
|
143 |
end |
|
|
144 |
end |
|
|
145 |
end |
|
|
146 |
N2=size(AMP_buf1,2); |
|
|
147 |
if N2>8 |
|
|
148 |
AMP_buf1=AMP_buf1(2:9); % 确保只存储最近的8个特征波峰; |
|
|
149 |
end |
|
|
150 |
% 下面的if与博文中的公式对应 |
|
|
151 |
if en==1 |
|
|
152 |
thr1=0.7*mean(AMP_buf1); |
|
|
153 |
thr0=0.25*mean(AMP_buf1); |
|
|
154 |
else |
|
|
155 |
if en==0 |
|
|
156 |
thr1=thr1-(abs(m_l(j)-mean(AMP_buf1)))/2; |
|
|
157 |
thr0=0.4*m_l(j); |
|
|
158 |
end |
|
|
159 |
end |
|
|
160 |
end |
|
|
161 |
if thr1<=thr_lim1 % 确保阈值高于下限 |
|
|
162 |
thr1=thr_lim1; |
|
|
163 |
end |
|
|
164 |
|
|
|
165 |
if thr0<=thr_lim0 |
|
|
166 |
thr0=thr_lim0; |
|
|
167 |
end |
|
|
168 |
|
|
|
169 |
thr1_buf=[thr1_buf thr1]; |
|
|
170 |
thr0_buf=[thr0_buf thr0]; |
|
|
171 |
end |
|
|
172 |
delay=round(l1/2)-2*w+2; |
|
|
173 |
QRS_ind=QRS_buf1-delay; % 减去延迟,得到最终结果; |
|
|
174 |
QRS_amp=s(QRS_ind); |
|
|
175 |
toc |
|
|
176 |
if gr==1 %绘图 |
|
|
177 |
subplot(2,1,1);plot(m);axis([1 size(m,2) -0.3 1.6*max(m)]); |
|
|
178 |
hold on;title('Feature signal and thresholds');grid on; |
|
|
179 |
plot(QRS_buf1,m(QRS_buf1),'ro'); |
|
|
180 |
plot(thr1_buf,'r'); |
|
|
181 |
plot(thr0_buf,'k'); |
|
|
182 |
legend('Feature Signal','QRS Locations','Threshold1','Threshold0'); |
|
|
183 |
subplot(2,1,2);plot(s);%axis([1 size(s,2) min(s) 1.5*max(s)]); |
|
|
184 |
xlabel('n');ylabel('Voltage / mV'); |
|
|
185 |
hold on;title('The result on the raw ECG');grid on; |
|
|
186 |
plot(QRS_ind,QRS_amp,'ro'); |
|
|
187 |
legend('Raw ECG','QRS Locations'); |
|
|
188 |
end |
|
|
189 |
end |
|
|
190 |
|