ARTICLE DETAIL

资讯详情

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

变压器油中溶解气体DGA故障诊断:从IEC三比值法到机器学习实战

变压器油中溶解气体DGA故障诊断:从IEC三比值法到机器学习实战 变压器油里那七八种溶解气体一台百来块的油色谱在线监测装置或者一次例行化验就能拿到。但拿到之后怎么从这些数字里看出变压器内部到底在“憋什么大招”就是DGA故障诊断要解决的事。我做这个项目的目的很直接把溶解气体分析DGA从教科书里的经验规则变成一套能运行、能验证、能出报告的代码流程顺手把清洗好的数据也一起整理出来。整套东西适合刚接触电力设备状态检修的工程师、做故障诊断算法研究的同学也适合想在企业内部快速搭一个诊断原型的团队。文章里的代码都用Python写数据是结构化表格拉到本地就能跑。这套项目的核心不是堆模型而是把“绝缘油里溶解气体浓度”翻译成“变压器内部故障状态”。所以我会先从物理原理和数据形态讲起再走一遍经典IEC三比值法的代码实现然后是机器学习建模流程最后专门聊模型评估和部署时最容易翻车的几个细节。1. 为什么变压器油中溶解气体能“说”出故障DGA原理与数据形态1.1 变压器内部故障如何变成油里的气体油浸式变压器内部填充的绝缘油和绝缘纸正常情况下化学性质很稳定。但当设备内部出现异常工况——比如局部放电、过热、电弧——油纸绝缘材料就会在电和热的双重作用下发生裂解产生氢气、甲烷、乙烷、乙烯、乙炔等低分子烃类气体。这些气体一部分溶解在油里一部分聚集在气体继电器中。关键点在于不同故障类型产生的气体组合和比例是有规律可循的。这就像人发烧时白细胞会升高但具体是细菌感染还是病毒感染要看不同指标的比例。DGA诊断的物理基础就是气体产物的“指纹特征”与故障能量密度之间的对应关系局部放电低能量密度主要产氢少量甲烷。因为放电能量不足以打断碳碳键只够打断碳氢键所以以氢气为主。热故障温度升高温度超过300℃时碳碳键开始断裂产生乙烯、甲烷温度越高乙烯占比越大。电弧放电高能量密度油和纸在电弧高温下直接裂解产生大量乙炔这是判断放电性故障的决定性气体。一台正常老化的变压器也会产气但浓度和产气速率都处在较低水平。DGA诊断的第一个动作其实就是拿气体浓度和产气速率去对标“正常范围”超出限度才进入故障类型判断环节。1.2 DGA数据长什么样特征列与标签体系要写代码做诊断先把数据结构定义清楚。DGA原始数据通常是一张包含特征列和标签列的表格每行代表变压器在某次取样时的油色谱化验结果。我的数据集里用到的核心特征列是七种气体的体积分数单位用μL/L也就是ppm这是电力行业油色谱分析的通用单位气体名称中文名化学式典型产生原因H2氢气H2局部放电、电弧放电CH4甲烷CH4低温过热、放电C2H6乙烷C2H6低温热分解C2H4乙烯C2H4中高温过热C2H2乙炔C2H2电弧放电、高温热解CO一氧化碳CO固体绝缘纸过热CO2二氧化碳CO2固体绝缘老化标签列是我根据IEC 60599和DL/T 722等标准梳理出来的故障类型编码完整分为七类标签值故障类型说明0正常无需停机检修1局部放电低能量放电早期绝缘缺陷2低温过热300℃通常由过载或油道堵塞引起3中温过热300~700℃导体接触不良等4高温过热700℃严重过热需尽快处理5低能放电悬浮电位放电、火花放电6电弧放电高能放电最危险需立即停电1.3 构建一份规整的DGA数据集网上能下载到的公开DGA数据集不少但大部分存在几个通病数值缺失、标签命名不统一、还有用“正常/异常”二分类糊弄人的。我在整理数据时做了三件事第一统一单位的转换。有些数据源用的是ppm有些是μL/L有些甚至给百分比浓度。我在预处理阶段统一换算成μL/L百分比数值乘以10000。第二删除全零行。如果某次取样所有气体浓度都是0说明油样可能没取好或者检测仪器没跑通这种样本放进模型只会制造噪声。第三标签对齐。把“PD”“局部放电”“低能量放电”这类同义表述统一映射到整数标签上。这一步看着简单实际处理时能过滤掉将近20%的脏数据这是很多论文复现时不会提到的坑。完成清洗之后最终CSV文件长这样H2,CH4,C2H6,C2H4,C2H2,CO,CO2,label 56,78,32,45,0,120,800,0 120,45,12,20,95,90,650,6 35,110,48,160,0,140,950,4第一行是正常样本各类气体浓度都在合理区间第二行乙炔浓度高达95μL/L对应电弧放电第三行乙烯160μL/L、乙炔为0典型高温过热特征。做机器学习之前先人工看几十条数据形成数感对后面理解模型输出帮助很大。2. 先把经典规则跑通IEC三比值法的代码化与边界认知2.1 三比值规则的编码逻辑回顾IEC三比值法的核心思路不复杂取五种关键气体构造三个比值每个比值按阈值范围编码成0、1、2组合出三位编码后查表得到故障类型。三个比值是CH4/H2反映热分解与放电分解的比例C2H2/C2H4反映放电能量高低C2H4/C2H6反映热分解温度高低每个比值的编码规则如下比值范围CH4/H2编码C2H2/C2H4编码C2H4/C2H6编码 0.11——0.1 ~ 10—01 ~ 32013 ~ 10212≥ 10222其他C2H2/C2H4 0.1—1—比值编码组合对应故障类型这就是“三比值”名称的来历。逻辑本身并不复杂适合做规则的代码落地。2.2 用Python把三比值规则写成可复用的诊断函数我写了一个iec_three_ratio函数输入七个气体浓度输出故障类型名称。实现时注意处理分母为零和比值越界的情况def iec_three_ratio(h2, ch4, c2h6, c2h4, c2h2, co, co2): IEC三比值法诊断 返回: (编码字符串, 诊断结果) # 处理分母为零的情况 h2 max(h2, 1e-9) c2h4 max(c2h4, 1e-9) c2h6 max(c2h6, 1e-9) ratio1 ch4 / h2 ratio2 c2h2 / c2h4 ratio3 c2h4 / c2h6 # 编码CH4/H2 if ratio1 0.1: code1 1 elif ratio1 1: code1 0 else: code1 2 # 编码C2H2/C2H4 if ratio2 0.1: code2 1 elif ratio2 3: code2 0 else: code2 2 # 编码C2H4/C2H6 if ratio3 1: code3 0 elif ratio3 3: code3 1 else: code3 2 code f{code1}{code2}{code3} mapping { 010: 局部放电, 020: 局部放电, 001: 低温过热(300℃), 002: 中温过热(300-700℃), 021: 高温过热(700℃), 110: 低能放电, 120: 低能放电, 100: 电弧放电, 101: 电弧放电, 121: 电弧放电, 000: 正常, 200: 正常, } result mapping.get(code, 无法判断) return code, result函数签名里把CO和CO2也加进来了虽然三比值法用不到但保持接口统一后面机器学习特征工程可以直接复用同一份数据。2.3 三比值法的典型失效场景与代码应对实际用下来三比值法最麻烦的是两类情况。第一类比值刚好落在阈值边界上。比如CH4/H2等于1.0编码该算0还是2标准条文里写了“1~3区间”但现场化验数据很难精确等于整数真遇到边界值我的处理方式是同时输出两个可能编码把两种故障类型都报给检修人员参考不硬选一个。代码里可以用一个边界容差逻辑处理def encode_ratio_with_tolerance(value, boundary, tol0.05): 边界值容忍编码避免因为化验误差导致跳变 if abs(value - boundary) tol: return boundary if value boundary: return 0 return 1第二类五类故障之外的情况。实际数据里会出现编码组合查不到对应故障类型比如“111”。这时候三比值法的查表直接给“无法判断”。我的经验是遇到查不到的编码不要强行归到某一类而是返回原始特征让后续的机器学习模型来兜底——规则给先验模型做精细判断两条路并行。3. 数据驱动的故障诊断特征工程与机器学习建模全流程3.1 为什么规则之后还要建模IEC三比值法虽然经典但它存在一个先天短板只用了五种气体构造三个比值信息量被压缩得很厉害。现场数据里CO和CO2本身蕴含着固体绝缘过热的信息三比值法完全没用上同时三比值法的阈值是行业经验总结出来的未必在每一台变压器上都最优。机器学习的思路不一样它不做先验假设让算法自己从大量标注样本中学出特征与故障的映射关系。我在这个项目里跑下来树模型在七分类任务上准确率能到88%—92%比三比值法的70%左右有明显提升。更重要的是机器学习模型能给出概率输出而不只是一个硬分类结果——这一点对现场检修决策非常有用因为概率低的诊断结果复核优先级应该更高。3.2 特征工程与训练集划分气体浓度的数量级跨度很大H2可能在几十到几千ppm浮动而CO2可能到几千甚至上万ppm。直接喂给决策树模型没问题但如果后续要换SVM、逻辑回归这类对尺度敏感的模型必须先做标准化。我的特征工程方案分三步第一步原始浓度做对数变换。气体浓度分布通常右偏少数高浓度样本会把模型带偏。对数变换后分布更接近正态模型更容易学到规律import numpy as np gas_cols [H2, CH4, C2H6, C2H4, C2H2, CO, CO2] def log_transform(df, cols): df_log df.copy() for col in cols: # 加1避免log(0)的问题 df_log[col _log] np.log1p(df[col]) return df_log第二步保留比值特征。虽然机器学习能自动捕捉特征交互但领域知识明确告诉我们甲烷/氢气和乙炔/乙烯这两个比例是诊断的关键信息直接构造出来放进特征集相当于给模型开了小灶。第三步加入总可燃气体浓度THCTotal Hydrocarbon即五种烃类气体之和。这个特征在实际检修中常用于判断设备整体劣化程度。训练集划分有个细节DGA数据通常来自不同地区、不同厂家、不同电压等级的变压器如果简单随机切分训练集中可能恰好都是某一类变压器的样本导致模型泛化能力虚高。我用按设备ID分组的GroupShuffleSplit确保同一台变压器的数据不会同时出现在训练集和测试集里。3.3 模型选型与训练细节我在项目里对比了随机森林、XGBoost和LightGBM三个经典树模型最终默认推荐LightGBM。原因有三第一训练速度快。同样的数据量LightGBM的直方图算法比XGBoost的预排序算法快3—5倍调参周期短很多。第二对类别特征友好。DGA数据里如果加入变压器的电压等级、冷却方式等现场信息LightGBM可以直接处理类别特征省去独热编码。第三内存占用低。笔记本电脑上跑几千条样本毫无压力。核心训练代码import lightgbm as lgb from sklearn.model_selection import GroupShuffleSplit from sklearn.metrics import classification_report # 特征列与标签列 feature_cols [col _log for col in gas_cols] [CH4_H2, C2H2_C2H4, THC] # 按设备ID分组切分数据 gss GroupShuffleSplit(n_splits1, test_size0.25, random_state42) train_idx, test_idx next(gss.split(X, y, groupsdevice_ids)) X_train, X_test X.iloc[train_idx], X.iloc[test_idx] y_train, y_test y.iloc[train_idx], y.iloc[test_idx] # LightGBM分类器 model lgb.LGBMClassifier( n_estimators300, learning_rate0.05, num_leaves31, max_depth-1, class_weightbalanced, # 处理类别不平衡 random_state42 ) model.fit(X_train, y_train) # 测试集评估 y_pred model.predict(X_test) print(classification_report(y_test, y_pred, target_namesclass_names))class_weightbalanced这个参数值得单独说一下。DGA数据集里“正常”样本往往远多于“电弧放电”样本如果不管类别不平衡模型会倾向于把所有样本都预测成多数类整体准确率看着高但最危险的放电故障一个都识别不出来。设置class_weightbalanced就是让模型在训练时对少数类样本的错分给予更高惩罚迫使它学到少数类的特征。训练完模型之后保存模型文件供后续调用import joblib joblib.dump(model, dga_xgb_model.pkl)4. 模型评估与现场部署必须直面的几个实际问题4.1 用混淆矩阵看清七类故障的识别短板准确率不是唯一的评价指标在故障诊断场景里甚至不是最重要的指标。我习惯先打印混淆矩阵看每一类故障具体被误判成了什么import matplotlib.pyplot as plt import seaborn as sns from sklearn.metrics import confusion_matrix cm confusion_matrix(y_test, y_pred) plt.figure(figsize(10, 8)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsclass_names, yticklabelsclass_names) plt.ylabel(真实故障类型) plt.xlabel(预测故障类型) plt.show()我跑出来的混淆矩阵里有一个典型问题值得说道中温过热标签3和高温过热标签4之间经常互相混淆。原因是这两类故障在气体比例上本身就有连续性——300℃和700℃之间并没有一个绝对的分界线部分样本处于过渡区间气体特征介于两者之间。这就好比黄昏时分让你判断“现在是白天还是晚上”边界本来就是模糊的。应对办法有两个层面。第一在现场报告里把“中温过热”“高温过热”合并成“热故障”大类作为一级结论再给出倾向性判断“偏中温”或“偏高溫”这样不违背诊断逻辑也不会因为过细的划分导致误判被放大。第二在模型层面引入软标签让标签3和标签4的样本在训练时相互有一定概率而不是一成不变的硬编码实测能提升3—5个百分点的F1值。4.2 样本不平衡与误报率控制DGA数据天然存在样本不平衡问题。“正常”类样本数量多、获取成本低“电弧放电”样本数量少因为一旦真发生电弧放电这台变压器就要停电检修很难再采集到后续数据。我手里的数据集中正常样本占比接近45%而电弧放电样本只有8%。处理不平衡除了前面提到的class_weight还可以用SMOTE过采样。但这里我要泼一盆冷水SMOTE在合成少数类样本时是在特征空间里的少数类样本之间线性插值生成新样本。DGA数据的不同特征之间不是完全独立的盲目插值可能生成出物理上不合理的样本比如氢气浓度极低但乙炔浓度极高的“合成电弧放电”——真实设备中这种情况几乎不存在。我试用过SMOTE准确率提升不明显反而让模型在真实数据上误报率上升。更推荐的做法是调整判断阈值。LightGBM默认用0.5作为分类阈值但我们可以把少数类放电类故障的阈值调低到0.3让模型更“敏感”# 获取预测概率而不是硬标签 y_prob model.predict_proba(X_test) # 给放电类故障(标签5,6)更低的判定阈值 thresholds np.full(y_prob.shape[1], 0.5) thresholds[5] 0.3 thresholds[6] 0.3 y_pred_adj (y_prob thresholds).argmax(axis1)这样调整后个别正常样本可能被误报成放电但换来的是放电故障不漏报。在生产环境里一次漏报的代价是变压器损坏、非计划停电远高于一次误报产生的现场复核成本。孰轻孰重做运维的老师傅心里都有杆秤。4.3 特征重要性让黑盒诊断结果能对着检修人员讲清楚现场检修人员不一定信任模型输出“预测为电弧放电”这句话。他们更希望看到“因为乙炔浓度升高、且乙烯浓度上升模型判断为电弧放电”这样才能结合自己的经验做最终判断。所以在项目中我加入了特征重要性分析# 方法一基于内置特征重要性的全局解释 import pandas as pd importance_df pd.DataFrame({ feature: feature_cols, importance: model.feature_importances_ }).sort_values(importance, ascendingFalse) print(importance_df.head(10))我的模型跑下来特征重要性排前三的通常是C2H2_log乙炔对数浓度、C2H4_log乙烯对数浓度、CH4_H2甲烷/氢气比值。这个结果完全符合领域知识也提供了一道“验证防线”如果某个模型的Top特征里居然出现了CO2这种几乎不参与故障类型判别的特征那你就要怀疑数据集或者模型是不是出了问题。用领域知识校验模型行为是数据驱动方法落地时最容易被忽略但最关键的一步。如果想做单样本级别的解释可以用SHAP库import shap explainer shap.TreeExplainer(model) shap_values explainer.shap_values(X_test.iloc[[0]]) # 解释第一号样本 shap.summary_plot(shap_values, X_test.iloc[[0]], feature_namesfeature_cols)SHAP值能展示每一个特征对诊断结果的贡献方向与大小对“乙炔浓度推高了放电类故障概率”这类结论给出数值级别的支撑。这也是我建议所有做DGA诊断模型的人都应该加上的一步——解释性不是锦上添花而是设备和人身安全场景下的硬需求。最后再分享一个小经验这套诊断流程我从规则版迭代到模型版最大的心得是不要把规则和模型对立起来。三比值法编码结果完全可以作为一维额外特征输入给LightGBM相当于把几十年行业经验作为先验知识灌进模型里。我最终线上跑的版本就是在原始7维气体特征之外加上了三比值编码和总烃含量整体准确率比只用原始特征的版本又高了2%左右。数据和完整代码我都整理好了拿到后从data/dga_samples.csv开始跑一遍配合本文的诊断代码基本能覆盖日常DGA数据分析的所有流程。
返回列表