ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CEEMD-BP神经网络轴承故障诊断:从振动信号到特征提取实战

CEEMD-BP神经网络轴承故障诊断:从振动信号到特征提取实战 简介一份面向轴承故障诊断、设备健康管理与数据建模研究者的专业论文资料系统阐述基于CEEMD与BP神经网络的大数据轴承故障诊断方法。资源包内含一个PDF文档、共约253KB完整呈现从原始信号CEEMD分解降噪、重构信号与时频域特征提取到BP神经网络结构设计、参数确定及故障状态推断的完整技术链路同时穿插大数据类型与七个V特征的背景分析。已有142人学习下载。读者可循此掌握CEEMD分解原理及其在信号降噪中的应用理解峭度指标、峰值指数、重心频率、均方频率等特征参数的选取依据并借鉴BP网络在多输入非线性映射中的构建与训练思路。文中对大数据特点及其在设备诊断中作用的梳理亦为规模化传感数据的处理与数据建模实践提供了参考。1. 基于CEEMD-BP神经网络的轴承故障诊断先把这套组合解决的问题讲清楚做旋转机械状态监测的人都有个共识轴承一坏设备一半的停机时间就跟着来而振动信号里的早期故障特征往往被噪声和工况波动盖得严严实实。基于CEEMD-BP神经网络的轴承故障诊断就是把互补集合经验模态分解CEEMD和BP神经网络串成一条流水线先用CEEMD把非线性、非平稳的振动信号拆成一组本征模态函数IMF再提取能量占比、峭度等特征喂给BP神经网络做故障分类。这套组合在大数据场景下尤其实用不需要昂贵的机理建模只要标注好正常、内圈、外圈、滚动体这几类状态就能训练出扛得住海量监测数据的分类器。适合设备健康管理工程师、工业大数据分析开发以及写故障诊断方向课题的学生。2. CEEMD分解的原理与参数先把模态混叠这个老问题讲透2.1 EMD的局限为什么轴承信号老是分解不干净EMD 是希尔伯特-黄变换的核心步骤它把信号自适应地筛成一组本征模态函数IMF筛分过程不需要预设基函数这一点对轴承振动这种典型的非线性、非平稳信号非常友好。但 EMD 有一个被反复吐槽的老毛病——模态混叠。直观地说就是本应属于不同时间尺度的成分被塞进了同一个 IMF或者同一个冲击成分被拆散到好几个 IMF 里。轴承内圈故障的振动信号里既有转频谐波又有周期性的冲击衰减还叠加着随机噪声这三类成分的时间尺度差别很大纯 EMD 筛分时经常在冲击附近发生模态混叠把一个故障冲击的响应拆得七零八落后面提特征时根本分不清哪个分量代表故障。EEMD集合经验模态分解的应对办法是给原始信号叠加白噪声利用白噪声在时频域均匀铺开的特性把不同尺度的成分“冲散”再多次平均。白噪声让每次分解略有不同平均后噪声被抹掉模态混叠也确实减轻了。但 EEMD 有个副作用白噪声的残余不会被完全平均掉重构信号和原始信号之间存在偏差而且每次试验可能筛出不同数量的 IMF到后面做批量特征提取时特征维度对不齐的问题非常让人头疼。CEEMD 的思路更直接不是只加正噪声而是每次同时加一对正、负噪声做两次分解再取平均。正负噪声在平均过程中相互抵消残留噪声比 EEMD 小一个量级模态混叠的抑制效果也更稳定。工业现场落地时选 CEEMD 而不是 EEMD原因就两条轴承早期故障的冲击成分很弱经不起 EEMD 残差噪声再“洗一遍”故障诊断要的是可复现的特征正负互补对让同一段信号每次跑出来的 IMF 更稳定。下面这个表把三者的差异列清楚方便选型时对照。方法辅助噪声残留噪声模态混叠抑制计算量EMD无无差低EEMD单侧白噪声有残差中中CEEMD正负互补噪声对基本抵消好高2.2 用互补噪声对实现CEEMD一段可以直接跑的分解代码PyEMD 库自带 CEEMDAN 接口但 CEEMD 的思想和它完全同源。我一般在工程里直接用手写的互补噪声对实现原因只有一个可以固定max_imf从源头保证每个样本分解出来的 IMF 行数一致后面特征维度才不会错位。下面这段代码可以直接跑。import numpy as np from PyEMD import EMD def _align_imfs(a, b, max_imf): # 正负两次分解的 IMF 数量可能不同统一补零到 max_imf 行再截断 pa np.vstack([a, np.zeros((max_imf - a.shape[0], a.shape[1]))]) pb np.vstack([b, np.zeros((max_imf - b.shape[0], b.shape[1]))]) return pa[:max_imf], pb[:max_imf] def ceemd(signal, trials50, std_ratio0.05, max_imf8): # trials: 互补噪声对试验次数std_ratio: 噪声幅值相对信号标准差的比例 noise_std std_ratio * np.std(signal) rng np.random.default_rng(42) # 固定随机种子保证结果可复现 acc np.zeros((max_imf, len(signal))) for _ in range(trials): noise rng.normal(0, noise_std, sizesignal.shape) imf_pos EMD(max_imfmax_imf)(signal noise) # 正噪声分解 imf_neg EMD(max_imfmax_imf)(signal - noise) # 负噪声分解 imf_pos, imf_neg _align_imfs(imf_pos, imf_neg, max_imf) acc (imf_pos imf_neg) / 2.0 # 互补对平均噪声抵消 return acc / trials逻辑说明每次试验对加噪后的信号分别做正、负两次 EMD_align_imfs用补零统一行数再取平均。正负噪声在同一位置的幅值相反平均后辅助噪声被抵消留下的是信号本身的分解结果trials次重复进一步稳定随机性。参数上std_ratio一般取 0.050.2太大把真实成分淹没太小模态混叠抑制效果变差trials取 30100再大收益很小但计算时间翻倍max_imf固定为 8轴承信号前 68 个 IMF 基本包含了 95% 以上的能量后面的分量多为低频趋势项对分类没有贡献。提示PyEMD 需要用 pip 安装。如果不希望手写直接用 PyEMD 自带的 CEEMDAN 接口也能跑通但要注意它不保证每次输出的 IMF 行数一致特征提取前必须做对齐处理。使用示例fs 2048 t np.arange(0, 2, 1 / fs) # 模拟转频 30Hz 2倍频 120Hz 周期冲击 随机噪声 signal (0.5 * np.sin(2 * np.pi * 30 * t) 0.3 * np.sin(2 * np.pi * 120 * t) 0.8 * np.exp(-2000 * (t % 0.1 - 0.02) ** 2) 0.1 * np.random.randn(len(t))) imfs ceemd(signal, trials50, std_ratio0.05, max_imf8) print(imfs.shape) # (8, 4096)2.3 分解质量怎么看频谱分离度和能量占比代码跑通只是第一步分解质量决定后面特征有没有区分度。我一般用两个指标检查。第一个是相关系数每个 IMF 与原始信号的 Pearson 相关系数正常情况下应该递减第一个 IMF 捕捉最高频成分相关系数通常在 0.50.8后续越来越低如果中间某个 IMF 的相关系数突然反弹说明分解得不够干净或者噪声幅值设置不合适。第二个是能量占比计算每个 IMF 能量占全部 IMF 总能量的比例正常分布是前几个 IMF 占比高、快速衰减如果能量分散在 6 个 IMF 上都不收敛多半是std_ratio设得太大。from scipy.stats import pearsonr for i, imf in enumerate(imfs): r, _ pearsonr(signal, imf) energy np.sum(imf ** 2) / np.sum(imfs ** 2) print(fIMF{i1}: corr{r:.3f}, energy_ratio{energy:.3f})经验上std_ratio从 0.05 往上调时能量分布会逐渐右移调到 0.1 左右通常是轴承信号的一个甜点位。分解完的 IMF 直接作为特征来源下一步就是设计特征向量喂给 BP 神经网络。3. BP神经网络建模与特征向量构造IMF怎么变成网络的输入3.1 特征要压缩从IMF到能量占比、峭度和偏度分解后每个样本得到 8×4096 的矩阵8 个 IMF 每个都是 4096 个采样点。直接把原始采样点作为 BP 输入不现实维度 32768训练样本量又不够模型必然过拟合。常见做法是把每个 IMF 压缩成几个统计量拼成一个固定长度的特征向量。轴承故障在频域上表现为特定频带的能量抬升在时域上表现为冲击导致的峭度变化因此下面这组特征在工程里最常用。特征含义对故障的敏感点能量占比该 IMF 能量占总能量的比例不同故障激发的频带不同能量落点不同峭度四阶中心矩归一化冲击型故障内圈、外圈点蚀峭度显著升高偏度三阶中心矩归一化信号不对称程度滚动体故障常伴随标准差幅值波动幅度整体幅值水平工况变化时也会变特征提取代码from scipy.stats import kurtosis, skew def extract_imf_features(imfs): # imfs 形状 (n_imf, n_samples)这里固定取前 8 行 total_energy np.sum(imfs ** 2) feats [] for imf in imfs: e_ratio np.sum(imf ** 2) / total_energy # 能量占比归一化后不受幅值影响 feats.extend([ e_ratio, kurtosis(imf), # 峭度冲击越强值越大 skew(imf), # 偏度分布不对称程度 np.std(imf), # 幅值标准差 ]) return np.array(feats) # 长度 8 * 4 32参数说明特征向量长度固定为 32 维其中每个 IMF 的能量占比相加等于 1这一维度天然归一化不受传感器灵敏度影响。峭度和偏度对脉冲型故障非常敏感但数值范围可能到几十甚至上百所以后面进 BP 之前必须做标准化。如果样本量很小可以只取前 6 个 IMF 的特征砍到 24 维减少过拟合风险。3.2 网络结构怎么定输入层32、输出层4、隐层一到两层一张标准的 BP 神经网络结构图是这样的最左边输入层节点数等于特征维度这里就是 32最右边输出层节点数等于故障类别数这里是 4 类正常、内圈故障、外圈故障、滚动体故障用 softmax 归一化成概率中间一到两个隐层。隐层节点数没有金科玉律工程上我先按输入维数与输出维数乘积的平方根起算也就是 sqrt(32×4)≈11但实际用 adam 优化器时64 到 32 的隐层组合往往收敛更快、准确率更高因为容量大了之后优化器能自己找到更好的解配合正则就能压住过拟合。激活函数选 relu 而不是 sigmoid 或 tanh原因有二relu 的梯度不饱和两层往上的结构也不会梯度消失故障特征经标准化后正负都有relu 的稀疏激活恰好能把不敏感的分量关掉。输出层用 softmax损失函数用交叉熵。训练过程就是反向传播梯度下降这就是 BP 名字的由来但现在没人手写梯度了adam 是默认选择它把一阶动量和二阶动量都考虑进去收敛比纯 SGD 稳得多。为什么选 BP 而不是 SVM 或者随机森林在故障诊断场景里BP 的优势是类别多了之后重训成本低新增一个故障类型只需改输出层再训练而且特征工程完善之后BP 对特征间非线性组合的拟合能力最直接。SVM 在小样本上确实能打但样本量上来之后核矩阵计算吃内存扩展性差随机森林不需要标准化但它对连续特征边界的分割比较粗糙在峭度、能量占比这种连续值特征上不如 BP 平滑。3.3 用MLPClassifier训练五个必调参数一次说清直接上代码from sklearn.preprocessing import StandardScaler from sklearn.neural_network import MLPClassifier from sklearn.model_selection import train_test_split # 标准化是硬前提能量占比是 0~1峭度可能到几十量纲差太大会让优化器走偏 scaler StandardScaler() X_scaled scaler.fit_transform(X) model MLPClassifier( hidden_layer_sizes(64, 32), # 两个隐层先按经验定后面用验证集微调 activationrelu, # 隐层激活函数输出层自动用 softmax solveradam, # 优化器在多数轴承数据上就是默认最佳项 alpha0.0001, # L2 正则系数防过拟合样本少时调到 0.001 batch_size64, # 小批量梯度下降内存紧张就降到 32 learning_rate_init0.001, # adam 初始学习率过大震荡、过小收敛慢 max_iter300, # 配合 early_stopping不必硬跑满 early_stoppingTrue, # 监控验证集损失连续 10 轮不降就停 random_state42 # 固定随机种子方便复现实验 ) model.fit(X_scaled, y)参数说明都在注释里这里说两个经验点early_stoppingTrue时max_iter不用设太大300 足够验证集损失不降就停能省下大量无用迭代alpha从 1e-4 起调如果训练准确率极高而测试集很差先把alpha往 1e-3 方向调而不是去加隐层这个顺序在故障诊断里大概率对。4. 大数据场景的数据组织与训练策略振动数据规模化落地的三个动作4.1 连续信号切样本窗口长度和重叠率怎么配工业现场采集的是连续振动波形一段几小时的数据里可能只有几十次故障冲击。建模前要把长信号切成固定长度的样本窗口每个窗口对应一个样本、一个标签。窗口长度取决于转速。轴承每转一圈至少产生一次冲击激励要保证一个窗口里包含 20 圈以上的旋转周期故障特征才稳定。以常见的 1500 r/min转频 25Hz为例窗口取 12 秒既包含 2550 个旋转周期又不至于把工况漂移也框进来。采样率 2048Hz 时2 秒窗口就是 4096 点正好是 CEEMD 比较舒服的输入长度。重叠率决定样本总量和样本间相关性。重叠越高样本越多但相邻窗口高度相似相当于把同一个振动事件复制了好几份训练集和测试集如果随机切分准确率会虚高。我一般取 50% 重叠既能把样本量翻倍又不会让相邻样本几乎一样。步长小于窗口的一半就开始产生明显的冗余计算这是大数据场景下最不值得花的钱。def sliding_windows(signal, win_len, step, fs): # win_len 和 step 单位是秒返回二维数组每行一个窗口样本 ws, ss int(win_len * fs), int(step * fs) n len(signal) return np.array([signal[i:i ws] for i in range(0, n - ws, ss)]) # 示例2 秒窗口、1 秒步长10 分钟数据得到 599 个样本 windows sliding_windows(raw_signal, win_len2.0, step1.0, fs2048) print(windows.shape) # (599, 4096)4.2 批量特征提取管线multiprocessing让CEEMD不再拖后腿CEEMD 是纯 CPU 迭代计算4096 点信号一次分解在普通机器上要几十到一百多毫秒听起来不慢但乘以几十万个窗口就成了灾难。大数据场景下这一步的瓶颈几乎全在特征提取而不是模型训练常见做法是写成可并行的管线每个窗口独立分解、独立提特征天然适合多进程。from multiprocessing import Pool def window_to_feature(window): # 每个进程内执行完整分解特征提取进程间无共享状态 imfs ceemd(window, trials30, std_ratio0.05, max_imf8) return extract_imf_features(imfs) if __name__ __main__: windows sliding_windows(raw_signal, win_len2.0, step1.0, fs2048) with Pool(processes8) as pool: # 进程数设为本机物理核数 X pool.map(window_to_feature, windows) X np.vstack(X) # 每行 32 维直接变成训练矩阵pool.map会按进程数把窗口列表拆块分发结果按输入顺序返回所以X的顺序和windows一一对应后面打标签不会错位。进程数设为本机物理核数而不是逻辑核数因为 CEEMD 是密集计算超线程带来的额外收益有限。如果内存紧张把windows改成生成器、按批次喂给pool.imap效果一样。还要注意trials30是精度和速度的折中值离线分析可以调到 100批量产线特征提取建议保持 30。4.3 大数据训练的三个关键动作分设备切分、类别加权、集群化第一个动作是切分方式。几十万样本随机切分训练/测试集是故障诊断里最常见的翻车点同一个连续信号切出的相邻窗口高度相关随机切分会把同一个事件同时放进两边测试准确率虚高到不真实。正确做法是按设备或按时间段切分同一台设备的样本全部进训练集或全部进测试集绝不能两边都有。from sklearn.model_selection import GroupKFold # groups 里每个设备一个 idGroupKFold 保证同一设备只出现在一个折里 gkf GroupKFold(n_splits5) for train_idx, val_idx in gkf.split(X_scaled, y, groupsdevice_ids): pass # 每个折的 train/val 在设备维度上完全隔离第二个动作是类别不平衡。设备大部分时间正常故障样本天然稀缺BP 会偏向多数类。注意 sklearn 的MLPClassifier没有class_weight参数正确做法是在fit时传sample_weight或者对少数类做 SMOTE 过采样。样本加权最简单from sklearn.utils.class_weight import compute_class_weight cw compute_class_weight(balanced, classesnp.unique(y), yy) model.fit(X_scaled, y, sample_weightcw[y]) # 少数类样本获得更高权重第三个动作是集群化。数据量到 TB 级、单机内存扛不住时常见做法是把“滑窗 CEEMD 特征提取”写成 Spark 作业每个分区跑一段窗口输出特征向量到 Parquet 文件模型训练反而不是瓶颈32 维输入、两层 MLP 在任何规模下都能在单机完成。这也是工业大数据集群部署策略里最典型的模式计算往数据那边移动而不是把数据拉到一台机器上。5. CEEMD-BP落地避坑五个让模型翻车的真实问题5.1 IMF数量对不齐特征维度直接报错现象同一批数据跑出来有的样本分解出 8 个 IMF有的只有 6 个特征向量长度不一致np.vstack(X)直接抛维度错误。用 PyEMD 自带接口跑时尤其常见。原因EMD 类分解的 IMF 数量由信号自身结构决定正常信号和故障信号的频带结构不同筛出的分量数量天然不同正负噪声两次分解筛出的 IMF 数也未必相等直接相加会因形状不一致报错。解决手写 CEEMD 时固定max_imf8并用_align_imfs补零对齐特征提取只取前 8 行超出部分丢弃。补零行的能量占比为 0对应标准差、峭度特征也接近 0对分类结果影响很小但要保证训练和测试走同一条对齐逻辑。5.2 训练集准确率高得离谱换台设备就崩现象交叉验证 98%部署到另一条产线后准确率掉到 70% 出头现场工程师直接说模型就是个黑匣子不敢用。原因样本随机切分造成数据泄漏。相邻窗口几乎相同模型记住的是这段信号的具体噪声模式不是故障本质而不同设备的转速、负载、安装刚度都不一致信号分布整体偏移模型没见过这种分布就崩了。解决严格按设备或时间段切分交叉验证用GroupKFold。如果换设备后准确率仍然明显下降考虑做转速归一化把信号按转频重采样到统一转频下或者把转速、负载作为辅助特征一起输入这一步在跨产线场景里几乎是必做的。5.3 特征提取算了一晚上还没跑完现象几百 GB 振动数据单进程滑窗特征提取跑了 10 个小时第二天一看才处理了 60%整个项目卡死在数据预处理上。原因CEEMD 是迭代筛分过程串行计算耗时线性增长很多人还把重叠率设到 90%制造了大量冗余窗口每个窗口都完整做一次分解计算量翻了好几倍。解决重叠率降到 50%用multiprocessing.Pool按文件并行数据清洗阶段先把平稳无故障的长段过滤掉只对幅值或峭度超阈值的区段做精细分解。另外可以先在 1000 个窗口上试跑统计单窗口平均耗时乘以总窗口数估算整体时间别等跑完才发现烧不动。5.4 故障样本太少模型把所有样本都判成正常现象训练完准确率 95%打开混淆矩阵发现故障类召回率接近 0高准确率全靠正常类样本撑起来故障一个都没抓住。原因工业现场设备大部分时间正常运行故障样本不到总量的 5%。BP 在类别严重失衡时天然偏向多数类因为把少数类全判错总损失也不大优化器觉得这样“划算”。解决优先用sample_weight给少数类加权代码见 4.3样本量允许时用 SMOTE 合成少数类样本。注意 SMOTE 一定要在特征层面做不要在原始信号层面做否则合成的“振动信号”在物理上不成立模型学到的全是假模式。5.5 端点效应把IMF两端折弯特征被污染现象分解出的 IMF 两端幅值明显上翘或下弯能量占比和峭度特征异常偏大而且窗口越短越明显。原因EMD 类方法在信号端点处用三次样条插值端点之外没有数据约束筛分过程把两端的误差越放越大这就是端点效应。CEEMD 能平均掉一部分随机噪声但端点处的系统性畸变还在。解决分解前对窗口做镜像延拓把两端各外延 10% 再分解分解后裁掉延拓段只保留原始窗口部分的 IMF。滑窗切分时留出重叠余量也能间接缓解端点问题因为窗口边界处恰好是冲击峰值的概率降低了。6. 验证模型与特征有效性混淆矩阵和分组交叉验证给结果上保险模型训练完不是看个 accuracy 就完了。故障诊断里最容易骗人的就是单次随机切分的准确率尤其当样本来自同一个连续信号时。我现在的习惯是只信两样东西按设备分组的交叉验证分数和测试集上的混淆矩阵。from sklearn.metrics import classification_report from sklearn.model_selection import cross_val_score, GroupKFold # 单次测试集的分类报告重点看每个类别的召回率而不是总准确率 print(classification_report(y_test, y_pred, target_names[正常, 内圈, 外圈, 滚动体])) # 按设备分组交叉验证分数均值±方差才有说服力 scores cross_val_score(model, X_scaled, y, cvGroupKFold(n_splits5), groupsdevice_ids) print(fGroupKFold acc: {scores.mean():.3f} ± {scores.std():.3f})混淆矩阵里我重点看两类错误正常样本被误判成故障误报率高会让现场频繁停机检查早期故障被误判成正常这才是最贵的事故源头。如果误报集中在某一个故障类别上说明该类的特征和其他类重叠严重回去看能量占比特征多半是两类故障激发的频带太接近需要补充频带特征或者换更高采样率的数据。再花十分钟做一个消融对比就能证明 CEEMD 这一步的价值同一份数据分别用“原始时域统计特征 BP”和“CEEMD 特征 BP”跑同一个GroupKFold如果后者均值高 3 个百分点以上说明分解确实在起作用。把两组scores结果画成柱状图也是故障分析报告里最直观的数据可视化材料。最后一个建议把scaler和model一起用joblib打包成一份模型文件部署时直接加载预测前对实时窗口做同样的 CEEMD 分解和特征提取。我踩过一次坑部署时忘了带标准化器实时数据进来的尺度对不上模型输出全是同一个类别排查了大半天。现在我的习惯是标准化器、模型、特征提取函数三件套打进同一个文件验证和部署共用一套代码路径。如果你打算把 CEEMD-BP 这套方案放进产线建议也从一开始就把这条验证-部署链路固定下来。希望帮到你。本文还有配套的精品资源点击获取
返回列表