简介:这是一份基于MATLAB的VMD(变分模态分解)算法实现与演示资源,面向信号处理、故障诊断及数据分析方向的学习者,主要解决模态混叠下如何自适应确定分解阶数的问题。包内包含14个文件,涵盖4个MATLAB脚本(m)、1个数据文件(mat)、3个图像文件(jpg)及3个图形文件(fig),另有3个备份脚本(asv),合计约1.33MB,便于直接运行和二次修改。围绕中心频率相近原则,算法可在分解后自动梳理各模态分量的中心频率,辅助判断最佳分解层数,避免人为设定阶数带来的不确定性。附带三个示意图与对应fig图窗,可直观看到原始信号、小波包结果及分解效果。已有622人学习下载,资源体量适中,适合初学者快速上手,也适合用作教学演示或论文实验的基础框架。
1. 从频带混叠到可复现分解:VMD 为什么值得自己写一遍
做振动信号、电力谐波或脑电分析的人,大概率都遇到过这类尴尬:用 EMD 分解出十几个 IMF,模态混叠严重,根本分不清哪个分量对应哪条物理频带;试着换小波包,又得为母小波和分解层数吵半天。变分模态分解(VMD)把问题改写成变分优化,不再是递归筛信号,而是一次性把信号拆成若干个带限模态,每个模态都有自己的中心频率和带宽。这个思路带来的直接好处是,分解结果在大多数场景下比 EMD 稳定,中心频率可以打印成表格,模态数量 K 也不靠肉眼猜,能通过频率间隔算出来。
本篇文章围绕 VMD 在 MATLAB 下的完整落地路径展开,从算法参数含义讲到怎么用中心频率判断过分解,再给出判定最佳阶数的可执行方案。你不需要提前懂凸优化,但最好用过 MATLAB 的脚本编辑器,并且知道 FFT 是什么。文中涉及的代码都能直接复制到 R2016b 及以上版本运行,不依赖第三方工具箱。适合正在做故障诊断、信号去噪、时频分析,或者正在为论文里的"分解层数怎么定"补实验的工程师和研究生。
2. VMD 的核心机制与 MATLAB 里绕不开的四个参数
VMD 全称 Variational Mode Decomposition,2014 年由 Dragomiretskiy 和 Zosso 提出。它的目标是把实信号 f(t) 分解为 K 个模态 u_k(t),每个模态是调幅调频信号,具有各自的中心频率 ω_k。求解时构造带约束的变分问题:每个模态的带宽估计值之和最小,同时所有模态之和等于原信号。约束问题的求解采用乘子交替方向法(ADMM),把原问题转化为迭代更新 u_k、ω_k 和拉格朗日乘子 λ 三个子问题,迭代到满足收敛条件为止。
2.1 VMD 与 EMD 的本质差异:从递归筛选到变分优化
EMD 的做法是"筛",每轮找极值包络、减均值,把最高频成分先剥出来,剩余信号继续迭代,误差会沿着分解路径逐级累积,且对采样率和噪声敏感。VMD 则把问题转化为“给定 K 个中心频率,求一组带宽受限的模态”,在频域内完成求解,不需要递归,也就没有包络拟合带来的累积误差。
这带来的直接好处是模态之间的频率重叠明显更少。以两个频率非常接近的正弦分量(50 Hz 和 55 Hz)为例,EMD 往往只能分解出一个混合分量,或者产生端点飞翼;VMD 只要把惩罚因子调到合理区间,两个中心频率能在迭代中分离到各自的窄带上。代价是 VMD 需要预设 K 值,且算法对 K 和惩罚因子 α 的敏感度比 EMD 对停止条件的敏感度更高。K 设大了会出现虚假模态,设小了会把两个本应独立的分量压成一个模态,这是后面用中心频率定阶的动机来源。
2.2 MATLAB 中 VMD 的调用方式与返回值结构
MATLAB 从 R2019a 开始内置 vmd 函数,位于 Signal Processing Toolbox 中。如果没有该工具箱,也可以从 File Exchange 找到原始实现,两者核心逻辑一致,只是返回值结构不同。下面以内置函数为例说明。
% 生成仿真信号:两个正弦 + 一个调幅分量 + 小幅噪声 fs = 1000; % 采样率 1000 Hz t = (0:1999) / fs; % 2 秒 f1 = 50; f2 = 120; f3 = 200; x = 1.5 * sin(2*pi*f1*t) + 0.8 * sin(2*pi*f2*t) + (1 + 0.5*cos(2*pi*t)) .* sin(2*pi*f3*t); x = x + 0.05 * randn(size(t)); % 高斯白噪声 % 调用 vmd,隐式参数使用默认值 [imf, res] = vmd(x);这段代码把信号分解成一组模态,imf 的每一列是一个模态,res 是残差分量。vmd 默认使用 K = 5,惩罚因子 α 由内部估计得到,当信号频率成分完全未知时,这个默认设置只能作为起点,不能作为结论。后面的分析会基于 imf 逐列计算中心频率,再反过来判断 K 设定是否合理。
2.3 惩罚因子 α、K、τ 和 DC 的实际含义
| 参数 | 作用 | 设置建议 |
|---|---|---|
| K | 模态个数 | 从 3 或 5 起步,通过中心频率相近原则校验 |
| α | 带宽惩罚因子 | 默认值偏保守;信号频率相近时调大到 2000~5000 |
| τ | 噪声容限 | 0 表示无噪声;噪声明显时取 1e-6 到 1e-4 |
| DC | 是否把直流分量单独作为第 1 个模态 | 有直流偏置时选 1 |
α 是 VMD 参数中最重要的一个,它控制着模态带宽的宽容度。α 越大,每个模态的带宽越窄,中心频率分离得越开,但太大会导致模态丢失边缘频率信息;α 越小,带宽越宽,低频和高频之间的混叠会加剧。以 50/120 Hz 的双频仿真信号为例,α 从默认值降到 500 时,两个中心频率依然能够分开,但 50 Hz 模态的频率响应会出现旁瓣泄漏;把 α 升到 5000,两个模态的频率曲线更干净,但收敛速度会变慢。
τ 只在带噪场景下有意义,VMD 原论文中给出的建议是当信号含噪时设为较小的正数,起平滑作用。实际排查时,先固定 K = 3,把 α 分别取 1000、3000、5000 跑三遍,打印中心频率,看频率值是否偏移;若 α 在较大范围内中心频率保持稳定,说明该 K 下的分解结构是可信的。这比直接看时域波形判断混叠要准确得多。
3. 用 MATLAB 实现 VMD 分解并量化各模态的中心频率
有了基础调用之后,需要解决两个实际问题:第一,vmd 输出的 imf 不保证按频率排序,用于后续分析时需要先算每个模态的中心频率并重新排列;第二,如何量化中心频率,不能靠频谱图上目测峰值,而要用能量加权或峰值检测得到相对稳定的数值。
3.1 频谱峰值法快速估算中心频率
最简单直接的做法是取每个模态的 FFT 幅度谱,找到幅度最大的频率点作为中心频率。对于仿真信号,这条路径是可靠的;但对真实信号,频谱峰值可能落在一个毛刺上,导致中心频率抖动。下面给出一个足够稳健的代码段,用于批量计算所有模态的中心频率和带宽估计:
% 对 imf 逐列计算幅度谱和中心频率 N = size(imf, 1); f_axis = (0:N-1) * fs / N; % 频率轴 num_modes = size(imf, 2); center_freqs = zeros(1, num_modes); bandwidths = zeros(1, num_modes); for k = 1:num_modes spec = abs(fft(imf(:, k))); spec_half = spec(1:floor(N/2)); % 取单边谱 f_half = f_axis(1:floor(N/2)); [~, idx] = max(spec_half); center_freqs(k) = f_half(idx); % 以峰值 3dB 带宽估计该模态的宽度 half_max = spec_half(idx) / sqrt(2); above_idx = find(spec_half >= half_max); if ~isempty(above_idx) bandwidths(k) = f_half(above_idx(end)) - f_half(above_idx(1)); end end % 按中心频率升序排列 [center_freqs_sorted, sort_idx] = sort(center_freqs);这段代码中,spec_half 取前 N/2 个点来获得单边谱,是出于实信号频谱对称的考虑;half_max 用幅度除以 sqrt(2) 而不是除以 2,对应功率的 3dB 衰减点,这样带宽估计和信号处理惯例一致。排序的目的是让后续“中心频率相近原则”的判断逻辑更直观,从低频到高频逐个检查相邻模态之间的间隔。
3.2 用能量加权代替峰值法应对噪声干扰
真实信号的频谱往往没有清晰的单峰,直接用幅度最大值作为中心频率会带来随机误差。常见的改进方式是取该模态功率谱的能量加权平均频率,重量在功率高的频带上自然压低噪声的影响。代码实现如下:
% 能量加权频率:频率按功率占比加权求和 center_freqs_weighted = zeros(1, num_modes); for k = 1:num_modes spec = abs(fft(imf(:, k))).^2; % 功率谱 spec_half = spec(1:floor(N/2)); f_half = f_axis(1:floor(N/2)); total_power = sum(spec_half); if total_power > 0 center_freqs_weighted(k) = sum(f_half .* spec_half) / total_power; else center_freqs_weighted(k) = NaN; end end能量加权频率对谱峰形状不敏感,在模态带宽较宽或者受临近分量泄漏影响时,加权值更接近该模态的“质心频率”。实际做法是同时算峰值法和加权法,两者差值小于 5% 时说明该模态形态规整,差值过大说明频谱不干净,需要检查是不是出现了虚假模态或者参数不合适。
3.3 在噪声场景下验证分解有效性
部署上述计算前,先把上一节仿真信号的信噪比从 20dB 降到 5dB,重新运行 vmd,你会看到中心频率不再是精确的 50/120/200,而是会偏移,部分模态之间可能出现边界模糊。此时把 vmd 的 τ 从 0 改为 5e-5,再做一次分解,对比两个中心频率序列。这个流程可以用于检查自己的信号是否处于 VMD 的适用范围——如果提高 τ 之后中心频率变化超过 10%,说明当前 K 下的分解不稳定,优先检查参数而不是信号。
提示:中心频率是个统计量,不要用一次分解的结果下结论。同一段数据换不同的起始点做多次分解,观察中心频率的标准差,标准差小于 1 Hz 才说明 K 的选取是可信的。
4. 基于中心频率相近原则确定最佳阶数 K 的完整判据
VMD 最麻烦的问题永远是 K 定多少。K 过小,模式混叠;K 过大,出现虚假模态。中心频率相近原则提供了一种客观判断路径:对同一信号,从小到大依次取 K,分解后提取各模态中心频率;当 K 增大时,若新增模态的中心频率与既有模态高度接近(小于设定阈值),说明 K 已经超出信号实际包含的模态数量,上一档 K 就是最佳阶数。
4.1 中心频率相近原则的数学定义与阈值设定
设有 K 个模态的中心频率集合 ω = {ω_1, ω_2, …, ω_K},相邻频率间隔定义为 Δω_i = ω_{i+1} - ω_i,(i = 1, 2, … K-1)。当 K 增加到 K+1 后,新的频率集合中有至少一个元素与旧集合的某个元素满足 |Δω| < ε·fs,即可判定发生过分解。ε 是归一化阈值,取值在 0.01~0.05 之间,对应采样频率的 1%~5%。
对 fs = 1000 Hz 的信号,ε = 0.02 意味着两个中心频率差距小于 20 Hz 就判为接近。这个值用在工频信号上偏大,用于故障诊断的高频振动信号(几百赫兹量级)则需要取下限 0.01,避免把本应合并的模态拆开。更稳妥的做法是用频率比来判断:当新增模态的中心频率落在已有模态中心频率的 ±10% 区间内时,认为发生过分解。
4.2 遍历 K 值并记录中心频率的 MATLAB 脚本
下面这段脚本把从 K=2 到 K=8 的遍历和频率记录封装为一个函数,输出一个矩阵,方便观察 K 变化时中心频率的演化趋势:
function freq_table = sweep_vmd_k(x, fs, Kmax) % 遍历不同 K 值,记录每个模态的中心频率 % 输入:x 为信号,fs 为采样率,Kmax 为最大分解层数 % 输出:freq_table 为 Kmax 行矩阵,每行对应一个 K 值的中心频率结果 freq_table = nan(Kmax, Kmax); % 预分配,空位填 NaN for K = 2:Kmax [imf, ~] = vmd(x, 'NumIMF', K, 'Alpha', 3000); n_modes = size(imf, 2); N = length(x); f_axis = (0:N-1) * fs / N; row_freqs = zeros(1, n_modes); for k = 1:n_modes spec = abs(fft(imf(:, k))); spec_half = spec(1:floor(N/2)); f_half = f_axis(1:floor(N/2)); [~, idx] = max(spec_half); row_freqs(k) = f_half(idx); end row_freqs = sort(row_freqs); % 升序排列 freq_table(K, 1:n_modes) = row_freqs; end end脚本运行时,freq_table 第 i 行即有 i 个有效数值。观察行的演化:如果第 K 行的中心频率与 K-1 行的前 K-1 个频率几乎一致,只是新增了一个低频或高频模态,说明新增模态可能是真实分量;如果第 K 行的新增模态中心频率落在旧有某两个模态之间,且和其他模态距离极近,则发生虚假分解的概率很高。
4.3 中心频率去重与间隔判断的自动判定流程
人工看表判断适合小数据量,但真实项目里往往需要批处理许多段信号,需要把判断流程自动化。下面给出一个依据频率间隔做自动筛选的脚本片段:
% 依据最小频率间隔判断过分解 function best_K = find_best_K(freq_table, fs, min_gap_ratio) % min_gap_ratio 为归一化最小间隔阈值,建议 0.02~0.05 min_gap = min_gap_ratio * fs; % 换算为实际频率 for K = 2:size(freq_table, 1) freqs = freq_table(K, ~isnan(freq_table(K, :))); if length(freqs) < 2 best_K = K; break; end gaps = diff(freqs); if min(gaps) < min_gap best_K = K - 1; % 当前 K 发生过分解,回退 return; end end best_K = size(freq_table, 1); % 兜底 end这段逻辑的核心是:从低 K 起检查相邻频率间隔,出现间隔小于阈值的时刻,就认定当前 K 产生了虚假模态,返回上一档 K 作为最佳值。注意,这个阈值必须根据信号特性具体标定,不能所有场景都用同一数值。频率间隔阈值设置得过小,过分解检不出;设置得过大,会把真实存在的相邻频率成分误判为同一模态。兼顾两者的实践方式是同时打印中心频率表格和频带宽度,当模态带宽明显大于相邻间隔时,即使间隔高于阈值,也建议视为不稳定解。
4.4 不同信号类型下阈值的调整策略
| 信号类型 | 典型频率范围 | 推荐 min_gap_ratio | 注意事项 |
|---|---|---|---|
| 工频/电网信号 | 50~400 Hz | 0.05 | 间隔可以放宽 |
| 机械设备振动 | 500 Hz~10 kHz | 0.01 | 需要精确分离边频带 |
| 脑电/生理信号 | 0.5~100 Hz | 0.02 | 低频段中心频率偏差小 |
| 音频信号 | 20 Hz~20 kHz | 0.02 | 需结合人耳感知频带 |
机械设备振动信号中常见的故障特征频率及其谐波、边频带往往靠得极近,中心频率间隔小是常态,此时阈值的细微变化会直接影响 K 值判定的结果。应对方法是把中心频率相近原则和残差能量占比规则结合使用:分解后残差的均方根能量大幅下降,同时过分解检查通过,此时的 K 才可被记为最佳阶数。
5. 验证最佳 K 值的实操技巧与边界情况处理
5.1 中心频率稳定性曲线验证法
遍历 K 值之后,画一张中心频率演化曲线图,横轴为 K 值,纵轴为中心频率,每个模态的频率点用不同颜色标记。一个正常收敛的 VMD 分解会表现出如下特征:当 K 从最佳值往上加时,新出现的模态中心频率会与老模态中心频率在图中重叠或阶梯状靠拢;当 K 小于最佳值时,频率点之间呈现明显的空白间隔。具体绘图代码不再展开,核心是利用前一步已经算好的 freq_table,用 plot 按行绘制即可。
这张图比任何数值表都更直观,适合贴在故障诊断报告或论文附录中。审稿人或现场工程师看到中心频率几乎重合的点,就能明白 K 的取值为什么需要设在这个档位。
5.2 对欠分解和过分解分别做校正
欠分解时,最常见的是两个真实分量被压缩成一个模态,模态的中心频率落在二者之间,时域波形呈现拍频现象,频谱上表现为一个宽峰或双峰。处理方式是增大 K 并调大 α,迫使算法把该频带劈开。具体到 MATLAB 中,可以保持 K 不变,将 α 提高一倍再分解,观察中心频率附近幅度谱是否出现凹陷;如果凹陷出现,说明原本就是两个分量。
过分解时,虚假模态会出现在能量极低的频带上,其中心频率可能是任意值。检查方式是对每个模态计算能量占比,低于总能量 1% 的模态先标记为疑似虚假模态,再结合中心频率和相邻模态比较,确认后直接丢弃该 K 值。两个现象叠加出现时,以中心频率相近原则为准,残差能量作为辅助判断,避免人为挑选结果的嫌疑。
5.3 免于参数困扰的快速排错清单
- vmd 内置函数的输入参数名在不同版本有差异,报错时先用 doc vmd 查看当前版本支持的键值对,R2023b 之前的写法要注意 NumIMF 参数名是否可用。
- 中心频率总是靠近低频端、模态波形严重拖尾时,是 α 设置太小,不是 K 的问题,优先调整 α。
- 分解结果中第一个模态持续为 0 或几乎为 0,检查信号是否去均值;未去均值的信号会导致 VMD 在直流附近分配一个无效模态。
- 仿真信号实验中,用 randn 产生的噪声每次运行结果不同,固定随机种子 rng(1) 保证可复现。
5.4 边界情况:非平稳调频信号和极短信号的适用边界
当信号的瞬时频率随时间快速变化时(例如线性调频信号),中心频率本身失去了“中心”含义,VMD 的收敛能力和分解精度都会下降,中心频率相近原则的可靠性也随之降低。此时应改用时频分析工具或重新设计信号模型,不要强行套用 VMD。
极短信号(少于 20 个振荡周期)分解出的中心频率分辨率受限,FFT 的频率分辨率是 fs/N,N 过小时中心频率的量化误差可能掩盖真实的频率间隔,导致相近原则失效。般做法是把信号补零加长后再计算中心频率,补零不改变频谱峰值位置,但能提高插值密度,减小量化误差。
本文还有配套的精品资源,点击获取