变压器故障谐波信号数据实战:从FFT特征提取到神经网络故障诊断
发布时间:2026/10/2 4:38:41来源:尧图网络
简介这份变压器故障谐波信号数据面向电力设备故障诊断与神经网络算法实践者尤其适合正在做分类、检测类模型训练与测试的学生和工程师。资源聚焦变压器运行中因故障产生的谐波信号特征可用于验证BP等网络在故障识别任务上的表现帮助解决真实工况样本难获取、实验数据不足的问题。压缩包共2个文件以txt说明文档与m脚本为主前者交代数据背景与使用方式后者提供可直接运行的示例代码整体约5KB体量轻便、便于快速导入实验环境。目前已有470人学习下载说明其在相关课程设计与小型科研场景中具有一定参考价值。读者可据此搭建从数据加载、特征输入到模型训练测试的完整流程理解谐波信号与故障类型之间的对应关系并在此基础上替换网络结构或调整参数形成自己的对比实验与排错思路。1. 变压器故障谐波信号数据一份能直接喂给神经网络的实战数据集做电力设备状态监测的工程师大概都有过这种体验想验证一个故障诊断模型算法框架搭好了结果卡在数据上。要么是现场录的波形格式五花八门要么是故障样本少得可怜正常样本一大堆类别严重不平衡。这份「变压器故障谐波信号数据」就是冲着这个痛点来的——它把变压器在不同运行状态下的谐波信号做了结构化整理直接对标神经网络训练所需的输入格式。适合谁用做电力设备故障诊断的研究生、搞状态监测的算法工程师、以及需要快速验证模型可行性的从业者。你不用再从零攒数据拿到手就能跑通从数据加载到模型训练的全流程。下面我按实际拆包和复现的顺序把这份数据的用法、参数设置和踩过的坑一条条讲清楚。2. 谐波信号怎么变成神经网络的输入从原始波形到训练张量2.1 先搞清楚这份数据里到底有什么拿到一份信号数据第一件事不是急着写模型而是把数据结构摸清楚。这份变压器故障谐波信号数据核心是不同故障类型下的谐波分量记录。常见做法是按时域波形采样再通过 FFT 变换提取各次谐波幅值和相位。数据里通常包含正常状态、绕组变形、铁芯故障、匝间短路等几类标签每类对应若干采样样本。我一般会先跑一段脚本把数据的基本形态打出来看import numpy as np import os data_dir ./transformer_harmonics for fname in os.listdir(data_dir): if fname.endswith(.npy): arr np.load(os.path.join(data_dir, fname)) print(f{fname} | shape: {arr.shape} | dtype: {arr.dtype} | fmin: {arr.min():.4f} | max: {arr.max():.4f})这段代码做三件事遍历数据目录、加载每个.npy文件、打印形状和数值范围。重点看shape的第二维——如果是(样本数, 特征数)说明已经做过特征提取如果是(样本数, 采样点数)那就是原始时序需要你自己做变换。dtype一般是float32或float64如果遇到object类型说明数据里混了非数值内容得先清洗。参数上要留意采样率。谐波分析对采样率有硬要求根据奈奎斯特采样定理要分析到第 25 次谐波50Hz 基波对应 1250Hz采样率至少得 2500Hz 以上。我见过有人拿 1200Hz 采样的数据做 25 次谐波分析结果高频段全是混叠模型学到的都是假特征。这份数据如果标注了采样率务必先确认这个数。2.2 特征工程FFT 之后还要做什么原始时域波形直接喂给神经网络不是不行但收敛慢、对超参敏感。常见做法是先做 FFT取各次谐波的幅值作为特征向量。具体步骤import numpy as np def extract_harmonics(signal, fs, max_order25, base_freq50): signal: 一维时域波形 fs: 采样率 max_order: 最大谐波次数 base_freq: 基波频率 返回: 各次谐波幅值组成的向量 n len(signal) spectrum np.fft.rfft(signal) / n freqs np.fft.rfftfreq(n, d1/fs) harmonics [] for order in range(1, max_order 1): target order * base_freq idx np.argmin(np.abs(freqs - target)) harmonics.append(np.abs(spectrum[idx])) return np.array(harmonics, dtypenp.float32)逻辑说明rfft返回的是复数频谱除以n做归一化避免样本长度不同导致幅值不可比。rfftfreq生成对应的频率轴。对每个谐波次数找到频率轴上最接近目标频率的索引取幅值。这里用argmin而不是精确匹配是因为实际采样率和 FFT 分辨率很难让目标频率正好落在某个频点上。参数怎么调max_order设多少取决于你的诊断需求。变压器故障诊断一般关注 2 到 25 次谐波再高次的能量占比很小加了反而引入噪声。base_freq国内是 50Hz如果数据来自其他地区要改成 60Hz。fs必须和实际采样率一致填错了整个频率轴都偏。做完这一步每个样本就变成了一个 25 维的向量。如果数据量够大可以直接用这个向量训练全连接网络如果想保留更多信息可以把幅值和相位拼在一起变成 50 维。2.3 标签处理与数据集划分谐波特征有了接下来处理标签。这份数据的标签通常是字符串或整数编码的故障类型。神经网络要求标签是数值型而且如果是多分类最好做 one-hot 编码。from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split import numpy as np # 假设 labels 是字符串列表features 是上一步提取的特征矩阵 le LabelEncoder() y le.fit_transform(labels) print(类别映射:, dict(zip(le.classes_, range(len(le.classes_))))) X_train, X_test, y_train, y_test train_test_split( features, y, test_size0.2, random_state42, stratifyy ) print(f训练集: {X_train.shape}, 测试集: {X_test.shape})LabelEncoder把字符串标签转成 0 到 K-1 的整数。stratifyy是关键参数——它保证训练集和测试集里各类别的比例一致。变压器故障数据往往类别不平衡正常样本远多于故障样本不加stratify很可能测试集里某个故障类一个样本都没有评估结果完全不可信。test_size0.2是常规选择但如果总样本少于 500建议改成 0.3留出足够的测试样本。random_state固定住保证每次划分一致方便复现。注意如果某个类别的样本数少于 10分层抽样也可能出问题。这时候要么合并稀有类别要么用 SMOTE 做过采样别硬跑。3. 用 PyTorch 搭一个能跑通的故障分类网络3.1 网络结构怎么定别一上来就上 Transformer谐波特征向量维度不高25 到 50 维样本量通常也就几千条。这种场景下全连接网络MLP是最务实的选择。我见过有人拿这份数据直接上 Transformer结果参数量比样本数还多训练 loss 震荡得没法看。不是说 Transformer 不行是数据规模撑不起来。一个够用的 MLP 结构import torch import torch.nn as nn class HarmonicNet(nn.Module): def __init__(self, input_dim, num_classes): super().__init__() self.net nn.Sequential( nn.Linear(input_dim, 128), nn.BatchNorm1d(128), nn.ReLU(), nn.Dropout(0.3), nn.Linear(128, 64), nn.BatchNorm1d(64), nn.ReLU(), nn.Dropout(0.3), nn.Linear(64, num_classes) ) def forward(self, x): return self.net(x)逐层说明第一层把输入维度映射到 128BatchNorm1d做批归一化加速收敛的同时对谐波幅值的量纲差异有抑制作用——各次谐波的幅值可能差几个数量级不做归一化训练会很慢。ReLU是标配激活函数。Dropout(0.3)防过拟合如果训练集小于 2000 条可以调到 0.4 或 0.5。第二层降到 64最后输出到类别数。input_dim就是上一步提取的特征维度num_classes是故障类别总数。这两个参数必须和数据对齐写死了后面换数据就得改。3.2 训练循环里的关键参数网络定义好了训练循环里有几个参数直接决定能不能收敛from torch.utils.data import DataLoader, TensorDataset # 转成 Tensor X_train_t torch.tensor(X_train, dtypetorch.float32) y_train_t torch.tensor(y_train, dtypetorch.long) train_ds TensorDataset(X_train_t, y_train_t) train_loader DataLoader(train_ds, batch_size64, shuffleTrue) model HarmonicNet(input_dimX_train.shape[1], num_classeslen(le.classes_)) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr1e-3, weight_decay1e-4) for epoch in range(100): model.train() total_loss 0 for xb, yb in train_loader: optimizer.zero_grad() out model(xb) loss criterion(out, yb) loss.backward() optimizer.step() total_loss loss.item() if (epoch 1) % 20 0: print(fEpoch {epoch1} | Loss: {total_loss/len(train_loader):.4f})batch_size64是起点样本少就降到 32样本多可以升到 128。lr1e-3是 Adam 的常用学习率如果 loss 下降太慢调到 5e-3如果震荡调到 5e-4。weight_decay1e-4是 L2 正则配合 Dropout 一起压制过拟合。CrossEntropyLoss内部已经包含了 softmax所以网络最后一层不要加 softmax加了反而会导致数值不稳定。这是新手最容易翻车的地方之一。训练轮数设 100 是保守值实际看 loss 曲线。如果 40 轮之后 loss 基本不动了就可以停。别死磕到 100 轮过拟合了反而坏事。3.3 评估不能只看准确率训练完了评估阶段有个坑类别不平衡时准确率会骗人。如果正常样本占 90%模型全预测正常也能拿 90% 准确率但故障一个都没抓到。from sklearn.metrics import classification_report, confusion_matrix model.eval() with torch.no_grad(): X_test_t torch.tensor(X_test, dtypetorch.float32) logits model(X_test_t) preds logits.argmax(dim1).numpy() print(classification_report(y_test, preds, target_namesle.classes_)) print(confusion_matrix(y_test, preds))classification_report会输出每个类别的 precision、recall 和 F1。重点看故障类别的 recall——漏报一个故障的代价远大于误报。confusion_matrix能看出哪些类别容易被混淆比如绕组变形和匝间短路在谐波特征上可能很接近混淆矩阵会直接暴露这个问题。如果某个故障类 recall 低于 0.7说明特征区分度不够得回头检查 FFT 的谐波次数选得对不对或者考虑加相位特征。4. 避坑与排查这份数据用起来容易翻车的五个地方4.1 采样率不匹配导致谐波频率偏移现象提取出来的谐波幅值分布和理论预期对不上比如 3 次谐波比 5 次还小但理论上 3 次应该更显著。原因数据采集时的实际采样率和文件里标注的不一致或者你在代码里填的fs是估计值。采样率偏差会让rfftfreq生成的频率轴整体偏移argmin找到的频点就不是真正的谐波位置。解决拿一段已知频率的标准信号比如 50Hz 正弦波过一遍你的提取流程看峰值是否落在 50Hz。如果偏了反推实际采样率。别信标注信验证。4.2 幅值量纲差异导致训练不收敛现象loss 从第一轮就很大降不下去或者直接变成 NaN。原因各次谐波的幅值可能差好几个数量级基波幅值可能是高次谐波的几百倍。不做归一化直接喂给网络梯度会被大量纲特征主导。解决在特征提取后加一步标准化。常见做法是减均值除标准差或者用MinMaxScaler缩放到 [0,1]。如果用了BatchNorm1d第一层之后能缓解但输入端的量纲差异太大时BN 也救不回来。4.3 训练集和测试集划分时没做分层现象测试集准确率很高但某个故障类的 recall 是 0混淆矩阵里那一行全是 0。原因train_test_split没加stratify参数稀有故障类恰好全被分到了训练集测试集里一个都没有。解决划分时强制stratifyy。如果某个类样本太少导致分层失败先做数据增强或过采样别硬分。4.4 标签编码顺序和类别名对不上现象classification_report里类别名和实际故障类型对不上比如把正常状态标成了匝间短路。原因LabelEncoder按字母序编码如果你的类别名是中文或拼音编码顺序可能和你预期的完全不同。解决打印le.classes_确认映射关系别凭记忆。或者在编码前手动指定类别顺序用pd.Categorical固定。4.5 过拟合训练 loss 一直降验证 loss 先降后升现象训练集准确率 99%测试集只有 70% 多。原因模型容量相对数据量太大或者 Dropout 率设得太低又或者训练轮数太多。解决先加 Dropout从 0.3 起调。再加 L2 正则weight_decay从 1e-4 调到 1e-3。还不行就减网络层数或每层神经元数。最后的手段是早停——验证 loss 连续 10 轮不降就停。5. 进阶技巧用交叉验证和混淆矩阵把模型压榨到极限5.1 单次划分不够上 K 折交叉验证前面用train_test_split做单次划分评估结果受随机种子影响很大。换一个random_state准确率可能差好几个百分点。要得到更可靠的评估用 K 折交叉验证。from sklearn.model_selection import StratifiedKFold import numpy as np skf StratifiedKFold(n_splits5, shuffleTrue, random_state42) fold_scores [] for fold, (train_idx, val_idx) in enumerate(skf.split(features, y)): X_tr, X_val features[train_idx], features[val_idx] y_tr, y_val y[train_idx], y[val_idx] model HarmonicNet(input_dimX_tr.shape[1], num_classeslen(le.classes_)) optimizer torch.optim.Adam(model.parameters(), lr1e-3, weight_decay1e-4) criterion nn.CrossEntropyLoss() X_tr_t torch.tensor(X_tr, dtypetorch.float32) y_tr_t torch.tensor(y_tr, dtypetorch.long) loader DataLoader(TensorDataset(X_tr_t, y_tr_t), batch_size64, shuffleTrue) for epoch in range(80): model.train() for xb, yb in loader: optimizer.zero_grad() loss criterion(model(xb), yb) loss.backward() optimizer.step() model.eval() with torch.no_grad(): val_preds model(torch.tensor(X_val, dtypetorch.float32)).argmax(dim1).numpy() acc (val_preds y_val).mean() fold_scores.append(acc) print(fFold {fold1} | Acc: {acc:.4f}) print(f平均准确率: {np.mean(fold_scores):.4f} ± {np.std(fold_scores):.4f})StratifiedKFold保证每一折里各类别比例一致。n_splits5是常规选择样本少可以设 10。最终报告的是平均准确率和标准差——标准差大说明模型对数据划分敏感稳定性不够。我一般会跑完 5 折后把每折的混淆矩阵都存下来看哪些类别在所有折里都容易混。如果某个类别在 5 折里 consistently 被误判那就是特征本身的问题换模型架构也解决不了。5.2 混淆矩阵的进阶读法普通混淆矩阵只看对角线但真正有价值的信息在非对角线。把 5 折的混淆矩阵加起来归一化后看百分比import seaborn as sns import matplotlib.pyplot as plt # 假设 all_cms 是 5 折混淆矩阵的列表 total_cm sum(all_cms) norm_cm total_cm.astype(float) / total_cm.sum(axis1, keepdimsTrue) plt.figure(figsize(8, 6)) sns.heatmap(norm_cm, annotTrue, fmt.2f, cmapBlues, xticklabelsle.classes_, yticklabelsle.classes_) plt.xlabel(预测) plt.ylabel(真实) plt.tight_layout() plt.savefig(confusion_matrix.png, dpi150)归一化后每一行加起来是 1。如果某个故障类有 30% 被误判成另一个类说明这两个类在谐波特征空间里重叠严重。解决办法有两个方向一是加更多区分性特征比如相位差、总谐波畸变率二是用代价敏感学习给误判更高的惩罚权重。5.3 一个我踩过的坑有次我用这份数据跑了一个 1D-CNN直接把原始时域波形喂进去想着让网络自己学特征。结果训练了 200 轮测试集准确率卡在 60% 上不去。后来换成 FFT 特征加 MLP同样的数据准确率直接到 85%。原因很简单原始波形里的故障信息被基波的巨大能量掩盖了CNN 的卷积核在时域上根本抓不到高次谐波的微弱变化。从那以后我每次拿到信号数据都强制先走一遍频域分析确认谐波特征是否可分再决定用不用端到端模型。这份变压器故障谐波信号数据的价值在于它把频域特征已经整理好了你不需要重复我踩过的那个坑。但前提是你得按上面的步骤把采样率、归一化、分层划分这几件事做对。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网