EMD分解与希尔伯特变换能量谱分析

如何对信号进行经验模态分解(EMD),然后对各个本征模态函数(IMF)进行希尔伯特变换,最终获得能量谱的完整MATLAB实现。

算法原理概述

EMD + Hilbert变换流程

复制代码
原始信号 
    → EMD分解 → 多个IMF分量 + 残差
    → 对每个IMF进行Hilbert变换 → 解析信号
    → 计算瞬时频率和瞬时幅度
    → 构建Hilbert谱
    → 计算能量谱密度

MATLAB完整实现

1. 主程序:EMD-Hilbert能量谱分析

matlab 复制代码
function [hht_spectrum, energy_density, imfs] = emd_hilbert_energy_analysis(signal, fs, varargin)
% EMD分解与希尔伯特变换能量谱分析
% 输入:
%   signal - 输入信号
%   fs - 采样频率
%   varargin - 可选参数
% 输出:
%   hht_spectrum - Hilbert谱
%   energy_density - 能量谱密度
%   imfs - IMF分量

    %% 参数设置
    p = inputParser;
    addParameter(p, 'num_imfs', 10, @isnumeric);      % 最大IMF数量
    addParameter(p, 'max_iterations', 1000, @isnumeric); % 最大迭代次数
    addParameter(p, 'stop_threshold', 0.05, @isnumeric); % 停止阈值
    addParameter(p, 'plot_results', true, @islogical); % 是否绘图
    addParameter(p, 'energy_band', [0, fs/2], @isnumeric); % 能量谱频带
    
    parse(p, varargin{:});
    params = p.Results;
    
    fprintf('开始EMD-Hilbert能量谱分析...\n');
    fprintf('信号长度: %d, 采样率: %.1f Hz\n', length(signal), fs);
    
    %% 步骤1: EMD分解
    tic;
    fprintf('正在进行EMD分解...\n');
    
    imfs = emd_decomposition(signal, ...
        'max_imfs', params.num_imfs, ...
        'max_iterations', params.max_iterations, ...
        'stop_threshold', params.stop_threshold);
    
    decomposition_time = toc;
    fprintf('EMD分解完成! 得到 %d 个IMF分量, 耗时: %.2f 秒\n', size(imfs, 1), decomposition_time);
    
    %% 步骤2: 希尔伯特变换与能量计算
    fprintf('正在进行希尔伯特变换...\n');
    
    [hht_spectrum, instantaneous_freq, instantaneous_amp] = ...
        hilbert_spectrum_analysis(imfs, fs);
    
    %% 步骤3: 能量谱计算
    fprintf('计算能量谱密度...\n');
    
    energy_density = calculate_energy_spectrum(hht_spectrum, ...
        instantaneous_freq, fs, params.energy_band);
    
    %% 步骤4: 结果显示
    if params.plot_results
        plot_emd_hilbert_results(signal, fs, imfs, hht_spectrum, ...
            instantaneous_freq, energy_density);
    end
    
    fprintf('EMD-Hilbert能量谱分析完成!\n');
end

2. EMD分解核心函数

