1. 为什么一定要把重构和孤岛划分放进同一个模型1.1 我先踩过的坑分开建模看着省事实际处处漏水刚接触主动配电网故障恢复那会儿我第一反应和大家一样把问题拆成两步走。第一步做网络重构把故障段隔离出去恢复非故障区域的供电第二步在恢复不了的末端区域看看哪些分布式电源DER能带起孤岛运行。两个问题各自有成熟算法看起来风险小、见效快。但这个思路在实际仿真里给我上了一课。有一次我在IEEE 33节点系统上做故障恢复测试故障点在支路6-7下游有光伏和储能。第一步重构还算顺利把环网开关合上、把联络开关调了调恢复了大部分负荷。但到第二步做孤岛划分时发现剩余没恢复的负荷和可用的DER容量对不上——光伏出力的间歇性导致孤岛内功率平衡根本撑不住储能SOC又不够。最后算出来的最优恢复方案实际上孤岛内每隔几分钟就要切一次负荷。问题出在哪重构和孤岛划分本质上是耦合的。重构决定的开关状态直接影响了孤岛划分的可行域而孤岛划分结果又反过来限制了重构的恢复范围。分开建模等于人为砍掉了这两者之间的约束耦合看起来每个子问题都很清晰拼到一起却得到不可行或者次优的方案。更麻烦的是电网运行要求故障后快速给出恢复策略分开建模要做两次计算时间上也不占优势。所以后来的思路非常明确把重构和孤岛划分当作一个统一优化问题来解。决策变量里既包含开关状态也包含孤岛的划分方式约束里既有配电网辐射状拓扑约束也有孤岛内功率平衡约束。目标函数统一考虑恢复负荷量、开关操作代价、网络损耗。这就是标题里说的统一模型。1.2 统一模型到底统一了什么很多文章喜欢把统一挂在嘴上但落地的时候需要说清楚它到底统一在哪几个层面。第一层是决策变量的统一。传统重构的决策变量是分段开关和联络开关的状态0/1变量孤岛划分的决策变量是负荷节点和DER节点的分群归属哪个节点进哪个孤岛。统一模型里这两类变量必须同时出现在一个优化问题中不存在先算一个再算另一个的先后关系。第二层是约束条件的统一。配电网辐射状运行约束、潮流等式约束、节点电压上下限约束、支路容量约束、孤岛内功率平衡约束、DER出力约束、储能SOC约束这些约束在物理上本来就同时存在。分开建模时各算各的统一模型必须把它们放进同一个约束集里。第三层是时间尺度的统一。故障恢复不是单点时刻的静态决策负荷在恢复过程中会变化光伏出力会波动储能SOC会演替。严格意义上的统一模型应该考虑故障后多个时间断面的联合优化也就是时序统一。升级版本里我把这个考虑进去了用多时段模型的框架去承载单时段模型的核心逻辑。第四层是求解框架的统一。既然是一个问题就要用一套求解框架。我实际用的是混合整数二阶锥规划MISOCP具体来说有两层嵌套外层通过二进制变量枚举开关状态和孤岛归属内层通过凸松弛处理非线性潮流约束。Matlab里用YALMIP建模底层求解器可选Gurobi或Cplex后面章节我会贴核心代码。2. 统一模型的数学表达目标函数、决策变量与约束条件2.1 目标函数不只看恢复了多少负荷故障恢复的目标函数不能简单写成恢复负荷最大。你想想实际场景配电网调度员最关心的是哪些负荷恢复了、恢复了多少、操作了多少次开关、恢复后网损大不大。这些都该进目标函数但权重要拉开。我用的目标函数分三块第一块是恢复供电的负荷量加权求和。权重可以是负荷优先级一级负荷、二级负荷、三级负荷也可以是负荷有功功率大小。第二块是开关操作次数惩罚。分段开关、联络开关的每次分合都要算代价。频繁操作在真实配电网上是大事开关寿命有限操作时间也长。第三块是网络有功损耗。恢复供电本身有成本网损越小越好。具体表达式可以写成min F -Σ(w_i * P_i * x_i) λ_sw * Σ|s_j - s_j0| λ_loss * ΣPloss其中x_i是负荷节点恢复状态s_j是开关状态s_j0是故障前状态P_i是负荷有功功率w_i是优先级权重。第一项带负号是因为要最大化恢复负荷后面两项是惩罚项。这只是一种常见写法。你要是重点研究储能支撑下的黑启动目标函数就要加上恢复的DER容量最大或者储能剩余电量最充足之类的项。2.2 决策变量的精细拆分统一模型里有两类核心决策变量第一类是拓扑状态变量。每条支路有一个0/1变量表示接通或断开每个开关分段开关、联络开关有一个0/1变量表示开合状态。注意这两个变量不完全等价一条支路可能有开关也可能没有但为了统一建模我习惯直接对支路定义状态变量。第二类是运行变量。节点电压幅值连续变量、节点注入有功和无功功率连续变量、支路电流幅值连续变量、孤岛归属标识0/1变量每个节点是否属于某个孤岛、DER出力连续变量、储能充放电功率连续变量。还有一类容易被忽略的变量是孤岛编号变量。在多孤岛场景下要给每个孤岛一个编号然后给每个节点指派它属于哪个孤岛。这通常用一组0/1变量来表示每对节点孤岛一个变量。工程上孤岛数量事先不知道所以先假设最大允许孤岛数然后允许空孤岛存在。变量一多求解规模就上去了。IEEE 33节点系统基础版本大概有33个节点、37条支路变量量级还好。但如果扩展到IEEE 123节点或者真实的几百节点馈线网络变量数会快速膨胀。后面讲求解策略时会专门说这个事。2.3 潮流约束非线性等式怎么处理配电网潮流方程本质是非线性等式约束直接扔给求解器问题就变成了混合整数非线性规划MINLP求解难度急剧增加。我的处理方案很直接用DistFlow分支潮流方程然后做二阶锥松弛。DistFlow方程长这样P_j P_i - I_ij² * R_ij - P_load_j P_DER_j Q_j Q_i - I_ij² * X_ij - Q_load_j Q_DER_j U_j² U_i² - 2*(R_ij*P_ij X_ij*Q_ij) (R_ij²X_ij²)*I_ij²其中第一、二条是节点有功/无功平衡第三条是电压降方程。I_ij²和U_i²是非线性项但可以通过变量替换变成线性表达式再补一个二阶锥约束U_i² (I_ij² * (R_ij² X_ij²)) ... 的形式经过变量替换和二阶锥松弛之后整个潮流约束变成了线性等式加上二阶锥不等式属于凸优化范畴。这一步非常关键想跟大家强调一个点二阶锥松弛的精确性不是天然保证的。松弛后的最优解有可能不是原问题的可行解。实际处理中我一般会加一道验证算完MISOCP结果后把开关状态固定下来重新跑一次精确潮流计算比如用Newton-Raphson法校验误差。绝大多数情况下松弛间隙1%可以直接接受。如果出现松弛间隙过大说明这个场景下二阶锥松弛可能不够紧就得考虑加割平面约束或者改用其他凸松弛手段。2.4 拓扑约束辐射状结构怎么用数学语言表达配电网正常运行要求开环运行也就是网络结构必须是辐射状森林。这个约束在数学上不好写常见做法有两种。第一种是公共交通矩阵约束。对网络中的每个连通分量都要满足支路数节点数-1这一条件。在网络不连通的情况下因为有孤岛要对每个孤岛或者每个连通子图单独校验。写成数学形式Σβ_ij |V_k| - |K|其中β_ij是支路状态变量|V_k|是节点数量|K|是连通分量数量。第二种是生成树约束的单商品流松弛。给每个节点分配一个流量变量根节点提供流量每个节点消耗1单位流量支路只有开着才能完整传输流量。这种方法的优点是线性缺点是容易引入额外的整数变量。我实测下来对IEEE 33节点系统公共交通矩阵约束配YALMIP求解效率已经够用。但对更大的系统单商品流约束的求解效率会更好。这个要和求解时间一起考量。2.5 孤岛划分约束连通性、功率平衡和DER能力孤岛划分比重构多出来的约束主要在三个地方。连通性约束。每个孤岛必须是一个连通子图不能出现孤岛里有一个节点但它的邻居全部不在孤岛里这种孤立节点。常见做法是用图论中的生成树约束对每个孤岛做连通性限制。也可以用一个技巧人为添加一个虚拟根节点让虚拟根通过虚拟边连到每个孤岛内的任意一个节点然后要求整个图是一棵辐射状树。这样每条实际支路的开关状态和每个节点归属孤岛的状态就通过虚拟网络统一起来了。功率平衡约束。每个孤岛内部必须满足有功和无功功率平衡。孤岛内所有DER出力加上储能放电功率要能覆盖孤岛内所有负荷的消耗再算上孤岛内的网络损耗ΣP_DER P_bess_discharge ΣP_load * x_i Ploss_island这个约束实时反映了孤岛能不能独立撑住。工程上我一般会多加一个安全裕度系数比如1.1倍负荷能力要求避免DER出力波动导致孤岛频繁崩溃。DER能力约束。包括光伏逆变器容量限制、储能充放电功率限制和SOC上下限约束0 P_pv P_pv_max -P_bess_max P_bess P_bess_discharge_max SOC_min SOC SOC_max SOC(t1) SOC(t) - P_bess * Δt / E_rated这里有一个重要的实操细节储能SOC约束在多时段模型里是时序耦合的状态量不能简单当成单时段约束来处理。如果你的场景涉及多时段恢复策略光写SOC上下限是不够的必须把相邻时段之间的SOC状态转移方程写进去。3. 求解策略选择与Matlab实现架构3.1 YALMIP加求解器还是自己写启发式算法统一模型建出来之后面临一个很现实的问题拿什么去解理论上这是MISOCP问题成熟的商业求解器如Gurobi和Cplex都能处理。用Matlab的话首选方案是YALMIP工具箱配合这些求解器。YALMIP负责把优化问题建模成标准形式求解器负责真正的数值计算。我实测下来Gurobi在MISOCP这类问题上要比Cplex快不少尤其是节点规模超过100时差距更加明显。但这不代表启发式算法就没用了。有两种场景下我反而推荐启发式算法系统规模特别大几百上千个节点MISOCP求解时间超过实际恢复允许的时间窗口。你不希望依赖商业授权或者现场环境根本没有Gurobi许可证。我自己的代码实现里做了双引擎设计默认走YALMIP加求解器的精确求解路径同时保留一个遗传算法GA版本的备选方案。GA的编码方式很简单基因就是所有开关的状态序列和每个节点的孤岛归属序列解码之后通过潮流计算校验约束得分通过目标函数计算。效果上GA跑IEEE 33节点没问题但每次计算都要调用潮流函数速度确实不如MISOCP理论上的求解时间。3.2 Matlab代码的整体架构规划我习惯把整个项目拆成模块文件分而治之main_adn_recovery.m主入口程序。设置算例参数、定义故障位置、调用优化模型、输出结果。case_ieee33.m算例数据定义。包括节点坐标、负荷功率、支路阻抗、开关位置、DER参数。build_unified_model.m统一模型建立。输入算例数据和故障场景输出YALMIP优化问题。solve_misocp.m调用YALMIP求解MISOCP问题。check_feasibility.m结果校验。对MISOCP解做精确潮流回代。plot_recovery_map.m结果可视化。画出恢复后的网络拓扑和孤岛分布。代码文件之间耦合要尽量低尤其是算例数据和优化建模必须分开。你需要跑不同规模、不同参数算例的时候直接换数据文件就行不用动模型代码。这也是我经历过几次改数据导致建模代码失控之后才养成的习惯。下面这段是build_unified_model.m的核心代码片段我简化过注释方便看逻辑function [model, params] build_unified_model(caseData, faultInfo, opt) % 提取算例基础数据 nb caseData.nb; % 节点数量 nl caseData.nl; % 支路数量 from caseData.branch(:,1); to caseData.branch(:,2); R caseData.branch(:,3); X caseData.branch(:,4); P_load caseData.load(:,1); Q_load caseData.load(:,2); % 决策变量 s binvar(nl, 1); % 支路开合状态,1闭合 x_load binvar(nb, 1); % 负荷恢复状态,1恢复 island_id binvar(nb, maxIslands); % 节点归属孤岛 % 连续变量 U sdpvar(nb, 1); % 节点电压幅值 I2 sdpvar(nl, 1); % 支路电流平方 P sdpvar(nl, 1); % 支路有功 Q sdpvar(nl, 1); % 支路无功 P_pv sdpvar(nb, 1); % 光伏有功出力 P_bess sdpvar(nb, 1); % 储能充放电功率 % 目标函数 Objective -sum(weights .* P_load .* x_load) ... lambda_sw * sum(abs(s - s0)) ... lambda_loss * sum(I2 .* R); % 约束集合 Constraints []; % 辐射状拓扑约束 Constraints [Constraints, forest_constraint(s, from, to, nb)]; % 潮流方程约束 Constraints [Constraints, distflow_constraints(P, Q, U, I2, ...)]; % 孤岛功率平衡 Constraints [Constraints, island_power_balance(...)]; % DER出力范围 Constraints [Constraints, 0 P_pv P_pv_max]; Constraints [Constraints, -P_bess_max P_bess P_bess_discharge_max]; model optimizer(Constraints, Objective, sdpsettings(solver,gurobi), ... [], [s; x_load; P_pv; P_bess]); end3.3 从单时段模型升级到多时段统一模型版本升级的核心变化在时序维度。单时段模型里所有变量都是同一个时间断面的快照求解相对简单。多时段模型的框架下每个节点、每个支路、每个DER的变量都要扩成T个时段。具体来说我把所有拓扑开关变量固定在整个故障处理时间窗口内因为实际电网中开关频繁动作不现实。但DER出力和储能充放电功率允许在每个时段内调整。这样模型变成了拓扑是一次性决策运行是多时段调度的两层结构更贴近电网调度员的实际操作习惯。多时段模型引入了一个额外的计算挑战变量数量直接乘以T。T取24对应一天24小时时IEEE 33节点系统的MI变量就从几十个膨胀到几百个。求解时间随之急剧上升。我的经验是如果只做故障恢复的日前策略T取12左右已经够用如果做日内滚动修正T取4到6个时段用滚动时域控制避免维度爆炸。4. IEEE 33节点系统仿真参数设置与实测结果4.1 测试算例与故障场景定义我用的标准测试系统是IEEE 33节点配电网。这个系统有多条联络开关支路具备重构的典型拓扑结构。基础参数包括基准电压12.66kV总有功负荷约3715kW总无功负荷约2300kVar系统包含多个分段开关和联络开关。为了测试统一模型的实际表现我设置了三种典型故障场景场景A支路6-7发生三相短路故障故障隔离后节点6下游约40%的负荷失电。场景B支路15-16发生故障这在IEEE 33节点系统中属于馈线末端故障影响范围相对小。场景C主馈线首端支路1-2故障这个故障会让系统绝大部分负荷失电对重构和孤岛划分能力考验最大。每种场景下我都在系统内配置了两个分布式电源节点一个光伏电站容量600kW和一个储能系统容量500kWh最大充放电功率250kW。电源位置选择了故障后可能形成孤岛的关键节点附近。4.2 统一模型和分步建模的实测数据对比我拿同一套故障场景分别跑了分步建模和统一建模结果差异非常明显。先看场景A负荷恢复率分步建模最终恢复了约82%的失电负荷统一模型达到了96%。差距的来源就在于孤岛划分。分步建模在重构阶段没有优先恢复光伏和储能覆盖范围内的关键负荷等重构结果固定后再去划分孤岛发现光伏覆盖区域已经有几条支路被重构方案切开了。统一模型在优化开关状态的同时赋予了孤岛划分更大的灵活性使光伏和储能能带着更多负荷形成孤岛。再看开关操作次数。分步建模需要先做一次重构操作序列再做一次孤岛划分操作序列两个阶段加起来总共操作了7个开关。统一模型最后只操作了4个开关因为一开始就综合了孤岛划分的需求避免了重构阶段为了恢复某个小负荷而额外操作的开关。场景C最极端。主馈线首端故障意味着重构手段几乎失效大部分负荷必须靠孤岛运行恢复。统一模型在这种情况下依然能形成2个合理的孤岛恢复率达到了73%。分步建模在这个场景下反复尝试了很多组合最后只恢复了41%的负荷而且求解时间比统一模型还长——因为它实际上跑了两个优化。求解时间方面场景A统一模型用Gurobi 9.5求解MISOCP问题约耗时4.8秒分步建模两个子问题加起来约耗时7.2秒。场景C统一模型耗时约11.3秒虽然比场景A慢但仍在可接受范围内。4.3 孤岛划分的可视化结果与运行指标仿真结果画出来之后里面的信息量比单纯看数字大得多。场景A的恢复策略很直观主网通过重构恢复了节点7到18的负荷同时光伏所在的节点25附近形成一个孤岛储能所在节点33附近形成另一个小孤岛。两个孤岛内的负荷加起来约500kW占失电负荷的三分之一左右。也就是说如果没有孤岛划分这500kW的负荷只能等主网恢复恢复时间可能要延长几十倍。电压指标也值得一看。孤岛内因为DER就地支撑电压其实还不错两个孤岛的电压最低点都在0.95 p.u.以上。主网恢复区域因为重构后路径变长馈线末端电压偏低场景A的主网恢复区域最低电压到了0.92 p.u.这个点。这说明统一模型需要把电压约束的权重调高一点特别是在重负载情况下。5. 调试经验与避坑指南5.1 二阶锥松弛不紧导致的假最优解这是我在多次仿真中最常遇到的问题。MISOCP松弛之后得到的最优解回代进原始非线性潮流方程时可能会违反电压方程。我举一个具体案例。场景C中有一次迭代求解得到的最优方案显示电压都在0.95 p.u.以上但固定开关状态后跑精确潮流发现有一个节点电压实际只有0.93 p.u.超出了安全范围。原因就在于二阶锥约束被松弛得不够紧在分布式电源高渗透区域松弛间隙达到了3.5%。解决这个问题我目前验证有效的做法有两个。第一个是加约束收紧松弛。对每个节点额外增加一个关于电压平方的线性化约束。虽然不能完全消除松弛间隙但能把间隙压到1%以内。第二个是迭代收紧法。求解MISOCP后检查松弛间隙如果大于阈值比如1%就把当前解对应的约束作为新的割平面加回去重新求解。一般迭代2-3次就能收敛到一个物理可行解。提示松弛间隙这个指标可以在Gurobi的日志里直接看到留意MISOCP每轮迭代后间隙的变化趋势。如果间隙一直在高位卡住不动大概率是该场景下二阶锥松弛不够紧而不是求解器出了问题。5.2 孤岛功率平衡约束的保守与激进孤岛功率平衡约束写得过紧会白白丢掉可恢复的负荷。我一开始直接用孤岛内DER总出力等于负荷总需求结果储能SOC稍微往下掉一点模型就判定某个孤岛不可行直接弃掉整个孤岛方案。后来我把约束改成了包含SOC时间演变的多时段平衡形式允许储能在一段时间内放电支撑负荷这才让储能真正发挥作用。实测下来相同场景下负荷恢复率能提升8%到12%。反过来也别太激进。允许储能一直放电到底会让孤岛运行时间严重不足短时间看着恢复了实际上过两小时就撑不下去了。我建议给孤岛持续时间设一个下限比如至少支撑2小时这个约束在最终结果里体现为储能SOC的终值下限。5.3 开关操作次数惩罚项的权重开关操作惩罚项λ_sw的取值对结果影响非常大。取小了模型会倾向于频繁操作开关换取更低的网损或更高的恢复量取大了模型会放弃很多本可以通过适当操作开关实现的恢复机会。我的经验是先跑敏感性分析看看λ_sw从0.01变化到10时恢复率的变化。一般来说恢复率会随着λ_sw增大而阶跃下降。取恢复率开始阶跃下降之前的最大λ_sw作为权重可以平衡操作代价和恢复效益。5.4 求解器的热启动策略大场景下MISOCP求解时间长热启动能显著加速。Gurobi支持把上一次的解作为初始解传入新模型。故障场景变更时比如故障位置挪了一下最优开关状态的差异往往不大热启动的加速效果非常明显。我实测在场景A基础上改故障位置热启动后求解时间从4.8秒降到2.7秒。实现热启动很简单在YALMIP的sdpsettings里指定初始值即可sdpsettings(solver,gurobi,gurobi.StartSolution, x_init)5.5 故障隔离逻辑与重构之间的衔接这个细节特别容易栽跟头。故障发生后故障点两侧的开关必须断开这是隔离故障的前提。但如果你直接在优化模型里把这些开关状态固定为0等效于排除了这部分支路从重构中恢复的可能性。正确做法是分两步先确定最小故障隔离区域把故障段两侧开关的故障隔离状态和优化重构状态分开处理。故障隔离开关必须在优化开始之前强制断开并且这些支路不允许出现在任何恢复方案中。其他开关则正常参与优化。这个逻辑必须写进约束集里我之前因为漏掉这个强制约束算出来的方案里故障支路居然被恢复了直接导致方案在工程上不可执行。6. 怎么把你的场景适配到这个统一模型里6.1 增加多类型DER的灵活性我的代码里默认考虑了光伏和储能两类DER。你要是有风电、柴油发电机、微型燃气轮机只需要做两件事在case数据文件里增加DER类型字段在建模代码里增加对应DER的出力约束。风电的随机性可以用场景法处理也就是生成多个风电出力场景每个场景对应一个子模型最后做场景聚合。微型燃气轮机则要增加爬坡约束和最小启停时间约束这些约束在多时段模型里天然好加。6.2 考虑负荷的时序变化配电网负荷不是恒定不变的。在故障恢复时间窗口内负荷曲线会有峰谷变化。如果只取峰值负荷来计算恢复方案结果会过度保守——低谷时段明明能恢复更多负荷但因为峰值约束而不敢操作。解决办法很简单把负荷改成多时段的时序数据。每个时段取对应时段的负荷值恢复状态x_load如果包含时序维度则允许在不同时段有不同负荷恢复比例。当然这样决策变量更多求解时间更长需要权衡。6.3 扩展到弱环网场景传统配电网一般是辐射状但有些新建配电网是弱环网设计。统一模型要适配弱环网需要做一个小改动辐射状拓扑约束替换为环形拓扑约束。约束表达式从支路数节点数-1改为支路数节点数并且所有节点度数至少为2。其他约束基本可以复用。实测在弱环网上故障恢复的灵活度会高不少因为系统有更多路径可选。6.4 把Matlab代码封装成可复用的工具写科研代码和写工程代码是两回事。如果你的目标是能在不同算例上反复测试我建议花时间把代码模块化。我自己整理的封装方式输入是一个结构体CaseData包含所有算例参数。输出是一个结构体Result包含恢复拓扑、孤岛分布、电压分布、恢复负荷列表。求解器类型、松弛阈值、权重系数等作为配置参数传入。这样任何人拿到代码后只需要改CaseData就能复现你的方法。你后续换算例、加算法也不用大动干戈。