Bootstrap

基于Python的心率分析

一、简介

本篇文章主要讲解心率信号的快速傅里叶变化、滤波器的实现和最后心率的获取。

  1. 环境:anaconda(Spyder)
  2. 版本:Python3.6.0
  3. 数据获取网址:https://archive.physionet.org/cgi-bin/atm/ATM
  4. 参考:https://docs.huihoo.com/scipy/scipy-zh-cn/filters.html#firiir

二、心率波形显示

在PhysioBank ATM找到相关的心电信号数据,保存为Excel或者mat文件,读取相关数据,通过plot函数库进行绘图。

import pylab as pl
import scipy.io as sio
import numpy as np

data = sio.loadmat('11950_02m.mat')
data = data['val']
data = data[1]

#中文显示
pl.rcParams['font.sans-serif']=['SimHei']
pl.rcParams['axes.unicode_minus'] = False

pl.legend()
pl.xlabel(u"时间")
pl.ylabel(u"幅值")
pl.title(u"心电信号")
pl.plot(data)

在这里插入图片描述

三、傅里叶变换

https://www.jianshu.com/p/994050a42724
这篇文章对时域、频域之间的关系进行的详细的讲解,有兴趣的可以了解一下,有助于你对傅里叶变换的理解。
下面我们对心电信号进行傅里叶变换,可以得到心电信号在频域中的相关分布情况

sampling_rate = 250
fft_size = 250
t = np.arange(0,1.0,1.0/sampling_rate)
xs = data[:fft_size]
xs = xs.flatten()#将列转换为行,重要

xf = np.fft.rfft(xs)/fft_size
freqs = np.linspace(0,sampling_rate/2,fft_size/2+1)
xfp = 20*np.log10(np.clip(np.abs(xf),1e-20,1e100))

这里调用的是numpy函数库的fft函数,xs参数必须为行向量数组,否则得到错误的数据。
在这里插入图片描述
由傅里叶变换之后的波形图,我们可以看出在10Hz~30Hz这个区间的波形比较平缓。
接下来分析一下心率波形的组成
在这里插入图片描述
我们一般都是通过获取R波的个数来得出心率的。R波的信号成分在20Hz以上,T波成分一般在10Hz以下。(这里是网上的总结,不知怎么得来的,希望路过的大侠,帮忙解答一下)
这里与傅里叶变换之后的波形基本吻合。

四、滤波器的实现

1、低通滤波器

先实现一个低通滤波器,这里调用remez函数实现一个截止频率为10Hz的低通滤波器。
remez()
参数1:滤波器的长度,生成滤波参数的个数;
参数2:通带和截带;截止频率/采样率,本文中为10/250=0.04;
参数3:增益
调用freqz函数计算频率响应

import scipy.signal as signal

low = signal.remez(65,(0,0.03,0.04,0.50),(1,0.01))
w,h = signal.freqz(low,1)

pl.plot(w/2/np.pi,20*np.log10(np.abs(h)))

可以得到如下的频率响应曲线图
在这里插入图片描述
接下来调用lfilter函数创建FIR低通滤波器,导入一秒的心电数据。
lfilter()
参数1:bandb为调用remez函数生成的滤波器参数;
参数2:当banda为1时表示创建FIR滤波器;
参数3:导入的数据。

banda=1
bandb=np.array([0.0626444,-0.00591505,-0.00644119,-0.00733662,-0.00858695,-0.0100849,-0.0117168,-0.0133311,-0.0148219,-0.0160526,-0.0169183,-0.017282,-0.0170576,-0.0161446,-0.0145,-0.0120671,-0.00885165,-0.0048518,-0.000134043,0.00524337,0.0111587,0.0175071,0.0241233,0.0308625,0.0375254,0.0439567,0.0499621,0.0553981,0.0600621,0.0638317,0.066553,0.0683189,0.0789989,0.0683189,0.066553,0.0638317,0.0600621,0.0553981,0.0499621,0.0439567,0.0375254,0.0308625,0.0241233,0.0175071,0.0111587,0.00524337,-0.000134043,-0.0048518,-0.00885165,-0.0120671,-0.0145,-0.0161446,-0.0170576,-0.017282,-0.0169183,-0.0160526,-0.0148219,-0.0133311,-0.0117168,-0.0100849,-0.00858695,-0.00733662,-0.00644119,-0.00591505,0.0626444])

deBandFilterData = signal.lfilter(bandb,banda, xs)

图1为原始数据,图2为经过低通滤波后的数据。
在这里插入图片描述
可以看出R波被完全滤除,保留了T波。

2、带通滤波器

这里调用remez函数实现通带为10Hz~20Hz的带通滤波器。

low = signal.remez(33,(0,0.03,0.04,0.50),(0.01,1))
high = signal.remez(33,(0,0.1,0.12,0.50),(1,0.01))
DD = np.convolve(low,high)
w,h = signal.freqz(DD ,1)
pl.plot(w/2/np.pi,20*np.log10(np.abs(h)))

在这里插入图片描述

banda = 1
bandb=np.array([-0.00802303,-7.24425e-05,0.00152734,0.00348844,0.00495073,0.00515223,0.00377258,0.00122724,-0.00140695,-0.00274613,-0.00159154,0.0025182,0.00897934,0.0161445,0.0218003,0.0238291,-0.0429597,-0.00113136,-0.00286913,-0.00207864,-0.0025121,-0.00886799,-0.0243103,-0.0478642,-0.0738221,-0.0930648,-0.0958544,-0.0757677,-0.0329661,0.0246284,0.0831973,0.127074,0.138074,0.127074,0.0831973,0.0246284,-0.0329661,-0.0757677,-0.0958544,-0.0930648,-0.0738221,-0.0478642,-0.0243103,-0.00886799,-0.0025121,-0.00207864,-0.00286913,-0.00113136,-0.0429597,0.0238291,0.0218003,0.0161445,0.00897934,0.0025182,-0.00159154,-0.00274613,-0.00140695,0.00122724,0.00377258,0.00515223,0.00495073,0.00348844,0.00152734,-7.24425e-05,-0.00802303])

deBandFilterData = signal.lfilter(bandb,banda, xs)

在这里插入图片描述
经过带通滤波器之后,得到的波形,我们可以看出保存了R波,滤掉了T波。

五、心率的计算

得到滤波信号之后,我们来看一下心率的计算 ,这里主要是统计R波的个数。

;