简介针对配电网故障后的快速重构需求这份MATLAB程序采用DistFlow潮流模型面向电力系统相关专业学生、科研人员及配网规划工程师支持输入任意故障线路编号后自动求解优化重构方案。程序内置辐射状与连续状约束确保网络连通性并以网损与弃负荷最小为目标将二阶锥、电压电流、欧姆定律及潮流平衡等条件纳入约束便于替换目标函数扩展研究实际使用时可自行修改故障线路编号输出重构后的网络结构与目标值便于开展多场景对比分析。rar压缩包内共3个文件以2个m脚本和1个txt参考文献说明为主整体仅5KB其中m脚本分别对应算法主体与IEEE33节点算例txt提供参考论文线索结构精简可直接运行。已有517人学习下载适合用于配电网重构教学演示、故障恢复算法验证及DistFlow建模入门。1. 配电网故障重构为什么绕不开 DistFlow一句潮流方程决定程序成败处理配电网故障重构时我手头始终留着一套基于 DistFlow 潮流的 MATLAB 程序。原因很直接配电网拓扑复杂、R/X 比高用传统牛拉法做潮流计算容易陷入雅可比矩阵的病态迭代而 DistFlow 把辐射状配电网的潮流方程拆成一条条馈线的递推关系不构建全网导纳矩阵也不做矩阵分解在 MATLAB 里几十行代码就能算完一次方案校验。它解决的核心问题是故障隔离后哪些开关可以合、合上去电压会不会越限、失电负荷能恢复多少。适合正在做配电网故障恢复策略、馈线自动化方案验证或者把重构算法写成 MATLAB 程序的工程师和研究生。这篇笔记就从 DistFlow 的递推原理讲起一路写到故障隔离、拓扑判定、粒子群求解和边界坑。2. DistFlow 潮流是怎么把配电网算明白的递推方程、MATLAB 实现与三个边界问题2.1 电压与功率的递推关系Baran-Wu 方程的工程解读DistFlow 这个名字来自 Baran 和 Wu 在九十年代提出的辐射状配电网潮流模型。它不求解全网联立方程而是沿着馈线从根节点向末梢逐支路递推。设某条支路末端节点为 k其父节点为 p支路电阻为 r(k)、电抗为 x(k)则流经该支路的有功 P(k)、无功 Q(k) 与节点电压平方 V2(k) 满足如下关系V2(k) V2(p) - 2[r(k)P(k) x(k)Q(k)] [r(k)^2 x(k)^2][P(k)^2 Q(k)^2] / V2(p)其中 P(k) 等于节点 k 自身负荷加上其所有下游支路的出口功率Q(k) 同理。这个方程的工程含义很直白功率从变电站逐级流向末梢电压沿着馈线逐级跌落而跌落幅度由有功、无功和阻抗共同决定。相比牛拉法DistFlow 的优势在于不需要计算雅可比矩阵也不需要稀疏求解器计算复杂度从 O(N^2) 量级降到接近 O(N)对几百个节点的配电网重构场景来说这个差距是决定性的。很多初学者会忽略一点DistFlow 的前提是严格辐射状拓扑每个节点只有一个父节点不存在环网。重构过程中如果两个联络开关同时合上失电区被两个电源同时供电DistFlow 的直接递推就会失效。这也是为什么重构程序的框架里拓扑检测必须放在潮流计算之前。2.2 用 MATLAB 函数封装一条馈线的 DistFlow 前推回代下面这段代码是我常用的 DistFlow 前推回代实现输入要求节点按“根到叶”拓扑排序即父节点编号小于子节点编号。这个假设可以通过后续章节的 BFS 拓扑遍历来保证。function [V2, Pbr, Qbr, iter] distflow_radial(parent, r, x, PL, QL, V02, tol) % parent: 1xN 数组parent(k) 为节点 k 的父节点编号根节点 parent(1)0 % r, x: 1xN 数组支路阻抗标幺值存放在末节点下标上 % PL, QL: 1xN 数组节点有功/无功负荷标幺值 % V02: 根节点电压平方标幺值通常取 1.0 或 1.03^2 % tol: 电压平方迭代收敛阈值默认 1e-6 N length(PL); V2 V02 * ones(1, N); % 电压平方初值给 1.0 pu^2 Pbr zeros(1, N); % 支路有功存放在末节点下标 Qbr zeros(1, N); for iter 1:100 V2_old V2; % ---------- 前推先给支路功率赋节点负荷 ---------- Pbr(:) PL(:); Qbr(:) QL(:); % 从末梢向根节点累加下游功率与网损 for k N:-1:2 p parent(k); S2 Pbr(k)^2 Qbr(k)^2; dP r(k) * S2 / V2(k); % 支路有功损耗 dQ x(k) * S2 / V2(k); % 支路无功损耗 Pbr(p) Pbr(p) Pbr(k) dP; Qbr(p) Qbr(p) Qbr(k) dQ; end % ---------- 回代从根节点向末梢更新电压 ---------- for k 2:N p parent(k); S2 Pbr(k)^2 Qbr(k)^2; V2(k) V2(p) - 2*(r(k)*Pbr(k) x(k)*Qbr(k)) ... (r(k)^2 x(k)^2) * S2 / V2(p); end if max(abs(V2 - V2_old)) tol break; end end end逻辑说明前推阶段先让每个节点的支路功率等于该节点自身负荷再按节点编号倒序逐个把“节点 k 的支路功率及其损耗”累加到父节点上。由于编号满足 parent(k) k倒序遍历时节点 k 的所有子节点都已经先把自己累加到了 Pbr(k) 上因此一轮扫描就能完成全网功率聚合。回代阶段再从根节点出发用支路功率和阻抗逐级修正电压平方。参数说明标幺值换算建议基准容量取 10 MVA、基准电压取线路额定电压电阻标幺值等于欧姆值乘以基准容量再除以基准电压平方。V02 不建议设成 1.0工程上我会设 1.03 的平方因为故障重构后末端电压通常会比正常方式更低根节点留一点电压裕度能显著提高方案通过率。收敛阈值 tol 取 1e-6 足够对弱馈线可以放宽到 1e-5 来减少迭代次数。2.3 收敛判据和初值选择DistFlow 的玄学不在方程而在判据DistFlow 前推回代本质上是一个固定点迭代前推功率依赖电压回代电压依赖功率两个环节互相嵌套。收敛性由三件事决定初值、阻尼系数和收敛阈值。电压平方初值不能给 0因为前推公式里 S2/V2(k) 会触发除零我一般统一给 V02也就是假设全网额定电压起步。这个初值在大多数配电网场景下离真值很近十几轮迭代就能收敛。另一个常见问题是迭代振荡。当馈线很长、末端负荷很重时电压平方会在 0.8 到 1.05 之间反复横跳。处理办法是给回代加阻尼V2 alpha * V2_new (1 - alpha) * V2_oldalpha 取 0.5 到 0.8。alpha 越小越稳但收敛越慢。如果加了阻尼仍然发散优先检查支路阻抗标幺值是否算错尤其是 10 kV 线路用 0.4 kV 基准电压这种单位混用错误那比任何算法问题都致命。3. 故障隔离后的拓扑怎么变从支路开断到失电区判定的 MATLAB 实现3.1 故障重构的两阶段流程先隔离后转供故障重构和正常方式下的网络重构有一个本质区别前者必须先把故障支路从拓扑中摘除再考虑恢复供电。完整流程分两步。第一步是故障隔离把故障支路两侧的开关断开此时部分非故障区域会因拓扑解列而失电第二步是负荷转供通过操作联络开关和分段开关把失电区重新接入某个带电馈线。这两步在 MATLAB 程序里对应两个数据结构变更邻接矩阵中故障支路对应位置置 0然后重新扫描拓扑。需要特别注意故障隔离后失电区可能不止一个连通块。一条馈线中间发生故障故障点下游全部失电对侧联络开关如果能触及这部分区域它就是一个可转供的失电岛如果故障点上游还有其他分段开关上游的失电区可能独立存在。程序不能假设只有一个失电区必须用拓扑遍历把所有带电区域和失电区域分别枚举出来。3.2 用 BFS 从根节点判定失电区一段不用矩阵幂的拓扑遍历判定失电区最直接的方法是从变电站节点做广度优先搜索。闭合支路看成无向图的边从电源节点能访问到的节点就是带电节点访问不到且原本带电的节点就是故障隔离后的失电节点。MATLAB 里不需要调用 graph 对象用邻接矩阵加一个队列就能完成function reach reachable_nodes(adj, source) % adj: NxN 稀疏逻辑矩阵adj(i,j)1 表示节点 i、j 之间开关闭合 % source: 电源节点编号可以是多个变电站节点的行向量 % reach: Nx1 逻辑向量reach(i)1 表示节点 i 带电 N size(adj, 1); reach false(1, N); q source(:).; % 队列初始化存待访问节点 reach(q) true; while ~isempty(q) cur q(1); q(1) []; % 弹出队首 nb find(adj(cur, :) ~reach); % 未访问过的邻接节点 reach(nb) true; q [q, nb]; end reach reach(:); end逻辑说明source 可以传入多个变电站节点对应多电源配电网。每次从队列弹出一个节点找出所有闭合且未访问的邻接节点标记后入队。循环直到队列为空此时 reach 向量就是带电区域掩码。故障隔离后失电节点集合就是 ~reach 与正常方式下 originally_energized 的交集。参数说明邻接矩阵 adj 建议用 sparse 稀疏矩阵存储配电网节点数通常几百到上千稀疏结构能让 find 和索引访问都保持高效。如果拓扑中有联络开关初始构建 adj 时要把联络开关的闭合状态纳入否则 BFS 会漏掉潜在转供路径。3.3 邻接矩阵与开关状态如何映射到 DistFlow 计算顺序BFS 得出了带电节点集合但 distflow_radial 函数还需要一个 parent 数组也就是每个节点的父节点编号。这一步是重构程序里最容易出错的地方不能用原始网络的 parent因为开关状态改变后功率流向和供电路径都变了。正确做法是以带电区域为子图重新做一次拓扑排序。% 提取带电区域的子邻接矩阵 sub_adj adj(reach, reach); % 用 BFS 返回的访问顺序作为新的节点编号顺序 % 这里直接调用 3.2 的 reachable_nodes但需要一个记录顺序的版本 order []; q source(:).; visited false(1, N); visited(q) true; while ~isempty(q) cur q(1); q(1) []; order(end1) cur; % 记录出队顺序即根到叶的顺序 nb find(sub_adj(cur, :) ~visited); visited(nb) true; q [q, nb]; end new_id(order) 1:length(order); parent zeros(1, N); for k 2:length(order) node order(k); neighbors find(sub_adj(node, :)); % 父节点是已经访问过、且在 order 中排在当前节点前面的邻居 parent_candidate neighbors(visited(neighbors) new_id(neighbors) new_id(node)); parent(k) parent_candidate(1); end逻辑说明这段代码把 BFS 的出队顺序作为新的编号顺序。因为 BFS 按层扩展父节点一定比子节点先出队天然满足 parent(k) k 的拓扑排序条件。new_id 做一次反查就能把原始节点编号映射到新编号支路阻抗和负荷也要按同样的映射关系重排再喂给 distflow_radial。这里有个工程细节故障隔离后失电区如果通过联络开关合闸重新接入电网那么新拓扑的根节点仍然是变电站节点但供电路径可能跨过多个联络开关。重排 parent 数组时不能只盯着原始馈线关系要从新的子图邻接矩阵出发重新搜索。这一步骤漏掉DistFlow 算出来的电压分布就是错的方向。4. 把重构问题写进 MATLAB基本环编码与二进制粒子群求解4.1 为什么要用启发式算法而不是直接穷举配电网重构的决策变量是所有可控开关的状态典型规模在几十到上百个开关。穷举所有组合是 2 的 N 次方量级对 60 个开关就是 2^60 种方案MATLAB 在合理时间内不可能跑完。同时重构问题本身是非凸的目标函数里既有负荷恢复量又有网损约束里还有辐射状拓扑和电压上下限常规优化工具箱很难直接处理。因此工程上常用的做法是智能优化算法其中二进制粒子群 BPSO 是 MATLAB 上最好落地的一种。原因有三第一开关状态天然是 0/1 变量和二进制粒子一一对应第二粒子群不需要梯度信息目标函数可以直接把 DistFlow 计算封装成函数第三代码量小不依赖额外工具箱近十年的 MATLAB 版本都能跑。如果你熟悉 CVX 或 YALMIPDistFlow 的二阶锥松弛也能把问题转成可全局求解的 SOCP但那是另一套技术路线这篇笔记以不依赖额外工具箱的 BPSO 为主线。4.2 基本环编码把辐射状约束嵌进解结构直接用 0/1 向量表示全部开关状态最大的麻烦是大多数随机解都不满足辐射状约束要么成环要么出现失电孤岛。文献里一个非常实用的技巧是基本环编码。先把所有联络开关闭合得到一个包含环网的初始拓扑每个联络开关对应一个基本环环内通常包含多个分段开关。重构的目标就是在每个基本环内至少断开一个开关从而打破所有环路。编码规则如下表所示开关编号是全局唯一的联络开关关联的基本环环内开关编号集合编码维度含义环 1{7, 12, 19, 23}该环内必须至少有一个开关断开环 2{8, 13, 20, 24}该环内必须至少有一个开关断开环 3{9, 14, 21, 25}该环内必须至少有一个开关断开粒子群每个维度的取值不再是“全部开关的 0/1 状态”而是每个环内断开的开关编号。这样生成的解天然满足必要条件“每个基本环至少一个开关断开”辐射状约束的搜索空间大幅缩小。注意这只是必要条件两个环共用同一个断开开关时仍可能局部成环解码后还需要用 BFS 验证一遍全网络连通性。4.3 BPSO 求解器骨架状态翻转概率与约束处理下面是一段可扩展的 BPSO 主循环骨架。为了控制篇幅我略去了网架数据的读取部分重点展示二进制状态更新和环约束修复逻辑% 基本参数 Npop 40; % 种群规模 Ndim 3; % 基本环数量 MaxIter 100; % 最大迭代次数 c1 1.8; c2 1.8; % 个体/全局学习因子 ring {[7 12 19 23], [8 13 20 24], [9 14 21 25]}; % 基本环开关集合 % 初始化每个粒子在每个环内随机选一个开关断开 x zeros(Npop, Ndim); for i 1:Npop for b 1:Ndim x(i, b) ring{b}(randi(length(ring{b}))); end end v zeros(Npop, Ndim); fitness zeros(Npop, 1); for i 1:Npop fitness(i) calc_fitness(x(i, :)); % 目标函数见 4.4 节说明 end [pbest, pbest_id] min(fitness); gbest_x x(pbest_id, :); gbest_fit pbest; for t 1:MaxIter w 0.9 - 0.5 * t / MaxIter; % 惯性权重线性递减 for i 1:Npop % 计算二进制速度与个体最优、全局最优逐维比较 v(i,:) w * v(i,:) ... c1 * rand(1,Ndim) .* (x(i,:) ~ pbest_x(i,:)) ... c2 * rand(1,Ndim) .* (x(i,:) ~ gbest_x); % 用 sigmoid 概率决定是否改变当前开关选择 prob 1 ./ (1 exp(-v(i,:))); for b 1:Ndim if rand prob(b) % 在当前环内换一个不同的开关断开 candidates ring{b}(ring{b} ~ x(i, b)); x(i, b) candidates(randi(length(candidates))); end end end % 解码并评估全部粒子 for i 1:Npop fitness(i) calc_fitness(x(i, :)); end % 更新个体最优和全局最优 for i 1:Npop if fitness(i) pbest(i) pbest(i) fitness(i); pbest_x(i, :) x(i, :); end end [best, id] min(pbest); if best gbest_fit gbest_fit best; gbest_x pbest_x(id, :); end end % 最优方案就是 gbest_x 对应的开关组合逻辑说明粒子每一维存的是当前环内“断开开关的编号”速度被改写成“当前选择与历史最优选择是否相同”的 0/1 差异和再经 sigmoid 映射为换开关的概率。这种写法避免了标准 BPSO 在连续数值映射到开关编号时的取整问题。环约束修复体现在更新逻辑里替换开关时只在同一个环的候选集合中选任何时刻每个环都保持有一个断开开关。参数说明种群规模 Npop 取 30 到 60 之间维数很少时 40 够用。学习因子 c1、c2 都取 1.8 左右惯性权重从 0.9 线性降到 0.4这是粒子群收敛性和探索能力最常用的折中组合。如果你的配电网规模大、基本环数量超过十Npop 要增到 80 以上否则后期会过早收敛到局部解。4.4 目标函数的两种形态失电量优先还是网损优先故障重构的目标函数不是只有一个标准答案。故障刚发生时首要目标是最大化恢复供电量也就是最小化失电负荷但恢复供电后网架可能运行在接近极限的状态因此还要在目标中叠加网损惩罚和开关动作次数惩罚。常用形式如下fitness w1 * lost_load w2 * P_loss_total w3 * num_switch_actions其中 lost_load 是最终仍然失电的负荷总量P_loss_total 是重构后全网线损num_switch_actions 是相对故障前状态的开关操作次数。三个权重需要按工程优先级标定故障场景下 w1 远大于 w2因为少恢复 1 MW 负荷比多损耗 0.1 MW 严重得多。我一般取 w1 100w2 1w3 5让算法优先保证恢复率再考虑经济性。计算 fitness 的流程是把粒子解码成开关状态更新邻接矩阵做 BFS 确认所有恢复节点有电再调用 distflow_radial 算电压和网损。如果发现某个恢复节点电压越限或某条支路过载直接给予一个很大的惩罚值比如 1e6让粒子群绕开这个不可行解。注意“节点连通”不等于“节点能正常供电”DistFlow 必须跑一遍那些电压低于 0.90 pu 的节点不能算作恢复成功。5. 故障重构 MATLAB 实现必踩的五个坑现象、原因与排查顺序5.1 DistFlow 算到一半就发散电压平方变成负数现象distflow_radial 迭代不收敛V2 向量出现负值程序直接报 NaN。原因大概率不是算法问题而是初值或标幺值设置错误。我见过最典型的场景是 10 kV 馈线用 0.4 kV 的基准电压做标幺换算电阻电抗标幺值放大了几百倍前推功率时损耗项大得离谱。其次是根节点电压初值给了 0导致第一条支路回代时就出现负数。解决先用最简单的两节点算例验证 distflow_radial 本身比如一根 10 km 的架空线带 2 MW 负荷手算电压降落和程序输出对比。确认公式没问题后再检查基准容量和基准电压是否全局统一。给 V02 赋 1.03 的平方并在回代后加一条 V2 max(V2, 0.1) 的保护语句防止个别节点电压跌到接近零导致除零错误。5.2 重构结果“看起来恢复供电”实际拓扑成了环网现象目标函数算出的恢复负荷很漂亮但把开关状态画出来发现两个联络开关同时闭合失电区被两个电源同时供电。这种现象的原因在于只检查了每个基本环“至少有一个断开开关”没检查全局连通性。基本环编码保证了每个环都有断开点但两个环可能共享同一个断开开关或者某个失电岛通过两个联络开关接到了同一个带电馈线的两个不同位置形成局部环。解决解码后必须用 reachable_nodes 对全网做一次 BFS并统计闭合支路数量。辐射状配电网在 N 个节点、M 个变电站出口下闭合支路数如果超过 N - M就说明存在环网。检测到环网时把该粒子的 fitness 直接设为惩罚值或者随机断开环内另一个开关后重新评估。5.3 负荷恢复量算得虚高和实际现场不符现象程序显示恢复了 90% 的失电负荷但现场试送电时开关一合就跳闸实际只能恢复 60%。原因通常是目标函数把“失电区连通”直接等同于“失电区恢复供电”忽略了转供后部分末端节点电压跌破允许值也忽略了线路载流能力约束。连通只代表有电气路径不代表这条路径能把负荷送过去。解决在 calc_fitness 里先跑 DistFlow再对每个失电区的末端节点做电压判断。电压低于 0.90 pu 的节点其负荷要从恢复量中扣掉任一支路视在功率超过载流量上限整个方案判为不可行。这个校验会让粒子群前期收敛变慢但产出的方案才真正具备可执行性。5.4 联络开关合闸成功非故障区电压反而跌破下限现象重构后失电区恢复了但原本带电的馈线末端电压从 0.97 pu 掉到 0.88 pu出现了新的越限。原因很好理解转供负荷全部压到了相邻馈线上让那条馈线从轻载变成重载电压跌落急剧加大。重构优化时如果只盯着失电区而不看全网的电压分布就会把这种“拆东墙补西墙”的方案评成最优解。解决DistFlow 回代时把全部带电区域都纳入计算不只算失电区。全网电压最低点直接写进目标函数的惩罚项。另一个实用技巧是给每条联络开关合闸方案加一个预筛选用忽略网损的线性 DistFlow 快速估算转供馈线的首端功率如果首端功率已经超过馈线容量的一半就直接跳过不做完整潮流迭代能为粒子群节省大量时间。5.5 粒子群跑了几小时还不出结果把 DistFlow 当牛拉法反复算现象100 个粒子迭代 100 次每次都要重新构建邻接矩阵、重新做 BFS、重新算 DistFlow算完一看 CPU 跑了几小时。原因不是 MATLAB 慢而是每轮评估都重复了不变的拓扑计算。配电网节点编号、支路阻抗、负荷数据在优化过程中完全不变变的只有开关状态对应的邻接矩阵很多中间结构不需要重复生成。解决优化开始前把节点支路表、基本环集合、每条馈线的固定阻抗数据全部缓存成全局变量。粒子评估时只更新开关状态到邻接矩阵复用预计算的支路顺序。另一个技巧是两阶段评估先用线性 DistFlow 估算电压电压全部合格的方案才进入精确 DistFlow 校验绝大多数随机解会在第一阶段被淘汰精确潮流调用次数能减少 80% 以上。6. 重构结果的验证技巧先把拓扑画出来再谈优化指标6.1 五分钟内用 graph 对象可视化开关组合优化算法给出的开关组合是一串数字数字看不出问题拓扑图一眼就能看出有没有环、有没有孤岛、转供路径是否绕远。MATLAB 自带的 graph 对象配合 plot 就能完成可视化不需要额外绘图工具箱G graph(adj_new); % adj_new 是重构后闭合支路的稀疏邻接矩阵 figure; p plot(G, Layout, layered); p.NodeLabel {}; highlight(p, restore_nodes, NodeColor, g); % 失电恢复节点标绿 highlight(p, fault_node, NodeColor, r); % 故障节点标红逻辑说明layered 布局对辐射状配电网很友好馈线从根节点向下展开环网结构会以横向回折的方式暴露出来。恢复节点和故障节点用不同颜色高亮后转供路径是否合理、有没有死胡同一眼就能判断。每次粒子群更新完全局最优解我都习惯先把图打出来看一眼再决定要不要调权重。6.2 三个必查的量化指标恢复率、最低电压、开关动作数可视化之外最终方案还要过三个量化指标。恢复负荷率是最核心的指标等于恢复负荷除以故障隔离后的失电负荷总量最低节点电压要标记出具体位置确认不在馈线末端之外的特殊位置开关动作次数决定了现场操作的可行性和倒闸时间。这三个指标可以汇总成一张方案对比表指标指标含义工程建议值负荷恢复率恢复负荷 / 失电负荷不低于 85%目标 100%最低节点电压全网最低电压标幺值不低于 0.90 pu最好不低于 0.93 pu开关动作次数重构方案开关操作总数越少越好一般不超过 5 次我最常踩的问题是把恢复率算到了 100%但最低电压在 0.89 pu现场根本无法执行。后来养成的习惯是输出方案时强制打印这三个指标任何指标越限就退回优化循环而不是手工接受结果。重构完成后的拓扑图也要归档保存作为倒闸操作票的参考。这套流程配合基于 DistFlow 的 MATLAB 程序能把故障重构从“拍脑袋合闸”变成“先算后合”希望帮到你。本文还有配套的精品资源点击获取