资讯动态

基于HHT的电机故障诊断:从EMD分解到边际谱分析

发布时间:2026/10/26 22:38:33 来源:尧图企业网站定制
简介面向电机故障诊断与信号处理方向的MATLAB代码资源聚焦希尔伯特黄变换HHT在电机内外圈故障识别中的应用。HHT由经验模态分解EMD和希尔伯特谱分析HSA组成能自适应处理非线性、非平稳信号尤其适合电机运行时的电流、电压波动分析。代码包将这一方法封装为可运行脚本通过分解得到固有模态函数IMF再求取瞬时频率和幅度从而在希尔伯特谱中直观呈现异常频率成分的变化帮助识别内圈绝缘老化或外圈短路引起的谐波失真、高频分量等故障特征。压缩包内共6个文件均为.m脚本覆盖从EMD分解、希尔伯特谱计算到峰值查找、FFT辅助分析的完整流程整体体积仅3KB结构精练、便于快速移植和二次开发。目前已有231人学习下载适合电机故障诊断初学者、相关课程设计者以及需要复现HHT算法的研究人员。借助这套程序读者不仅能理解HHT处理非平稳信号的关键步骤还可以通过调整分解参数和阈值将方法适配到自己的实测故障数据中进一步定位故障特征频率为预防性维护和健康管理提供量化依据。1. HHT 在电机故障诊断里解决的是傅里叶看不出的那部分信号做电机故障诊断的人多半有过这种经历从现场采回一段电流信号FFT 一画全是在基频和整数次谐波上立着的高峰故障该有的边带被埋在 50Hz 主峰旁边几乎看不出来。这不是仪器不行而是电流信号本身叠加了非平稳的瞬态冲击傅里叶变换对这种“频率随时间变化”的分量天然不敏感。希尔伯特黄变换Hilbert Huang Transform, HHT正是冲着这个问题来的。它先用经验模态分解把信号按尺度自适应拆开再用希尔伯特变换求每个分量的瞬时频率可以从时频图上直接看到故障冲击发生在哪个时刻、落在哪个频段。这套程序包把整个流程都封装成了 MATLAB 函数emd.m做分解HilbertAnalysis.m求瞬时频率和幅值plot_hht.m画谱图FFTAnalysis.m用来做对比验证。想搭一条能跑的电机故障信号分析链路不用自己从头写数学库直接改参数就行。下面按实际调用顺序拆开讲清楚每一段。2. EMD 分解是第一步从 emd.m 看懂“剥洋葱”式的故障信号拆解2.1 包络插值与筛分迭代不设滤波器的信号拆解HHT 的根基是 EMD它做的事情通俗讲就是“剥洋葱”把一段复杂信号一层层拆开每一层都是一个内在模态函数IMF代表信号里某一类局部振荡。拆解过程不需要预设中心频率也不需要选小波基函数全部由信号自身的极值点驱动。我在整套程序里最先看的是emd.m它的核心循环逻辑如下function [imf, residual] emd(x, sd_threshold, max_sift) % x 输入信号一维行向量或列向量 % sd_threshold 筛分停止阈值 SD常见取值 0.2~0.3 % max_sift 单个 IMF 最多筛分次数防止过筛导致振荡被抹平 r x; % 残差信号逐层剥离后的剩余部分 imf_total []; % 用于堆叠所有 IMF while true h r; % 每得到一个 IMF就从原信号里减掉它对残差继续分解 for iter 1:max_sift [up, down] envelope_estimate(h); % 对极大值、极小值分别做三次样条插值 m (up down) / 2; % 上下包络均值相当于“局部直流” h h - m; % 减去均值包络让信号变得更对称 if sd(h, m, sd_threshold) % 判断均值包络是否足够小 break; end end imf_total [imf_total; h]; % 当前 h 已被筛成一条 IMF r r - h; % 从残差中挖掉这一层 % 残差变成单调或幅值接近 0就认为分解结束 if max(abs(r)) 1e-8 || length(findpeaks(r)) 1 residual r; break; end end end这个函数里最值得关注的是envelope_estimate这一步它先找出信号所有局部极大值和局部极小值然后用三次样条分别插值得到上下两条包络。均值包络m相当于一条随信号局部变化的“零线”用h - m反复迭代IMF 的条件是上下包络均值处处接近零同时过零点数与极值点数之差不超过 1。sd_threshold控制筛分到什么程度算停调得越小IMF 越“纯净”但计算量也成倍增加max_sift是保险丝防止程序死循环。整套程序里这两个参数的默认值就是现场调诊断参数时最常动的地方。2.2 为什么用自适应分解而不是带通滤波对故障诊断的直接影响一开始做电机故障信号时我也习惯先叠加带通滤波器把目标频段抠出来。但遇到一个实际问题故障早期你根本不知道异常频率落在哪。定子绕组绝缘老化产生的高频纹波或者局部放电引起的瞬态冲击频带可能宽达几百赫兹而且会随着转速波动漂移。这时候固定中心频率的带通滤波很容易把有用分量切掉一半。EMD 就不需要这种“先验”它按信号自身的局部时间尺度逐层剥开。比如一段信号由 50Hz 工频和一段衰减很快的高频振荡组成EMD 会先把高频振荡单独挑出来做成第一个 IMF再把工频留在后面的分量里。故障信息往往集中在频率较高的前几个 IMF后几个 IMF 则对应趋势项和低频摆动。这和滤波器组相比省去了反复试中心频率的环节尤其适合现场数据信噪比不高的情况。方法是否需要预设频带对非平稳信号在电机故障诊断中的作用FFT需要先知道带宽整体频谱被平均瞬态被抹平适合稳态谐波边带分析作为参考小波包变换需要选小波基和层数可以时频分析但分辨率固定适合已知故障频段后的精细分析EMD方式不需要自适应逐层提取局部振荡适合未知频段的早期故障筛查实际用这套程序时我通常的做法是先把前几个 IMF 叠加起来看时域形态能明显看到周期性的冲击尖峰这就是后续希尔伯特变换最有价值的那部分信号。3. 从 IMF 到希尔伯特谱HilbertAnalysis.m 与 plot_hht.m 的完整解读3.1 瞬时频率不是对整段信号求导而是从解析信号相位来的拿到 IMF 之后下一步就是对这个分量做希尔伯特变换求它的瞬时频率和瞬时幅值。这里的核心思路是构造解析信号把原始 IMF 作为实部它的希尔伯特变换作为虚部由此得到一个复数信号相位随时间的变化率就是瞬时频率模值就是瞬时幅值包络。对应程序里的HilbertAnalysis.m核心代码是这样的function [inst_freq, inst_amp] HilbertAnalysis(imf, fs) % imf 输入的单个 IMF 分量 % fs 采样率单位 Hz analytic hilbert(imf); % 构造解析信号返回复数序列 inst_amp abs(analytic); % 瞬时幅值包络反映该振荡的强弱变化 phase unwrap(angle(analytic)); % 解卷绕相位避免 2π 跳变 inst_freq diff(phase) / (2*pi) * fs; % 相位对时间求导再换算成 Hz end这里有个容易忽略的点diff会让输出长度比输入少 1。后面画图时如果直接把inst_freq和原始时间轴对齐末端会错位常见处理是取相邻时间点的平均值居中或者在末尾补一个重复值。我在实际使用时习惯丢掉最后 5 个点因为端点附近的瞬时频率本身就不稳定留着反而干扰判断。瞬时频率在这里的含义和“FFT 谱线频率”完全不同它把频率看成时间的函数可以表达“某个时刻出现了频率突然升高的冲击”。这对电机内外圈故障很有用——绝缘损坏产生的间歇性放电在时间轴上表现为一串窄脉冲在瞬时频率曲线上就是一段高频突起。3.2 边际谱与峰值定位findpeaks.m 在故障特征提取中的作用plot_hht.m的作用是把每个 IMF 的瞬时频率和瞬时幅值画成二维时频图横轴时间、纵轴频率颜色深浅代表幅值能量。单看时频图能定性判断故障位置但要做更客观的判断还需要把信号在时间方向压缩成一条“边际谱”曲线。这条曲线的横轴对应频率纵轴代表整个分析时间段内该频率成分累积的能量性质上和傅里叶谱相似但计算过程包含了对非平稳分量的刻画。程序包里配套的findpeaks.m就是用来在边际谱上定位峰值的。构建边际谱的常用做法如下function [marginal, freq_axis] build_marginal(hht_matrix, freq_axis, time_axis) % hht_matrix 希尔伯特谱矩阵行对应频率列对应时间 % freq_axis 频率坐标向量单位 Hz % time_axis 时间坐标向量单位 s marginal sum(hht_matrix, 2); % 沿时间方向累加得到每个频率上的总能量 marginal marginal / max(marginal); % 归一化方便在同一图上对比多组数据 [pks, locs] findpeaks(marginal); % 提取局部峰值及其位置 % pks 峰值幅值 % locs 对应 freq_axis(locs) 就是峰值的中心频率 endfindpeaks返回的locs是本轮诊断最直接的输出把它和工频 50Hz、谐波频率做对比如果出现非整数倍的异常峰或者原来没有的宽频隆起基本可以锁定故障信号出现。做内外圈故障识别的时候我会把这些峰值的中心频率和幅值记录下来作为下一步分类的关键特征。具体到这份程序FFTAnalysis.m也做了一次频谱峰值定位把两个结果摆在一起可以互相验证。4. 用 mainhht.m 串一条完整诊断流水线从原始电流到故障结论4.1 主脚本的参数设定采样率、数据长度和预处理mainhht.m是整套流程的入口。现场采样的数据不会直接扔进emd.m需要先处理三件事采样率要足够高、数据段要足够长、直流和工频趋势要先去掉。常见参数配置如下表可以直接套用参数常用取值说明采样率 fs10 kHz ~ 20 kHz过低会把高频故障分量混叠到低频区分析时长1 ~ 2 秒太短看不到完整的故障周期太长 EMD 计算极慢去均值减去信号均值避免第一条 IMF 被直流偏置干扰去工频趋势按时间局部去趋势防止包络均值被大尺度工频摆动带偏主流程的调用框架是这样的fs 10000; t (0:N-1) / fs; % 时间轴 x load(motor_signal.mat); % 现场采样的电流信号 x x - mean(x); % 去直流利于 EMD 收敛 imfs emd(x, 0.25, 200); % 调用核心分解函数 for k 1:min(4, size(imfs, 1)) % 只分析前几个高频 IMF [inst_freq, inst_amp] HilbertAnalysis(imfs(k, :), fs); plot_hht(t(1:end-1), inst_freq, inst_amp); % 画时频图 end FFTAnalysis(x, fs); % 同时跑一遍 FFT作为对照emd(x, 0.25, 200)表示 SD 阈值取 0.25单个 IMF 最多迭代 200 次。SD 阈值越小IMF 分得越细但过小的阈值会把一个完整冲击拆到多个 IMF 里后面避坑章节会细说。预处理这一步常常被新手跳过直接对原始信号跑 EMD结果就是第一条 IMF 里掺着缓慢变化的工频趋势时频图上会多出一条不该有的低频亮线。4.2 每个模块的调用顺序与输出含义整套程序的调用顺序是load加载数据 →emd.m逐层分解 → 对感兴趣的 IMF 做HilbertAnalysis.m求瞬时频率和幅值 →plot_hht.m绘制时频分布 →findpeaks.m在边际谱上定位异常频率。每跑一次 HHT我习惯先看时频图上的“亮带”有没有出现在非工频频段再看边际谱峰值是否稳定。这里提一下FFTAnalysis.m的位置它不参与 HHT 主流程而是放在旁边做校验。FFT 的好处是稳定、直观对周期性的稳态故障能给出明确的线谱HHT 的优势在瞬态和间歇性故障。二者结论如果一致故障判断基本可以确定如果不一致优先以 HHT 时频图上反复出现的异常频带为准因为同样的特征在 FFT 里可能被谐波掩盖。4.3 和 FFTAnalysis.m 的对比同一段故障信号两种工具看到的差异分析维度FFTHHT频率分辨率固定由数据窗决定可变由筛分精度决定对瞬态冲击能量被摊到整个窗上看不见发生时刻能同时看出“何时”和“何频”对稳态工频清晰锐利也有清晰峰但计算开销大对微弱早期故障容易被大谐波掩盖高频 IMF 相对独立更容易暴露同一段带外圈故障的电流信号FFT 频谱上可能只在某个边带出现 1~2 dB 的隆起肉眼很难和正常工况区分但时频图上异常频段会形成周期性色块这就是 HHT 的独特价值。5. HHT 上机避坑清单端点效应、模态混叠和采样率选择5.1 端点飞翼甩出来的“假故障频率”现象时频图两端出现大斜率亮线像是信号末尾突然多了一堆高频分量明明这段数据是正常停机采集的却看起来像特大盘式故障。原因三次样条插值需要把包络延伸到信号端点之外两个端点附近找不到对称的极值点包络在两端失真筛分出来的第一个 IMF 会被强行拔高瞬时频率随之歪曲。解决分析时把首尾各切掉 5%~10% 的数据或者对信号做镜像延拓后再跑 EMD。我在脚本里实际采取的做法是每次plot_hht只显示中间 80% 的时间范围不给端点假象上图上当的机会。5.2 间歇性冲击把 IMF“劈开”模态混叠现象正常的故障冲击在时频图上被截成几段同一频率的亮线断断续续无法连成一条清晰轨迹。原因电机电流里的工频是持续存在的强分量而故障冲击是间歇性的弱分量EMD 筛分时间歇分量会扰乱极值点的分布导致同一时间尺度被分到多个 IMF 里。解决提高采样率让冲击信号有足够的时间分辨率或者把整段信号分成长度相近的几个子段分别做 EMD再把时频图拼接。如果条件允许对这类混叠问题最常见的做法是改用带白噪声的 EEMD但程序包里没有现成实现分段处理是最不折腾且有效的方案。5.3 过筛分把故障冲击切成多个 IMF现象同一个冲击特征同时出现在连续三个 IMF 的时频图上能量被摊薄了。原因SD 阈值设得太小筛分迭代把信号里每一处细节都“磨”平了本应是一个完整振荡的局部冲击被拆成了多条独立 IMF。解决把sd_threshold往上调从 0.2 改到 0.3 左右或者给max_sift设置一个较小值让每个 IMF 只需满足过零点和包络对称的基本条件就退出循环。判据以“边际谱上能区分出独立峰值”为准不是 IMF 越光滑越好光滑过头反而失去物理意义。5.4 别忘了先确认“内圈/外圈故障”的定义再谈特征频率现象对照轴承特征频率公式去算内外圈损伤频率怎么都对不上 HHT 谱里的峰。原因这份资源里的“内圈故障”“外圈故障”指的是定子绕组故障——内圈通常指靠近电机轴心的绕组外圈指更远离轴心的绕组并不是轴承滚道的内圈、外圈。把两套定义混用是刚上手最容易踩的坑。解决先向数据采集方确认故障描述口径再决定用边带频率还是用绝缘放电的宽频冲击来匹配。对于绕组类故障可留意电流波形中出现的高频振荡分量或者局部短路引发的特定频率幅值起伏而不是直接套用机械损伤公式。6. 进阶技巧把边际谱压缩成定长特征向量喂给后续分类到这一步整套 HHT 流程已经能从一段原始电流里画出干净的时频图和边际谱但诊断不能只靠肉眼。实际工程里我们需要把“有没有故障”“是哪种故障”变成可量化的数值方便用简单阈值或分类器做自动判断。我这里的习惯做法是把边际谱按频段切成若干个 bin每个 bin 求和后再归一化得到一个长度固定的特征向量。function feat margin_to_feature(marginal, freq_axis, band_edges) % marginal 归一化后的边际谱列向量 % freq_axis 对应的频率轴单位 Hz % band_edges 频段边界例如 [0 50 150 300 500 800] feat zeros(1, length(band_edges) - 1); for k 1:length(band_edges) - 1 idx freq_axis band_edges(k) freq_axis band_edges(k 1); feat(k) sum(marginal(idx)); % 该频段内的累积能量 end feat feat / sum(feat); % 归一化弱化绝对幅值差异 end频段边界怎么定取决于你的诊断对象如果做定子绕组故障重点看 150Hz~800Hz 的宽频分量变化前面几个 bin 就会反映高频振荡的强弱如果做轴承类损伤则应该把频段边界设在机械特征频率附近。归一化这步我坚持每次都做因为现场采样的电流幅值会随着负载波动绝对能量不具备可比性只有相对能量分布才能稳定反映故障状态。做特征向量的同时我会把每次诊断的边际谱峰值、峰值频率一并存成一张表% 假设已经通过 findpeaks 得到 pks 和 locs records [records; fs, band_edges, pks, freq_axis(locs)];后期积累到几十组数据后哪几组正常、哪几组是内圈绕组故障、哪几组是外圈分别贴上标签直接作为分类器输入。这套程序的真正价值不在于单次分析而在于把 HHT 变成一个可以批量处理数据的稳定工具。从那以后我每次跑电机故障诊断项目都会强制走一遍这套流程先 EMD 分离 IMF再希尔伯特变换画谱最后归一化存特征任何一步不满足就回头查参数。希望这份拆解能帮你在自己的信号上少走几趟弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