简介:遗传算法优化VMD(GA-VMD)技术结合遗传算法与变分模态分解,面向非线性、非平稳信号分析需求,适用于电力系统故障诊断、机械健康监测、声音识别等场景。资源包共27个文件,以15个Matlab脚本为核心,覆盖GA-VMD主程序、VMD分解、样本熵计算等功能,另含2份txt使用说明、2个fig图像、5张jpeg结果图及示例数据Excel和mat文件,整个压缩包约2.3MB,源码与数据组织清晰,可直接运行与二次开发。目前已有460人学习下载。使用时可调整主程序中的种群大小、迭代次数、交叉与变异概率,并结合分解模态数优化曲线、惩罚因子优化曲线和适应度曲线,深入理解参数对分解精度和稳定性的影响,为科研与工程应用提供实用工具。
1. GA-VMD 不是魔法,是把 VMD 的两个“手拧参数”变成了进化搜索问题
做旋转机械故障诊断的同学大概率都遇到过这种尴尬:拿到一段齿轮折断的振动信号,用 VMD 分解,分解效果完全取决于你预先填的模态数 K 和惩罚因子 alpha。K 填小了,故障冲击和齿轮啮合频率挤在一个模态里;K 填大了,一个正常频率被拆成两半,出现模态混叠。反复试凑参数的时间比分析信号本身还长。GA-VMD 解决的问题就是这么直接:把 K 和 alpha 当作遗传算法种群里的个体,用包络熵或样本熵当作适应度,让机器自己去找最优分解参数。这个项目是一套完整的 MATLAB 实现,从 GA 优化到 VMD 分解,再到样本熵特征提取和频谱绘图,全部封装在 .m 文件里。
对需要处理非平稳信号的人来说,这套代码的价值不在于“调通了”,而在于它把优化—分解—特征提取的链路打通了:你能看到每一代 K 和 alpha 如何变化,能看到适应度曲线什么时候收敛。下面我按理论、代码、实战和调参技巧的顺序把这条链路拆开讲。
2. VMD 为什么需要 GA:两个关键参数决定了分解的“分寸”
2.1 VMD 的约束变分模型与 K、alpha 的物理含义
VMD 的做法是把原始信号 f(t) 分解为 K 个固有模态函数 u_k(t),每个模态都围绕一个中心频率 omega_k 波动。它的目标函数是一个约束变分问题:在“所有模态之和等于原信号”的约束下,最小化各模态的带宽估计总和。所谓带宽估计,就是每个模态的解析信号梯度 L2 范数的平方。alpha 是二次惩罚项系数,它约束的是“模态与中心频率的偏离程度”——alpha 越大,模态带宽越窄,对噪声越敏感;alpha 越小,模态越扁,容易把相邻频率成分混在一起。
在实际运行中,K 决定了分解的“细度”。一个 2000 Hz 采样、包含齿轮啮合频率及其边频带的信号,如果 K 设为 3,那么啮合频率和故障特征频率可能被强行绑定在一个模态里;如果 K 设为 8,高频噪声会被分出好几个“假模态”。更麻烦的是,最优 K 会随工况变化:同一台设备,正常状态和断齿状态的最优 K 可能差出 2~3 个。这就是 VMD 需要自动寻优的根本原因——它不是一次标定、长期使用的算法,而是一个需要随信号特性调整的算法。
2.2 遗传算法如何对这两个参数编码并评估优劣
GA 在这个场景里不处理信号,只处理“参数选择”。典型的做法是把 K(取整到 2~10)和 alpha(可取 100~3000)级联编码成个体染色体。在本套代码中,个体向量是一个二维行向量 [K, alpha],K 用整数编码,alpha 用实数编码。种群大小默认为 20 左右,迭代次数 30~50 次,交叉概率 0.8,变异概率 0.05。这些数值不是凭空来的,而是与适应度函数的计算成本有关——每评估一个个体,就要完整跑一次 VMD,振动信号越长、K 越大,这次分解耗时越长。如果种群设到 50、迭代到 100,一晚上可能只够跑一次故障数据。
适应度函数是重中之重。常见做法是计算分解后各 IMF 的包络熵或样本熵,取平均值或最小值作为适应度值。包络熵反映模态的稀疏性与脉冲性:齿轮断齿产生的冲击越明显,某个模态的包络熵越低,说明分解越贴合故障特征。因此 GA 的适应度方向是“越小越好”。本套代码里同时预留了 Sample_Entropy.m 和 ShannonEn.m 两种熵计算接口,前者适合对模态复杂度建模,后者适合衡量包络谱稀疏性。
提示:适应度函数不要只盯均值。若某一模态包络熵极低、其他模态一团糟,均值会被“平均”掉。建议至少看一眼最优个体的全部 IMF 包络熵分布,再做最终判定。
GA 的三个遗传算子在这个项目里的具体表现:
- 选择采用锦标赛选择,每次随机取两个个体比较适应度,胜者进入交配池,避免轮盘赌在适应度数值接近时失去选择压力。
- 交叉采用算术交叉,两个父代的 alpha 分量按线性插值产生子代,K 分量在取整后做均匀交叉。
- 变异是对 alpha 做高斯扰动,对 K 以一定概率替换为上下界内的随机整数,变异步长随迭代次数衰减,前期粗搜、后期精调。
3. 工程链路拆解:从 main_gavmd.m 到 VMD.m 的调用与参数映射
3.1 文件清单与调用关系
拿到 ga-vmd.zip 解压后,核心文件大致分三组:优化组、分解组、特征与绘图组。优化组是 GA_VMD.m、fun.m、Cross.m、Mutation.m;分解组是 VMD.m 和 select.m;特征与绘图组是 Sample_Entropy.m、ShannonEn.m、plot_fft.m、fig_show.m、fig_text.m。主程序是 main_gavmd.m,它负责加载信号、调用 GA、绘制收敛曲线,并把最终 K 和 alpha 传回 VMD.m。
调用顺序非常清晰:main_gavmd.m 先读入信号,然后调用 GA_VMD.m 做全局寻优。GA_VMD 每评估一个个体,就调用一次 fun.m,fun.m 内部把个体解码成 K 和 alpha 后调用 VMD.m 完成分解,分解得到的所有 IMF 输入 Sample_Entropy.m 计算出适应度。迭代结束后,最优个体再被送入 VMD.m 做一次最终分解,输出 imf 分量的时域图和频谱图。这套结构的好处是每个模块可以单独替换——你想把自己的适应度函数加进去,只需要改 fun.m 的返回值。
3.2 main_gavmd.m 中的参数设置与调用代码
打开 main_gavmd.m,核心的 GA 参数区块大致如下:
%% 遗传算法参数设置 pop_size = 20; % 种群规模 max_gen = 30; % 最大迭代次数 pc = 0.8; % 交叉概率 pm = 0.05; % 变异概率 K_bound = [2, 10]; % 模态数搜索范围 alpha_bound = [100, 3000]; % 惩罚因子搜索范围 %% 加载信号 data = load('齿轮折断状态测试组.txt'); sig = data(:, 2); % 通常第二列为振动加速度 fs = 8192; % 采样频率,按实际修改 %% 调用GA-VMD [best_K, best_alpha, fitness_curve, best_curve] = ... GA_VMD(sig, fs, pop_size, max_gen, pc, pm, K_bound, alpha_bound); %% 用最优参数做最终分解 [u, u_hat, omega] = VMD(sig, alpha_bound(end), 0, best_K, 0, 1, 1e-7);这段代码里最需要注意的有三点:采样频率 fs 必须与本数据的实际采样率一致,否则后面频谱图的横坐标全部错误;K_bound 的上限不要设得太大,VMD 中 K 超过信号实际可分离模态数后会出现虚假模态,且单次分解时间线性增长;alpha_bound 的范围建议按信号幅值量级调整,若信号经过归一化处理,alpha 取 100~3000 足够覆盖大多数场景。
GA_VMD.m 的内部循环结构也不复杂,每代先按锦标赛选择父代,再做交叉和变异得到子代种群,随后逐个调用 fun.m。fun.m 里 VMD 分解参数的选取很关键:VMD.m 的第三个参数是噪声容忍度 tau,多数场合设 0;第四个参数是 DC 分量控制,设 0 表示不考虑直流;第六个参数 init 设为 1 表示中心频率采用均匀初始化。这里不要随意调整,否则会导致同一组 K 和 alpha 在不同次运行中得到不同的分解结果,让 GA 的适应度评估失去确定性。
3.3 适应度函数的挂载方式
fun.m 是整套代码的灵魂,它决定 GA 在朝哪个方向搜索。本套代码默认的计算逻辑如下:
function fitness = fun(individual, sig, fs) K = round(individual(1)); alpha = individual(2); [u, ~, ~] = VMD(sig, alpha, 0, K, 0, 1, 1e-7); entropy_list = zeros(1, K); for i = 1:K entropy_list(i) = Sample_Entropy(u(i, :), 2, 0.2 * std(u(i, :))); end fitness = mean(entropy_list); % GA 最小化 end这里的 Sample_Entropy 函数参数分别是数据序列、嵌入维度 m 和相似容差 r。嵌入维度一般取 2,r 取 0.1~0.25 倍原始序列标准差,这是一种成熟的工程经验值。r 太小则熵值对噪声敏感,r 太大则不同状态的熵值差异被抹平。如果你处理的是强噪声信号,建议把 r 适当调大到 0.2~0.3 倍标准差,故障冲击的熵差依然能保留下来。
注意:VMD.m 的输出 u 是 K x N 的矩阵,N 为信号长度,行向量是一个 IMF。Sample_Entropy.m 要求输入为行向量,如果你的数据是列向量,先做转置,否则会报维度错误。
4. 齿轮折断数据实战:从原始振动信号到 IMF 样本熵特征
4.1 数据准备与预处理
项目自带的“齿轮折断状态测试组.txt”是典型的齿轮箱故障模拟数据,包含一个齿完整折断后的振动加速度时程。拿到数据后,不要直接丢进 VMD,先做两件基础工作:去均值和幅值归一化。齿轮振动信号往往含有直流偏置,VMD 对直流分量非常敏感,若不去均值,第一个 IMF 会默认变成一个近似直流的低频分量,挤压真实故障模态的空间。我做实战时会先写一段预处理:
data = load('齿轮折断状态测试组.txt'); sig = data(:, 2); sig = sig - mean(sig); % 去直流 sig = sig / max(abs(sig)); % 归一化到 [-1,1] fs = 8192; % 按实际采样率填入归一化之后再喂给 GA-VMD,alpha 的搜索范围就可以固定在 100~3000,不会因为原始信号幅值达到 10 m/s² 而把最优 alpha 推到上万。这是很多第一次用该代码的人最容易踩的坑——不看量级直接套默认参数,结果 GA 迭代几十代仍然找不出合理的模态分解。
4.2 分解结果与时域/频谱解读
跑完 main_gavmd.m 后,工作区会出现 imf 分量,同时生成 imf 分量的时域图.fig 和 imf 分量的频谱图.jpeg。以断齿故障为例,我通常设 pop_size=20、max_gen=30,大约 15 代后适应度曲线已经趋于平缓,得到的最优解常落在 K=5~7、alpha 约 1200~2000 之间。分解出的前两个 IMF 分别对应齿轮啮合频率附近的高频载波及断齿冲击产生的边频带。第三、四个 IMF 则是故障特征频率及其倍频成分,时域上能看到明显的周期性冲击脉冲。
频谱图的读取要结合齿轮箱具体参数。假设该测试齿轮的齿数 Z=32,轴的转频 fr=10 Hz,则啮合频率 fm=fr*Z=320 Hz,断齿故障特征频率就是转频 10 Hz 及其倍频。在 VMD 的频谱图里,最理想的 IMF 应该只包含以某个中心频率为中心的窄带谱峰,左右各有几个调制边频带。如果某个 IMF 的频谱图出现三个以上的分离峰,说明 K 可能偏小,故障频率和某个干扰频率被绑在了同一个模态里;如果相邻两个 IMF 的主峰频率非常接近,比如 315 Hz 和 318 Hz,说明 K 偏大导致模态混叠。这套判据在参数调试时非常有用。
4.3 用样本熵量化分解效果并区分故障状态
样本熵是衡量时间序列复杂度的指标,故障冲击越规则、周期性越强,对应模态的样本熵往往越低。我常把分解后的 IMF1~IMF6 的样本熵计算出来,做成特征向量作为后续分类器的输入。项目中的 Sample_Entropy.m 可以直接调用:
for i = 1:best_K SE(i) = Sample_Entropy(u(i, :), 2, 0.15 * std(u(i, :))); end对一组健康齿轮和一组断齿齿轮分别做 GA-VMD 分解,取适配度最好的前 4 个 IMF 的样本熵,典型的表现是:
| 状态 | IMF1 样本熵 | IMF2 样本熵 | IMF3 样本熵 | IMF4 样本熵 |
|---|---|---|---|---|
| 正常 | 0.31 | 0.27 | 0.24 | 0.22 |
| 断齿 | 0.38 | 0.21 | 0.15 | 0.12 |
断齿状态下 IMF3、IMF4 的熵值明显下降,是因为故障冲击把能量集中在少数模态中,使得这些模态的波形趋向规则脉冲,复杂度降低。而 IMF1 的熵值上升,往往是因为断齿引起的调制加大了高频载波的随机波动。实际判断时,不要只看单个 IMF 的熵值,要观察整个熵值序列的落差和分布。若训练 SVM 或 KNN,把全部 IMF 的样本熵连成一个特征向量比只取前三个更稳定。
5. 收敛曲线判读技巧:适应度、K 和 alpha 三条曲线一起看
5.1 三种曲线的各自职责
GA-VMD 运行结束后会输出适应度曲线、分解模态数的优化过程曲线和惩罚因子的优化过程曲线。这三条曲线不是装饰,而是判断 “优化是否真收敛” 的关键。
适应度曲线描述的是每一代最优个体的包络熵均值变化。健康状态下,它通常前 5 代快速下降,之后逐渐平稳,最终停留在一个较小的值。断齿状态下,由于冲击分量明显,曲线前段的下降斜率会更陡。如果适应度曲线从第 1 代到第 30 代一直在锯齿状跳动,没有任何收敛趋势,说明适应度函数对参数变化过于敏感,多半是 alpha 搜索范围过宽、VMD 分解不稳定产生的,此时应缩小 alpha_bound。
最优 K 的曲线反映 GA 搜索模态数的路径:初期 K 在 2~10 之间大幅跳动,后期稳定在某个值附近。若末期 K 仍然在相邻整数间反复横跳,表示不同 K 值对应的适应度差异小于 VMD 分解的数值噪声,这时不需要纠结 K 的精确值,取两个 K 值中适应度更低的一个即可。最优 alpha 的曲线更平滑,因为 alpha 是连续变量,GA 在真实值附近会做高斯精密搜索。若 alpha 的最终值紧贴搜索边界,比如正好等于 3000,说明你的界限设窄了,应该扩大上界重新运行。
5.2 一个实用技巧:先粗定 K,再单独调 alpha
我在处理现场数据时常用一个省时间的方法:第一次运行把 max_gen 设为 15,alpha_bound 放宽到 [100, 5000],K_bound 设为 [2, 10],目的是让 GA 快速定位 K 的大致范围。得到初步最优 K 后,把 K 固定为这个整数,手动对 alpha 做 5 次 VMD 扫描,alpha 取 500、1000、1500、2000、2500,计算每次的包络熵均值,画出 alpha—熵值曲线。选择熵值最低的 alpha,再以它为中心做一次小范围搜索。这样做比把 GA 的所有代都花在不同 K 的试凑上高效得多,尤其当你一次要处理几十组实验数据时。
另一个容易忽略的细节是:每次运行 GA-VMD 之前,一定要在命令窗口执行clear; close all;清空工作区。这套代码中的main_gavmd.asv是 MATLAB 自动保存的备份文件,不是有效程序入口。运行 Code.m 和 test.m 之前,检查是否与 main_gavmd.m 在同一目录且没有函数名冲突。如果出现 “无法识别函数 VMD” 的报错,优先检查 VMD.m 是否真的在 MATLAB 搜索路径下,而不是直接怀疑 GA 优化逻辑。做故障诊断时,把最终保存的 imf 分量时域图与原始信号的包络谱对照一下:若 VMD 的某个 IMF 包络谱中存在清晰的故障特征频率,说明 GA 确实找到了有物理意义的参数组合。
本文还有配套的精品资源,点击获取