类EMD的“信号分解方法”横向对比详解,EMD,EEMD,CEEMD,CEEMDAN,ICEEMDAN,EWT,VMD优劣对比。附一行代码实现所有分解方法,7合1的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方法对同一段信号进行分解,并进行横向对比。

2.1 一个便捷的封装函数

之前专栏中对于每种分解方法都提供了分解和画图函数,不过对于上述方法都有需求同学,使用这7种单独封装的函数不免麻烦的很。

为了解决这一难题,这里要隆重介绍一下新封装的函数,使用一个函数,可以实现上述7中分解方法画图,比如如果想做EMD分解,只需要写:

% 2.1 参数设置
options.MaxNumIMFs = 3; %最大的IMF数量,注意实际分解得到的imf数量可能会小于此数
% 2.2 绘制分解图
[imf,~,elapsedTime,reconError] = pEMDs(data,FsOrT,'EMD', options);   %调用分解画图函数,data为待分解变量

运行后可以得到三张图:

如果绘制分解结果及各分量的频谱图,可以执行下边这样代码:

[imf,~,elapsedTime,reconError] = pEMDsandFFT(data,FsOrT,'EMD', options);  %调用分解画图函数,data为待分解变量

可以绘制出如下图像:

如果要使用其他的分解方法,只需要将上边代码中的'EMD'换成对应的名称即可,比如:

[imf,~,elapsedTime,reconError] = pEMDs(data,FsOrT,'EEMD', options);     %执行EEMD分解和画图
[imf,~,elapsedTime,reconError] = pEMDs(data,FsOrT,'CEEMD', options);    %执行CEEMD分解和画图
[imf,CenFs,elapsedTime,reconError] = pEMDs(data,FsOrT,'VMD', options);  %执行VMD分解和画图
% 其他的分解方法形式类似,不一一列举了

2.2 七种分解方法的横向对比结果

使用上边讲到的函数,实现对同一信号分解的横向比测。

(1)仿真信号

首先生成一组测试信号,由二次趋势项、啁啾信号和分段余弦共同组成,采样频率为1000Hz。

%% 1.生产仿真信号
fs = 1e3;
t = 0:1/fs:1-1/fs;

x = 6*t.^2 + cos(4*pi*t+10*pi*t.^2) + [cos(60*pi*(t(t<=0.5))) cos(100*pi*(t(t>0.5)-10*pi))];

figure('color','w')
tiledlayout('flow')
nexttile
plot(t,[zeros(1,length(t)/2) cos(100*pi*(t(length(t)/2+1:end))-10*pi)])
xlabel('Time (s)')
ylabel('Cosine')

nexttile
plot(t,[cos(60*pi*(t(1:length(t)/2))) zeros(1,length(t)/2)])
xlabel('Time (s)')
ylabel('Cosine')

nexttile
plot(t,cos(4*pi*t+10*pi*t.^2))
xlabel('Time (s)')
ylabel('Chirp')

nexttile
plot(t,6*t.^2)
xlabel('Time (s)')
ylabel('Quadratic trend')

nexttile(5,[1 2])
plot(t,x)
xlabel('Time (s)')
ylabel('Signal')

绘制出来是这样的图像,上边四张图是信号的四个成分,最下边的图像是合成信号,理想状态下我们希望能将该合成信号还原为上边的四个分量。

(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)运行时间

经统计,七种分解方法的运行时间为:

分解方法运行时间
EMD0.011845秒
EEMD1.7365秒
CEEMD1.6244秒
CEEMDAN1.3909秒
ICEEMDAN1.1743秒
EWT0.018225秒
VMD0.063633秒

(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)、程序运行时间、重构误差。

关于这两个函数更详细的参数及介绍可以看这里:

