本篇是下边这篇的姊妹篇:Mr.看海:类EMD的“信号分解方法”横向对比详解,EMD,EEMD,CEEMD,CEEMDAN,ICEEMDAN,EWT,VMD优劣对比。附一行代码实现所有分解方法,7合1的MATLAB代码!
该篇将代码替换为了python版本,其他地方与上一篇相同。
目前网上没有iceemdan的python版本代码,本篇中将该方法予以补全。另外vmd分解使用的vmdpy工具包在分解奇数数量的信号时,其分解结果的数据长度会缩短1,对于此bug,在本文的代码中也予以修复。
需要注意的是,由于python和MATLAB平台的差异,导致对于相同数据使用相同的方法,其运算结果、运算效率会存在差异。
在之前的一系列文章中,我介绍了包括EMD,EEMD,CEEMD,CEEMDAN,ICEEMDAN,EWT,VMD在内的一系列所谓“类EMD”的分解方法。同学们在使用过程中经常会需要对比这些算法的优劣,并在论文中加以呈现;也有一些同学想直接知道结论,究竟哪个方法最好呢?
这篇文章就来回答这个问题,并且给出一系列的评价方法,方便大家使用,并且同样封装了极其易用的函数。
一、怎样评价模态分解结果的优劣
“类EMD”算法之所以能够衍生出这一系列的方法,往往都是要解决这以下几个层面的问题:
1.1 模态混叠
模态混叠是评价分解结果的最重要标准,因为我们都希望每个IMF分量代表一个独立的震荡模式,便于后续的分析和解释。
模态混叠通常有两种表现形式:一种是本应分离的震荡模态出现在同一个IMF分量中,另一种是单个模态被错误地分解到多个IMF分量中。
模态混叠我们通常可以在频谱中进行判断。
下图中是第一种模态混叠:
本应分离的震荡模态出现在同一个IMF分量中
这是第二种模态混叠:
单个模态被错误地分解到多个IMF分量中
1.2 端点效应
端点效应是指在信号分解过程中,由于边界处理不当而导致的分解结果在信号两端出现的失真或畸变现象。这个问题在许多EMD及其衍生算法中都存在。
直观点来说,端点效应是这样产生的:
在EMD分解过程中,有这样一个步骤:要根据原始信号上下极值点,分别画出上、下包络线。
我们看一下信号的左端,上包络线(蓝色)和下包络线(红色)在时刻0的数值是难以确定的:
尤其是当信号震荡频率不高时,信号中的第一个极大值和极小值点可能距离0时刻点都比较远,由于缺少前后的数据点,插值算法无法准确估计包络线的走势,那么将会有很大一段包络线是“凭空猜测”出来的。这就会带来两端分解结果的不准确。
更为严重的是,由于EMD类算法通常需要多次迭代来提取IMF,端点处的误差可能会累积和放大,导致后续IMF的提取越来越不准确。
图中红圈处是比较明显的端点效应的影响结果
因此,端点效应也是衡量模态分解方法的标准之一,只不过这个也需要通过肉眼来判断,没有量化的指标评判。
1.3 重构误差
理想情况下,经过类EMD分解后的各个分量在相加之后,应该是等于原信号的。
不过由于在实际分解计算中,受到停止准则、浮点运算误差以及算法本身缺陷等因素的干扰,导致各分量重构后不能完全与原始信号相等,而是有一个很小的误差值。通常情况下,这个误差由于数量级相对于原始信号要小得多,不会影响算法应用,不过也常常用作衡量算法优劣的指标之一。(重构误差的单位和原始信号是一样的)
例如之前的文章里,我们对比过EEMD和CEEMD两个方法的重构误差值。可以看出,对于不同的分解方法,重构3误差值的差别可能是十分大的。
EEMD方法的重构残余量
CEEMD方法的重构残余量
1.4 运行时间
在处理大规模数据或需要实时处理的应用场景中,运行时间是评价模态分解方法的一个重要实用指标。不同的分解算法由于其内部机制和计算复杂度的差异,运行时间可能会有显著不同。
对于巨大的数据量,一个程序可能会跑一整天时间,所以更高的运行效率也是比较重要的。
二、实例分析
下边我将针对上述四个评价标准,分别使用EMD,EEMD,CEEMD,CEEMDAN,ICEEMDAN,EWT,VMD方法对同一段信号进行分解,并进行横向对比。
上述方法中,EMD,EEMD,CEEMD方法使用的是PyEMD包,EWT使用的是ewtpy包,所以在程序运行前,需要执行下述指令进行安装:
pip install EMD-signal
pip install ewtpy
ICEEMDAN是笔者根据MATLAB中的iceemdan文件的写法进行修改的,vmd方法则是根据vmdpy的基础上修改了bug实现的。
2.1 一个便捷的封装函数
之前专栏中对于每种分解方法都提供了分解和画图函数,不过对于上述方法都有需求同学,使用这7种单独封装的函数不免麻烦的很。
为了解决这一难题,这里要隆重介绍一下新封装的函数,使用一个函数,可以实现上述7中分解方法画图,比如如果想做EMD分解,只需要写:
# 2.1 参数设置
options = {'MaxNumIMFs': 3} # 最大的IMF数量,这个数量中包含趋势项
# 2.2 绘制分解图
imf, _, elapsedTime, reconError = pEMDs(data, FsOrT, 'EMD', options)
运行后可以得到三张图:
如果绘制分解结果及各分量的频谱图,可以执行下边这样代码:
imf, elapsedTime, reconError = pEMDsandFFT(data, FsOrT, 'EMD', options) # 2.3 绘制分解图及频谱图
可以绘制出如下图像:
如果要使用其他的分解方法,只需要将上边代码中的'EMD'换成对应的名称即可,比如:
imf, elapsedTime, reconError = pEMDs(data, FsOrT, 'EEMD', options) #执行EEMD分解和画图
imf, elapsedTime, reconError = pEMDs(data, FsOrT, 'CEEMD', options) #执行CEEMD分解和画图
imf, elapsedTime, reconError = pEMDs(data, FsOrT, 'VMD', options) #执行VMD分解和画图
# 其他的分解方法形式类似,不一一列举了
2.2 七种分解方法的横向对比结果
使用上边讲到的函数,实现对同一信号分解的横向比测。
(1)仿真信号
首先生成一组测试信号,由二次趋势项、啁啾信号和分段余弦共同组成,采样频率为1000Hz。此文件保存到了Excel文件中,直接导入使用就行。
绘制出来是这样的图像,上边四张图是信号的四个成分,最下边的图像是合成信号,理想状态下我们希望能将该合成信号还原为上边的四个分量。
(2)分解结果分析
然后我们调用上边讲到的函数进行EMD,EEMD,CEEMD,CEEMDAN,ICEEMDAN,EWT,VMD分解和画图,得到以下运行结果:
7种分解方法的分解结果
从这个分解结果来看,VMD分解的模态混叠最少,模态分解得最分明。EMD和EWT存在欠分解,而EEMD、CEEMD、CEEMDAN和ICEEMDAN存在过分解,需结合imf分量的重构来使用。
端点效应EMD方法控制得较好一些,其他分解方法或多或少都有一些端点效应。
(3)重构误差
对于重构误差,结果如下:
其中EMD、CEEMD,CEEMDAN,ICEEMDAN,EWT都是在10的-15次方这个量级,这个结果几乎可以忽略不计;EEMD则在10的-1次方的量级,结果较为一般;VMD的重构误差最大,最大值在0.5左右。
(4)运行时间
经统计,七种分解方法的运行时间为:
分解方法 | 运行时间 |
---|---|
EMD | 0.01秒 |
EEMD | 2.77秒 |
CEEMD | 6.83秒 |
CEEMDAN | 6.70秒 |
ICEEMDAN | 5.56秒 |
EWT | 0.01秒 |
VMD | 0.05秒 |
(5)总结
针对上边这个数据案例,从四个维度判断各种方法的好坏,结果大致如下:
分解方法 | 模态混叠抑制 | 端点效应抑制 | 重构误差 | 运行时间 |
---|---|---|---|---|
EMD | 较差 | 好 | 好 | 好 |
EEMD | 较好 | 较好 | 差 | 较差 |
CEEMD | 较好 | 较好 | 好 | 较差 |
CEEMDAN | 较好 | 较好 | 好 | 较差 |
ICEEMDAN | 较好 | 较好 | 好 | 较差 |
EWT | 差 | 较好 | 较差 | 好 |
VMD | 好 | 较好 | 较差 | 较好 |
需要注意的是,上边的结论只针对案例中的数据,如果换一段数据,各个判断维度的结论可能会有所不同。
三、一个主观结论
可能有些同学想要一个更加直观的结论,上述分解方法究竟那种最好。
其实在算法的实际应用中,抑制模态混叠是最重要的目的。其他的判断维度都在其次,所以我的推荐排序如下:
1.VMD属于最为推荐的方法,重构误差的缺点也掩盖不了他的光芒。
2.CEEMD,CEEMDAN,ICEEMDAN三者同属于第二梯队,使用时需要考虑结合imf重构使用,如果考虑算法的先进性,则是ICEEMDAN>CEEMDAN>CEEMD
3.EEMD属于第三梯队,作为改进方法有其优越性,但也有比较明显的短板。
4.EMD和EWT属于第四梯队,虽然EWT属于比较新的分解方法,不过在实际使用中效果往往不太理想,在使用时可能需要更为细致的调教方法。
四、推荐大家使用封装函数
最后再介绍一下封装函数,它可以一行代码实现7种模态分解和画图,包括EMD,EEMD,CEEMD,CEEMDAN,ICEEMDAN,EWT,VMD。同时也可以输出分解结果、中心频率(仅对VMD)、程序运行时间、重构误差。
关于这两个函数更详细的参数及介绍可以看这里:
def pEMDs(data, FsOrT, methodSel, options=None):
"""
整合版"类EMD"分解函数,调用该函数将会分解并画图(模态分解图,无频谱),会绘制重构误差图。
参数:
- data: 待分解的一维数据。
- FsOrT: 采样频率或采样时间向量。如果为采样频率,该变量输入单个值;如果为时间向量,该变量为与data相同长度的一维向量。如果未知采样频率,可设置为1。
- methodSel: 选择分解方法,可选值为'EMD','EEMD','CEEMD','CEEMDAN','ICEEMDAN','EWT','VMD'。
- options: 一个包含其他可设置参数的字典。对于不同分解方法,需要设置的参数有所不同。
- 'Nstd': 附加噪声标准差与数据标准差之比,默认为0.2。
- 'NE': 对信号的平均次数,默认为100。
- 'MaxIter': 最大迭代次数,默认为1000。
- 'MaxNumIMFs': 最大的IMF数量,在EMD和EWT中可选设置,默认为None。
- 'alpha': 惩罚因子,在VMD中设置,默认值为2000。
- 'K': 指定分解模态数,仅在VMD中可设置。
- 'tol': 收敛容差,在VMD中设置,是优化的停止准则之一,可以取1e-6~5e-6。
返回值:
- imf: 内涵模态分量,统一为n*m格式,其中n为模态数,m为数据点数。例如imf[0,:]即IMF1,imf[-1,:]即为残差。注意,调用该函数得到的imf,其排列均是从高频向低频排列,这也是为了方便大家研究使用而保持了统一。
- elapsedTime: 程序运行时间,单位为秒。
- reconError: 重构误差。
代码说明:http://khsci.com/docs/index.php/2024/06/27/emdspy/
更多说明:https://zhuanlan.zhihu.com/p/707752292/
"""
def pEMDsandFFT(data, FsOrT, methodSel, options=None):
"""
整合版"类EMD"分解函数,调用该函数将会分解并画图(模态分解图与各IMF分量频谱对照图),会绘制重构误差图。
参数:
- data: 待分解的一维数据。
- FsOrT: 采样频率或采样时间向量。如果为采样频率,该变量输入单个值;如果为时间向量,该变量为与data相同长度的一维向量。如果未知采样频率,可设置为1。
- methodSel: 选择分解方法,可选值为'EMD','EEMD','CEEMD','CEEMDAN','ICEEMDAN','EWT','VMD'。
- options: 一个包含其他可设置参数的字典。对于不同分解方法,需要设置的参数有所不同。
- 'Nstd': 附加噪声标准差与数据标准差之比,默认为0.2。
- 'NE': 对信号的平均次数,默认为100。
- 'MaxIter': 最大迭代次数,默认为1000。
- 'MaxNumIMFs': 最大的IMF数量,在EMD和EWT中可选设置,默认为None。
- 'alpha': 惩罚因子,在VMD中设置,默认值为2000。
- 'K': 指定分解模态数,仅在VMD中可设置。
- 'tol': 收敛容差,在VMD中设置,是优化的停止准则之一,可以取1e-6~5e-6。
返回值:
- imf: 内涵模态分量,统一为n*m格式,其中n为模态数,m为数据点数。例如imf[0,:]即IMF1,imf[-1,:]即为残差。注意,调用该函数得到的imf,其排列均是从高频向低频排列,这也是为了方便大家研究使用而保持了统一。
- elapsedTime: 程序运行时间,单位为秒。
- reconError: 重构误差。
"""
代码中有七种分解方法的演示案例程序,大家需要做的基本就只需要替换数据就行。
需要上述函数文件以及测试代码的同学,可以在公众号 khscience(看海的城堡)中回复“类EMD”,可以免费获取试用版代码~
扩展阅读
1 Mr.看海:这篇文章能让你明白经验模态分解(EMD)——基础理论篇
2 Mr.看海:这篇文章能让你明白经验模态分解(EMD)——IMF的物理含义
3 Mr.看海:这篇文章能让你明白经验模态分解(EMD)——EMD在MATLAB中的实现方法
4 Mr.看海:希尔伯特-黄变换(HHT)的前世今生——一个从瞬时频率讲起的故事
5 Mr.看海:希尔伯特谱、边际谱、包络谱、瞬时频率/幅值/相位——Hilbert分析衍生方法及MATLAB实现
6 Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第一篇)——EEMD
7 Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第二篇)——CEEMD
8 Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第三篇)——CEEMDAN
9 Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第四篇)——VMD
10 Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第五篇)——ICEEMDAN
11 Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第六篇)——LMD
12 Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第七篇)——EWT
13 Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第八篇)——离散小波变换DWT(小波分解)
14 Mr.看海:“类EMD”算法分解后要怎样使用(1)——内涵模态分量IMF的方差贡献率、平均周期、相关系数的计算及MATLAB代码实现
15 Mr.看海:“类EMD”算法分解后要怎样使用(2)——高频、低频、趋势项分量判别与重构,及MATLAB代码实现
16 Mr.看海:【滤波专题-第7篇】“类EMD”算法分解后要怎样使用(3)——EMD降噪方法及MATLAB代码实现
17 Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第九篇)——小波包变换(WPT)/小波包分解(WPD)
18 Mr.看海:类EMD的“信号分解方法”横向对比详解,EMD,EEMD,CEEMD,CEEMDAN,ICEEMDAN,EWT,VMD优劣对比。附一行代码实现所有分解方法,7合1的MATLAB代码!