的变压器DGA故障诊断与Python实现)
简介基于概率神经网络PNN的变压器故障诊断MATLAB源码面向电力系统运维人员、故障诊断研究人员及电气工程相关专业学生用于解决变压器多类故障如过热、放电、绝缘异常等的快速识别与分类问题。压缩包共含2个文件1个m脚本承载完整建模与测试流程1个mat数据文件提供可直接运行的输入样本整体仅6KB轻量易用。代码实现涵盖数据预处理、高斯核模式层构建、Parzen窗概率密度估计、类别概率比较与分类输出等核心环节逻辑紧凑、注释明确便于读者快速理解PNN原理并二次开发。目前已有329人学习下载适合作为入门概率神经网络故障诊断的参考实现也可在代码基础上调整特征维度、核参数与训练样本适配油色谱分析、电气参量、声学信号等不同诊断场景实现算法快速验证与效果对比。1. 变压器故障诊断里的pnnfd把“像不像”变成可计算的概率变压器故障诊断里油中溶解气体分析DGA被用了三十多年但按气体比值查编码表的方式有个老问题比值组合一旦落在编码表之外或者一组数据同时满足两套判据现场就得靠老师傅拍板。pnnfd 这条路我一般理解为“概率神经网络故障诊断”Probabilistic Neural Network Fault Diagnosis的落地写法它的核心不是把输入分到某一个类而是给出“属于过热、放电、受潮”的概率分布。好处是模糊样本不会被硬编码成错误结论而是被低置信度标记出来让运维人员决定是复测还是停电检查。这套方法适合做设备状态监测、油务试验数据分析和预警系统搭建的工程师也适合想给传统阈值判断加一层概率视角的团队。2. 给pnnfd准备变压器故障样本DGA特征、标签和数据划分2.1 变压器故障诊断先定状态七种典型类别与DGA特征变压器故障诊断不是把“正常/异常”二分就结束工程上通常按故障性质分成局部放电、低能放电、高能放电、中低温过热、高温过热、受潮加一个正常状态共七类。pnnfd 的输出层就对应这些类别类别顺序一旦在训练时打乱后面部署时的结论映射也会跟着乱所以我一般在项目开头就把类别字典固定下来。DGA特征选哪些我在实际项目里优先用五种特征气体氢气、甲烷、乙烷、乙烯、乙炔以及一氧化碳和二氧化碳。注意一氧化碳和二氧化碳反映固体绝缘老化如果故障诊断目标只针对放电和过热可以把它们作为辅助特征不放进主模型。下面这张表是常见做法特征顺序影响模型的可解释性我建议固定顺序后不要再变。特征名含义典型故障线索H2氢气局部放电、电弧放电初期CH4甲烷低温过热、放电伴随C2H6乙烷热分解的中间产物C2H4乙烯中高温过热C2H2乙炔电弧放电、高能放电CO一氧化碳固体绝缘过热CO2二氧化碳绝缘老化特征顺序我按“氢气、甲烷、乙烷、乙烯、乙炔”固定为五维输入CO和CO2放进扩展特征。这样做的好处是训练和部署时只要读同一份配置不用每次回忆字段顺序。2.2 构造pnnfd可用的样本集标签编码与数据划分拿到历史油务试验数据后第一件事不是直接丢给模型而是把文本结论转成数字标签。比如“正常”记为0“低温过热”记为1“中温过热”记为2“高温过热”记为3“局部放电”记为4“低能放电”记为5“高能放电”记为6。注意不同资料对过热温度的分段标准不一样我用的是DL/T 722里的常见分段低于300度为低温300到700度为中温高于700度为高温。下面这段代码演示了如何构造一个pnnfd能直接消费的数据集。实际项目中数据来自数据库或Excel结构一般是“设备编号、试验日期、气体浓度、故障结论”。import numpy as np import pandas as pd from sklearn.model_selection import train_test_split # 这里用模拟数据演示结构7个特征5个DGA主特征后2个是CO/CO2 # 真实数据请替换成油务试验台账 rng np.random.default_rng(42) n_samples 1200 X rng.gamma(2.0, 1.5, size(n_samples, 7)) # 不同故障类型气体比例关系不同 # 这里不追求物理精确只演示特征矩阵和标签的构造方式 y rng.integers(0, 7, sizen_samples) feature_names [H2, CH4, C2H6, C2H4, C2H2, CO, CO2] labels { 0: 正常, 1: 低温过热, 2: 中温过热, 3: 高温过热, 4: 局部放电, 5: 低能放电, 6: 高能放电, } df pd.DataFrame(X, columnsfeature_names) df[fault_code] y df[fault_type] df[fault_code].map(labels) # 划分训练集和测试集stratify保证各类别比例在两边一致 train_df, test_df train_test_split(df, test_size0.25, stratifydf[fault_code], random_state7) print(f训练集 {train_df.shape[0]} 条测试集 {test_df.shape[0]} 条) print(train_df[fault_type].value_counts())这段代码有两处值得说明。一是train_test_split加上stratify不然两类样本量相差5倍以上时小数类容易在测试集里分不到样本二是特征顺序固定在feature_names里后面训练和部署都从这里读避免手工改列名时把顺序搞错。2.3 归一化与类别不平衡pnnfd对量纲和先验的敏感点气体浓度范围跨度很大乙炔可以低到零点几乙烯可以到几千。概率神经网络的距离计算对量纲敏感如果不做归一化大数值特征会主导整个距离函数。常见的做法是取对数后再做z-score归一化或者直接用最小最大归一化。我一般先对浓度取log1p因为气体浓度从0.1到1000跨了四个数量级线性缩放会把小数点后的差异压没。类别不平衡是另一个问题。现场数据里“正常”样本通常占六成以上“低能放电”可能只有几十条。PNN在模式层每个类别单独一组径向基神经元样本少的类别在求和层得到的密度估计更尖锐、也更不稳定。我会先统计每类样本数如果最少类少于训练集的10%用SMOTE做类内过采样或者对样本少的类别随机复制一次。注意过采样要在划分训练集之后做绝不能让测试集混入合成样本。3. 用Python搭建pnnfd训练管线从PNN到可训练的变压器故障分类器3.1 概率神经网络四层结构与pnnfd的改动先讲结构。经典PNN有四层输入层、模式层、求和层、决策层。每个训练样本对应模式层的一个径向基神经元中心就是该样本的特征向量求和层把同一类别的神经元输出加总再除以该类样本数得到该类别的概率密度估计决策层比较这些估计取最大者作为分类结果。这个结构的好处是没有传统BP网络那样的迭代训练一次前向计算就能得到结果。pnnfd这个写法在工程上一般不会直接用原始PNN而是做三处改动。第一模式层的径向基宽度sigma不取全局固定值而是按每个类别内的平均距离初始化第二求和层多输出一个归一化后的概率向量而不是只给最大值这样后续可以设置置信度阈值第三在决策层前面加一层线性变换让模型在样本量足够时可以用梯度下降微调处理PNN对重叠分布分类偏弱的问题。简而言之pnnfd是PNN加了一点可训练外壳而不是另一个全新网络。3.2 最小可跑通的pnnfd训练代码下面这段代码用NumPy和SciPy实现了一个简化版pnnfd核心。完整生产代码通常会包成类但这里把逻辑摊开方便理解每一步。import numpy as np from scipy.spatial.distance import cdist from sklearn.preprocessing import StandardScaler def train_pnn(X_train, y_train, sigmaNone): 简化版pnnfd训练模式中心训练样本返回sigma和类别列表 classes np.unique(y_train) if sigma is None: # 取所有样本两两距离中位数的一半作为默认sigma dist_mat cdist(X_train, X_train) np.fill_diagonal(dist_mat, np.inf) sigma np.median(dist_mat[dist_mat ! np.inf]) / 2.0 return { patterns: X_train, labels: y_train, sigma: sigma, classes: classes, } def predict_pnn(model, X_test): 输出每个样本的类别概率向量而不是只给最可能的类别 dist cdist(X_test, model[patterns]) activations np.exp(-(dist ** 2) / (2 * model[sigma] ** 2)) probs [] for cls in model[classes]: mask model[labels] cls # 同一类模式层神经元输出取平均得到该类概率密度 cls_score activations[:, mask].mean(axis1) probs.append(cls_score) probs np.vstack(probs).T # 归一化为概率分布 prob_norm probs / (probs.sum(axis1, keepdimsTrue) 1e-12) return prob_norm这里的关键点有两个。第一个是sigma的初始化我用所有训练样本两两距离的中位数一半作为起点避免出现sigma太小导致所有激活值都接近0或者sigma太大导致类别差异被抹平。第二个是归一化加了1e-12是防止某一行全为0时除以零的边界情况这在气体浓度分布极度集中时会发生。提示真实数据里如果某类只有一个样本求和层求平均时不会出错但概率密度估计会退化成一个尖峰。这类样本要么补充数据要么在训练前做一次聚类合并。3.3 sigma怎么调三个可复现的搜索方法sigma是pnnfd模型里最敏感的超参数。我一般按以下顺序做搜索。第一网格搜索对sigma分别乘以0.1、0.5、1.0、2.0、5.0在验证集上看分类准确率和平均对数损失第二再按类别细调若某个小类的召回率偏低对该类单独加大sigma让它的概率密度估计平滑一些第三若数据量超过一万条先用随机抽样的方式在1万条样本上定一个粗略最优值再在全量上训练。下面是网格搜索的参考实现。from sklearn.model_selection import cross_val_score from sklearn.base import BaseEstimator, ClassifierMixin class PNNClassifier(BaseEstimator, ClassifierMixin): def __init__(self, sigma1.0): self.sigma sigma def fit(self, X, y): self.model_ train_pnn(X, y, sigmaself.sigma) return self def predict(self, X): prob predict_pnn(self.model_, X) return np.argmax(prob, axis1) sigma_candidates [0.1, 0.3, 0.5, 1.0, 2.0, 5.0] # 用3折交叉验证筛选变压器故障样本通常不大折数不宜过高 for s in sigma_candidates: clf PNNClassifier(sigmas) scores cross_val_score(clf, X_scaled, y, cv3, scoringaccuracy) print(fsigma{s:.2f}, 准确率{scores.mean():.3f}/-{scores.std():.3f})调sigma时刻意关注验证集上的每类召回率而不只看整体准确率。因为数据里“正常”类占多数整体准确率很容易被正常类拉高但局部放电和高能放电这两个对现场最关键的类别却可能被忽略。下面是我对不同sigma量级的行为预期sigma倍率适用场景故障诊断表现0.1-0.3样本多、噪声小过拟合风险高训练集准确率高但测试集抖动0.5-2.0大多数DGA数据推荐起点故障类别区分度稳定5.0以上各类重叠严重每类召回率趋于平均但分辨率下降4. pnnfd的变压器故障诊断评估映射表、混淆矩阵与置信度阈值4.1 从概率向量到故障结论固定编码映射表模型输出的是7个类别的概率现场系统里需要一个稳定的映射关系。下面这张表我每次都直接写到配置文件里防止开发人员自己另搞一套。类别索引故障代码结论用于报告0NORMAL正常1T1低温过热300℃2T2中温过热300-700℃3T3高温过热700℃4PD局部放电5D1低能放电6D2高能放电这里的索引顺序必须和训练时一致。我踩过最典型的坑训练脚本里labels用字典测试脚本里用list两者顺序不一致导致“高能放电”被报告成“正常”。所以映射表只留一份训练和部署都用同一个JSON文件读取。4.2 评估代码除了准确率还要看混淆矩阵和kappa系数准确率在类别不平衡的数据上会骗人。假设正常类占65%一个把所有样本都判成正常的模型准确率也有65%这在变压器故障诊断场景里完全不可用。我一般同时计算三类指标每类召回率、混淆矩阵、Cohen Kappa系数。Kappa系数对偶然一致的修正很严格一般0.6以上才算工程可用。下面的代码展示评估过程。数据沿用第2章划分好的test_df。from sklearn.metrics import confusion_matrix, classification_report, cohen_kappa_score # 假设 X_test_scaled、y_test 已经准备好clf是训练好的pnnfd模型 y_pred clf.predict(X_test_scaled) # 每类的精确率、召回率、F1都看一下 report classification_report( y_test, y_pred, target_nameslist(labels.values()), digits3 ) print(report) cm confusion_matrix(y_test, y_pred) print(混淆矩阵行为真实列为预测:) print(cm) kappa cohen_kappa_score(y_test, y_pred) print(fkappa {kappa:.3f})重点看两类位置。第一是局部放电和高能放电是否互相混淆它们的DGA特征在低浓度区间很接近混淆是常见情况第二是正常类是否吞掉了低温过热样本这通常说明模型对低幅值变化的敏感度不够可以尝试把sigma调小。4.3 边界样本处理最大概率不够高时输出“待复查”pnnfd和传统比值法的最大差别在边界样本的处理。三比值法遇到编码表外的组合直接报“无对应故障”而pnnfd可以输出“最大概率只有0.35没有类别明显占优”这种信息。这非常有价值现场收到这类结果可以安排复测或经验判断而不是硬套一个结论。我给系统定的标准是最大概率大于等于0.6输出该故障类别最大概率在0.4到0.6之间输出“建议复测并记录趋势”最大概率低于0.4输出“特征气体组合异常需结合其他试验综合判断”。这个阈值可以按你手上的数据质量调整数据噪声大就调高到0.7。注意阈值应该写在配置文件里评估的时候用同一个阈值算在线指标不要训练时一套、部署时另一套。5. 把pnnfd落到现场的技巧增量更新与气体分布漂移排查5.1 新样本来了不重训的增量更新方式现场每个月都会新增油务试验数据如果每条都触发全量重训系统维护成本太高。PNN在增量更新上其实有天然优势新样本就是新的模式层神经元直接在patterns矩阵中追加一行即可。但要注意两点样本存储不能无限追加否则预测时算距离的矩阵越来越大线上响应会劣化sigma要跟着新数据微调可以用最近一次全部数据的距离中位数重新计算不必每次用网格搜索。我在生产环境里采用批量更新的策略每攒到100条经过人工确认的新样本就触发一次模型重建。所谓重建不是重新调超参数而是重新计算sigma和重置模式层。这样既不会让单个坏样本长期污染模型也不会因为更新太频繁导致结果抖动。5.2 先查数据漂移还是先查设备故障线上系统运行一段时间后大概率会出现一类现象模型频繁给出低置信度结果明明设备检修记录显示没什么异常。这种情况不要急着调模型先做数据漂移检查。比较当前三个月的气体浓度分布和训练集分布如果差异显著可能不是设备状态变了而是检测仪器更换了量程、取样方式和环境温度影响了溶解度。常见做法是用兼容性指标PSIPopulation Stability Index。如果PSI大于0.25说明分布有明显变化需要重新采集样本或对特征做分段校准。代码上用scipy的统计检验也可以但PSI对工程人员更直观。真正有效的排查顺序是先校验输入数据再确认映射表最后才动模型参数这个顺序帮我省去了很多无用功。5.3 用概率输出做趋势曲线提前一个周期发现劣化最后一招比较实用不要只保存最终的故障结论把pnnfd输出的概率向量按时间存下来。比如某台变压器连续三次油务试验的“高温过热”概率从0.2升到0.5、再到0.55尽管故障结论一直显示“正常”这个趋势本身就值得关注。我可以据此提前安排缩短试验周期而不是等到阈值被突破后才告警。具体落地时把概率向量存成JSON或者宽表每行是试验日期和七个类别概率前台渲染时用堆叠面积图展示运维人员一眼就能看出哪个类别的概率在缓慢抬头。概率趋势曲线比单点结论多了一个维度这也是pnnfd相对传统编码法在运维侧最实用的附加价值。本文还有配套的精品资源点击获取