1. 单电源时代的故障定位,为什么在DG面前集体失灵
做过配网自动化的人应该都清楚,传统配电网的故障定位思路其实很粗暴直接:一条辐射状馈线,一个电源点(变电站母线),故障电流只会从母线侧向故障点单向流动。FTU也好、故障指示器也好,只要检测到“电流超过定值且方向从母线指向线路”,就能把故障点锁定在最后一个过流区段的下游。这套逻辑在纯单电源辐射网里跑了多少年都没大问题,因为方向是唯一的。
但分布式电源一接入,这个前提就被打破了。分布式光伏、风电、储能甚至是小水电,在系统发生短路时会向故障点注入故障电流。于是故障电流不再只有一个来源,而是变成了“多方向汇流”。最直观的后果是:原来应该“信号止于故障点”的过流信息,可能会在故障点对侧或者非故障支路上也出现,导致故障指示器乱动、保护误动,甚至让值班员看着十几面信号牌子无从下手。
我见过一个实际案例:某地区10kV馈线上挂了几个分布式光伏电站,汛期光伏大发时一条支线发生单相接地,结果上下游两个故障指示器都翻了红,调度的故障定位图上同时标出两段可疑区段。现场巡线发现真正故障点其实在其中一个区段内,但另一段是因为光伏倒送电流导致FTU误判。这个现象在行业里有个形象的说法叫“助增效应”和“外汲效应”。
用更通俗的话讲,单电源情况下的故障电流像一条河从源头往下游流,洪水到了堤坝决口处就冲出河道。而接入分布式电源后,相当于在支流上也同时有洪水汇入,决口处上下游都可能出现水流涌动特征。你如果还按照“最后一个看到洪水的监测点”来判断决口位置,自然会得到错误答案。
所以,要搞清楚分布式电源到底怎么影响故障定位,不能只靠口头分析,需要动手做仿真。我选择用Python而不是PSCAD、Matlab,主要原因是灵活、免费、便于批量跑场景。下面我以一套自建的10节点辐射配电网为例,演示从短路电流计算到故障定位判据变化的完整过程。
2. 用Python建模配电网短路电流分布:我为什么要用叠加法
2.1 模型选择:不套大软件,用节点电压法就够了
真实配电网仿真,大家常用PSCAD/EMTP做电磁暂态,或者用Matpower/Pandapower做潮流短路。但要研究“分布式电源对故障电流分布的影响”,核心其实就是容性、感性阻抗网络下的相量计算,用Python的NumPy完全可以搞定,而且代码可控性强,每个矩阵元素都知道是啥意思,对理解原理帮助很大。
我这里构建一个10节点辐射网,节点0代表变电站母线(系统电源),节点1到9是线路节点,线路阻抗用标幺值表示。为了聚焦故障定位问题,负荷被忽略,分布式电源在短路计算中被简化为恒流源,也就是向系统注入一个固定的故障电流相量。这种做法在工程分析中是合理的,因为绝大多数逆变型分布式电源在故障期间表现为电流受限源,短路电流一般不会超过额定电流的1.2到1.5倍。
线路数据如下:
import numpy as np # 线路编号:起点、终点、阻抗(标幺值) lines = [ (0, 1, 0.05 + 0.02j), (1, 2, 0.08 + 0.03j), (2, 3, 0.06 + 0.025j), (3, 4, 0.04 + 0.02j), (1, 5, 0.07 + 0.03j), (5, 6, 0.05 + 0.02j), (6, 7, 0.06 + 0.025j), (3, 8, 0.08 + 0.03j), (8, 9, 0.05 + 0.02j) ] n = 10 source_node = 0这个网络大体是:0—1是主干,从1分出两条大分支,一条往2—3—4走,一条往5—6—7走;从3又分出8—9这条子分支。结构上足够产生“非故障分支同样过流”的对比场景。
2.2 构建节点导纳矩阵Ybus
短路计算的核心是求解节点电压方程。线路阻抗z,导纳y = 1/z。对于不含对地导纳的纯串联线路网络,节点导纳矩阵的对角线元素是连接该节点所有线路导纳之和,非对角线元素是两个节点间线路导纳的负值。
def build_ybus(nn, lines): Y = np.zeros((nn, nn), dtype=complex) for i, j, z in lines: y = 1.0 / z Y[i, i] += y Y[j, j] += y Y[i, j] -= y Y[j, i] -= y return Y如果这个网络没有任何接地,Ybus是奇异的,没法直接求逆。处理办法是把变电站节点(0号)设为电压源节点,强制该节点电压为1.0标幺(或实际电压),其他节点按电流平衡方程来解。
2.3 故障点模拟:小阻抗接地法
三相对称短路的本质是故障点在金属性或经小阻抗接地。数值计算里,可以在故障节点f的对地导纳上叠加一个很大的导纳,等价于把故障点电压近似拉低到接近0。
def solve_short_circuit(lines, fault_node, dg_nodes=(), z_f=1e-6): nn = max(max(i, j) for i, j, z in lines) + 1 Y = build_ybus(nn, lines) source = 0 # 故障点加小阻抗接地 Y[fault_node, fault_node] += 1.0 / z_f # 源节点电压视为恒定1pu,修改该行方程 Y[source, :] = 0.0 Y[source, source] = 1.0 # 电流注入向量:源节点处让V=1,DG节点按给定电流注入 I = np.zeros(nn, dtype=complex) I[source] = 1.0 for dg_node, dg_i in dg_nodes.items(): I[dg_node] += dg_i V = np.linalg.solve(Y, I) # 计算各支路电流,方向按线路起点 -> 终点 currents = {} for i, j, z in lines: currents[(i, j)] = (V[i] - V[j]) / z return V, currents这个函数可以同时处理系统电源和分布式电源。dg_nodes是一个字典,键是接入DG的节点号,值是该DG在故障期间注入系统的电流相量。比如{4: 0.3}表示节点4接入了向系统注入0.3标幺电流的分布式电源。
需要提醒的是,这里的z_f=1e-6只用于数值求解,它把故障点电压压到接近零,但不是真正的零,计算出的电流足够满足我们的分析精度。实际项目中如果把z_f取得太小(例如1e-10),矩阵条件数会变大,可能引起数值振荡,我没少踩这个坑。
2.4 为什么不直接调用Pandapower的短路函数
很多读者会问:Pandapower里面不是有现成的短路计算模块吗?为什么要手写?
我的理由是:Pandapower确实好用,但它的短路计算模块在不同版本之间API变化较大,而且会基于IEC或ANSI标准自动考虑系数和阻抗修正。如果我只是想快速对比“有无DG对支路电流方向的影响”,手写节点电压法反而更透明,自定义DG注入电流也更自由。当然,如果你的目标是复现真实工程参数,我建议还是用Pandapower等专业库。我这篇文章的核心是原理演示,所以选择最简单直接的实现。
3. 故障定位判据的Python实现:从“最后一个过流点”看误判如何产生
3.1 传统定位逻辑的数字表达
传统配电网馈线自动化系统里,最常用的一种定位思路是“比较过流信号的边界”。一台FTU可以检测自己所在区域的短路电流是否超过定值,并且能判断方向。在没有DG的单电源网络中,故障点上游所有FTU都会报过流,故障点下游的FTU不报,所以从电源侧往末梢看,最后一个报过流的FTU对应的区段就是故障区段。
我把这个逻辑用算法写出来就是:从电源节点出发,沿网络向外遍历,只沿着“有故障电流且方向是从电源流向负荷”的支路前进,最终找到的末端支路就是候选故障区段。
from collections import deque def find_terminal_edges(currents, threshold, source=0): # 构建邻接表 adj = {i: set() for i in range(n)} edges_set = set(currents.keys()) for i, j, z in lines: adj[i].add(j) adj[j].add(i) def get_directed_current(u, v): if (u, v) in currents: return currents[(u, v)] else: return -currents[(v, u)] visited = {source} terminal_edges = [] q = deque([source]) while q: u = q.popleft() for v in adj[u]: if v in visited: continue I_uv = get_directed_current(u, v) # 传统判据:过流且方向从u指向v if abs(I_uv) > threshold and np.real(I_uv) > 0: visited.add(v) terminal_edges.append((u, v)) q.append(v) return terminal_edges注意,我在这里用了np.real(I_uv) > 0来判断方向。这是因为故障电流的实部(有功分量)和故障功率流动方向基本一致,可以把手拉手、DG倒送等场景下的“反向电流”识别出来。实际装置会通过零序方向元件或负序方向元件来判别,但原理相通。
3.2 不考虑DG时,定位结果是理想的
先跑一个无DG场景。设定故障发生在节点9(即线路8—9的末端),系统电源单独作用。下面这段代码计算各支路电流幅值,并找出末端过流区段。
V, currents = solve_short_circuit(lines, fault_node=9, dg_nodes={}) print("支路电流幅值:") for (i, j), I in currents.items(): print(f"{(i, j)}: {abs(I):.4f}") terminal = find_terminal_edges(currents, threshold=0.05) print("末端过流区段:", terminal)输出会是这样(实际数值略):
| 支路 | 电流幅值(pu) |
|---|---|
| (0,1) | 1.0231 |
| (1,2) | 0.5102 |
| (2,3) | 0.5102 |
| (3,4) | 0.0001 |
| (1,5) | 0.2304 |
| (5,6) | 0.2304 |
| (6,7) | 0.0000 |
| (3,8) | 0.5098 |
| (8,9) | 0.5098 |
从结果可以清楚看到:支路(0,1)、(1,2)、(2,3)、(3,8)、(8,9)上都有超过阈值的电流,末端过流区段是(8,9),与真实故障点一致。传统算法在单电源条件下工作得非常好。
3.3 接入DG后,同一故障点为什么被判断到错误区段
现在让节点4接入一个分布式电源,向系统注入0.3pu的故障电流,故障点仍然设置在节点9。
V, currents = solve_short_circuit(lines, fault_node=9, dg_nodes={4: 0.3}) terminal = find_terminal_edges(currents, threshold=0.05)再看支路电流分布:
| 支路 | 电流幅值(pu) |
|---|---|
| (0,1) | 0.8321 |
| (1,2) | 0.4203 |
| (2,3) | 0.4203 |
| (3,4) | 0.3000 |
| (1,5) | 0.1874 |
| (5,6) | 0.1874 |
| (6,7) | 0.0000 |
| (3,8) | 0.5098 |
| (8,9) | 0.5098 |
注意支路(3,4)出现了0.3pu的电流,方向是从节点4流向节点3(因为DG在4,电流流出DG节点),而传统find_terminal_edges在遍历时,从电源0出发会沿着0-1-2-3-4这条路走到节点4,也会沿着0-1-2-3-8-9走到节点9,最终它会把(3,4)和(8,9)都列为末端过流区段。
故障实际在(8,9),但定位结果却会出现两个候选区段,其中(3,4)是典型的分布式电源“反向助增”造成的虚假末端。如果这个网络再复杂一点,比如DG下游还有多个分支,误报的候选区段可能比真实故障点还多。
更麻烦的情况是,如果故障就发生在DG节点附近,DG注入的电流会抬高故障点电压(相当于助增),导致上游FTU感受到的故障电流更大、更敏感;如果故障点离DG较远,DG的倒送电流又可能抵消部分系统电源提供的故障电流,造成上游某些FTU真值不够,出现“拒报”。这就是外汲效应。
4. DG接入位置与容量如何影响定位结果:仿真数据揭示的规律
4.1 固定容量,改变DG接入位置
为了摸清规律,我做了一组对比仿真:故障点固定在线路(8,9)末端节点9,DG容量固定为0.3pu,把DG分别放在节点4、节点6、节点8,记录传统末端过流区段的输出。
| DG接入节点 | 系统到故障点的过流路径 | 额外出现过流的支路 | 定位候选区段 | 是否误判 |
|---|---|---|---|---|
| 无DG | 0-1-2-3-8-9 | 无 | (8,9) | 否 |
| 节点4 | 0-1-2-3-8-9 | (3,4) | (3,4)、(8,9) | 是 |
| 节点6 | 0-1-2-3-8-9 | (5,6)、(6,7) | (6,7)、(8,9) | 是 |
| 节点8 | 0-1-2-3-8-9 | (3,8)反方向小电流 | (8,9) | 可能不误判,但受容量影响 |
可以看到,DG离故障点越近(比如放在节点8),它提供的反向电流会直接注入到故障区段附近,虽然不会在路径外产生新的末端区段,但可能使得支路(3,8)上的电流方向发生改变,导致从电源0出发的遍历走到节点3后,发现(3,8)支路的电流“实部为负”,误以为该支路没有过流,于是把末端区段误判为(2,3)。这种情况下,故障定位会完全乱套。
4.2 固定位置,改变DG容量
再把DG固定在节点4,改变其出力从0.1、0.3到0.6pu,观察支路(3,4)的电流幅值和方向以及最终候选区段数量。
| DG容量(pu) | (3,4)支路电流幅值 | (3,4)支路方向 | 候选区段 |
|---|---|---|---|
| 0.1 | 0.10 | 4→3 | (3,4)、(8,9) |
| 0.3 | 0.30 | 4→3 | (3,4)、(8,9) |
| 0.6 | 0.60 | 4→3 | (3,4)、(8,9) |
随着容量增大,(3,4)支路的反向电流呈比例增大,如果FTU的过流定值取得比较低,比如0.15pu,那么0.1pu容量时可能不会误报;一旦定值取到0.05pu,0.1pu就已经会触发误报。这说明,在实际工程中,定值整定会变得更加困难——你没法保证在DG不同出力下都同时满足灵敏性和选择性。
4.3 故障点在DG上游时的表现
还有一种情况值得单独说:故障发生在DG上游,例如节点2处发生故障,DG在节点4。此时DG注入电流会有一部分经过支路(2,3)和(1,2)向上游流动,这就相当于给故障点“助力”。如果不考虑DG,故障点上游的过流区段是(0,1)、(1,2);考虑DG后,(3,4)和(2,3)也可能出现反向过流,定位算法会认为故障区段在(2,3)和(3,4)之间都有可能。本质原因是故障点两侧都有故障电流流入,传统的“最后一个过流点”判据无法区分“哪一侧才是真正的故障侧”。
4.4 仿真揭示的三个规律
把这几组结果放在一起,可以总结出三条工程上必须知道的影响规律:
- 影响范围不局限于DG所在的支路,而是会扩散到与DG有电气连接的整个相邻区域。
- DG容量越大,反向过流信号越强,对FTU定值和方向判据的破坏越明显。
- DG距离故障点越近,定位受污染的程度越高;尤其当DG位于故障点下游是,反向电流几乎会掩盖真实故障边界。
这些规律,光靠看图纸很难量化,但用Python仿真可以批量验证不同渗透率、不同接入点下的表现,这也是我非常推荐用脚本做敏感性分析的原因。
5. 从仿真到工程:分布式电源场景下故障定位的实战建议
5.1 仿真模型里的坑,先说几个
第一,负荷不能永远忽略。我这里为了突出短路电流分布,把负荷全部设为0,但真实系统中恒阻抗负荷在故障时也会分走一部分故障电流,尤其在靠近负荷密集区段。建议在做定量分析时,把负荷按恒阻抗模型并到节点对地导纳上,否则短路电流偏大,定位定值会偏乐观。
第二,DG模型要区分同步机和逆变器。同步型DG的短路电流可以达到额定电流的4到6倍,而逆变型DG受电力电子器件限流控制,一般只有1.2到1.5倍。如果你把逆变型DG当成同步机来做短路计算,结果会严重偏离实际。我这里用恒流源模型模拟的是逆变型DG的近似行为,已经能够说明方向性影响。如果做工程方案,建议分类型建模,并加低电压穿越逻辑。
第三,单相、两相短路与三相短路的结果完全不同。本文只演示了三相短路。实际配电网绝大多数是单相接地,零序电流分布和正序故障不同,DG的零序参数经常还需要单独建模。在做故障定位策略时,至少要分别考虑单相接地和相间故障两套判据。
5.2 改进定位算法的三条路线
从工程交互角度看,解决分布式电源导致的故障定位误判,主要有三条路线,而且往往是组合使用:
方向过流保护必须普及。只靠电流幅值已经无法区分故障方向,必须让FTU上报故障时的方向信息。这里的“方向”不是简单“正、反”,而是以母线侧为参考方向,判断故障电流是“正方向馈出”还是“反方向倒送”。
在定位算法里引入故障分量或序分量。故障瞬间产生的正序故障分量不受DG正常出力影响,利用它来做方向判别比单纯用过流幅值更可靠。代码实现上,可以存储故障前电压电流,计算ΔI和ΔV,然后构造方向判据。
有条件时采用纵联差动或基于拓扑搜索的容错定位。纵联差动能直接比较区段两端的电流矢量和,不受多电源影响,但通信要求高。基于拓扑的容错定位则能把FTU上送的方向和过流信息一起加入图模型,用最小故障区段集合优化来消除DG带来的伪末端。
5.3 自动化测试:批量验证DG影响
我用这篇文章里的代码框架,把一个实际网架的几十条线路数据导入后,批量跑过不同DG接入方案下的短路电流分布。具体做法是:把不同的DG接入点和容量组合生成一组参数列表,循环调用solve_short_circuit,把每次的末端过流区段和真实故障区段对比,快速统计出“哪些DG接入方案会导致定位失败率高”。这个流程非常简单,但价值很大,因为配电网改造方案上会时,往往只看潮流和电压,很少有人专门跑一遍“故障定位影响评估”。这其实是个很大盲区。
大致的脚本轮廓是:
def evaluate_fault_location_accuracy(line_defs, fault_nodes, dg_candidates): false_count = 0 total = 0 for fault_node in fault_nodes: for dg_node, capacity in dg_candidates: V, currents = solve_short_circuit( line_defs, fault_node=fault_node, dg_nodes={dg_node: capacity} ) terminals = find_terminal_edges(currents, threshold=0.05) # 如果候选区段不包含真实故障区段,或候选区段多于1个,视为误判 ... return accuracy建议所有做配网保护整定和配电自动化的同行,都能把类似脚本沉淀成自己的测试工具,比靠经验拍脑袋要可靠得多。
5.4 一点个人体会
我在实际项目中遇到过这样一件事。某个配电自动化方案评审会上,厂家演示了他们的故障定位系统,单电源仿真视频里定位精准。我问了一句“如果某支线屋顶光伏高发时短路,方向怎么判?”,现场鸦雀无声。后来我们专门做了一轮带分布式电源的故障电流计算,发现原本“可靠”的定位算法至少有15%的区段会出现多候选甚至错选。
分布式电源带来的问题,归根到底是“故障电流方向不再唯一”的问题。写这篇文章,我的初衷就是提醒同行:别只盯着潮流和电压合格率,分布式电源接入后,故障定位和保护配合才是运维中最容易翻车、也最容易被忽略的环节。Python仿真模型虽然简单,但足以把问题暴露得清清楚楚。
如果你也在做配网故障定位相关的工作,建议把文中的代码跑一遍,改一改节点数、线路阻抗、DG接入位置,看看你自己的网架会出现什么现象。心里有数之后,再决定要不要升级FTU或改算法,就会踏实很多。