ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

RLMD信号分解算法详解:原理、MATLAB实现与故障特征提取

RLMD信号分解算法详解:原理、MATLAB实现与故障特征提取 这段时间一直在折腾信号分解尤其是有一次处理一组旋转机械的振动仿真数据时FFT频谱上看不出任何故障特征试了经验模态分解又觉得模态混叠得一塌糊涂。后来我把目光转向鲁棒局部均值分解RLMD整个分析流程才真正打开缺口。如果你也在做机械故障诊断、生物医学信号处理或者应对非线性非平稳信号的分解需求这篇内容应该能帮到你。我会把RLMD的原理、MATLAB代码骨架、参数调节、实际案例和踩坑经验一次讲透不绕弯子。1. RLMD 和 LMD 的差异在哪里1.1 为什么传统 LMD 让人又爱又恨局部均值分解LMD和 EMD 一样属于自适应时频分析方法目标是把一个复杂信号拆成若干个有物理意义的分量。但与 EMD 分解出 IMF 不同LMD 分解出的是乘积函数Product Function简称 PF。每个 PF 都由一个包络信号和一个纯调频信号相乘得到瞬时幅值信息和瞬时频率信息天然分开这在分析调幅-调频信号时非常有优势。LMD 的基本思路是不断从信号中减去局部均值再用包络解调把一个复杂信号分离成多个 PF 和一个残余项。听起来很美好但真正上手之后你会发现几个痛点。第一包络估计依赖滑动平均窗口宽度得靠人拍脑袋选不对时包络曲线失真严重。第二信号两端的极值点缺失导致端点处边界效应明显分解结果两边经常发散。第三内部筛选迭代到底跑多少次该停没有可靠判据固定次数很容易把纯调频信号迭代成“砖头”。这三个问题不解决LMD 在实际数据分析上就不可用。1.2 RLMD 的鲁棒性体现在哪几个环节RLMD 的全称是 Robust Local Mean Decomposition核心思路就是把上面三个“人为选参”的环节全部变成自适应过程。一是在包络估计环节不再是单一滑动平均而是在多种插值/平滑策略中根据信号局部特征自动挑选最优方式这样在处理强冲击、弱调制等不同形态信号时都有更好的包络贴合度。二是在边界条件处理上通过候选边界延拓方案的自动择优来抑制端部发散常见候选包括镜像延拓、对称延拓、线性外插延拓等。三是在迭代终止判据上引入了收敛指标判断筛选迭代不再靠固定次数硬停而是让算法自己判断该停在哪一步。我自己的体会是RLMD 最值钱的地方不是某个巧妙的数学技巧而是它把“调试成本”从使用者身上转移到了算法内部。你用默认参数跑大多数信号都能得到一个相对合理的分解结果这在工程环境下实在太重要了。2. MATLAB 动手实现 RLMD 核心框架2.1 主循环与数据结构设计在 MATLAB 里实现 RLMD前提是理解它的两层循环结构。外层循环负责剥离出一个又一个 PF内层循环负责对当前待分解信号做“筛选”让它逐渐逼近纯调频信号。我习惯把最简实现拆成三个子函数再加一个主循环脚本。子函数分别是边界延拓、极值点搜索、包络计算。先看主循环骨架function [PFs, residual] my_rlmd(x, params) if nargin 2, params rlmd_default_params(); end x x(:).; N length(x); PFs zeros(params.max_pf, N); res x; pf_cnt 0; for k 1:params.max_pf h res; % 内层迭代筛选纯调频信号 for it 1:params.max_iter % 边界延拓后提取极值点 h_ext boundary_extend(h, params.boundary, params.ext_len); [iM, im] find_extrema(h_ext); if numel(iM) 2 || numel(im) 2 break; end % 计算上、下包络与局部均值 u_ext envelope_by_method(h_ext, iM, params.env_method); l_ext envelope_by_method(h_ext, im, params.env_method); u u_ext(params.ext_len1:end-params.ext_len); l l_ext(params.ext_len1:end-params.ext_len); m (u l) / 2; a abs(u - l) / 2; % 减去均值用包络解调 h h - m; a max(a, eps); % 防止除零 h h ./ a; % 判断是否已收敛为纯调频信号 if max(abs(a - 1)) params.conv_th break; end end % 内层结束后重新计算最终包络并生成 PF h_ext boundary_extend(h, params.boundary, params.ext_len); [iM, im] find_extrema(h_ext); u_ext envelope_by_method(h_ext, iM, params.env_method); l_ext envelope_by_method(h_ext, im, params.env_method); a abs(u_ext - l_ext) / 2; a a(params.ext_len1:end-params.ext_len); PF a .* h; PFs(k, :) PF; res res - PF; pf_cnt k; % 判断剩余分量是否已没有足够极值点 [iM2, im2] find_extrema(res); if numel(iM2) 2 || numel(im2) 2 break; end end PFs PFs(1:pf_cnt, :); residual res; end这个代码框架可以直接跑通但我必须强调两点。第一边界延拓长度 ext_len 不能太少否则端点效应没消除也别太长否则延拓部分的极值点会污染真实信号。我的经验值是取信号长度的 5% 左右上限 100 点左右。第二外层循环剥离 PF 后剩余分量 res 的极值点数量会快速减少当少于 2 对时说明信号已经单调或趋于平稳没有继续分解的必要。2.2 三个最容易写错的地方第一个坑是边界延拓的索引偏移。你在扩展序列上找到了包络和均值但如果不把扩展部分切掉就参与后续计算结果会整体平移PF 的起点和终点完全错位。所以我在代码里特意用u_ext(ext_len1:end-ext_len)把延拓区域裁掉保证和原始信号对齐这一步一定要写对。第二个坑是极值点搜索的“平台段”问题。很多实际信号存在连续几个采样点数值相同的情况常规的diff(sign(diff(x)))方法会漏掉这些平台两端的极值点导致包络估计出现偏差。我的做法是在搜索极值点之前先对信号做一次毫米级的扰动或者写循环搜索时把等值两侧的情况都考虑进去。第三个坑是包络为负或为零。包络信号理论上应该是非负的但由于插值方法不当或噪声干扰计算出来的上包络和下包络可能在局部发生交叉导致abs(u-l)/2出现异常小值。我的处理是加一个eps保护并在调试阶段把包络曲线画出来看一旦发现交叉位置就要考虑切换插值策略。3. RLMD 调参指南参数表与不同信号场景3.1 关键参数速查表很多朋友拿到 RLMD 代码就问“参数怎么设”这里我整理了一份简明参数表都是实际调试中的有效范围。需要说明的是这些参数相互之间有耦合不要单独调某一个。参数名含义常用范围注意事项max_pf最大 PF 分解层数5~10别设太大超过 8 层后多半是高频噪声残余max_iter内层筛选最大迭代次数20~50太小收敛不了太大纯调频信号会被削成方波conv_th收敛阈值1e-4 ~ 1e-2越小越严格分解越充分但也越慢boundary边界延拓方式mirror / linear / symmetric端点冲击明显时优先选 linearext_len延拓长度信号长度的 2%~10%太短不抑制边界效应太长拖慢计算env_method包络估计方法spline / linear / moving_avg强冲击信号选 linear平缓信号选 spline3.2 不同信号类型的调参差异机械振动信号往往包含强烈的冲击衰减成分信号前端和后端经常出现幅值突变。这种信号我建议boundary选linear线性外插对冲击信号的端点抑制效果好于镜像延拓。包络方法上优先考虑spline但如果冲击密度很高、相邻冲击间隔太短样条插值会在冲击峰之间扯出额外振荡这时换成linear反而更稳。生物医学信号比如心电、脑电基线和低频漂移明显。我的一般流程是先做一次去趋势处理再用 RLMD 分解。conv_th可以适当放松到 5e-3因为这类信号本身信噪比有限过分追求收敛只会把噪声也分解成独立分量。语音和声学信号的频带经常重叠分解时容易出现模态混叠。这个问题靠调 RLMD 参数解决不了根本我的建议是先对信号做分帧加窗每一帧内近似平稳再分解能从结构上避开混叠。需要特别说明的是max_pf不是越大越好。我曾经试过把参数设到 12结果后 3 个 PF 每个都是“高频噪声 残余趋势”的混合体毫无物理意义。检查方法是把每个 PF 的瞬时频率均值画出来如果某个 PF 的瞬时频率比原始信号的 Nyquist 频率还高说明它在分解噪声。4. 实战案例滚动轴承故障特征提取4.1 构造带故障特征的仿真信号滚动轴承故障诊断是 RLMD 应用最多的场景之一。当轴承外圈出现局部损伤时滚动体每经过损伤点就会产生一次冲击激发轴承座或传感器的结构共振。这个冲击的重复频率就是故障特征频率通常位于 100~300 Hz 之间而共振频率可能高达数千赫兹所以直接对原始信号做 FFT 只能看到共振峰根本看不到故障频率。我用仿真信号来展示 RLMD 的完整流程。假设采样率 20 kHz转频 30 Hz外圈故障特征频率是 5.5 倍转频系统共振频率设为 3000 Hz信号长度 1 秒。fs 20000; t (0:fs-1)/fs; fr 30; bpfo 5.5 * fr; % 外圈故障频率165 Hz f_res 3000; % 结构共振频率 x 0.8*sin(2*pi*fr*t) 0.2*sin(2*pi*2*fr*t); % 外圈故障冲击序列 t_imp 1/bpfo : 1/bpfo : 1; for i 1:length(t_imp) t0 t_imp(i); idx find(t t0, 1); if ~isempty(idx) x(idx:end) x(idx:end) 1.5 * exp(-250*(t(idx:end)-t0)) .* sin(2*pi*f_res*(t(idx:end)-t0)); end end % 添加噪声模拟真实采集环境 rng(42); x x 0.1*randn(size(t));跑完这段仿真信号直接做 FFT 你会发现频谱在 3000 Hz 附近有一簇能量但 165 Hz 及其倍频处几乎看不到明显谱线。故障特征完全被共振调制和噪声掩盖了。4.2 分解后包络谱获得故障特征接下来把 RLMD 用上。为了聚焦效果我取分解出的第二个 PF 分量做 Hilbert 包络解调再对包络信号做 FFT。params rlmd_default_params(); params.max_pf 6; params.boundary linear; params.env_method spline; [PFs, ~] my_rlmd(x, params); pf2 PFs(2, :); env_sig abs(hilbert(pf2)); env_sig env_sig - mean(env_sig); N length(env_sig); f_axis (0:N/2-1) * fs / N; spec_env abs(fft(env_sig)); spec_env spec_env(1:N/2); plot(f_axis, spec_env); xline(bpfo, --r, BPFO); xline(2*bpfo, --r, 2xBPFO); xlim([0 1000]);实测下来在 165 Hz、330 Hz、495 Hz 处会出现清晰谱峰说明 PF 成功捕获了被共振调制的冲击成分。这个过程的本质是 RLMD 做了一次自适应带通滤波把与故障冲击相关的共振成分从噪声中分离出来再通过包络谱解调出故障特征频率。如果直接用原始信号的包络谱谱线会被噪声摊平很难识别。我还对比过 EMD 在这个仿真数据上的表现。EMD 也能分解出包含共振成分的 IMF但模态混叠导致故障频率的边带更乱有时还需要多试几次才能稳定出结果。RLMD 的优势在于分解结果相对稳定PF 分量少而聚焦这对自动诊断算法非常友好。5. 常见问题与排错手册5.1 典型症状速查表实际用 RLMD 过程中我踩过的坑和帮别人解决的报错可以汇总成一张速查表按症状排查效率很高。症状可能原因排查方向分解出超过 10 个 PFmax_pf 设太大或收敛阈值太松先固定 max_pf6再调小 conv_th第一个 PF 全是高频噪声信号本身信噪比过低包络估计被噪声带偏先做中值滤波或小波去噪端点处 PF 严重发散边界延拓方式和信号形态不匹配换成 linear 试验检查 ext_len某层 PF 幅值远超原始信号包络在局部出现异常尖峰画包络曲线检查是否插值过冲分解结果每次跑不一样极值点搜索对平台段敏感或有随机初始化处理等值点固定随机种子计算时间太长信号太长滑动平均窗口过大降采样预处理或缩短 ext_len5.2 我的排查流程和心得我的调试流程一般是先用一组已知成分的仿真信号验证代码正确性比如“低频正弦 高频冲击 白噪声”这种黄金组合。如果 RLMD 不能把它拆成预期 PF说明参数边界或极值点处理有问题这时候先不碰参数先把每个中间变量画出来。中间变量最值得看的是内层迭代里的上下包络、局部均值 m 和包络信号 a。如果能明显看到包络曲线交叉或局部包络变成负值基本就是插值方法不适合当前信号形态。我会逐一尝试spline、linear观察哪个情况下 a 曲线更平坦、更接近 1这就找到了合适的包络估计策略。还有一个很实用的小技巧在函数里临时加一行把每次外层分解后的res残差能量打出来。如果某轮分解后残差能量反而大于分解前说明该层 PF 不真实应立即终止迭代。6. 我在实际工程中积累的几个建议6.1 预处理比算法本身更重要无论 RLMD 多鲁棒给它喂垃圾数据它还是会还给你一份垃圾分解。去直流、去趋势、异常值剔除这三步不能省。尤其趋势项如果不先去干净RLMD 的残差分量会承担一个非平稳趋势挤压正常 PF 的频带空间导致第一层 PF 就出现畸变。去趋势我推荐用平滑先验方法或简单的多项式拟合而不是一概用高通滤波因为高通滤波会改变低频成分相位影响后续包络谱的物理意义。6.2 什么时候别迷信 RLMDRLMD 不是什么万能钥匙。如果信号本身就是平稳、近似线性的直接 FFT 和功率谱分析足够不需要上自适应分解。如果信号里模态混叠严重比如两个频率成分相差 1.5 倍以内任何自适应分解方法都很难分离这时考虑谱峭度或盲源分离可能更合适。在实际在线监测场景中我强烈建议不要每次采集都重调参数。固定一组在离线阶段验证过的参数组合只在需要时调整max_pf这样既能保证处理速度又能让后续提取的特征值保持可比性。毕竟工程上稳定可比比单个样本算得精致重要得多。6.3 一个可以直接抄的封装思路为了让 RLMD 能和 MATLAB 自带的emd函数无缝切换建议把参数结构体封装成类接口统一成r rlmd(x, fs, Name, Value)的形式。内部用inputParser校验参数输出统一成结构体包含PFs、residual、params三个字段。这样后续做批量测试时只需要来回切换函数名不用改下游分析逻辑。我自己的封装库里还有一个隐藏功能在输出结构体里记录每个 PF 的瞬时频率和瞬时幅值。有了这两个量很多下游诊断指标可以直接算比如峰值因子、峭度、故障特征能量比不必再对每个 PF 单独跑一遍 Hilbert 变换。这个小改动省下的时间足够你多喝两杯咖啡了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进