matlab 复制代码
function imfs = emd_decomposition(signal, varargin)
% EMD经验模态分解
% 实现经典的EMD算法将信号分解为IMF分量

    % 参数解析
    p = inputParser;
    addParameter(p, 'max_imfs', 10, @isnumeric);
    addParameter(p, 'max_iterations', 1000, @isnumeric);
    addParameter(p, 'stop_threshold', 0.05, @isnumeric);
    parse(p, varargin{:});
    
    max_imfs = p.Results.max_imfs;
    max_iterations = p.Results.max_iterations;
    stop_threshold = p.Results.stop_threshold;
    
    signal = signal(:);  % 确保列向量
    N = length(signal);
    residual = signal;
    imfs = [];
    
    for imf_idx = 1:max_imfs
        fprintf('  提取IMF %d...', imf_idx);
        
        h = residual;  % 当前待提取的IMF
        iteration_count = 0;
        
        while iteration_count < max_iterations
            iteration_count = iteration_count + 1;
            
            % 寻找局部极值点
            [max_locs, min_locs] = find_local_extrema(h);
            
            % 检查是否满足IMF条件
            if length(max_locs) < 2 || length(min_locs) < 2
                fprintf('极值点不足,停止分解\n');
                break;
            end
            
            % 计算上下包络线
            upper_env = compute_envelope(h, max_locs, 'spline');
            lower_env = compute_envelope(h, min_locs, 'spline');
            
            % 计算均值包络线
            mean_env = (upper_env + lower_env) / 2;
            
            % 更新h
            h_prev = h;
            h = h - mean_env;
            
            % 检查停止条件
            stop_value = compute_stop_criteria(h_prev, h, mean_env);
            if stop_value < stop_threshold
                break;
            end
        end
        
        % 保存IMF
        imfs = [imfs; h'];
        residual = residual - h;
        
        fprintf('完成 (迭代次数: %d)\n', iteration_count);
        
        % 检查残差是否足够小
        if sum(residual.^2) < 1e-10 * sum(signal.^2) || ...
           length(find_local_extrema(residual)) < 2
            fprintf('残差已足够小,分解完成\n');
            break;
        end
    end
    
    % 添加残差作为最后一个分量
    if ~isempty(residual)
        imfs = [imfs; residual'];
    end
end

function [max_locs, min_locs] = find_local_extrema(x)
% 寻找局部极值点
    diff_x = diff(x);
    sign_changes = diff(sign(diff_x));
    
    % 极大值点 (二阶导数为负)
    max_locs = find(sign_changes < 0) + 1;
    
    % 极小值点 (二阶导数为正)
    min_locs = find(sign_changes > 0) + 1;
    
    % 确保端点被正确处理
    if x(1) > x(2)
        max_locs = [1; max_locs];
    else
        min_locs = [1; min_locs];
    end
    
    if x(end) > x(end-1)
        max_locs = [max_locs; length(x)];
    else
        min_locs = [min_locs; length(x)];
    end
end

function envelope = compute_envelope(x, extr_locs, method)
% 计算包络线
    t = 1:length(x);
    
    if strcmpi(method, 'spline')
        % 三次样条插值
        if length(extr_locs) >= 4
            envelope = spline(extr_locs, x(extr_locs), t);
        else
            % 极值点太少,使用线性插值
            envelope = interp1(extr_locs, x(extr_locs), t, 'linear', 'extrap');
        end
    else
        % 线性插值
        envelope = interp1(extr_locs, x(extr_locs), t, 'linear', 'extrap');
    end
end

function stop_value = compute_stop_criteria(h_prev, h, mean_env)
% 计算停止准则
    % 使用基于标准差的方法
    numerator = sum((h_prev - h).^2);
    denominator = sum(h_prev.^2);
    
    if denominator == 0
        stop_value = 0;
    else
        stop_value = numerator / denominator;
    end
end

3. 希尔伯特变换与谱分析

matlab 复制代码
function [hht_spectrum, instantaneous_freq, instantaneous_amp] = ...
    hilbert_spectrum_analysis(imfs, fs)
% 希尔伯特谱分析
% 对每个IMF进行希尔伯特变换,计算瞬时频率和幅度

    [num_imfs, N] = size(imfs);
    t = (0:N-1) / fs;
    
    % 初始化输出变量
    instantaneous_freq = zeros(num_imfs, N);
    instantaneous_amp = zeros(num_imfs, N);
    hht_spectrum = zeros(num_imfs, N);
    
    for i = 1:num_imfs
        fprintf('  处理IMF %d 的希尔伯特变换...\n', i);
        
        current_imf = imfs(i, :);
        
        % 希尔伯特变换获得解析信号
        analytic_signal = hilbert(current_imf);
        
        % 计算瞬时幅度
        instantaneous_amp(i, :) = abs(analytic_signal);
        
        % 计算瞬时相位(解卷绕)
        instantaneous_phase = unwrap(angle(analytic_signal));
        
        % 计算瞬时频率 (导数方法)
        instantaneous_freq(i, :) = diff([instantaneous_phase(1), instantaneous_phase]) * fs / (2 * pi);
        
        % 限制频率范围为正值
        instantaneous_freq(i, instantaneous_freq(i, :) < 0) = 0;
        instantaneous_freq(i, instantaneous_freq(i, :) > fs/2) = fs/2;
        
        % 构建Hilbert谱 (幅度平方表示能量)
        hht_spectrum(i, :) = instantaneous_amp(i, :).^2;
    end
end

4. 能量谱计算函数

matlab 复制代码
function energy_density = calculate_energy_spectrum(hht_spectrum, ...
    instantaneous_freq, fs, energy_band)
% 计算能量谱密度

    [num_imfs, N] = size(hht_spectrum);
    
    % 频率分辨率设置
    freq_resolution = 1;  % Hz
    freq_bins = energy_band(1):freq_resolution:energy_band(2);
    
    % 初始化能量谱矩阵
    energy_density = zeros(num_imfs, length(freq_bins)-1);
    
    for i = 1:num_imfs
        fprintf('  计算IMF %d 的能量谱...\n', i);
        
        for t = 1:N
            current_freq = instantaneous_freq(i, t);
            current_energy = hht_spectrum(i, t);
            
            % 找到对应的频率区间
            freq_bin_idx = find(freq_bins <= current_freq, 1, 'last');
            
            if ~isempty(freq_bin_idx) && freq_bin_idx < length(freq_bins)
                energy_density(i, freq_bin_idx) = energy_density(i, freq_bin_idx) + current_energy;
            end
        end
        
        % 归一化能量谱
        if sum(energy_density(i, :)) > 0
            energy_density(i, :) = energy_density(i, :) / sum(energy_density(i, :));
        end
    end
    
    % 计算总能量谱
    total_energy_density = sum(energy_density, 1);
    if sum(total_energy_density) > 0
        total_energy_density = total_energy_density / sum(total_energy_density);
    end
    
    energy_density = [energy_density; total_energy_density];
end

5. 结果可视化函数

matlab 复制代码
function plot_emd_hilbert_results(signal, fs, imfs, hht_spectrum, ...
    instantaneous_freq, energy_density)
% 绘制EMD-Hilbert分析结果

    N = length(signal);
    t = (0:N-1) / fs;
    num_imfs = size(imfs, 1);
    
    % 创建图形窗口
    figure('Position', [100, 100, 1400, 1000]);
    
    %% 子图1: 原始信号
    subplot(4, 3, 1);
    plot(t, signal, 'b', 'LineWidth', 1.5);
    title('原始信号', 'FontSize', 12, 'FontWeight', 'bold');
    xlabel('时间 (s)');
    ylabel('幅值');
    grid on;
    
    %% 子图2: EMD分解结果
    subplot(4, 3, [2, 3]);
    plot_offset = 0;
    colors = parula(num_imfs);
    
    for i = 1:num_imfs
        plot(t, imfs(i, :) + plot_offset, 'Color', colors(i, :), 'LineWidth', 1.2);
        hold on;
        text(t(end) + 0.02, plot_offset, sprintf('IMF%d', i), ...
            'FontSize', 10, 'HorizontalAlignment', 'left');
        
        if i < num_imfs
            plot_offset = plot_offset + max(abs(imfs(i, :))) * 1.5;
        end
    end
    
    title('EMD分解结果', 'FontSize', 12, 'FontWeight', 'bold');
    xlabel('时间 (s)');
    ylabel('IMF分量');
    grid on;
    xlim([t(1), t(end)]);
    
    %% 子图3: Hilbert谱 (时频谱)
    subplot(4, 3, [4, 5]);
    
    [T, F] = meshgrid(t, 1:num_imfs);
    surf(T, F, hht_spectrum, 'EdgeColor', 'none');
    view(2);
    colormap(jet);
    colorbar;
    title('Hilbert谱 (时频分布)', 'FontSize', 12, 'FontWeight', 'bold');
    xlabel('时间 (s)');
    ylabel('IMF序号');
    
    %% 子图4: 瞬时频率
    subplot(4, 3, 6);
    hold on;
    for i = 1:num_imfs
        plot(t, instantaneous_freq(i, :), 'Color', colors(i, :), 'LineWidth', 1);
    end
    title('瞬时频率', 'FontSize', 12, 'FontWeight', 'bold');
    xlabel('时间 (s)');
    ylabel('频率 (Hz)');
    grid on;
    legend(arrayfun(@(x) sprintf('IMF%d', x), 1:num_imfs, 'UniformOutput', false), ...
        'Location', 'best', 'FontSize', 8);
    
    %% 子图5: 各IMF能量谱
    subplot(4, 3, [7, 8]);
    freq_bins = 1:size(energy_density, 2);
    bar_data = energy_density(1:end-1, :)';
    
    h_bar = bar(freq_bins, bar_data, 'stacked');
    title('各IMF分量能量谱分布', 'FontSize', 12, 'FontWeight', 'bold');
    xlabel('频率区间');
    ylabel('归一化能量');
    legend(arrayfun(@(x) sprintf('IMF%d', x), 1:num_imfs, 'UniformOutput', false), ...
        'Location', 'best', 'FontSize', 8);
    grid on;
    
    %% 子图6: 总能量谱
    subplot(4, 3, [9, 10]);
    total_energy = energy_density(end, :);
    stem(freq_bins, total_energy, 'filled', 'LineWidth', 1.5, 'MarkerSize', 4);
    title('总能量谱密度', 'FontSize', 12, 'FontWeight', 'bold');
    xlabel('频率区间');
    ylabel('能量密度');
    grid on;
    
    %% 子图7: 能量分布统计
    subplot(4, 3, [11, 12]);
    
    % 计算各IMF能量贡献
    imf_energy_contribution = zeros(1, num_imfs);
    for i = 1:num_imfs
        imf_energy_contribution(i) = sum(hht_spectrum(i, :));
    end
    total_energy = sum(imf_energy_contribution);
    imf_energy_contribution = imf_energy_contribution / total_energy * 100;
    
    pie(imf_energy_contribution, arrayfun(@(x) sprintf('IMF%d\n%.1f%%', x, ...
        imf_energy_contribution(x)), 1:num_imfs, 'UniformOutput', false));
    title('各IMF能量贡献比例', 'FontSize', 12, 'FontWeight', 'bold');
    
    sgtitle('EMD分解与希尔伯特能量谱分析', 'FontSize', 14, 'FontWeight', 'bold');
end

6. 测试用例与演示

matlab 复制代码
%% 测试函数:模拟信号分析
function test_emd_hilbert_analysis()
% 测试EMD-Hilbert能量谱分析

    fprintf('=== EMD-Hilbert能量谱分析测试 ===\n\n');
    
    % 生成测试信号
    fs = 1000;  % 采样频率 1000 Hz
    t = 0:1/fs:2;  % 2秒信号
    
    % 多分量测试信号
    signal = 2 * sin(2*pi*50*t) .* (1 + 0.5*sin(2*pi*5*t)) + ...  % 调幅信号
             1.5 * sin(2*pi*120*t) + ...                         % 高频分量
             0.8 * chirp(t, 80, 2, 20) + ...                     % 扫频信号
             0.3 * randn(size(t));                               % 噪声
    
    fprintf('生成测试信号:\n');
    fprintf('   - 50Hz调幅信号\n');
    fprintf('   - 120Hz正弦信号\n');
    fprintf('   - 80-20Hz扫频信号\n');
    fprintf('   - 高斯白噪声\n\n');
    
    % 执行EMD-Hilbert分析
    [hht_spectrum, energy_density, imfs] = emd_hilbert_energy_analysis(...
        signal, fs, ...
        'num_imfs', 8, ...
        'max_iterations', 500, ...
        'plot_results', true, ...
        'energy_band', [0, 200]);
    
    % 显示能量分析结果
    display_energy_analysis(imfs, hht_spectrum);
end

function display_energy_analysis(imfs, hht_spectrum)
% 显示能量分析结果

    fprintf('\n=== 能量分析结果 ===\n\n');
    
    num_imfs = size(imfs, 1);
    total_energy = sum(hht_spectrum(:));
    
    fprintf('%-8s %-12s %-12s %-15s\n', ...
        'IMF', '能量', '能量百分比', '累计百分比');
    fprintf('%s\n', repmat('-', 1, 50));
    
    cumulative_percentage = 0;
    for i = 1:num_imfs
        imf_energy = sum(hht_spectrum(i, :));
        percentage = imf_energy / total_energy * 100;
        cumulative_percentage = cumulative_percentage + percentage;
        
        fprintf('IMF%-5d %-12.4e %-11.2f%% %-14.2f%%\n', ...
            i, imf_energy, percentage, cumulative_percentage);
    end
    
    fprintf('%s\n', repmat('-', 1, 50));
    fprintf('总计    %-12.4e %-11.2f%%\n', total_energy, 100.0);
    
    % 显示主要能量集中区域
    fprintf('\n主要能量集中分析:\n');
    energy_threshold = 0.05;  % 5%能量阈值
    
    significant_imfs = [];
    for i = 1:num_imfs
        imf_energy = sum(hht_spectrum(i, :)) / total_energy;
        if imf_energy > energy_threshold
            significant_imfs = [significant_imfs, i];
        end
    end
    
    if ~isempty(significant_imfs)
        fprintf('主要能量集中在: IMF%s\n', mat2str(significant_imfs));
        fprintf('这些IMF包含了 %.2f%% 的总能量\n', ...
            sum(hht_spectrum(significant_imfs, :), 'all') / total_energy * 100);
    else
        fprintf('能量分布较为均匀,无明显主导IMF\n');
    end
end

%% 实际应用示例:故障诊断信号分析
function bearing_fault_analysis()
% 轴承故障信号分析示例

    fprintf('=== 轴承故障诊断信号分析 ===\n\n');
    
    % 模拟轴承故障信号 (简化模型)
    fs = 12000;  % 12 kHz采样频率
    t = 0:1/fs:1;  % 1秒信号
    
    % 轴承故障特征频率 (示例)
    bpfo = 120;  % 外圈故障频率 120 Hz
    bpfi = 145;  % 内圈故障频率 145 Hz
    bsf = 65;    % 滚动体故障频率 65 Hz
    ftf = 15;    % 保持架故障频率 15 Hz
    
    % 生成故障信号
    fundamental = 0.8 * sin(2*pi*30*t);  % 转频 30 Hz
    
    % 故障冲击序列
    fault_impacts = zeros(size(t));
    impact_interval = round(fs / bpfo);  % 外圈故障冲击间隔
    impact_locations = 1:impact_interval:length(t);
    fault_impacts(impact_locations) = 1.5;
    
    % 共振响应
    resonance_freq = 3000;  % 3 kHz 共振频率
    resonance_signal = filter([1, -1.8*cos(2*pi*resonance_freq/fs), 0.81], ...
        [1, -1.2*cos(2*pi*resonance_freq/fs), 0.25], fault_impacts);
    
    % 合成信号
    signal = fundamental + resonance_signal + 0.1 * randn(size(t));
    
    fprintf('轴承故障信号特征:\n');
    fprintf('  转频: 30 Hz\n');
    fprintf('  外圈故障频率: 120 Hz\n');
    fprintf('  系统共振频率: 3000 Hz\n\n');
    
    % 执行EMD-Hilbert分析
    [hht_spectrum, energy_density, imfs] = emd_hilbert_energy_analysis(...
        signal, fs, ...
        'num_imfs', 6, ...
        'energy_band', [0, 5000], ...
        'plot_results', true);
    
    % 故障特征提取
    extract_fault_features(imfs, hht_spectrum, fs, [bpfo, bpfi, bsf, ftf]);
end

function extract_fault_features(imfs, hht_spectrum, fs, fault_freqs)
% 提取故障特征
    
    fprintf('\n=== 故障特征分析 ===\n\n');
    
    % 计算各IMF的频谱
    num_imfs = size(imfs, 1);
    
    for i = 1:num_imfs
        % FFT分析
        imf_fft = fft(imfs(i, :));
        N = length(imf_fft);
        f = (0:N-1) * fs / N;
        
        % 寻找主要频率成分
        [~, dominant_freq_idx] = max(abs(imf_fft(1:floor(N/2))));
        dominant_freq = f(dominant_freq_idx);
        
        fprintf('IMF%d 主要频率成分: %.2f Hz\n', i, dominant_freq);
        
        % 检查是否接近已知故障频率
        for j = 1:length(fault_freqs)
            if abs(dominant_freq - fault_freqs(j)) < 10  % 10 Hz容差
                switch j
                    case 1
                        fprintf('  → 检测到外圈故障特征!\n');
                    case 2
                        fprintf('  → 检测到内圈故障特征!\n');
                    case 3
                        fprintf('  → 检测到滚动体故障特征!\n');
                    case 4
                        fprintf('  → 检测到保持架故障特征!\n');
                end
            end
        end
    end
end

参考代码 emd分解之后再进行希尔伯特变换,获得能量谱 www.3dddown.com/csa/77762.html

算法特点与优势

EMD-Hilbert方法的优势

  1. 自适应分解 - EMD根据信号特性自动分解
  2. 局部特征提取 - 能够捕捉非平稳信号的时变特性
  3. 能量定位 - 精确确定能量在时频域的分布
  4. 物理意义明确 - 每个IMF代表特定的振动模式

应用场景

  • 机械故障诊断 - 轴承、齿轮箱故障检测
  • 生物信号处理 - EEG、ECG信号分析
  • 地震信号分析 - 地层结构识别
  • 语音信号处理 - 语音特征提取
相关推荐
电脑小管家2 小时前
路由器怎么重新设置wifi密码
网络·windows·计算机外设·智能路由器·电脑
风途知识百科2 小时前
化工厂防爆气象站
网络·人工智能
老蒋新思维2 小时前
创客匠人峰会洞察:IP 信任为基,AI 效率为翼,知识变现的可持续增长模型
大数据·网络·人工智能·网络协议·tcp/ip·创始人ip·创客匠人
老蒋新思维2 小时前
创客匠人峰会新洞察:AI 时代创始人 IP 的生态位战略 —— 小众赛道如何靠 “精准卡位” 实现千万知识变现
网络·人工智能·网络协议·tcp/ip·重构·创始人ip·创客匠人
Arwen3032 小时前
内网IP证书:安全加密全指南
网络·网络协议·tcp/ip·ssl
虎皮辣椒小怪兽2 小时前
网络层协议及IP编址
网络·网络协议
发光小北2 小时前
SG-TCP232-110(单通道串口服务器)特点与功能介绍
服务器·网络·单片机
嘻哈baby3 小时前
QUIC协议深度解析:为什么它比TCP更快
网络·网络协议·tcp/ip
渡我白衣3 小时前
计算机组成原理(5):计算机的性能指标
服务器·网络·c++·人工智能·网络协议·tcp/ip·网络安全