EMD(Empirical Mode Decomposition)经验模态分解是1998年黄鄂博士在希尔伯特变换的基础上提出希尔伯特-黄变换(HHT)方法,其中包含经验模式分解(EMD)和希尔伯特变换(HT)两部分。EMD作为时频域的处理方法,可以将原始信号分解成为一系列固有模态函数(IMF),IMF分量是具有时变频率的震荡函数,能够反映出非平稳信号的局部特征。
与小波相比,小波变换需要选择小波基,并且小波基的选择对整个小波分析的结果影响很大,所以小波分析的基函数缺乏适应性;而EMD依据的是数据自身的时间尺度特征来进行信号分解,无需预先设定任何基函数,即使是对于一段未知信号也可以将其分解成若干个内涵模态分量,因此具有良好的自适应性,适用于分析人体生理信号,如脑电、心电等非线性非平稳信号。
EMD分解之前,需要先了解内涵模态分量的约束条件:
简单来说,对于约束1,样本信号要反复跨越横轴,即相邻两个极值点之间一定要跨越一次横轴;对于约束2,不明白的我们往下看完它的分解步骤再讲。
算法步骤
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()
# 获取心电数据极值--数据格式:列表
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()
# 原始信号 - 均值包络线 = 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()
瞬时频率
简单观察可知,从上到下依频率从高到底。 IMF7分量是导致原始信号基线漂移的主要原因,我们在重构信号时删去对应分量即可。但仍需对根据每个模态分量的瞬时频率求其时间长度内的平均频率,并判断所分析信号的主要频率成分,经过滤波筛选出所需的模态分量进行重构,而滤波方式我们可根据不同情况选择中值滤波、均值滤波、滤波器滤波等。
最后感谢生物医学工程实验室小伙伴们!!!