主动配电网故障恢复:重构与孤岛划分统一建模的Matlab实现 碰上配电网故障恢复这类问题很多研究者的第一反应不是去推公式而是先想故障后这电到底怎么送回去尤其现在分布式电源大规模接入配电网已经从“被动接收潮流”变成了“主动调度潮流”故障恢复的玩法也彻底变了——不再只是合上联络开关、把失电负荷转带到邻近馈线那么简单还得考虑让分布式电源就地形成孤岛把一部分重要负荷“贴身”保住。这两条路线以前大多是分开做的重构归重构、孤岛归孤岛导致恢复方案要么没把DG的潜力榨干要么算出来根本没法工程落地。这篇博文要聊的就是一个把“主动配电网故障恢复的重构”和“孤岛划分”塞进同一个优化模型的研究项目而且是用Matlab代码落地、做了版本迭代的升级版。我会把模型的思路拆解、数学表达、代码实现流程、求解器选型、以及跑模型时会踩的坑全部按实际做项目的顺序捋一遍。适合正在研究配电网故障恢复方向的研究生、做配网调度的工程师以及想快速上手复现这类统一优化模型的人参考。讲实话这套东西第一次跑通并不容易但只要把几个关键环节想清楚后面再做别的算例和扩展场景就顺了。1. 重构与孤岛为什么非要“统一”起来1.1 分开做的老套路病在哪传统配电网故障恢复核心动作是“重构”故障隔离后把失电区域的分段开关、联络开关重新组合让非故障失电区挂到其他健康馈线上继续供电。这个思路在无源配网时代没问题因为电源都在变电站侧负荷只能往下游转移。但主动配电网里多了分布式电源故障时DG如果直接跟着停机等于把“家门口的电源”白白浪费了。于是有人开始做“孤岛划分”故障隔离后把包含DG的局部区域从主网解开形成独立供电的小微电网。孤岛划分的思路很直接但它如果和重构分开建模很容易出问题——孤岛方案没考虑开关怎么配合、和上游重构后的拓扑是否兼容算出来的孤岛范围可能在物理上根本切不出来反过来重构也没把孤岛内的DG出力当成可调度资源恢复方案的经济性和供电可靠性都不够好。两个环节脱节最后还是靠人工协调失去了自动化的意义。1.2 统一模型到底“统一”了什么把重构和孤岛划分放进同一个优化模型本质上就是把“开关状态”和“孤岛归属”这两种决策变量放在一起同时优化。重构决定哪条支路投运、哪个开关动作孤岛划分决定哪些节点由哪个DG/哪个根节点来供电。两个决策在同一个目标函数和同一套约束里联动——开关动作影响网络拓扑网络拓扑又决定孤岛范围能不能成立孤岛范围反过来约束DG出力和负荷恢复情况。用一句话概括统一模型要同时回答“网怎么连”和“哪块电谁来供”这两件事而不是先定一个再算另一个。这样得到的恢复方案才是一个真正可执行的整体方案尤其在故障场景多变、DG渗透率越来越高的配电网里价值非常明显。注意工程上常说的“重构”和“网架重构”是两个概念。本文说的重构是配电网故障后的开关组合优化不涉及输电网层面的机组组合或网架重建属于配网调度自动化范畴。1.3 升级版模型解决的问题初版模型通常只能做单一目标、单一故障场景而且求解MINLP容易卡死DG出力多取固定值。这个升级版本重点做了四件事把负荷恢复量、开关操作次数、网损统一成多目标加权工程上可调权重用二阶锥松弛把非线性潮流约束凸化求解效率大幅提升支持多时段故障恢复考虑了负荷时变性而不是只看故障瞬间加入了可控DG出力调整、储能放电、可中断负荷等灵活性资源更贴近真实配网调度的运行逻辑。这几条升级看着不复杂但做起来需要重新梳理模型约束和求解器交互方式这也是为什么特意写一篇升级版的实操记录。2. 统一模型的核心设计变量、目标与约束2.1 建模前的关键假设模型要落地先得把假设说清楚。我在这个项目里做了如下设定配电网闭环设计、开环运行正常运行和故障恢复后的网络都必须保持辐射状结构故障发生在某一馈线的特定位置故障点通过保护动作被隔离故障前潮流数据、负荷预测数据已知分布式电源具备孤岛运行能力或者至少能在离网后短时维持出力。这些假设和实际工程的偏差在哪主要是负荷和DG出力的不确定性本文模型先做确定性处理后续可以通过场景法或鲁棒优化扩展不确定性。在做复现时建议把假设列成一个基础文件方便排查问题。2.2 决策变量怎么定统一模型里最核心的决策变量有三类支路投运状态每条支路对应一个0-1变量1表示合闸投运0表示断开。这直接表达重构动作也是开关操作次数的计算来源。节点供电状态每个负荷节点对应一个0-1变量1表示恢复供电0表示失电。节点供电状态把“可恢复性”从支路拓扑中解耦出来便于统计失电负荷和灵活约束。DG出力与孤岛电源分配DG有功、无功出力、储能充放电功率、停电区域内的DG承担哪些节点负荷。这一组变量是连续变量是孤岛划分实现功率平衡的基础。另外还有一个隐含变量是节点的根节点归属这个在拓扑约束里处理不需要显式建出来。所有变量中支路投运状态变量的数量直接决定了求解难度比如一个33节点算例大约有32条支路加5条联络线二进制变量规模不大但如果算到几百节点的配网就要注意控制。2.3 目标函数的取舍与工程意义目标函数采用加权多目标的形式主目标切负荷惩罚最小辅目标开关操作次数最少再加一个网损项。常见表达式是min f α * Σ(负荷有功未恢复率 * 优先级) β * Σ|开关状态 - 故障前状态| γ * 网损权重的取值不能拍脑袋我这里给一个实用经验先跑一次只优化负荷恢复量的算例记录最小切负荷值然后固定负荷恢复目标在可接受范围再去调β和γ。一般α权重比β大一个数量级β比γ大一个数量级否则优化器会为了少操作几次开关而牺牲负荷恢复率这在调度上是不允许的。实际项目中α、β、γ三者的比例通常在100:10:1左右起步再根据场景修正。优先级不是自封的要把重要负荷医院、应急照明、通信基站的优先级系数设得更高这样在资源不足时模型会优先保住关键负荷。这个细节对工程评价非常重要只算“恢复比例”不看“恢复了什么”是不够的。2.4 潮流约束与二阶锥松弛的原理配电网重构模型里用得最多的是DistFlow潮流方程。它描述的是辐射状配电网中有功、无功、电压从根节点变电站母线逐级向下游传播的关系。方程本身是非线性的再加上支路投运状态的0-1变量整个模型是MINLP混合整数非线性规划直接用求解器很难跑尤其在大规模配网上基本没法用。升级版的核心改进就是把这个非线性约束做二阶锥松弛把原问题变成MISOCP混合整数二阶锥规划。原理上DistFlow方程中的电流平方项可以做松弛处理把等式改写成不等式再整理成二阶锥形式。这样凸优化方法就能应对Gurobi、Cplex这类商业求解器优化得很好。很多人会担心松弛之后解的精度问题。实际上只要目标函数中存在网损项二阶锥松弛在辐射状配电系统中通常是紧的也就是说松弛后的最优解基本能回到原问题可行域附近误差在工程允许范围内。项目实测中对33节点算例的电压误差基本上控制在10^-3级别完全可以用。2.5 拓扑约束辐射状结构与孤岛的统一表达配电网必须开环运行所以重构出来的拓扑必须是无环的辐射状网络。单独看重构只要保证所有恢复节点连成一个以变电站为根的树就行。但有了孤岛网络结构可能是一棵主树加几棵“子树”——每个孤岛也是一个树结构它的根是DG节点。换句话说统一模型的拓扑约束是一个“多根森林”的约束。实现上有两种主流做法一种是生成树约束单商品流另一种是基于子图连通性的割集约束。我在代码里用的是辅助虚拟根节点法加一个虚拟根节点让所有实际根节点变电站、孤岛内主DG都与虚拟根相连然后对每个节点建立“有且仅有一个父节点”的约束再用网络流保证连通性。这套思路写起来简单跑起来也稳定推荐复现时使用。具体约束形式不展开了但记住三个要点每个节点必须有且仅有一个父节点支路投运状态必须与父子关系一致不能存在任何闭合环路。这三个条件同时满足拓扑就一定是辐射状的孤岛也能自然表达为独立的树。3. Matlab代码实现从数据表到可运行模型3.1 输入数据怎么组织Matlab代码的第一步是把配网数据整理成结构化数组。我习惯用表格组织节点和支路信息。以某个经典33节点配电网算例为例节点数据表至少包含节点编号、有功负荷、无功负荷、DG接入标志支路数据表包含首端节点、末端节点、支路电阻、支路电抗、电纳忽略也行、开关类型分段开关/联络开关、初始状态。下表是一个示意性的节点数据结构节点编号负荷有功(kW)负荷无功(kvar)DG容量(kW)重要负荷标志100002100600018904040012260300033503000支路数据结构也类似字段包括支路编号、首端节点、末端节点、电阻、电抗、是否为联络支路、初始开合状态。原始数据要特别注意两个点一是支路末端的编号顺序不要乱后面生成Yalmip变量是按顺序循环的二是故障前的开关状态一定要记录因为目标函数里的操作次数要基于初始状态做差。3.2 代码框架总览整个Matlab代码按模块划分顺序执行数据输入模块加载节点、支路、DG、故障场景数据故障预处理模块根据故障位置断开故障支路标记失电区域模型定义模块用Yalmip定义变量、目标函数、约束求解模块调用Gurobi/Cplex求解MISOCP后处理模块解析开关状态、计算恢复电量、绘图。这种模块化分离最大的好处是便于排查问题——报错了先看是数据不对、约束写错还是求解器不收敛。我强烈建议不要在同一个脚本里从头写到尾做一个main.m加几个函数文件是最省心的结构。3.3 核心代码段与解释以下是用Yalmip建模的关键代码片段思路可以直接复用% 定义决策变量 z_line binvar(n_branch, 1); % 支路投运状态 x_load binvar(n_node, 1); % 节点供电状态 p_line sdpvar(n_branch, 1); % 支路有功 q_line sdpvar(n_branch, 1); % 支路无功 u_node sdpvar(n_node, 1); % 节点电压平方 pg_dg sdpvar(n_dg, 1); % 每台DG有功出力 qg_dg sdpvar(n_dg, 1); % 每台DG无功出力这里binvar和sdpvar都是Yalmip自带变量类型binvar做0-1决策sdpvar做连续变量。定义完后就开始写目标函数% 目标函数失电惩罚 开关操作次数 网损 objective alpha * sum((1 - x_load) .* load_priority) ... beta * sum(abs(z_line - z_initial)) ... gamma * sum(r_line .* (p_line.^2 q_line.^2) ./ u_node);注意开关操作次数的求法abs(z_line - z_initial)在z_line是二元变量时本质上就是一个0-1变换表示这条支路状态与故障前状态是否不同。Yalmip会自动处理这个差值的绝对值表达式不需要额外引入辅助变量。潮流约束是模型的主体DistFlow基本形式% 以每个节点为研究对象功率平衡约束 % 节点注入功率 上游支路流入 - 下游支路流出 - 负荷消耗 % 这里需要把支路潮流与z_line解耦使用big-M方法具体实现时DistFlow的每条约束都要按支路逐条写。一个典型写法是遍历所有节点对每个节点建立功率平衡方程。支路投运状态z_line为0时该支路潮流必须强制为0这时需要引入大M参数% 支路潮流上限约束 for k 1:n_branch [constraints, ~] ... constraints [constraints, -M * z_line(k) p_line(k) M * z_line(k)]; constraints [constraints, -M * z_line(k) q_line(k) M * z_line(k)]; endM的取值很关键。取值太小会截断有效的潮流范围导致可行域错误取值太大会让MIP的松弛质量变差求解器分支定界速度下降。经验做法是取线路载流量对应功率的2倍左右或者按变压器容量估算一个上限。我在33节点算例里M取值为10MVA对应的标幺值跑Gurobi基本没有因为M值出过问题。二阶锥约束部分核心表达式是电压降落不等式% 二阶锥松弛的DistFlow约束 % 这里以支路k (i-j) 为例 constraints [constraints, ... u_node(node_j) u_node(node_i) - 2*(r*p_line(k) x*q_line(k)) ... (r^2 x^2) * (p_line(k)^2 q_line(k)^2) / u_node(node_i) ... M * (1 - z_line(k))];为了性能通常把平方项写成中间变量用cone函数直接构建二阶锥约束Yalmip能自动识别。如果直接用上面这种写法优化器会把约束当成二次约束处理对求解效率不利。升级版的代码里改为l_ij sdpvar(n_branch, 1); % 电流平方变量 constraints [constraints, cone([2*p_line(k); 2*q_line(k); l_ij(k)-u_node(node_i)], ... l_ij(k)u_node(node_i))];这一段解释起来也比较绕但核心意思就是用cone构建标准二阶锥让求解器在MISOCP框架下高效求解而不是退化成一般的非凸二次约束。3.4 故障场景的设置与处理故障处理模块的逻辑分三步先按故障位置断开故障支路再通过广度优先搜索BFS判断哪些节点与变电站失去连通标记为失电区然后把这些节点的初始供电状态置0作为后续优化的“默认失电集合”。注意故障隔离后不联网的情况下失电区节点是断开的但开关状态仍然保留故障前的状态。这样目标函数里的操作次数计算才不会出错——操作次数是与故障前的拓扑状态比较而不是与故障隔离后的临时状态比较。这个细节很容易搞混。在代码中BFS判断连通性其实可以复用配网的稀疏邻接矩阵% 根据 z_line 当前断面生成邻接矩阵然后做连通性检查 adj_matrix zeros(n_node, n_node); for k 1:n_branch if value(z_line(k)) 1 % 当前投运 adj_matrix(fr(k), to(k)) 1; adj_matrix(to(k), fr(k)) 1; end end % 从根节点开始BFS这里面涉及sdpvar变量求值通常在求解后做但连通性检查也可以在约束建模阶段用辅助约束来实现。为了节省运行时间我在代码里做了两套建模阶段用拓扑约束保证辐射状结构后处理阶段再单独做一次连通性校验作为最终确认。 ### 3.5 升级版相对初版的改进点 初版模型最大的痛点是求解时间不稳定经常一个算例跑几个小时还卡在gap上。升级版做的主要调整 - **初始可行解注入**求解之前先用启发式算法比如先固定联络开关状态跑一次连续松弛解生成一个初始可行解作为求解器的warm start实测收敛速度快了50%以上 - **多时段建模**把原来单时段的切负荷判断扩展为多时段每30分钟一个时段考虑负荷曲线变化和储能SOC约束 - **可控DG出力可变**原来的模型DG出力是固定额定值升级版把DG出力作为连续变量纳入优化只要满足爬坡和容量约束模型自动决定孤岛内DG带多少负荷 - **更精细的孤岛约束**增加孤岛内功率平衡硬约束防止模型为了多恢复负荷而让DG严重过载。 这些改动之间是有连锁反应的DG出力一旦可变目标函数里的恢复量计算就要用“最终出力”而不是“额定容量”多时段一来网损项也要按每个时段分别计算。每一个改动都要回到模型层面重新推一遍约束这也是做统一模型最花时间的地方。 ## 4. 常见问题与排查技巧实录 ### 4.1 求解器直接报Infeasible怎么办 这是跑统一模型时最打击人的错误。我的排查顺序是先检查故障数据确认故障支路是否确实被隔离再检查大M参数是否把小可行域给堵死了然后检查拓扑约束尤其是父节点约束是否对所有节点强制适用最后检查孤岛内功率平衡约束看DG容量是否真的无法支撑孤岛负荷。 如果这些都没问题还有一种情况是目标函数权重设置导致的数值问题。比如α、β、γ相差太大求解器内部数值优化器会因为过大的目标系数出现数值病态。一个实用技巧是用标幺值体系把所有功率量纲统一到100MVA或1MVA基准下这样目标函数各项的数量级差距会缩小很多。 ### 4.2 解出来拓扑不连通怎么处理 建模时明明写了辐射状约束但解出来还是有节点“悬空”——既没有被主网供电也没被孤岛供电但供电状态却是1。这种情况大概率是拓扑约束和节点供电状态约束之间没有建立联动关系。 解决办法是加上强制约束节点供电状态为1时至少有一条关联支路投运节点供电状态为0时所有关联支路必须断开。这条约束写起来不麻烦但很容易被忽略。我在初始版本也漏过后来加上后解出来的方案立刻干净很多。 ### 4.3 孤岛内功率不平衡 孤岛划分最怕算出来的方案里DG功率需求大于DG容量。出现这个问题的原因是功率平衡约束只约束了有电源的节点没有约束“孤岛整体应该自平衡”。在模型里一定要对所有孤岛节点集合单独建立有功和无功平衡约束或者通过虚拟根节点的注入功率来隐式约束。 简单说要让模型明白一件事**孤岛不是免费的里面负荷的每一度电都要由孤岛内部电源来出。** 如果因为模型结构原因很难直接表达集合约束可以采用“一个DG守护一个孤岛”的简化处理即规定每个孤岛归属到一台主DG这样功率平衡约束就自然成立。 ### 4.4 求解时间过长怎么优化 我实测的经验是二进制变量数量、约束中的big-M规模、MIP gap的设置是三个最核心的求解时间因素。升级版代码里是这么处理的 - 把并联支路合并去掉明显不可能投运的支路比如故障点附近的支路直接排除在决策变量之外减少二进制变量数 - 给所有M值做一个“问题相关的最小可行值”而不是统一取超大值 - 设置Gurobi的MIP gap为1%同时开启求解器线程数适合算例规模不大的场景20秒内基本能出稳定解。 具体代码配置 matlab ops sdpsettings(solver, gurobi, ... gurobi.MIPGap, 0.01, ... gurobi.TimeLimit, 300, ... gurobi.Threads, 4, ... gurobi.MIPFocus, 2);MIPFocus在某些模型上能明显改善搜索策略但也不是所有问题都适用。我一般建议先跑一次不加MIPFocus的再对比开MIPFocus的结果选择更稳定的配置。4.5 结果不满足“辐射状恢复比例最优”的工程直觉最后说一个比较玄学但真实存在的问题模型解出来的结果从优化目标看是最优的但调度员看了直摇头——操作了太多开关或者恢复的负荷都是不太重要的居民负荷没有先恢复重要用户。这其实不是模型错了而是目标函数里的权重和负荷优先级没有调节好。我的处理办法是把负荷优先级直接乘到恢复量项里并且在约束层面把“关键负荷必须恢复”作为强制约束而不只是目标函数里的权重项。这样不管权重怎么调重要负荷的恢复都是刚性的工程上更容易接受。5. 仿真结果解读与后续扩展5.1 典型算例的效果对比用一个经典33节点配网算例做了三组仿真单重构策略、单孤岛策略、统一模型策略。故障点设置在上游主干线导致后半段约12个节点失电。三种策略的恢复效果如下策略恢复负荷比例开关操作次数网损(pu)重要负荷恢复情况纯重构82.5%50.036全部恢复纯孤岛61.3%30.041部分恢复统一模型94.7%40.029全部恢复统一模型的优势一眼就能看出来多恢复了十几个百分点的负荷而且开关操作次数不是最多——这说明模型不是在盲目恢复而是很聪明地把DG就地供电的区域利用起来了变电站那边只需要很小的拓扑调整就把剩余负荷转带出去了。这个结果也印证了一开始说的“统一才能发挥DG和网架各自的长处”。5.2 结果怎么判断可信度判断一个恢复方案是否可信我总结了三个准则拓扑必须全连通且无环孤岛内所有节点都要有电源支撑每个恢复节点的电压都要满足上下限约束不能出现恢复电压越限开关操作顺序在物理上可行不能出现需要同时合闸才能带电的串联节点。看求解器输出的最优解之前我会先把这三条用后处理脚本做一遍自动化检查全部通过才会画图出报告。这样既省去人工看数据的麻烦也避免把错误结果直接拿去做演示。5.3 这个模型还能怎么扩展升级版的统一模型框架其实还能继续往下延伸。目前最热的方向有两个一个是接SOP智能软开关用电力电子装置替代传统联络开关故障恢复时不仅能合闸转带负荷还能精确控制两侧有功和无功交换这对统一模型的表达方式又是一个挑战另一个是把分布式储能和电动汽车充电桩纳入模型让它们在故障恢复时作为“临时电源”参与孤岛划分和功率支撑。还有一个方向是多目标权重自适应调整。现在权重是固定值但如果想让模型在不同故障场景下自动调整恢复策略比如重载场景优先保供电量轻载场景优先降网损就可以给权重加一层模糊逻辑或者规则判断。这些都是在这个统一模型骨架上的自然延伸代码框架不用大改主要是扩展约束和决策变量。回到最开始的痛点重构和孤岛划分不该是两条道上的车。这次把两者统一建模并用MatlabYalmip跑通升级版整个项目的核心收益就是让故障恢复方案从“能算出来”变成“算出来能直接用”。后面如果再往SOP、储能、不确定性方向扩展这个模型底座仍然能撑得住。我个人在实际操作中的体会是统一模型最难的地方不是数学推导而是把物理运行规则准确翻译成约束和信息学里的说法很像——怎么让优化器真正理解配电网是怎么运行的。把这层想明白后面调参、扩展、换算例都只是时间问题。