ecg-qc工具包实验ECG信号质量评估
参考
https://blog.csdn.net/weixin_61539900/article/details/124777025?spm=1001.2014.3001.5502
一 下载
尝试用pip install ecg_qc,但是导入包一直不成功
所以从github直接下载,下载地址如下
https://github.com/Aura-healthcare/ecg_qc
二 使用方法
对于源码的说明文档来自如下链接
可以参考原说明文档,也可以按照本篇分享内容进行
https://aura-healthcare.github.io/ecg_qc/index.html
1、下载后解压用pycharm打开,文件目录如下
2、在ecg_qc_main下新建python文件![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/dd1c5a10224441c664d1a948645c6b30.png)
3、可以计算的SQI类型
SQI(Signal Quality Indicator)是指信号质量指标,可以反映信号的质量好坏。ecg_qc中使用的有q_sqi、c_sqi、s_sqi、k_sqi、p_sqi、bas_sqi。
根据对信号的处理方式,六种SQI可以进行如下分类。
分类 | SQI类型 |
---|---|
基于频率分布 | s_sqi(偏度) |
k_sqi(峰度) | |
基于功率谱 | p_sqi(QRS的功率谱分布) |
bas_sqi(基线的相对功率) | |
基于RR间期 | q_sqi(基于两种R波检测算法) |
c_sqi(基于噪声或伪影对RR间期分布的影响) |
对六种SQI的说明
(1)s_sqi
s_sqi:基于ECG信号频率偏度的SQI。
偏度(Skewness)是衡量一个信号分布在其平均值周围的不对称性。它可以是负的、零或正的。当频率主要分布在左侧时,偏度值为负;频率主要分布在右侧时,偏度值为正。关于中心线对称时,偏度值为0。
定义如下:其中
μ
x
,
σ
\mu_x,\sigma
μx,σ分别表示信号的均值和方差。
s
_
s
q
i
=
E
{
(
x
−
μ
x
)
3
}
σ
3
s\_sqi=\frac{E\{(x-\mu_x)^3\}}{\sigma^3}
s_sqi=σ3E{(x−μx)3}
代码实现
def ssqi(ecg_signal: list) -> float:
num = np.mean((ecg_signal - np.mean(ecg_signal))**3)
s_sqi = num / (np.std(ecg_signal, ddof=1)**3)
s_sqi_score = float(round(s_sqi, 3))
return s_sqi_score
(2)k_sqi
k_sqi:基于ECG信号峰度的SQI。表征的是在平均值处峰值高低的指标,反映地是峰部的尖度。
峰度(Kurtosis)= 信号的四阶矩(
ν
4
\nu_4
ν4)。
定义如下:其中
μ
x
,
σ
\mu_x,\sigma
μx,σ分别表示信号的均值和方差。
k
_
s
q
i
=
E
{
(
x
−
μ
x
)
4
}
σ
4
−
5
k\_sqi=\frac{E\{(x-\mu_x)^4\}}{\sigma^4}-5
k_sqi=σ4E{(x−μx)4}−5
代码实现
def ksqi(ecg_signal: list) -> float:
num = np.mean((ecg_signal - np.mean(ecg_signal))**4)
k_sqi = num / (np.std(ecg_signal, ddof=1)**4)
k_sqi_fischer = k_sqi - 5.0
k_sqi_score = float(round(k_sqi_fischer, 3))
return k_sqi_score
(3)p_sqi
p_sqi:计算的是ECG信号中QRS波的频率谱分布。
即QSR波和全部ECG信号的功率比值。QRS波的功率集中在5-15Hz,ECG信号集中在5-40Hz。如果存在干扰,则高频的信号数量增加,则p_sqi的值会减小。(这里的频率范围可以根据ECG信号本身的情况设置为其他值)
代码实现
def psqi(ecg_signal: list, sampling_frequency: int) -> float:
n = len(ecg_signal)
t = 1 / sampling_frequency
yf = np.fft.fft(ecg_signal)
xf = np.linspace(0.0, 1.0/(2.0*t), n//2)
pds_num = [np.abs(yf[idx]) for idx in range(len(xf)) if
xf[idx] >= 5 and xf[idx] <= 15]
pds_denom = [np.abs(yf[idx]) for idx in range(len(xf)) if
xf[idx] >= 5 and xf[idx] <= 40]
p_sqi_score = float(np.round(sum(pds_num) / sum(pds_denom), 3))
return p_sqi_score
(4)bas_sqi
bas_sqi:基于基线功率谱的SQI。
与p_sqi相似,计算的是基线与整体ECG信号的功率比值。这里的基线功率范围取在0-1Hz,ECG信号的功率范围取在0-40Hz。如果没有基线漂移,则bas_sqi接近于1,如果存在基线漂移,则bas_sqi值减小。
代码实现
def bassqi(ecg_signal: list, sampling_frequency: int) -> float:
n = len(ecg_signal)
t = 1 / sampling_frequency
yf = np.fft.fft(ecg_signal)
xf = np.linspace(0.0, 1.0/(2.0*t), n//2)
pds_num = [np.abs(yf[idx]) for idx in range(len(xf)) if
xf[idx] >= 0 and xf[idx] <= 1]
pds_denom = [np.abs(yf[idx]) for idx in range(len(xf)) if
xf[idx] >= 0 and xf[idx] <= 40]
bas_sqi_score = float(np.round(1 - (sum(pds_num) / sum(pds_denom)), 3))
return bas_sqi_score
(5)c_sqi
c_sqi:根据ECG信号的可变性来衡量。首先使用biosppy模块对ECG信号进行R峰识别,然后对识别出来的R峰计算变异系数,即标准差除以均值。
代码实现
def csqi(ecg_signal: list, sampling_frequency: int) -> float:
with np.errstate(invalid='raise'):
try:
rri_list = bsp_ecg.hamilton_segmenter(
signal=np.array(ecg_signal),
sampling_rate=sampling_frequency)[0]
c_sqi_score = float(np.round(
np.std(rri_list, ddof=1) / np.mean(rri_list),
3))
except Exception:
c_sqi_score = 0
return c_sqi_score
(6)q_sqi
q_sqi:使用两种不同的ECG的R峰检测算法,计算两种算法识别出来的R峰算法的匹配程度。
计算公式:其中
R
1
、
R
2
、
m
a
t
c
h
e
d
R
R_1、R_2、matched_R
R1、R2、matchedR分别表示R峰算法1检测出的R峰个数,R峰算法2检测出的R峰个数、两个检测算法检测到的同样的R峰个数。
q
_
s
q
i
=
2
∗
m
a
t
c
h
e
d
R
R
1
+
R
2
q\_sqi = \frac{2*matched_R}{R_1+R_2}
q_sqi=R1+R22∗matchedR
代码实现
def qsqi(ecg_signal: list, sampling_frequency: int) -> float:
detectors = Detectors(sampling_frequency)
qrs_frames_swt = detectors.swt_detector(ecg_signal)
qrs_frames_hamilton = bsp_ecg.hamilton_segmenter(
signal=np.array(ecg_signal),
sampling_rate=sampling_frequency)[0]
q_sqi_score = compute_qrs_frames_correlation(qrs_frames_hamilton,
qrs_frames_swt,
sampling_frequency)
return q_sqi_score
def compute_qrs_frames_correlation(qrs_frames_1: list,
qrs_frames_2: list,
sampling_frequency: int,
matching_qrs_frames_tolerance=50) -> float:
single_frame_duration = 1/sampling_frequency
frame_tolerance = matching_qrs_frames_tolerance * (
0.001 / single_frame_duration)
# Catch complete failed QRS detection
if (len(qrs_frames_1) == 0 or len(qrs_frames_2) == 0):
return 0
i = 0
j = 0
matching_frames = 0
while i < len(qrs_frames_1) and j < len(qrs_frames_2):
min_qrs_frame = min(qrs_frames_1[i], qrs_frames_2[j])
# Get missing detected beats intervals
# Matching frames
if abs(qrs_frames_2[j] - qrs_frames_1[i]) < frame_tolerance:
matching_frames += 1
i += 1
j += 1
else:
# increment first QRS in frame list
if min_qrs_frame == qrs_frames_1[i]:
i += 1
else:
j += 1
correlation_coefs = 2 * matching_frames / (len(qrs_frames_1) +
len(qrs_frames_2))
correlation_coefs = round(correlation_coefs, 3)
4、类、函数说明
我们需要调用的函数全部来自ecg_qc_mian/ecg_qc
以下是对一些函数的介绍
类名/函数名 | 说明 | 输入 | 输出 |
---|---|---|---|
ecg_qc.ecg_qc.class EcgQc | 计算一段ECG信号的六个SQI,并根据这些SQI通过训练好的模型得出信号质量结果 | model_file=‘训练好的模型名称或路径’, sampling_frequency: int = ECG信号频率, normalized: bool = ECG信号是否需要标准化 | 信号质量:0或1 |
EcgQc.compute_sqi_scores(ecg_signal) | 根据一段ECG信号计算SQI | ECG信号 | 根据输入的ECG得出的6个SQI值 |
EcgQc.get_signal_quality | 根据输入的ECG信号,通过训练好的模型预测得出信号质量 | ECG信号 | 信号质量(0或1) |
EcgQc.predict_quality | 根据SQI分数,通过训练好的模型预测信号质量 | ECG的六个SQI | 信号质量(0或1) |
参考
1、李桥,俞梦孙. 重症监护病人心电导联信号质量评估[J]. 山东大学学报( 医学版) , 2007,45.
2、https://aura-healthcare.github.io/ecg_qc/index.html