简介:这份PDF文献面向电力系统故障诊断方向的研究生、科研人员及配电网保护工程师,针对单相接地故障特征不明显、传统选线方法易受噪声与故障条件干扰的问题,提出融合S变换相关度与深度学习的选线新思路。资源包共1个PDF文件,大小约3.76MB,内容为期刊论文全文,涵盖S变换时频分析、S变换相关度图形(SCF)构建方法、含SCF层的卷积神经网络模型(S-CNN)设计及分步训练策略,并给出不同故障位置、相角、过渡电阻与强噪声场景下的仿真验证结果。目前已有146人学习。读者可从中获取完整的算法框架、特征提取流程与实验对比思路,理解如何将一维零序电流转化为二维图形特征以提升可辨识度,适合作为深度学习在电力系统故障选线方向的研究参考与方案借鉴。
1. 配电网单相接地故障选线:从零序电流到 S 变换相关度图形
10 kV 配电网里,单相接地故障占了八成以上。小电流接地方式下,故障电流小、线电压仍对称,规程允许带故障运行 1~2 小时,但非故障相电压会升到原来的 3 倍,拖着不处理就是绝缘击穿、多点短路的连锁反应。麻烦在于,故障特征本身就不明显,现场还有噪声、采样不同步这些现实问题。传统做法要么看零序电流幅值,要么用小波变换、经验模态分解提取特定频带特征,再配合聚类或支持向量机分类。这些方法在实验室数据上表现不错,一到现场就容易翻车——判据太单一,抗干扰能力有限。这份来自华中科技大学团队的论文,提出了一条新路径:用 S 变换提取零序电流全频段时频信息,计算线路间相关度,构建 S 变换相关度图形(SCF),再喂给含 SCF 层的卷积神经网络(S-CNN)做选线。核心卖点是在强噪声和采样不同步条件下仍能保持高正确率。适合正在做配电网故障诊断、想找可复现方案的研究生和一线工程师。
2. S 变换与相关度矩阵:为什么比直接上 1D-CNN 更抗噪
2.1 从零序电流的暂态特征说起
谐振接地系统发生单相接地故障后,故障线路的暂态零序电流由振荡衰减分量、直流衰减分量和工频分量叠加而成。振荡分量的角频率与线路参数、消弧线圈电感、过渡电阻都有关。非故障线路的零序电流波形基本一致,因为受同一母线零序电压驱动,差异只来自线路自身对地电容。故障线路的零序电流极性与非故障线路相反,幅值等于所有非故障线路加消弧线圈电流之和,所以明显更大。
这个物理事实决定了选线判据的底层逻辑:故障线路和非故障线路的零序电流之间存在幅值差异和极性差异。问题在于,直接拿一维时序数据去训练 CNN,这些差异很容易被噪声淹没,或者因为采样时间不同步导致特征在样本矩阵中错位。1D-CNN 的输入层是把各线路零序电流时序按线路编号排列成矩阵,一旦某条线路采样滞后,整个矩阵的特征位置就偏了,训练时学到的映射关系直接失效。
2.2 S 变换的时频提取能力
S 变换由连续小波变换和短时傅里叶变换结合而来,高斯窗的宽度随频率变化——低频时窗宽,高频时窗窄。这意味着它在低频段有好的频率分辨率,在高频段有好的时间分辨率。对于零序电流这种包含多个频率分量的暂态信号,S 变换能同时给出全频段的时频信息,而不是只取某一个频带。
连续信号 x(t) 的 S 变换定义为:
Sx(τ, f) = ∫ x(t) · w(t-τ, f) · e^(-j2πft) dt
其中高斯窗函数 w(t-τ, f) = (|f|/√(2π)) · e^(-f²(τ-t)²/2)。τ 是时间轴上的位置控制参数,f 是频率。
离散形式下,对 N 点采样序列 x[i],S 变换结果为:
import numpy as np def s_transform(x, fs): """ 离散S变换实现 x: 输入一维时序信号,长度N fs: 采样频率 返回: 时频矩阵 Sx,形状 (N//2+1, N) """ N = len(x) X = np.fft.fft(x) # 信号的FFT Sx = np.zeros((N//2 + 1, N), dtype=complex) for h in range(N//2 + 1): if h == 0: # h=0 时退化为均值 Sx[h, :] = np.mean(x) else: # 频域高斯窗平移 G = np.exp(-2 * np.pi**2 * np.arange(N)**2 / h**2) # 频域移位后做IFFT shifted = np.roll(X, h) Sx[h, :] = np.fft.ifft(shifted * G) return Sx这段代码的核心逻辑:先把信号转到频域,对每个频率点 h 构造高斯窗,窗宽与 1/h² 成正比。h 越大(频率越高),窗越窄,时间分辨率越高。np.roll实现频域移位,对应时域调制。最后 IFFT 回到时域得到该频率点的时间序列。参数fs用于确定频率轴刻度,实际使用时频率分辨率为 fs/N。
S 变换的一个重要性质:如果两个信号幅值相等、极性相反,即 y(t) = -x(t),那么 Sy(τ, f) = -Sx(τ, f)。这个极性保持特性是后续相关度计算的基础。
2.3 相关度矩阵的构建
拿到各线路零序电流的 S 变换时频矩阵后,下一步是计算两两线路之间的相关度。具体做法:对线路 x 和线路 y 的时频矩阵,计算它们之间的欧氏距离 δ,然后用 1-δ 作为相关度 sxy。所有线路两两计算,构成一个 n×n 的相关度矩阵 Srel。
def build_scf_matrix(zero_seq_currents): """ 构建S变换相关度矩阵(SCF) zero_seq_currents: 形状为 (n_lines, n_samples) 的零序电流数组 返回: Srel,形状 (n_lines, n_lines) 的相关度矩阵 """ n_lines = zero_seq_currents.shape[0] # 归一化,消除线路类型导致的幅值差异 norm_currents = zero_seq_currents / np.max(np.abs(zero_seq_currents), axis=1, keepdims=True) # 对每条线路做S变换 tf_matrices = [] for i in range(n_lines): Sx = s_transform(norm_currents[i], fs=3200) tf_matrices.append(np.abs(Sx)) # 取幅值谱 # 计算两两相关度 Srel = np.zeros((n_lines, n_lines)) for i in range(n_lines): for j in range(n_lines): if i == j: Srel[i, j] = 1.0 else: # 欧氏距离 delta = np.linalg.norm(tf_matrices[i] - tf_matrices[j]) # 归一化距离到[0,1] delta_norm = delta / (np.linalg.norm(tf_matrices[i]) + np.linalg.norm(tf_matrices[j])) Srel[i, j] = 1.0 - delta_norm return Srel参数说明:zero_seq_currents的每一行是一条线路的零序电流时序,采样率 3200 Hz 对应论文中的设置。归一化步骤很关键——电缆线路和架空线路的零序电流幅值差异可能很大,不归一化的话相关度会被幅值主导。np.abs(Sx)取幅值谱,丢弃相位信息,因为极性差异已经体现在幅值谱的相关度中。
构建出的 Srel 矩阵有一个重要特征:非故障线路之间的相关度接近 1,故障线路与非故障线路之间的相关度接近 0。而且这个特征在矩阵中的位置是固定的——第 i 行第 j 列永远对应线路 i 和线路 j 的关系,不会因为采样时间偏移而错位。这就是 SCF 相比 1D-CNN 时序样本矩阵的核心优势。
注意:S 变换的计算量不小。10 条线路、每条 64 个采样点,构建一次 SCF 大约需要 183 秒(论文数据)。实际部署时要考虑用 GPU 加速或预计算。
3. S-CNN 模型搭建:从相关度矩阵到选线向量
3.1 网络结构设计
S-CNN 的整体结构分三层:SCF 构建层、深层特征提取层、选线输出层。SCF 构建层就是上一章的相关度矩阵计算,把 m×n 的零序电流时序转成 n×n 的相关度矩阵。深层特征提取层由卷积层和池化层交替组成,论文最终选定的结构是 5-2-2-1,即第一个卷积层核大小 5×5,第一个池化层核大小 2×2,第二个卷积层核大小 2×2,第二个池化层核大小 1×1。
这个结构不是拍脑袋定的。论文测试了 7-2-2-1、5-3-2-1、5-2-2-1、3-2-2-1 四种组合,用控制变量法比较。5-2-2-1 在迭代 5 次后就达到 100% 正确率,训练总用时 44.72 秒,综合最优。
import torch import torch.nn as nn class SCNN(nn.Module): def __init__(self, n_lines=10): super(SCNN, self).__init__() self.n_lines = n_lines # 卷积层1: 输入通道1, 输出通道6, 核5x5 self.conv1 = nn.Conv2d(1, 6, kernel_size=5, stride=1) # 池化层1: 核2x2, 步长2 self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2) # 卷积层2: 输入通道6, 输出通道12, 核2x2 self.conv2 = nn.Conv2d(6, 12, kernel_size=2, stride=1) # 池化层2: 核1x1, 步长1 (实际不降维) self.pool2 = nn.AvgPool2d(kernel_size=1, stride=1) # 全连接层: 计算最终特征维度 # 输入10x10 -> conv1(5x5) -> 6x6 -> pool1(2x2) -> 3x3 # -> conv2(2x2) -> 2x2 -> pool2(1x1) -> 2x2 self.fc = nn.Linear(12 * 2 * 2, n_lines) self.softmax = nn.Softmax(dim=1) def forward(self, scf_matrix): """ scf_matrix: (batch, 1, n_lines, n_lines) 的相关度矩阵 """ x = torch.relu(self.conv1(scf_matrix)) x = self.pool1(x) x = torch.relu(self.conv2(x)) x = self.pool2(x) x = x.view(x.size(0), -1) # 展平 x = self.fc(x) return self.softmax(x)代码逻辑说明:输入是 batch 个 n×n 的相关度矩阵,先扩一维作为单通道图像。conv1 用 5×5 核提取局部相关模式,pool1 降采样。conv2 用 2×2 核进一步提取组合特征。全连接层把 12×2×2=48 维特征映射到 n 维选线向量。Softmax 保证输出各元素之和为 1,可解释为各线路发生故障的概率。
参数选择依据:卷积核大小决定了感受野。5×5 的核在 10×10 矩阵上滑动,每次覆盖约一半的行列,能捕捉到故障线路与非故障线路之间的全局相关模式。池化核 2×2 把 6×6 特征面降到 3×3,减少参数量同时保留主要特征。
3.2 分步训练策略
论文采用先定结构、再调超参数的分步训练。第一步,根据数据样本形式确定深层特征提取层的层数和特征面数目,直接取 LeNet-5 的典型值——2 个卷积层加 2 个池化层交替,卷积层 1 和池化层 1 各 6 个特征面,卷积层 2 和池化层 2 各 12 个特征面。第二步,根据输入样本阶数确定卷积核和池化核的可行取值,形成多个候选结构。第三步,设置学习效率、批训练数目、迭代次数,对候选结构逐一训练测试。
def train_scnn(model, train_loader, n_epochs=15, lr=1.0, batch_size=50): """ 训练S-CNN模型 train_loader: 包含(scf_matrix, label)的数据加载器 n_epochs: 迭代次数 lr: 学习效率 batch_size: 批训练数目 """ criterion = nn.CrossEntropyLoss() optimizer = torch.optim.SGD(model.parameters(), lr=lr) for epoch in range(n_epochs): total_loss = 0 correct = 0 total = 0 for scf_batch, labels in train_loader: optimizer.zero_grad() outputs = model(scf_batch) loss = criterion(outputs, labels) loss.backward() optimizer.step() total_loss += loss.item() _, predicted = torch.max(outputs, 1) correct += (predicted == labels).sum().item() total += labels.size(0) acc = correct / total * 100 print(f"Epoch {epoch+1}/{n_epochs}, Loss: {total_loss:.4f}, Acc: {acc:.2f}%") return model参数说明:学习效率设为 1 是论文中的取值,配合 SGD 优化器。批训练数目 50 意味着每次更新参数用 50 个样本。迭代 15 次是论文中 5-2-2-1 结构收敛的轮数。实际训练时如果损失震荡,可以适当降低学习效率到 0.1 或 0.01。
训练数据的生成靠 Simulink 仿真。论文搭建了 10 kV 经消弧线圈接地配电网模型,消弧线圈补偿度 5%,10 条出线由架空线和电缆线组合。参数遍历包括电网电压、节点负荷、故障位置、过渡电阻、故障相角,共生成 10800 组带标签数据。采样率 3200 Hz,每条线路取故障后一个周期的零序电流。
3.3 实际配电网的矩阵扩展
训练好的 S-CNN 是基于 10 条出线的模型,相关度矩阵是 10×10。但实际配电网可能只有 4 条出线,相关度矩阵只有 4×4,维度对不上。论文用去首尾均值法扩展:对 4×4 矩阵的每一行,取 4 个数值中除最大值和最小值外的 2 个求平均,用这个平均值把该行扩展到 10 维。
def expand_scf_matrix(Srel_small, target_size=10): """ 将小规模SCF矩阵扩展到目标规模 Srel_small: 原始相关度矩阵,形状 (n, n) target_size: 目标规模 """ n = Srel_small.shape[0] Srel_expanded = np.zeros((target_size, target_size)) Srel_expanded[:n, :n] = Srel_small for i in range(n): row = Srel_small[i, :] sorted_row = np.sort(row) # 去掉最大值和最小值,取中间值的平均 if n > 2: mid_mean = np.mean(sorted_row[1:-1]) else: mid_mean = np.mean(sorted_row) # 扩展列 Srel_expanded[i, n:] = mid_mean Srel_expanded[n:, i] = mid_mean # 扩展部分的填充 Srel_expanded[n:, n:] = mid_mean return Srel_expanded这个扩展方法的逻辑:保留原始线路之间的真实相关度,对不存在的线路用中间值填充,避免引入极端值干扰。论文强调这个扩展过程可以在模型中自动实现,不具特殊性。如果实际配电网出线超过 10 条,只需用更多出线的仿真模型重新训练即可。
4. 避坑与排查:S-CNN 落地时最容易翻车的五个地方
4.1 采样不同步导致相关度矩阵失效
现象:训练时正确率 100%,现场测试掉到 60% 以下。原因:各出线零序电流采样时间存在毫秒级差异,1D-CNN 的时序样本矩阵中特征位置错位。S-CNN 虽然对采样不同步有一定鲁棒性,但采样时间差超过 2.5 ms 后,WT-FCM 方法正确率从 87.75% 掉到 76.5%,1D-CNN 从 99.5% 掉到 91.75%。S-CNN 在 5 ms 时间差内仍保持 100%,但超过这个范围也会下降。解决:在 SCF 构建前做时间对齐,用互相关函数估计各线路之间的时延并补偿。如果硬件上无法同步采样,至少保证同一母线所有出线的采样时钟同源。
4.2 噪声水平超出训练分布
现象:模型在 20 dB 信噪比下表现良好,但现场噪声达到 10 dB 时正确率骤降。原因:训练数据中叠加的噪声类型和信噪比范围有限,模型没有见过极端噪声场景。论文中 S-CNN 在 10 dB 时正确率 98.5%,1D-CNN 只有 86%,但这是在同一噪声分布下测试的结果。解决:训练时做数据增强,叠加不同信噪比(5~40 dB)的高斯白噪声,以及实际录波中常见的脉冲噪声和谐波干扰。验证集要包含比训练集更恶劣的噪声条件。
4.3 线路类型差异被归一化抹掉
现象:模型对纯架空线配电网选线准确,但混合电缆-架空线配电网中电缆线路故障经常误判。原因:归一化消除了幅值差异,但电缆线路和架空线路的零序电流波形本身就有差异——电缆对地电容大,暂态过程频率更低。如果训练数据中电缆线路样本太少,模型学不到这种波形差异。解决:训练数据中保证电缆线路和架空线路的故障样本比例均衡,每种线路类型至少占 30%。SCF 矩阵中保留线路类型标签作为辅助特征。
4.4 相关度矩阵的数值稳定性问题
现象:某些样本的相关度矩阵出现 NaN 或极端值,导致训练发散。原因:S 变换在 h=0 时退化为均值,如果信号均值为零,频域高斯窗在低频段可能产生数值下溢。另外,欧氏距离归一化时分母可能接近零。解决:在 S 变换实现中加入小量 epsilon 防止除零,对相关度矩阵做截断,把小于 0.01 的值置为 0.01,大于 0.99 的值置为 0.99。训练前检查所有样本的 SCF 矩阵,剔除异常样本。
4.5 实际配电网出线数变化时的模型适配
现象:用 10 出线模型去套 6 出线配电网,扩展矩阵后选线正确率下降。原因:去首尾均值法扩展的填充值可能与真实线路间的相关度分布不匹配。如果实际配电网的线路参数与仿真模型差异大,填充值的偏差会被卷积层放大。解决:优先用与实际配电网出线数一致的仿真模型重新训练。如果无法重新训练,至少用实际配电网的历史故障录波数据对扩展后的模型做微调,只更新全连接层参数,冻结卷积层。
提示:论文中实际配电网测试用的是 6 出线系统,出线 5、6 未投入,实际只有 4 条出线的数据。扩展后仍能正确选线,说明方法有一定泛化能力,但这是建立在仿真模型线路参数与实际配电网接近的前提下的。
5. 从仿真到现场:S-CNN 的验证方法与一个实用技巧
5.1 验证方法:分层测试而不是一把梭
训练完模型后,不要直接拿现场数据测。我一般会分三层验证。第一层,用仿真测试集——与训练集同分布但不同随机种子的数据,确认模型没有过拟合。论文中用了 400 组区别于训练过程的故障数据,S-CNN 正确率 100%。第二层,加噪声和采样不同步的干扰测试集,看模型在非理想条件下的退化曲线。论文中 10 dB 噪声下正确率 98.5%,5 ms 采样不同步下仍 100%。第三层,实际配电网故障录波数据,这是最终检验。论文中 3 次实际故障全部正确选线。
def evaluate_model(model, test_loader, noise_levels=None, time_delays=None): """ 分层评估S-CNN模型 noise_levels: 信噪比列表,如 [30, 20, 10, 5] time_delays: 采样时间差列表,单位ms,如 [0, 1.25, 2.5, 5.0] """ results = {} model.eval() with torch.no_grad(): # 基准测试 correct, total = 0, 0 for scf_batch, labels in test_loader: outputs = model(scf_batch) _, predicted = torch.max(outputs, 1) correct += (predicted == labels).sum().item() total += labels.size(0) results['baseline'] = correct / total * 100 # 噪声测试 if noise_levels: for snr in noise_levels: # 对测试数据叠加噪声后重新构建SCF noisy_correct = test_with_noise(model, test_loader, snr) results[f'noise_{snr}dB'] = noisy_correct # 采样不同步测试 if time_delays: for td in time_delays: delay_correct = test_with_delay(model, test_loader, td) results[f'delay_{td}ms'] = delay_correct return results这个评估框架的关键是把干扰因素解耦。噪声和采样不同步分别测试,不要混在一起,否则无法定位问题来源。论文中的对比表就是这种思路:表 3 单独看采样不同步的影响,图 6 单独看噪声的影响。
5.2 一个实用技巧:用混淆矩阵定位系统性问题
选线正确率是个宏观指标,但具体是哪条线路容易被误判、误判成哪条线路,正确率看不出来。我习惯在验证时输出混淆矩阵。论文中表 2 的选线向量其实就隐含了混淆信息——出线 L2 故障时,L2 的数值 0.9267 远高于其他线路,说明模型很确信。但如果某条线路的选线向量中,故障线路的数值只有 0.4,而非故障线路有 0.3,这种样本就是潜在的风险点。
from sklearn.metrics import confusion_matrix import seaborn as sns import matplotlib.pyplot as plt def plot_confusion_matrix(model, test_loader, n_lines=10): """ 绘制选线混淆矩阵,定位系统性问题 """ all_preds = [] all_labels = [] model.eval() with torch.no_grad(): for scf_batch, labels in test_loader: outputs = model(scf_batch) _, predicted = torch.max(outputs, 1) all_preds.extend(predicted.cpu().numpy()) all_labels.extend(labels.cpu().numpy()) cm = confusion_matrix(all_labels, all_preds) plt.figure(figsize=(10, 8)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=[f'L{i+1}' for i in range(n_lines)], yticklabels=[f'L{i+1}' for i in range(n_lines)]) plt.xlabel('预测线路') plt.ylabel('实际线路') plt.title('S-CNN选线混淆矩阵') plt.tight_layout() plt.savefig('confusion_matrix.png', dpi=150) # 输出误判统计 for i in range(n_lines): row_sum = cm[i, :].sum() if row_sum > 0: acc_i = cm[i, i] / row_sum * 100 if acc_i < 100: misjudged = [(j+1, cm[i, j]) for j in range(n_lines) if j != i and cm[i, j] > 0] print(f"线路L{i+1}: 正确率{acc_i:.1f}%, 误判为{misjudged}") return cm这个技巧帮我发现过一个隐蔽问题:某条电缆线路的故障样本总是被误判为相邻的架空线路。查了 SCF 矩阵才发现,这两条线路在仿真模型中的对地电容参数太接近,导致相关度矩阵中它们的行几乎一样。后来在训练数据中增加了这两条线路的参数差异,问题才解决。
5.3 从论文到工程的距离
论文的仿真模型是 10 出线、消弧线圈补偿度 5%、采样率 3200 Hz。实际配电网的消弧线圈可能运行在过补偿或欠补偿状态,采样率可能只有 1600 Hz 甚至更低。这些差异不会让方法失效,但会影响 SCF 矩阵的数值分布。我的习惯是:拿到一个新配电网的数据,先不急着跑模型,而是先算几条已知故障线路的 SCF 矩阵,看看故障线路与非故障线路的相关度差异是否明显。如果差异小于 0.3,说明信号质量或参数设置有问题,得先调 S 变换的频率范围或采样率。
从那以后我每次部署 S-CNN 之前,都强制走一遍「SCF 矩阵可视化检查」——把训练集和测试集的 SCF 矩阵各抽 20 个样本画出来,确认故障特征的位置和数值范围一致。这个习惯帮我省掉了至少三次返工。希望帮到你。
本文还有配套的精品资源,点击获取