信号处理笔记(1)EMD经验模态分解

一、 EMD简介

EMD(Empirical Mode Decomposition)经验模态分解是1998年黄鄂博士在希尔伯特变换的基础上提出希尔伯特-黄变换(HHT)方法,其中包含经验模式分解(EMD)和希尔伯特变换(HT)两部分。EMD作为时频域的处理方法,可以将原始信号分解成为一系列固有模态函数(IMF),IMF分量是具有时变频率的震荡函数,能够反映出非平稳信号的局部特征。

  • 自适应性

与小波相比,小波变换需要选择小波基,并且小波基的选择对整个小波分析的结果影响很大,所以小波分析的基函数缺乏适应性;而EMD依据的是数据自身的时间尺度特征来进行信号分解,无需预先设定任何基函数,即使是对于一段未知信号也可以将其分解成若干个内涵模态分量,因此具有良好的自适应性,适用于分析人体生理信号,如脑电、心电等非线性非平稳信号。

二、EMD分解步骤

EMD分解之前,需要先了解内涵模态分量的约束条件:

  • 1、在整个数据段内,极值点的个数和过零点的个数必须相等或相差最多不能超过一个。
  • 2、在任意时刻,由局部极大值点形成的上包络线和由局部极小值点形成的下包络线的平均值为零,即上、下包络线相对于时间轴局部对称。

简单来说,对于约束1,样本信号要反复跨越横轴,即相邻两个极值点之间一定要跨越一次横轴;对于约束2,不明白的我们往下看完它的分解步骤再讲。

算法步骤

  1. 找到原始信号X(t)的所有的极值点;
  2. 极值点拟合包络线。对于所有极大值点,通过三次样条函数拟合出上包络线Up_envelop;同理,将所有极小值点拟合出下包络线Low_envelop;(注:一定要包含所有极值点,不能有遗漏!)
  3. 计算均值包络线m(t)。即上、下包络线的均值;
  4. 原始信号X(t)减去均值包络线m(t),得到一个中间信号r(t);
  5. 判断中间信号r(t)是否满足IMF两个约束条件,如果满足则是一个IMF分量,不满足则返回步骤1反复迭代;
  6. 假设r(t)是分解出的第一个高频分量并记为IMF1,则均值包络线m(t)相对与IMF1是低频分量。然后将m(t)当作原始信号继续分解得到下一个IMF,直至残余分量是单调函数或常量时,停止分解。通常残余分量记为res。

EMD分解满足在这里插入图片描述

三、Python代码实现EMD分解

1、代码实现算法过程

  1. 求极值点
'''
样本信号来自于实验室采集胎心电数据
信号总长度69082,这里只选取1024个采样点
采样频率250hz
FecgSignal.Normal()是自写的一个归一化函数,请自行删去
'''

arr1_1_1 = np.genfromtxt('fecg_data\date_312\channel_data\BLE1-1-RF-channel1.txt', delimiter='\n', dtype=float)
iSampleCount = 1024  # 采样数
iSampleRate = 250   # 采样频率
# data为取采样点后的数据,array类型
data = np.array(FecgSignal.Normal(arr1_1_1, iSampleCount))
t = np.linspace(0, iSampleCount/iSampleRate, iSampleCount)
w = np.linspace(0, iSampleRate/2, int(iSampleCount/2))

# 获取心电数据极值--数据格式:元组
max_peaks = argrelextrema(data, np.greater)
min_peaks = argrelextrema(data, np.less)

# 绘制极值点图
plt.plot(data)
plt.scatter(max_peaks, data[max_peaks], c='r', label='Max Peaks')
plt.scatter(min_peaks, data[min_peaks], c='b', label='Min Peaks')
plt.legend()
plt.xlabel('Time/s')
plt.ylabel('Amplitude')
plt.title("Max&Min Peaks")
plt.show()

信号处理笔记(1)EMD经验模态分解_第1张图片局部放大来看
信号处理笔记(1)EMD经验模态分解_第2张图片

  1. 极值点拟合包络线,求均值包络线
# 获取心电数据极值--数据格式:列表
max_peaks = list(max_peaks[0])
min_peaks = list(min_peaks[0])
# 观测点长度
index = list(range(len(data)))
# 极值点拟合包络线
ipo_max = spi.splrep(max_peaks, data[max_peaks], k=3)  # 极大值样本点导入,生成参数
up_envelop = spi.splev(index, ipo_max)     # 上包络线
ipo_min = spi.splrep(min_peaks, data[min_peaks], k=3)  # 极小值样本点导入,生成参数
low_envelop = spi.splev(index, ipo_min)    # 下包络线
# 计算平均包络线
average_envelop = (up_envelop + low_envelop) / 2
# 绘上包络、下包络和均值包络线
plt.plot(t, data, label='Original')
plt.plot(t, up_envelop, label='Up Envelop')
plt.plot(t, low_envelop, label='Low Envelop')
plt.plot(t, average_envelop, label='Average Envelop')
plt.legend()
plt.xlabel('Time/s')
plt.ylabel('Amplitude')
plt.show()

信号处理笔记(1)EMD经验模态分解_第3张图片

  1. 求IMF分量并判断
# 原始信号 - 均值包络线 = IMF内涵模态分量
# imf即分解的第一个高频分量  均值包络线即剩余低频分量
imf = data - average_envelop
def isIMFs(imf):
    max_peaks = list(argrelextrema(imf, np.greater)[0])
    min_peaks = list(argrelextrema(imf, np.less)[0])
    if min(imf[max_peaks]) < 0 or max(imf[min_peaks]) > 0:
        return False
    else:
        return True

2、pyemd库实现EMD分解

pip install pyemd
!!!如果报错请把所有pyemd库中所有的PyEMD改为pyemd!!!
from pyemd import EMD, Visualisation

from pyemd import EMD, Visualisation

emd = EMD()
emd.emd(data)
# 内涵模态分量
imfs, res = emd.get_imfs_and_residue() 
vis = Visualisation()
vis.plot_imfs(imfs=imfs, residue=res, include_residue=True)
# 绘制所有IMF分量的瞬时频率
vis.plot_instant_freq(t, imfs=imfs)
plt.show()

信号处理笔记(1)EMD经验模态分解_第4张图片
瞬时频率
信号处理笔记(1)EMD经验模态分解_第5张图片
简单观察可知,从上到下依频率从高到底。 IMF7分量是导致原始信号基线漂移的主要原因,我们在重构信号时删去对应分量即可。但仍需对根据每个模态分量的瞬时频率求其时间长度内的平均频率,并判断所分析信号的主要频率成分,经过滤波筛选出所需的模态分量进行重构,而滤波方式我们可根据不同情况选择中值滤波、均值滤波、滤波器滤波等。

最后感谢生物医学工程实验室小伙伴们!!!

你可能感兴趣的:(算法,python,数据分析,信号处理)