function [imf,CenFs,elapsedTime,reconError] = pEMDs(data,FsOrT,methodSel, options)
% 整合版"类EMD"分解函数,调用该函数将会分解并画图(模态分解图,无频谱),会绘制重构误差图
% 目前可以实现的分解方法包括:
% EMD,EEMD,CEEMD,CEEMDAN,ICEEMDAN,EWT,VMD共7种
% 输入:
% data:待分解的数据(一维)
% FsOrT:采样频率或采样时间向量,如果为采样频率,该变量输入单个值;如果为时间向量,该变量为与y相同长度的一维向量。如果未知采样频率,可设置为1
% methodSel:选择分解方法,可以设置的选项包括:
%            -'EMD'
%            -'EEMD'
%            -'CEEMD'  
%            -'CEEMDAN'
%            -'ICEEMDAN'
%            -'EWT'
%            -'VMD'
% options:其他可设置的参数,使用结构体形式幅值,对于不同分解方法,需要设置的参数有所不同
%         - options.Nstd  为附加噪声标准差与Y标准差之比,默认为0.2 
%         - options.NE    为对信号的平均次数,默认为100
%         - options.MaxIter:最大迭代次数,默认为1000
%         - options.MaxNumIMFs 最大的IMF数量,在EMD和EWT中可选设置,默认为缺省
%         - options.alpha 惩罚因子,在VMD中设置,默认值为2000
%         - options.K     指定分解模态数,仅在VMD中可设置
%         - options.tol   收敛容差,在VMD中设置,是优化的停止准则之一,可以取 1e-6~5e-6
% 输出:
% imf:内涵模态分量,统一为n*m格式,其中n为模态数,m为数据点数。例如 imf(1,:)即IMF1,imf(end,:)即为残差
% 注意,调用该函数得到的imf,其排列均是从高频向低频排列,这也是为了方便大家研究使用而保持了统一
% CenFs:即CentralFrequencies,各imf分量的中心频率,仅VMD分解可以输出
% elapsedTime:程序运行时间,单位为秒
% reconError:重构误差,即原始信号与重构信号之间的均方根误差

% 注意:在使用该代码之前,请务必安装工具箱:http://khsci.com/docs/index.php/2020/04/09/1/

function [imf,CenFs,elapsedTime,reconError]  = pEMDsandFFT(data,FsOrT,methodSel, options)
% 画信号模态分解与各IMF分量频谱对照图,会绘制重构误差图
% 目前可以实现的分解方法包括:
% EMD,EEMD,CEEMD,CEEMDAN,ICEEMDAN,EWT,VMD共7种
% 输入:
% data:待分解的数据(一维)
% FsOrT:采样频率或采样时间向量,如果为采样频率,该变量输入单个值;如果为时间向量,该变量为与y相同长度的一维向量。如果未知采样频率,可设置为1
% methodSel:选择分解方法,可以设置的选项包括:
%            -'EMD'
%            -'EEMD'
%            -'CEEMD'
%            -'CEEMDAN'
%            -'ICEEMDAN'
%            -'EWT'
%            -'VMD'
% options:其他可设置的参数,使用结构体形式幅值,对于不同分解方法,需要设置的参数有所不同
%         - options.Nstd  为附加噪声标准差与Y标准差之比,默认为0.2
%         - options.NE    为对信号的平均次数,默认为100
%         - options.MaxIter:最大迭代次数,默认为1000
%         - options.MaxNumIMFs 最大的IMF数量,在EMD和EWT中可选设置,默认为缺省
%         - options.alpha 惩罚因子,在VMD中设置,默认值为2000
%         - options.K     指定分解模态数,仅在VMD中可设置
%         - options.tol   收敛容差,在VMD中设置,是优化的停止准则之一,可以取 1e-6~5e-6
% 输出:
% imf:内涵模态分量,统一为n*m格式,其中n为模态数,m为数据点数。例如 imf(1,:)即IMF1,imf(end,:)即为残差
% 注意,调用该函数得到的imf,其排列均是从高频向低频排列,这也是为了方便大家研究使用而保持了统一
% CenFs:即CentralFrequencies,各imf分量的中心频率,仅VMD分解可以输出
% elapsedTime:程序运行时间,单位为秒
% reconError:重构误差,即原始信号与重构信号之间的均方根误差

% 注意:在使用该代码之前,请务必安装工具箱:http://khsci.com/docs/index.php/2020/04/09/1/

代码中有七种分解方法的演示案例程序,大家需要做的基本就只需要替换数据就行。

需要上述函数文件以及测试代码的同学,可以在公众号 khscience(看海的城堡)中回复“类EMD”,可以免费获取试用版代码~

扩展阅读

Mr.看海:这篇文章能让你明白经验模态分解(EMD)——基础理论篇

Mr.看海:这篇文章能让你明白经验模态分解(EMD)——IMF的物理含义

Mr.看海:这篇文章能让你明白经验模态分解(EMD)——EMD在MATLAB中的实现方法

Mr.看海:希尔伯特-黄变换(HHT)的前世今生——一个从瞬时频率讲起的故事

Mr.看海:希尔伯特谱、边际谱、包络谱、瞬时频率/幅值/相位——Hilbert分析衍生方法及MATLAB实现

Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第一篇)——EEMD

Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第二篇)——CEEMD

Mr.看海:类EMD的“信号分解方法”及MATLAB实现(第三篇)——CEEMDAN

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)

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.看海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值