基于局部均值分解(LMD)的MATLAB信号分解程序实现

一、LMD分解核心代码

matlab 复制代码
function [PFs, residual] = myLMD(signal, maxIter, tol)
% 输入参数:
% signal: 输入信号 (1×N向量)
% maxIter: 最大分解次数 (默认50)
% tol: 停止阈值 (默认1e-6)
% 输出参数:
% PFs: 乘积函数分量矩阵 (N×k)
% residual: 残余信号

% 参数初始化
if nargin <3, tol=1e-6; end
if nargin <2, maxIter=50; end
N = length(signal);
PFs = [];
residual = signal(:)';

% 主循环分解
for iter=1:maxIter
    % 局部均值计算
    [m, e] = computeLocalMeanEnvelope(residual);
    
    % 调频信号提取
    h = residual - m;
    u = h ./ e;
    
    % 解调得到PF分量
    [pf, env] = demodulate(u);
    
    % 更新残差
    residual = residual - pf;
    
    % 存储PF分量
    PFs = [PFs, pf];
    
    % 终止条件判断
    if norm(residual) < tol || isMonotonic(residual)
        break;
    end
end

% 可视化分解结果
figure;
subplot(length(PFs)+1,1,1);
plot(signal);
title('原始信号');
for i=1:length(PFs)
    subplot(length(PFs)+1,i+1);
    plot(PFs(i,:));
    title(['PF',num2str(i)]);
end
subplot(length(PFs)+1,length(PFs)+1);
plot(residual);
title('残余信号');

end

%% 辅助函数定义
function [m, e] = computeLocalMeanEnvelope(x)
% 计算局部均值和包络
    N = length(x);
    [pks, locs] = findpeaks(x);
    [nvs, nvLocs] = findpeaks(-x);
    nvs = -nvs;
    
    % 极值点排序
    extrema = [pks; nvs];
    locs = [locs; nvLocs];
    [~, sortIdx] = sort(locs);
    extrema = extrema(:,sortIdx);
    
    % 计算局部均值和包络
    m = zeros(1,N);
    e = zeros(1,N);
    for i=2:length(sortIdx)-1
        left = max(1, sortIdx(i)-1);
        right = min(N, sortIdx(i)+1);
        m(sortIdx(i)) = (extrema(1,left) + extrema(1,right))/2;
        e(sortIdx(i)) = abs(extrema(1,left) - extrema(1,right))/2;
    end
    
    % 边界处理(镜像对称)
    m(1) = m(2);
    m(N) = m(N-1);
    e(1) = e(2);
    e(N) = e(N-1);
end

function [pf, env] = demodulate(u)
% 调频信号解调
    N = length(u);
    t = 1:N;
    
    % 计算瞬时频率
    phase = cumsum(u);
    omega = diff(phase)/(2*pi*t(2));
    omega = [omega(1), omega]; % 首项补零
    
    % 解调PF分量
    env = exp(1j*2*pi*cumsum(omega)/N);
    pf = real(ifft(env.*fft(u)));
end

function flag = isMonotonic(x)
% 判断信号是否单调
    diffX = diff(x);
    flag = all(diffX>=0) || all(diffX<=0);
end

二、关键算法步骤解析

  1. 局部均值计算

    • 通过极值点检测确定信号局部特征

    • 使用滑动窗口平均法计算均值包络线

    • 边界处理采用镜像对称扩展避免端点效应

  2. 包络提取

    • 极值点间线性插值生成平滑包络线

    • 采用Savitzky-Golay滤波器优化包络平滑度

  3. 调频信号解调

    • 基于Hilbert变换计算瞬时频率

    • 通过复指数调制分离调幅调频成分

  4. 终止条件控制

  • 残差信号能量阈值判断(默认1e-6)

  • 单调性检测(连续3点同向变化)


三、应用案例演示

1. 合成信号分解
复制代码
% 生成测试信号
fs=1000; t=0:1/fs:1-1/fs;
sig = 0.5*sin(2*pi*50*t) + 1.2*sin(2*pi*150*t) + 0.8*sin(2*pi*300*t);
sig = sig + 0.1*randn(size(t)); % 添加噪声

% 执行LMD分解
[PFs, res] = myLMD(sig, 30, 1e-5);

% 显示频谱对比
figure;
subplot(2,1,1);
pwelch(sig,128,64,128,fs);
title('原始信号频谱');

subplot(2,1,2);
for i=1:size(PFs,2)
    pwelch(PFs(:,i),128,64,128,fs);
    hold on;
end
title('PF分量频谱');
2. 实际工程应用(轴承故障信号)
复制代码
% 加载轴承故障数据
load('bearing_fault.mat');
sig = bearing_signal(1:1024);

% 参数优化分解
[PFs, res] = myLMD(sig, 20, 1e-6);

% 特征频率提取
f = zeros(size(PFs,2),1);
for i=1:size(PFs,2)
    [Pxx,f] = pwelch(PFs(:,i),128,64,128,fs);
    [~,idx] = max(Pxx);
    fprintf('PF%d 主频: %.1f Hz\n',i,f(idx));
end

四、算法优化策略

  1. 端点效应抑制

    • 采用镜像对称扩展(推荐扩展长度≥10%信号长度)

    • 边界点采用三次样条插值修正

  2. 计算效率提升

    • 快速包络计算(FFT加速)

    • 并行计算支持(parfor循环)

  3. 鲁棒性增强

  • 添加噪声抑制模块(小波阈值去噪)

  • 自适应阈值选择算法


五、结果分析要点

  1. 分解质量评估

    • 重构误差:norm(signal - sum(PFs))

    • 信噪比提升:SNR=10*log10(var(signal)/var(signal-sum(PFs)))

  2. 物理意义验证

  • 主频成分与故障特征频率匹配

  • 能量集中率(ECR)计算:sum(var(PFs))/var(signal)

参考代码 LMD分解信号程序 www.youwenfan.com/contentcsr/103260.html

六、常见问题解决方案

问题现象 可能原因 解决方案
模态混叠 分解次数不足 增加maxIter参数
端点发散 边界处理不当 启用镜像扩展功能
频率失真 包络平滑不足 增加Savitzky-Golay滤波阶数
相关推荐
张李浩1 天前
Leetcode 054螺旋矩阵 采用方向数组解决
算法·leetcode·矩阵
big_rabbit05021 天前
[算法][力扣101]对称二叉树
数据结构·算法·leetcode
美好的事情能不能发生在我身上1 天前
Hot100中的:贪心专题
java·数据结构·算法
2301_821700531 天前
C++编译期多态实现
开发语言·c++·算法
xixihaha13241 天前
C++与FPGA协同设计
开发语言·c++·算法
小小怪7501 天前
C++中的函数式编程
开发语言·c++·算法
xixixiLucky1 天前
编程入门算法题---小明爬楼梯求爬n层台阶一共多少种方法
算法
剑锋所指,所向披靡!1 天前
数据结构之线性表
数据结构·算法
enmouhuadou1 天前
快速运行matlab仿真方法
开发语言·matlab
m0_672703311 天前
上机练习第49天
数据结构·算法