概率神经网络PNN实现变压器故障诊断:从DGA特征到仿真实践 简介基于概率神经网络的变压器故障诊断源码资源面向电力系统运维人员、故障诊断研究者及机器学习初学者用于快速搭建变压器故障识别实验。资源包内含2个文件包括1个MATLAB脚本.m和1个数据文件.mat压缩包整体仅6KB轻量易用便于直接运行与二次改造。PNN模型通过输入层、模式层与分类层完成故障特征识别能够处理电气参数、油色谱分析等非线性数据实现变压器多种故障类型的有效区分。代码涉及数据预处理、高斯核参数设定、Parzen窗口概率密度估计及分类输出等关键环节可帮助读者完整理解PNN在工程诊断中的实现流程并掌握故障特征提取与分类器设计思路。目前已有329人学习下载适合需要结合程序代码开展故障诊断课题的初学者或工程人员。资源体量虽小但结构清晰可作为变压器故障诊断方向的入门样例与实验基线。1. pnnfd在变压器故障诊断里解决什么问题设备台账上写着“正常”第二天就报警打开色谱报告一看乙炔已经超过注意值——干变压器运维的多少都经历过这种心惊肉跳。pnnfd 拆开就是 Probabilistic Neural Network 加 Fault Diagnosis用概率神经网络做变压器故障诊断把油中溶解气体DGA数据变成故障结论。这个方向解决的核心问题很直接故障样本少、气体特征和故障类型之间又是强耦合的非线性关系传统阈值法和三比值法误判率高而 PNN 训练快、适合小样本、对噪声不敏感正好卡在变压器故障诊断的痛点上。适合谁做设备状态检修的工程师、写故障诊断代码的研究生以及被仿真数据和实测数据来回折磨的论文党。2. 变压器故障特征从哪来DGA三比值与特征向量构造2.1 油中溶解气体为什么是诊断的第一入口变压器内部绝缘油和绝缘纸在热和电作用下会分解出特征气体氢气H2、甲烷CH4、乙烷C2H6、乙烯C2H4、乙炔C2H2、一氧化碳CO和二氧化碳CO2。这七种气体其实是在告诉你绝缘材料“受了什么伤”——局部放电时氢气占主导高温过热时乙烯明显升高电弧放电则直接拉高乙炔。变压器不像旋转电机可以装一堆振动探头油色谱在线监测装置已经普及DGA 数据成本低、来源稳定所以工程上第一诊断入口基本都是它。但直接用七种气体浓度做特征有个问题不同变压器油量不同、负载不同绝对浓度差异很大。同一台设备冬天和夏天的产气速率也不一样。所以业界更常用的是气体之间的比值把“量”的信息换成“比例关系”的信息。这里要提一个经典工具——三比值法。它把三组比值C2H2/C2H4、CH4/H2、C2H4/C2H6分别离散成 0/1/2 编码组合后对照故障类型表。它简单但离散化边界非常粗暴后面第 5 章我会专门讲这个坑。2.2 三比值法的编码逻辑与特征局限三比值法的物理逻辑是分层的乙炔与乙烯的比值反映放电能量比值越高说明电弧越剧烈甲烷与氢气的比值反映热分解和放电分解的相对强弱乙烯与乙烷的比值反映热解温度温度越高乙烯占比越大。编码规则如下气体比值范围编码C2H2/C2H40.1 / 0.1~3 / 30 / 1 / 2CH4/H20.1 / 0.1~1 / 11 / 0 / 2C2H4/C2H61 / 1~3 / 30 / 1 / 2三个编码拼起来查 IEC 60599 或 GB/T 7252 里的表就能得到故障类型。比如 010 通常对应局部放电200 对应高能放电。它最大的问题在于边界值 0.1 和 3 附近测量误差稍微动一下编码就从 0 跳到 1结论从局部放电变成过热这是三比值法被诟病最多的地方。我给 PNN 做输入时一般不再做离散编码而是直接用连续比值。让模型自己去学比值和故障类型之间的映射关系等于把“边界怎么切”这个问题交给核密度估计而不是拍脑袋定阈值。特征向量就是三个连续比值如果样本量足够我还会把七种气体的对数浓度拼进去凑成十维特征但那样需要更多样本小数据集慎用。2.3 故障样本不足时怎么补从局部放电图谱到仿真数据变压器故障诊断项目起步时最头疼的就是样本真实故障样本少而且故障类型分布极不均匀——正常样本一大把高能放电样本可能只有两三条。常见做法是先用手头实测数据搭一个能跑通的小数据集再用仿真或公开文献里的典型数据扩充。补充一句如果你的方向是局部放电而不是 DGA特征就不是气体比值了而是局部放电典型图谱里的统计参数。PRPD 图谱相位分辨局部放电图谱横轴是工频相位、纵轴是放电幅值、颜色深浅代表放电次数从图谱里能提取最大放电幅值、平均放电量、正负半周不对称度等统计量同样可以喂给 PNN。下面是构造 DGA 演示数据集的代码这段代码的目的是让后续 PNN 模型有一个可复现的输入。import numpy as np def generate_dga_samples(n_per_class20, sigma0.35, seed42): 生成示意DGA三比值数据集共7类故障。 rng np.random.default_rng(seed) # 类别: 0正常 1低温过热 2中温过热 3高温过热 # 4局部放电 5低能放电 6高能放电 centers { 0: [0.05, 1.20, 0.80], # 正常老化 1: [0.04, 0.06, 0.60], # 低温过热 2: [0.05, 0.45, 1.60], # 中温过热 3: [0.80, 0.75, 3.20], # 高温过热 4: [0.02, 0.03, 0.20], # 局部放电 5: [1.10, 0.05, 0.45], # 低能放电 6: [1.45, 1.60, 1.15], # 高能放电 } X_list, y_list [], [] for cls, center in centers.items(): # lognormal保证生成的比值始终为正 samples rng.lognormal( meannp.log(center), sigmasigma, size(n_per_class, 3) ) X_list.append(samples) y_list.append(np.full(n_per_class, cls, dtypeint)) return np.vstack(X_list), np.concatenate(y_list) X_demo, y_demo generate_dga_samples(n_per_class20, sigma0.35, seed7) print(X_demo.shape, y_demo.shape)这里centers是每个故障类别在三维比值空间中的典型位置我按三比值法的典型区间设置的局部放电的 C2H2/C2H4 很低而高能放电的该比值极高。sigma0.35是对数正态分布的标准差控制类内散布程度调小数据更集中、分类更容易调大数据重叠更明显、更贴近真实情况。这类代码生成的数据只能用于跑通流程正式项目里务必用真实 DGA 记录替换。3. 手写概率神经网络PNN最小Python实现与参数调优3.1 PNN四层结构贝叶斯决策和Parzen窗PNN 的结构比 BP 网络简单得多只有四层输入层、模式层、求和层、输出层。输入层接收特征向量模式层每个训练样本对应一个神经元计算输入样本与这个训练样本的高斯距离求和层按类别把同类的模式层输出累加得到该类别的核密度估计输出层取密度最大的类别作为预测结果。它背后的数学是贝叶斯决策假设各类别先验概率相等给定未知样本 x分别估计它在每个类别下的条件概率密度选密度最大的类。密度估计用的是 Parzen 窗法高斯核函数写成f_c(x) (1 / n_c) * sum(exp(-||x - x_i||^2 / (2 * sigma^2)))看起来复杂代码里其实就是一个高斯距离求和。为什么 PNN 适合变压器故障诊断三个理由第一训练过程就是记住训练样本没有迭代不存在 BP 里的梯度消失和局部最优问题第二小样本下核密度估计比多层网络更稳不容易过拟合第三预测阶段可以随时往模式层加新样本天然支持增量学习这对在线监测很友好。代价是预测时要和所有训练样本算距离样本量过万后速度会下降但变压器故障诊断样本量一般只有几百到几千完全够用。3.2 最小可跑的 PNN 实现我一般不用现成的库直接手写 PNN核心逻辑不到三十行。向量化实现不仅代码简洁还比 for 循环快一到两个数量级。import numpy as np class PNN: 概率神经网络分类器高斯核无需迭代训练。 def __init__(self, sigma0.1): self.sigma sigma self.X_ None self.y_ None self.classes_ None def fit(self, X, y): fit只是保存训练样本没有迭代优化过程。 self.X_ np.asarray(X) self.y_ np.asarray(y) self.classes_ np.unique(y) return self def _kernel_matrix(self, X): 计算所有测试样本与所有训练样本的高斯核值。 X np.asarray(X) # diff的形状: (n_test, n_train, n_features) diff X[:, None, :] - self.X_[None, :, :] sq_dist np.sum(diff ** 2, axis2) return np.exp(-sq_dist / (2 * self.sigma ** 2)) def predict_proba(self, X): 返回每个类别的核密度估计值未归一化。 kernel self._kernel_matrix(X) proba np.zeros((kernel.shape[0], len(self.classes_))) for i, cls in enumerate(self.classes_): mask self.y_ cls proba[:, i] kernel[:, mask].mean(axis1) return proba def predict(self, X): proba self.predict_proba(X) return self.classes_[np.argmax(proba, axis1)]_kernel_matrix里的广播运算是关键X[:, None, :]把测试样本扩成三维self.X_[None, :, :]把训练样本扩成三维相减后每个测试样本和每个训练样本都有了距离向量。sq_dist累加得到欧氏距离平方最后用高斯核映射成相似度。predict_proba里mean(axis1)就是在做求和层的类内平均等价于公式里的 1/n_c 求和。3.3 训练与评估从划分数据集到读混淆矩阵PNN 虽然不需要训练但数据预处理一步都不能省。特征缩放尤其重要——三个比值量级差异很大C2H2/C2H4 可能到 5CH4/H2 可能只有 0.05如果不标准化欧氏距离会被大数值的特征主导。标准做法是先用训练集 fit 一个 StandardScaler再分别 transform 训练集和测试集。from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.metrics import accuracy_score, classification_report, confusion_matrix # 沿用上一章的数据生成函数 X, y generate_dga_samples(n_per_class20, sigma0.35, seed7) # stratify保证每类故障在训练/测试集中占比一致 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) scaler StandardScaler().fit(X_train) X_train_s scaler.transform(X_train) X_test_s scaler.transform(X_test) pnn PNN(sigma0.15) pnn.fit(X_train_s, y_train) y_pred pnn.predict(X_test_s) print(faccuracy {accuracy_score(y_test, y_pred):.3f}) print(classification_report(y_test, y_pred, digits3))stratifyy这段别省略。变压器故障数据天然不平衡正常样本多、故障样本少如果随机划分小类故障很可能在测试集里一个样本都没有整体准确率看着还行局部放电类的真实召回率完全不可知。classification_report 里每一类的 precision 和 recall 都要看尤其注意样本量少的类别。到这里一个跑得通的变压器故障诊断代码链路已经完整了。4. 用MATLAB/Simulink生成变压器故障数据从励磁涌流仿真到数据互通4.1 为什么数据集里要掺仿真数据实测 DGA 样本很难拿全七类故障尤其高能放电和电弧故障谁也不会为了收集数据让变压器真打一次穿。所以工程上常见做法是拿 MATLAB/Simulink 做变压器故障仿真把励磁涌流、匝间短路、三相短路等工况的电流波形跑出来再提取特征形成一个可训练的数据集。仿真数据替代不了实测但能把模型开发阶段最缺的“少数类样本”补齐。有一种翻车路径是仿真数据训练完拿实测数据一测准确率直接掉一半。原因一般是仿真模型太理想——变压器饱和特性没设置、剩磁初始条件没给、合闸角固定在一个值。仿真数据的作用是让模型先学会物理边界最后还是要用少量实测数据做迁移校准这个策略比纯仿真或纯实测都稳。4.2 励磁涌流仿真模型的搭建要点励磁涌流这个现象很适合用来理解变压器故障数据为什么难做。变压器空载合闸瞬间如果合闸角接近零度铁芯磁通从零突变到两倍额定磁通加上剩磁可能直接饱和激磁电流可以冲到额定电流的几倍甚至十几倍。这个电流波形是尖顶波、偏向时间轴一侧、含有大量二次谐波和匝间短路电流波形长得有点像这就是故障诊断的难点之一。Simulink 里的模型搭建常见做法是电源侧用正弦电压源变压器用饱和变压器模型老版本叫 SimPowerSystems现在归在 Simscape Electrical 里额定功率、额定频率、一次二次电压按实际设备参数填。变压器模块里有饱和特性参数一组是电流和磁通的对应点一定要设置默认线性模型是仿不出涌流的。合闸角通过电压源的相位参数控制想看最恶劣涌流就把相位设在 0 度附近。剩磁的设置在仿真里是个容易被忽略的细节。变压器模块如果没有显式的剩磁设置项可以通过给饱和电感赋初始磁通来实现把初始磁通设成额定磁通的 60%~80%方向与稳态磁通相反。这是仿真数据和实测数据能对得上的关键之一。4.3 故障工况设置与数据导出到 .mat除了励磁涌流还要设置故障工况二次侧三相短路、单相接地、匝间短路等。三相短路在 Simulink 里用故障模块设置触发时间即可比如 0.05 秒投入、0.15 秒切除。每种工况跑完把三相电流通过 To Workspace 模块导出成变量命名成 Ia、Ib、Ic再用 save 命令存成 .mat 文件save(sim_data.mat, t, Ia, Ib, Ic);t 是时间序列向量。这里提醒一句To Workspace 的采样时间要设小一点至少 10kHz 以上否则后面算谐波占比时频率分辨率不够。50Hz 基波下10kHz 采样率对应每周期 200 个点算到 5 次谐波没问题再高就力不从心了。4.4 从 .mat 到 PNN 输入Python 侧读取与特征拼接Simulink 导出的 .mat 文件Python 侧用 scipy.io 直接读。读取后不能把整段波形直接喂给 PNN先要提取特征。我把每个工况的电流波形算成一组统计量基波幅值、二次谐波占比、三次谐波占比、电流峰值和有效值。这些特征对区分励磁涌流和短路电流很有效——涌流的二次谐波占比通常超过 15%而短路电流的二次谐波占比一般低于 5%。from scipy.io import loadmat import numpy as np # 读取Simulink导出的仿真数据 data loadmat(sim_data.mat) t data[t].ravel() ia data[Ia].ravel() dt t[1] - t[0] fs 1.0 / dt # 去除开头直流偏置避免FFT频谱被直流分量淹没 ia_ac ia - np.mean(ia) # 计算频谱 fft_vals np.abs(np.fft.rfft(ia_ac)) freqs np.fft.rfftfreq(len(ia_ac), ddt) def harmonic_ratio(freqs, fft_vals, target_freq, base_freq50.0): 计算目标谐波与基波的幅值比。 target_idx np.argmin(np.abs(freqs - target_freq)) base_idx np.argmin(np.abs(freqs - base_freq)) return fft_vals[target_idx] / (fft_vals[base_idx] 1e-12) feature np.array([ fft_vals[np.argmin(np.abs(freqs - 50.0))], # 基波幅值 harmonic_ratio(freqs, fft_vals, 100.0), # 2次谐波占比 harmonic_ratio(freqs, fft_vals, 150.0), # 3次谐波占比 np.max(np.abs(ia)), # 电流峰值 np.sqrt(np.mean(ia ** 2)), # 电流有效值 ])harmonic_ratio里加1e-12是防止基波幅值接近零时除数为零。每个工况的波形都跑一遍这段代码得到一条特征向量所有工况汇总成一个特征矩阵。这个矩阵和第 2 章的 DGA 特征矩阵结构一样后续的标准化和 PNN 训练代码完全复用。仿真数据和实测数据混合时建议用第 5 章里说的方式做验证而不是直接把两部分堆在一起训练否则你根本不知道模型到底学到了仿真特征还是真实特征。5. 变压器故障诊断避坑清单5条高频踩坑与排查方法5.1 三比值编码边界值处理不当导致故障类型错判现象同一份 DGA 数据A 工具判局部放电B 工具判低能放电两边都说是按标准来的。原因三比值法在边界值 0.1、1、3 附近不同实现用的不等式不同有的用有的用0.1 这个点刚好掉进裂缝里。解决PNN 输入直接用连续比值不做离散编码把边界问题交给模型处理。如果必须做三比值对照代码里明确边界归属比如C2H2 / C2H4 0.1算编码 0写成注释让后来人看得懂。5.2 归一化顺序写反造成数据泄漏现象训练准确率 99%测试准确率只有 70%怎么调 sigma 都没用。原因很多人习惯先对全数据集做 StandardScaler 再划分训练集和测试集这等于让 scaler 偷看了测试集的均值和方法属于数据泄漏。解决先划分再scaler.fit(X_train)然后分别 transform 训练集和测试集。这个错误在故障诊断代码里出现频率极高我自己的项目里也翻过车排查顺序永远是先看预处理。5.3 平滑因子 sigma 一刀切导致过拟合或欠拟合现象sigma 设 0.01 时训练集全对、测试集一塌糊涂sigma 设 1.0 时所有类别概率几乎一样完全分不开。原因sigma 是高斯核的带宽。它太小核函数只对自己对应的训练样本有响应等价于记住了数据它太大密度估计被抹平成均匀分布。解决用网格搜索在 0.01 到 1.0 的对数范围里扫常见做法是试[0.05, 0.1, 0.2, 0.3, 0.5]选测试集 f1 最大的值。先固定训练集划分再去调 sigma否则每次结果不可比。5.4 样本划分不分层导致小类故障准确率虚高现象测试集整体准确率 85%但翻 classification_report 发现低能放电这一类 recall 是 0因为测试集里根本没有低能放电样本。原因变压器故障数据天然不平衡随机划分时小类被全部划进训练集。解决train_test_split加stratifyy交叉验证用StratifiedKFold。另外报告模型性能时不要只报整体准确率每一类的精确率和召回率都要列出来否则小类故障的漏报会被整体指标掩盖。5.5 励磁涌流仿真忽略剩磁导致特征分布偏移现象仿真数据训练完用实测涌流数据一测误判率特别高。原因Simulink 里变压器饱和模型默认剩磁为 0合闸瞬间没有偏磁涌流幅值偏小、二次谐波占比偏低特征分布和真实设备对不上。解决仿真时给变压器设置初始磁通一般取额定磁通的 60%~80%方向按合闸前铁芯残留磁通设置。同时把合闸角扫几个典型值比如 0 度、45 度、90 度让训练集覆盖从最恶劣涌流到轻微涌流的整个区间。6. 进阶把PNN封装成可搜索模型并接入在线监测流程PNN 的 sigma 参数对结果影响大手动试又费时间常见做法是把它包装成 sklearn 估计器直接接 GridSearchCV。注意 fit 方法里要返回 self并且保存 classes_ 属性这是 sklearn 接口的基本约定。from sklearn.base import BaseEstimator, ClassifierMixin from sklearn.model_selection import GridSearchCV class PNNEstimator(BaseEstimator, ClassifierMixin): def __init__(self, sigma0.1): self.sigma sigma def fit(self, X, y): self.classes_ np.unique(y) self.X_ np.asarray(X) self.y_ np.asarray(y) return self def predict_proba(self, X): kernel self._kernel_matrix(X) proba np.zeros((kernel.shape[0], len(self.classes_))) for i, cls in enumerate(self.classes_): proba[:, i] kernel[:, self.y_ cls].mean(axis1) return proba def predict(self, X): return self.classes_[np.argmax(self.predict_proba(X), axis1)] def _kernel_matrix(self, X): diff X[:, None, :] - self.X_[None, :, :] sq_dist np.sum(diff ** 2, axis2) return np.exp(-sq_dist / (2 * self.sigma ** 2)) param_grid {sigma: [0.05, 0.1, 0.2, 0.3, 0.5]} gs GridSearchCV(PNNEstimator(), param_grid, cv5, scoringf1_macro) gs.fit(X_train_s, y_train) print(gs.best_params_, gs.best_score_)搜索完 sigma 后在线监测流程大致是色谱在线监测装置每小时产出一组气体浓度程序算比值、用训练好的 scaler 标准化然后调 PNN 的 predict 得到故障类型结果推送到运维看板。PNN 在在线场景有个其他模型比不了的优势——新样本确认后直接追加进模式层不需要重新迭代训练模型跟着设备状态走。这也是为什么我在故障诊断项目里更愿意用 PNN 而不是 BP 或 SVM。我自己的教训是早期总想上复杂模型实际在小样本诊断场景里简单模型加干净特征才是能稳定落地的组合。数据泄漏、边界处理、sigma 调参这三个坑填平这个方案基本就立住了希望帮到你。本文还有配套的精品资源点击获取