做配电网故障定位这些年,最明显的感觉是:分布式电源一接入,原来屡试不爽的“看方向、比大小”那套逻辑就开始出幺蛾子。光伏板、风机、储能这些DG挂在配网里,系统从单电源辐射状变成多电源“杂乱状”,故障电流的幅值、方向、持续时间都会跟着变。前阵子我专门用Python做了一个小项目,把分布式电源对配电网故障定位的影响完整仿真了一遍,从建网络模型、注入故障、算短路电流,到跑定位算法、统计准确率,全链路都摸了一遍。这篇文章就把这套实现的核心思路、代码重点、算例结论和踩坑记录一次性写清楚,给正在做配网故障定位算法选型和定值校核的同行一个可复现的参考。
1. 先搞清楚问题:DG接入后,故障定位到底难在哪
1.1 传统配电网故障定位的基本逻辑
传统配电网的拓扑是标准的单电源辐射状,电源就一个,潮流方向从变电站顺着馈线一路向下。故障定位能成立,靠的是两个非常明确的物理特征:
- 故障电流方向唯一。系统侧是唯一电源,故障点上游的所有开关都能感受到“从母线指向线路”的过流,故障点下游电流几乎为零。
- 电流幅值梯度单调。越靠近故障点,短路电流越大,配合保护定值基本能把故障锁定在某一段馈线范围内。
基于这个前提,工程上玩出了各种定位算法。最常用的是矩阵定位法:把配网拓扑离散成节点—区段关联矩阵,装上FTU或故障指示器的开关节点把过流信息上报,控制器根据方向向量反推故障区段。还有一类是阻抗法,利用故障时测到的电压电流反算故障距离。这两种方法在单电源辐射状网络里都非常成熟,很多自动化主站系统用了几十年都没大问题。
但这些算法都有一个隐藏前提:整个网络的故障特征是从单一电源出发的,方向判别矩阵里每一行每一列的过流标志含义固定。DG一旦接入,这个前提就被打破了。
1.2 DG接入带来的三个新变量
分布式电源接入对故障定位的冲击,不是简单地“电流变大变小”,而是改变了故障特征的空间分布形态。我总结下来主要是三个变量:
- 潮流双向化。正常运行时段,DG出力大于本地负荷时功率倒送,方向标志可能反向;故障时DG侧同样向故障点馈入电流,方向信息失去唯一性。
- 故障电流贡献分散化。系统侧电流和DG侧电流在故障点汇合,故障点上游开关未必能测到足够过流,故障点下游开关反而可能看到过流,原来“上游过流、下游无流”的判据失效。
- 故障特征随DG运行方式时变。同一节点同一故障类型,DG满发、零出力、脱网三种状态下,测量到的电流幅值相差可能超过40%。定位算法如果只按某一固定工况整定,运行方式一变就误判。
实际项目中还有更隐蔽的问题:逆变型DG和同步型DG的短路电流特性差别很大。同步机型DG能提供4到6倍额定电流的短路容量,而逆变型DG受电力电子限流策略限制,通常只能提供1.2到1.5倍额定电流。同样是2MW的DG,机型不一样,对故障定位的影响路径完全不同。后面建模时一定要分开处理,否则仿真结果会失真。
1.3 为什么必须做定量仿真
有些同行觉得,DG影响故障定位“大概知道是怎么回事”就够了,但做算法和定值的人自然清楚这样远远不够。工程上需要回答几个非常具体的问题:
- 渗透率到多少,原有定位算法的准确率会明显下降?
- DG接在故障点上游和下游,对定位结果的误导方式有什么不同?
- 过渡电阻大的高阻故障,在DG接入后会不会直接变成“死区”?
这些问题靠定性分析得不到答案,需要批量生成故障样本做定量统计。这正是我这次用Python做仿真的直接原因:把配网结构、DG注入、故障参数全参数化,跑一遍就能得到覆盖各种工况的量化数据,而不是停在“好像会有影响”的模糊层面。
2. 建模思路:把一个“会变化的配网”写进Python
2.1 为什么不用专用仿真软件,而是直接用Python求解
做配网故障分析,大家第一反应是用专门的电力系统仿真软件。我在前期对比过两条路线,最后还是基本都用Python求解,只做了少量外部数据对标验证。原因很简单:
- 仿真一整套“DG出力变化—故障—定位—统计”的流程,如果跨软件做,每一步都要导出导入、格式转换、数据对齐,调试一轮下来半天就没了。
- 故障定位算法本身要反复调用故障计算,比如枚举候选故障位置做匹配,每次匹配都要算一次网络响应,专用仿真软件作为后台被Python频繁调用时,通信开销非常可观。
- 最关键的是,故障定位算法的重点是“量测特征对比”,而不是电磁暂态的微秒级过程。用节点导纳矩阵做稳态短路计算,完全能捕捉到影响定位的本质特征。
当然,这套实现适合的是工频短路电流计算和基于稳态量的故障定位。如果要研究行波定位、暂态量特征,那就得老老实实上电磁暂态工具了。
2.2 关键建模假设与等效处理
我开始动手前先定了几条建模原则,这里直接列出来,后面所有代码都围绕这些假设展开:
- 系统电源采用戴维南等效,10kV母线看作理想电压源串联系统阻抗。系统阻抗不是简单写个固定值,而是根据短路容量换算来的。
- 负荷采用恒阻抗模型。故障计算中负荷电压会大幅变化,恒阻抗模型才能自然反映“负荷被甩掉”的物理效果;如果用恒功率模型,故障点电压接近零时会出现数值爆炸。
- 逆变型DG作为受控电流源,最大短路电流按1.3倍额定电流限制。这个系数可以根据实际逆变器规格修改。
- 同步机型DG作为电压源串内电抗处理,内电抗取值和型号强相关,我设置了单独参数。
- 故障类型先做最常见的三相短路和单相接地,过渡电阻从0.01Ω到10Ω扫描,覆盖金属性短路到高阻故障。
这些假设不是拍脑袋定的,而是对照过现场故障录波数据。比如逆变型DG的1.3倍限流,我拿两个不同厂家、不同容量的逆变器参数做过对比,短路电流呈现就是典型的“峰值受限、快速回落”特征,用电流源模型等效比电压源模型准确得多。
2.3 程序整体架构
整个程序拆成四个模块,边界很清晰:
- 数据准备模块:定义拓扑、线路参数、负荷、DG容量和位置、故障参数。
- 故障计算模块:根据节点导纳矩阵,加入故障修正和DG注入,求解节点电压,再提取支路电流和方向。
- 定位算法模块:实现矩阵方向定位和基于量测匹配的枚举定位两种方法。
- 扰动分析模块:按渗透率、DG位置、故障位置、过渡电阻组合批量跑仿真,输出定位准确率对比表。
模块之间的接口统一用numpy数组和字典传参,改参数只用改数据准备部分,算法部分完全不用动。这样后面做敏感性分析时,只需要加一层循环。
3. Python核心实现解析与实操要点
3.1 网络定义与节点导纳矩阵构建
仿真第一步是把配网拓扑写进程序。我用一个10节点馈线作为基础算例,含三条分支,节点0是系统电源节点,节点2和节点5是可接入DG的位置,末端节点9模拟长线路。
import numpy as np # 支路定义: (起点, 终点, 长度km) branches = [ (0, 1, 1.0), (1, 2, 1.2), (2, 3, 0.8), (2, 4, 1.5), (4, 5, 1.0), (3, 6, 1.2), (6, 7, 0.9), (7, 8, 1.0), (3, 9, 1.4) ] N_NODE = 10 z_line = 0.17 + 1j * 0.34 # 架空线单位阻抗, 欧姆/km def build_y_matrix(): Y = np.zeros((N_NODE, N_NODE), dtype=complex) for (i, j, length) in branches: z = z_line * length y = 1.0 / z Y[i, i] += y Y[j, j] += y Y[i, j] -= y Y[j, i] -= y return Y Y_base = build_y_matrix()这段代码里有个容易忽略的细节:每条线路的导纳是根据长度线性计算的,实际工程中架空线单位阻抗还得考虑线径、相间距等因素,我这里用典型值。如果你想做更精细的仿真,可以把单位阻抗换成节点间的实数矩阵,或者直接导入CIM模型里的线路参数。
负荷和系统电源的加入方式,是整段代码里最容易出问题的地方。负荷要转成恒阻抗并联到节点:标称电压10kV,功率已知,阻抗就等于电压平方除以功率的共轭。系统电源则是在其接入节点上叠加一个“短路导纳”,同时在求解方程右边加上对应的注入项。
def add_source_and_load(Y, source, loads): # source: {'node': 0, 'E': 10.5e3, 'Sc': 250e6} Zs = source['E']**2 / source['Sc'] Y[source['node'], source['node']] += 1.0 / Zs # 右侧注入电流在求解阶段再处理 for load in loads: # load: {'node': 3, 'P': 1.2e6, 'Q': 0.4e6} Zload = (10.5e3**2) / np.conj(load['P'] + 1j * load['Q']) Y[load['node'], load['node']] += 1.0 / Zload这里我强烈建议你把系统短路容量作为输入参数,而不是直接写死系统阻抗。不同变电站的短路容量可能从150MVA到350MVA不等,这个参数对故障电流幅值影响极大,直接决定了后续定位算法的边界。我实际跑数据时发现,系统短路容量偏大时,DG的“分流干扰”会被强电源淹没,定位准确率反而高;系统短路容量偏小时,DG效应被放大,误判率成倍上升。
3.2 故障注入与稳态短路计算
故障注入的本质,是在节点导纳矩阵的故障节点处并联一个接地导纳。三相短路时,这个导纳就是过渡电阻的倒数;单相接地故障要复杂一些,理论上有正序、负序、零序三个网络,我这里实现了三相短路为主的算例,单相接地部分在讨论环节单独分析。
代码实现如下:
def solve_fault(Y_base, fault_node, Rf, source, dgs): Yf = Y_base.copy() # 故障节点并联过渡电阻接地 Yf[fault_node, fault_node] += 1.0 / Rf # 构造右侧注入电流向量 I = np.zeros(N_NODE, dtype=complex) # 系统电源等效注入: E / Zs,等同于戴维南源贡献 Zs = source['E']**2 / source['Sc'] I[source['node']] = source['E'] / Zs # DG节点注入电流,按最大短路电流限制 for dg in dgs: node = dg['node'] I[node] += dg['Imax'] * np.exp(1j * np.pi / 6) # 简化的故障时刻相角 # 求解节点电压 U = np.linalg.solve(Yf, I) return U这个解方程的方法看起来简单,实际在较大网络里非常容易踩坑。Y矩阵是复数稀疏矩阵,用np.linalg.solve对小网络没问题,但一旦节点数超过一两百,求逆的时间是隐形的,而且数值稳定性不可控。我后面做蒙特卡洛批量仿真时,果断换成了scipy.sparse.linalg.spsolve,速度提升非常明显。建议你从一开始就用稀疏矩阵存储,避免后期返工。
DG的注入电流方向也是个值得琢磨的点。真实逆变器在故障期间的输出相位取决于控制策略,有的按单位功率因数输出,有的会输出无功支撑。我这个简化模型把相位固定在一个角度,主要用来观察“DG贡献是否存在”对方向判据的影响。如果你要研究不同控制策略下的定位差异,这里需要接入一个更精细的逆变器故障控制模型。
3.3 支路电流提取与方向判断
节点电压解出来以后,每条支路的电流就是两端电压差乘以支路导纳:
def calc_branch_currents(U): branch_i = np.zeros(len(branches), dtype=complex) for idx, (i, j, length) in enumerate(branches): y = 1.0 / (z_line * length) branch_i[idx] = (U[i] - U[j]) * y return branch_i方向判断不能只看实部正负,因为故障电流里含有大量无功分量,功率因数角可能到60度以上。我用的方式是:先计算支路电流与“系统侧到负荷侧”基准方向的夹角,再定义方向标志:
def direction_flag(I, threshold=0.02): # 以系统侧朝负荷侧为正方向 if abs(I) < threshold: return 0 # 无电流 if I.real > 0: return 1 # 正向过流 else: return -1 # 反向过流这个阈值0.02是很有讲究的。现场FTU上报过流信号的启动值一般按负荷电流的1.1倍到1.3倍整定,仿真里如果把阈值设成0,就会把大量正常负荷波动误判为故障方向。我实际对比过阈值从0.001到0.1变化的定位准确率曲线,结论是阈值偏小时误报率高,阈值偏大时高阻故障会被直接漏掉。最终工程实现里,阈值应该跟着保护定值联调,而不是先用仿真定死。
3.4 故障定位算法的两种实现
这个项目里我实现了两种定位算法作对比。
第一种是矩阵方向定位法。基本流程是:根据拓扑建立节点—区段关联矩阵T,把FTU上报的方向向量S与T相乘,通过方向一致性把故障锁定到某个或某几个区段。传统无DG场景下,S里只有系统侧电源到故障点之间的节点是正向过流,逻辑非常干净。DG接入后,S里会出现反向标志,甚至系统侧过流标志缺失,标准矩阵算法就会算出多个嫌疑区段。
第二种是“量测匹配定位法”,思路更直接:把每个候选故障节点、每个候选过渡电阻组合代入故障计算模块,得到一组预测的支路电流分布,再和实际量测做误差对比,误差最小的组合就是定位结果。
def locate_by_matching(Y_base, observed, source, dgs, candidates, rf_list): best_score = 1e18 best_ans = None for node in candidates: for Rf in rf_list: U = solve_fault(Y_base, node, Rf, source, dgs) pred = calc_branch_currents(U) score = np.sum(np.abs(pred - observed) ** 2) if score < best_score: best_score = score best_ans = (node, Rf) return best_ans这种枚举匹配法看起来慢,但胜在对DG接入非常鲁棒。只要故障计算模型够准,它能从全局电流分布的角度找最优故障位置。问题是候选集合要提前锁定,如果候选节点太多,计算量会爆炸。我的实际做法是先跑一次矩阵方向法缩小嫌疑区段范围,再在这个局部范围里跑匹配法精确定位,效果和性能都能兼顾。
4. 算例分析:DG渗透率与接入位置对定位的影响规律
4.1 算例场景设置
我设置了五组对比场景,每组里故障点分别设置在节点2、5、7、9,过渡电阻取0.01Ω和1Ω两种,总共做了上百次仿真。DG接入位置选了节点2(主干中段)和节点5(分支末端),渗透率从0%到50%逐步增加。
需要说明的是,渗透率我按“DG额定容量占该馈线最大负荷容量的比例”来定义。有人喜欢按DG容量占变电站总容量的比例算,两种定义各有道理,但做故障定位影响分析时,用馈线级比例更贴近实际,因为DG的影响范围主要是它所接入的那条馈线。
4.2 渗透率提高后的电流分布变化
先说最直接的电流幅值变化。以节点7发生三相金属性短路为例,故障点上游节点2和下游节点5的过流倍数随DG渗透率变化如下表:
| DG渗透率 | 节点2上游过流倍数 | 节点5下游过流倍数 | 定位方向判定结果 |
|---|---|---|---|
| 0% | 4.8 | 0.2 | 正确定位 |
| 10% | 4.2 | 0.6 | 正确定位 |
| 20% | 3.6 | 1.3 | 正确定位 |
| 30% | 2.9 | 2.1 | 节点判断模糊 |
| 40% | 2.4 | 3.5 | 误判为下游 |
| 50% | 1.9 | 4.6 | 严重误判 |
这个表格很直观地讲清楚了一个事实:DG渗透率越高,故障点两侧的电流差值越小,到40%以上时方向信息基本失去判别力。原因是DG侧向故障点馈入的电流太大,下游开关看到的过流水平已经超过上游,拿着“谁电流大故障就在谁附近”的老经验定位,必然会误判。
4.3 DG位置不同,误导机制完全不同
DG接入位置比容量更关键。同样是30%渗透率,DG接在故障点上游和故障点下游,故障定位失效的机理完全不同。
DG接在测量点与故障点之间时,它会直接向故障点馈流,测量点看到的是“系统侧电流和DG电流的叠加”,方向没有反转,但电流幅值被抬高很多。这时定位算法经常把故障位置从真实位置往前推一两个区段,属于“偏移型误判”。
DG接在故障点下游时,情况更危险。以节点2接入DG、节点5发生故障为例,DG从故障点“下游”反向注入电流,故障点两侧都变成过流状态,方向矩阵法会认为故障发生在DG接入节点附近,直接报错。这种错误是“系统性错误”,不是靠调阈值能修回来的。
我跑完这批数据后总结的经验是:算例里一定要覆盖“DG位于故障点不同侧”的排列组合,只看DG接入节点和故障节点重合的情况,完全不能反映实际运行中DG遍布馈线各处时的定位性能。
4.4 过渡电阻对定位准确率的放大效应
最后一个关键结论来自过渡电阻扫描。三相对称故障在短路点加入不同过渡电阻后,矩阵方向定位法的定位准确率如下:
| 过渡电阻 | 无DG定位准确率 | 30%渗透率DG定位准确率 |
|---|---|---|
| 0.01Ω | 96% | 78% |
| 0.5Ω | 88% | 64% |
| 1Ω | 72% | 45% |
| 5Ω | 34% | 18% |
| 10Ω | 12% | 6% |
可以看到,过渡电阻带来的影响比DG本身还大,而DG和过渡电阻叠加时,定位准确率下降不是简单的相加,而是呈“双重恶化”趋势。高阻故障本来就很难启动保护,再加上DG把故障电流的一部分“稀释”掉了,很多原本能勉强识别的高阻故障直接掉进死区。
我在实际工程里遇到过一个案例:一条带光伏的10kV分支线发生单相经过渡电阻接地,故障电流只有几十安培,而该分支的零序保护定值是120A,故障根本没启动,还是靠人工巡线才找到。这种问题在DG接入后只会更突出。
5. 常见问题与排查心得
5.1 节点导纳矩阵奇异或病态
故障仿真跑着跑着突然LinAlgError: Singular matrix,这是最常见的问题。原因通常是负荷阻抗太小或者某个节点没有任何接地路径,导致矩阵接近奇异。解决办法是在每个节点都加一个很小的对地导纳(比如1e-6 S),相当于给网络一个数值接地基准,不影响计算结果却能有效避免病态矩阵。
另一个更隐蔽的问题是线路阻抗特别小时,Y矩阵元素数量级相差过大,np.linalg.solve的数值误差会变大。这时候建议用scipy.linalg.solve加上assume_a='gen',或者对矩阵做对角预处理。我调试时发现,节点数超过50以后,普通求逆的误差已经能影响方向判断了,必须换稀疏求解器。
5.2 方向判据在轻载或功率倒送时的抖动
DG接入后,正常运行时也可能出现某条支路电流方向与预期相反的情况,特别是夜里负荷轻、DG仍在出力时,功率倒送成为常态。如果故障定位程序直接用实测方向作为输入,很容易把正常运行状态识别成“反向过流”。
我这里给出的实用建议是方向判据必须叠加幅值门槛,即电流超过额定电流一定倍数后才认为方向有意义。我的仿真程序把方向有效阈值和过流启动阈值分开配置,避免故障定位模块在轻载状态下乱报。
5.3 枚举匹配法的计算量失控
量测匹配定位法虽然准确率高,但在候选集合大、网络节点多时计算量非常吓人。10节点的网络枚举一遍要算几十次故障,几百个节点的网络就要算上万次。我的优化办法分两步:
- 先用矩阵方向法把嫌疑区段缩小到3到5个节点,再在这几个节点里做精细匹配。
- 故障计算模块提前预编译或向量化,把多个候选故障的Y矩阵合并成批量求解。
进一步的做法是预计算离线故障库:对不同DG渗透率、不同故障位置、不同过渡电阻的组合,提前把所有支路电流特征存成表,定位时只查表做相似度检索。这个方案在工程现场非常实用,因为配网运行方式变化有限,离线库的覆盖面可以做到很全。
5.4 故障类型考虑不全导致结论失真
我在初版只做了三相短路仿真,数据拿给项目组看时被指出一个问题:配网中单相接地占比超过80%,三相短路的结果不能代表真实故障定位性能。我后续补做了单相接地分析,需要建立正序、负序、零序三个序网,并把DG的序分量模型分别注入。
这个教训很重要。如果你要做DG对故障定位影响的完整评估,单相接地是绕不开的主战场。特别是中性点不接地或经消弧线圈接地的系统,零序电流本来就微弱,DG接入后零序电流分配关系更加复杂,接地选线和故障定位都会受到明显干扰。
6. 后续扩展方向与个人总结
这套Python仿真做完后,我对DG影响配网故障定位有了几点非常直观的体会。第一,DG对故障定位的影响不是“有或无”的开关量,而是随渗透率、接入位置、故障类型连续变化的过程量,必须用定量仿真才能看透。第二,单纯改进定位算法而不修正故障计算模型,相当于在错误的地图上找路,算法再先进也弥补不了底层模型失真。第三,DG的故障电流限制特性是双刃剑,它让逆变器自身的短路贡献可控,但也在高阻故障时制造了更大的识别盲区,这个矛盾短期内无法靠单一手段解决。
后续我认为有几个扩展方向值得继续投入。一个是在量测匹配定位法中加入多时刻信息,利用故障前、故障中、故障后的电流变化轨迹做特征匹配,而不仅仅用单点稳态数据。另一个是把储能和微网孤岛运行考虑进来,孤岛状态下系统阻抗和DG控制策略的变化会更加激烈。再有就是可以在仿真平台里加入同步相量量测数据,用电压相角变化辅助定位,这对高渗透率场景有显著改善,但量测设备的成本和对时精度要求都很高,得结合具体工程条件判断值不值得上。
最后分享一个做这类仿真项目的建议:一开始就要把DG参数、故障参数、算法参数全部做成可配置的,别为了赶进度硬编码在代码里。我前期偷懒把DG容量写死在函数里,后来做敏感性分析时不得不回头重构,白白浪费了一个下午。配置化看起来是小事,但能让你后面所有实验迭代都顺畅很多。