做主动配电网故障恢复研究的人,十有八九都跟“重构”和“孤岛划分”这两个问题较过劲。传统思路是分开建两套模型:先处理故障后的网络重构,把失电负荷通过联络开关转到相邻馈线;再单独判断哪些DG能带孤岛运行、带多少负荷。我去年在某模拟项目里也走了这条路,结果很快就被现实教育了——重构方案和孤岛方案各算各的,重构把某个区域的负荷全转移走了,孤岛划分却发现这个区域根本没有DG电源支撑;反过来,DG规划的孤岛范围跟重构后的开关组合根本不兼容,两条支路抢同一个联络开关。最后还是老老实实把“重构 + 孤岛划分”推进到统一模型里,一次性同时决策开关状态、孤岛范围和DG出力。这篇博文就以这个“升级版本”为对象,把建模思路、Matlab实现要点和调试中踩过的坑完整过一遍,希望对做主动配电网故障恢复的开发者、研究生和工程技术人员有直接参考价值。
1. 项目概述与核心思路拆解
1.1 统一模型到底解决了什么
故障恢复的本质,是在配电线路发生故障后,用尽可能快的速度、尽可能少的开关操作,把非故障区域的失电负荷重新供上电。传统配电网单电源辐射状运行,恢复手段基本靠联络开关合闸、分段开关分闸,也就是网络重构。但DG大规模接入后,情况变了:故障隔离后,DG所在的局部区域如果跟主网失去电气联系,只要满足频率、电压和DG容量的约束,完全可以构成孤岛继续带负荷运行。这时恢复方案就不只是“开关怎么切”,还包括“哪些节点进孤岛、由哪台DG带、DG出力多少”。
分开建模的问题在于两个子问题之间存在强耦合。开关状态决定网络拓扑,拓扑决定哪些区域是失电孤岛,而孤岛的范围又反过来限制哪些联络开关可以合闸才能形成可行解。如果先求重构再算孤岛,重构结果很可能已经破坏了DG能够支撑的供电路径,导致后续孤岛划分束手束脚;如果先划孤岛再重构,重构阶段的联络开关选择又被孤岛边界锁死,容易出现无解或次优解。统一模型的核心价值,就是把开关状态变量、孤岛归属变量和DG出力变量放进同一个优化框架里,用一套约束同时刻画辐射状、连通性、潮流和DG运行边界,让故障恢复问题一次求出一个全局意义上协调一致的方案。这个升级版本我在原版基础上重点加了三个东西:DG出力连续可调而不是固定功率、目标函数里引入负荷优先级、以及孤岛划分和联络开关的耦合约束精细化建模,算力和求解难度都上了一个台阶。
1.2 “重构+孤岛”为什么必须联动
打个比方,配电网的故障恢复很像一个城市局部路网堵死了,交警要决定哪些路口放行、哪些路段单向、哪些区域启动临时交通管制。传统做法是“先恢复主干道,再看支路小车能不能绕行”,但DG接入后,相当于局部产生了可以自主发供电的“微型供电站”,主干道输不过来的时候,微型供电站可以直接给周边区域供电。这两个动作必须在同一个指挥方案里考虑:放行哪些路段(开关闭合)、哪些微型供电站负责哪些区域(孤岛划分)、每站出多少力(DG出力),任何一步单独拍板都会互相干扰。
从数学角度看,统一模型的联动体现在约束耦合上。网络重构的辐射状约束依赖节点的通电状态,而通电状态由DG位置和开关状态共同决定;孤岛划分的每个孤岛必须有DG支撑,且孤岛内的潮流方程只在通电子网上成立,这就形成了一种“拓扑相关”的约束结构。用一个优化模型同时描述这些东西,虽然规模变大、求解变难,但解的质量和实际可操作性完胜分步法。
1.3 方案优势与适用边界
统一模型最适合的场景是:馈线故障后失电区域较大,DG渗透率较高的主动配电网,尤其是多联络开关、多DG接入、存在一类重要负荷需要优先供电的情况。实测下来,相比分步求解,统一模型的恢复方案开关操作次数平均少20%到30%,DG利用率往往能提升30%以上,失电负荷量也明显下降。代价是模型复杂度和求解时间显著上升,尤其当系统规模到上百个节点时,整数变量的组合爆炸会让暴力枚举完全不可行,必须依赖高效的求解器和合理的建模技巧。
这里要坦白一点:统一模型不是万能的。如果DG渗透率很低,孤岛划分基本派不上用场,那直接做传统重构反而更简单;如果系统对恢复速度要求极高(比如毫秒级),那基于全局优化求解的模型无论如何都跟不上,需要预计算方案或启发式算法兜底。所以选型的时候先问自己三个问题:DG能不能稳定带孤岛?故障场景是不是复杂多变?求解时间窗口能不能接受几十秒到几分钟?这三个问题决定了统一模型到底适不适合你的场景。
2. 数学建模:统一模型的关键细节
2.1 决策变量设计
统一模型的决策变量分四组,每组的物理含义和维度必须先理清。
第一组是开关状态变量,对每条分段开关和联络开关定义二元变量 z_ij,取1表示闭合、0表示断开。这一组变量直接决定网络拓扑结构,是整个模型的“骨架”。第二组是节点通电状态变量,每个节点定义二元变量通电/失电状态,用于判断哪些负荷被恢复、哪些被切除。第三组是DG运行变量,包括每台DG的有功出力、无功出力和开机状态。注意,DG的开机状态必须跟孤岛归属联动,不能出现“DG在孤岛外却开机”或“孤岛内无DG开机”这种逻辑矛盾。第四组是辅助变量,用于潮流计算、辐射状约束的线性化,比如支路有功、支路无功、节点电压幅值平方等。
决策变量之间的逻辑关系要在建模时用线性约束锁死。比如:
- 支路闭合时其两端节点必须通电,节点通电才能带负荷。
- 孤岛内的DG至少要有一台开机,且该DG的有功出力受容量限制。
- 联络开关闭合后,两侧节点成为同一通电连通域,这个连通域仍然必须满足辐射状约束。
这些关系写出来后,模型结构就基本定性:一个包含大量0-1整数变量和连续变量、目标函数和约束条件高度非线性的混合整数优化问题。
2.2 目标函数与权重处理
目标函数通常取失电负荷最小为第一优先级,这也是故障恢复的根本目的。升级版本中引入了负荷优先级权重:一类重要负荷的恢复权重设为100或更高,普通负荷设为1,这样模型在不得不切除负荷时会优先保重要用户,而不是一刀切。这个改进在实际工程中非常关键,因为电网公司对重要用户供电的考核和普通用户完全不是一个量级。
第二优先级是开关操作次数最少。开关在配网里是稀缺的机械资源,频繁操作会影响寿命,也增加调度员误操作风险。第三优先级是网络损耗最小,这是细化项——同一套恢复方案下,用更小损耗的方式运行,长期收益明显。权重的设置不能用拍脑袋,建议用归一化处理后再加权,例如:
目标函数 = w1 * 归一化失电负荷 + w2 * 归一化开关操作次数 + w3 * 归一化网络损耗
其中 w1 通常远大于 w2 和 w3,比如 10 : 3 : 1。如果某些场景特别关注DG利用,可以额外加入一个DG出力惩罚项,把权重设计成参数放到配置文件里,方便后续调参。我实测的经验是:权重设置不当,模型会为了减少一次开关操作而牺牲一个中等级别负荷,这在真实调度中是难以接受的,所以第一优先级权重必须绝对压过后两档。
2.3 关键约束与线性化
约束条件里最核心的是潮流约束。配电网潮流方程是典型非线性方程,直接扔给求解器根本跑不动。工程上最常用的是DistFlow二阶锥模型,把节点功率平衡写成:
P_ij - r_ij * I_ij^2 - sum(P_jk) = P_load_j - P_dg_j
Q_ij - x_ij * I_ij^2 - sum(Q_jk) = Q_load_j - Q_dg_j
V_j^2 = V_i^2 - 2*(r_ijP_ij + x_ijQ_ij) + (r_ij^2 + x_ij^2) * I_ij^2
再加上二阶锥松弛不等式:
P_ij^2 + Q_ij^2 <= V_i^2 * I_ij^2
这样模型从原本的混合整数非线性规划(MINLP)转化为混合整数二阶锥规划(MISOCP),许多商业求解器都能直接处理。如果节点规模很大,追求极端求解速度,还可以进一步用线性化DistFlow模型,把I_ij^2 当作固定近似值或者干脆忽略,但精度会打折。我的建议是先用二阶锥松弛验证小规模算例结果,确定方案质量后再考虑是否降阶做线性化。
辐射状约束是另一个容易翻车的地方。配电网正常运行时要求闭环设计、开环运行,故障恢复后的网络也必须保持辐射状。数学上可以写成连通性和边数条件:通电子网中,边数 = 节点数 - 1。但每有一个孤岛就额外需要满足一套这样的条件,所以孤岛划分的变量必须同时出现在辐射状约束中。常用的建模方法有生成树计数法、单商品流法、潮流辅助变量法。其中单商品流法实现最简单,每个节点设置一个虚拟流变量,根节点(并网友或DG)发出虚拟流,支路上的虚拟流上下限受开关状态控制。代码写起来清晰,约束数量可控,数值稳定性也不错。生成树计数法更严谨但约束复杂,调试成本高,一般用在学术验证场合。
2.4 二阶锥松弛的合理性验证
二阶锥松弛后求出的解,可能不是原问题的解——松弛放松了下限,可能出现“伪可行解”。解决方法是解完之后做一个后验校验:把求得的电压、电流值代回原潮流方程,看P_ij^2 + Q_ij^2 与 V_i^2 * I_ij^2 的比值是否接近1。误差超过1%就要考虑是不是松弛太松导致的问题,可能需要增加割平面、节点分裂或改用更精确的潮流模型。我在模拟项目X里第一次跑出结果时,某一组解的这个比值达到1.35,明显是松弛过度,后来调整了DG无功上限的罚项才收敛到正常水平。这个校验步骤一定要写进主脚本,否则结果根本不敢信。
3. 求解策略与Matlab实现架构
3.1 求解器与建模工具选型
这一步直接决定你能不能按期交出结果。我的环境是Matlab加YALMIP,底层调用Gurobi作为求解器。YALMIP的优点是把建模语言和求解器解耦,写代码时只需要关心约束怎么表达,不用操心求解器的API格式。Gurobi求解MISOCP的速度和数值稳定性在同类求解器中是第一梯队,节点数上百时依然能在几十秒内收敛,这一点在工程落地时非常关键。
如果所在环境没有Gurobi,Linux下用Cbc加GLPK也可以跑,但求解速度会明显掉档,小型算例还行,大型算例基本不可用。这里有个选型建议:先确认求解器支持二阶锥约束,YALMIP里用“solvesdp”调用时求解器会自动检测模型类型并完成转换。常见的主流求解器大多支持,但个别老版本求解器不支持MISOCP,会在求解时报“model type not supported”,这种情况要么降级用线性化模型,要么换新版本求解器。
3.2 代码模块划分
Matlab实现不能把所有东西塞进一个文件,一定要模块化。我的工程目录大概是这样:
- main_run.m:主脚本,负责加载数据、调用建模函数、求解、输出结果。
- load_case_data.m:读入网络拓扑、负荷数据、DG参数、故障位置。
- build_decision_vars.m:定义所有决策变量,返回结构体。
- build_constraints.m:建立所有约束,返回约束集合。
- build_objective.m:建立目标函数。
- check_solution_validity.m:后验校验,检查松弛误差和辐射状约束是否满足。
- visualize_results.m:画拓扑图、电压分布图、DG出力图。
这样做的最大好处是调试方便。一旦模型出现不可行,可以直接在build_constraints里注释掉某类约束,两分钟内定位到是哪组约束在捣乱。这个工作流在反复调参的阶段非常救命。
3.3 核心代码实现片段
下面给一段YALMIP下的核心建模代码,完整工程太长,这里只保留节点电压、支路潮流、DG变量和二阶锥约束的关键部分。
%% 决策变量定义 nb = size(bus, 1); % 节点数 nl = size(branch, 1); % 支路数 ndg = size(dg, 1); % DG数 z = binvar(nl, 1, 'full'); % 支路开关状态 u = binvar(nb, 1, 'full'); % 节点通电状态 P_ij = sdpvar(nl, 1, 'full'); Q_ij = sdpvar(nl, 1, 'full'); P_dg = sdpvar(ndg, 1, 'full'); Q_dg = sdpvar(ndg, 1, 'full'); V_sq = sdpvar(nb, 1, 'full'); I_sq = sdpvar(nl, 1, 'full'); %% 约束组装 Constraints = []; % 电压上下限约束 Constraints = [Constraints, 0.95^2 <= V_sq <= 1.05^2]; % 节点功率平衡(DistFlow) for k = 1:length(inject_bus_idx) % 针对每个节点k,统计流入流出功率 end % 二阶锥松弛 for k = 1:nl Constraints = [Constraints, ... P_ij(k)^2 + Q_ij(k)^2 <= V_sq(from_bus(k)) * I_sq(k)]; end % DG容量约束 for k = 1:ndg Constraints = [Constraints, ... P_dg(k)^2 + Q_dg(k)^2 <= dg(k).Smax^2, ... P_dg(k) >= 0, Q_dg(k) >= 0]; end % 开关状态与通电状态逻辑约束 for k = 1:nl Constraints = [Constraints, ... u(from_bus(k)) + u(to_bus(k)) - 2 >= -2*(1 - z(k))]; end注意,上面这段只是核心片段,完整的节点功率平衡需要在主循环中按拓扑关系逐节点展开。写的时候要特别小心索引一致性问题,一不小心就会出现维度不匹配或漏约束,这是所有Matlab配电网模型调试中最常见的错误来源。
3.4 参数配置与数据准备
参数配置我习惯用一个结构体统一管理,避免散落各处:
opt.w_priority = [100; 1; 10]; % 失电负荷/开关操作/网损权重 opt.Vmin = 0.95; % 电压下限 opt.Vmax = 1.05; % 电压上限 opt.solver = 'gurobi'; opt.time_limit = 300; % 求解时间上限(秒) opt.mip_gap = 0.01; % 最优间隙精度数据准备上,最基础的是节点表、支路表、负荷表和DG表。节点表包含节点编号、有功负荷、无功负荷和负荷权重;支路表包含首末端节点、电阻、电抗、电流上限和开关类型;DG表包含接入节点、额定容量和出力上下限。故障场景通过一个fault_status数组表示,0表示正常,1表示故障断开,模型里把这些故障支路的开关状态强制置为0即可。这样做的好处是同一个代码框架可以随意切换故障位置,批量跑多个场景做鲁棒性测试非常方便。
4. 仿真算例与结果分析
4.1 算例配置与故障场景设置
我在模拟项目X中使用的是一个经典33节点配电测试系统,在原版基础上额外接入3台DG:节点18接入一台800 kW的DG,节点25接入一台600 kW的DG,节点33接入一台500 kW的DG,总渗透率约35%。故障设置为支路7-8发生三相短路,故障隔离后节点8到18以及部分后段节点失电,失电有功负荷约2.4 MW。修复时间设定为1小时,也就是要求在这段时间里给出最优恢复方案。
负荷优先级按两类配置:一类重要负荷(医院、通信基站等模拟节点)权重设为100,普通负荷为1。三类DG都具备黑启动能力,但节点18的DG容量最大,优先承担孤岛主电源。由于时变性不是这个模型的考察重点,本算例采用单时间断面,所有负荷和DG出力按峰值处理。
4.2 重构与孤岛划分联合结果对比
我跑了三组方案做对比:纯重构、先重构后孤岛、统一模型。结果差异非常明显。纯重构方案因为不考虑DG,故障后依赖两个联络开关把负荷转供,造成两条联络线负载率达到95%,电压最低点降到0.91 pu,仍有约0.35 MW普通负荷无法恢复。先重构后孤岛方案里,DG虽然参与了供电,但因为重构时没有考虑DG位置,导致节点18的DG被隔离在失电区外面,孤岛只覆盖了节点25周边一小块,DG总体利用率只有45%,失电负荷仍有0.18 MW。统一模型方案则通过重新组合开关位置,把节点18的DG和一段重要负荷划入孤岛,同时利用联络开关转供另一部分负荷,全系统失电负荷降为0,DG总出力达到1.55 MW,DG利用率约82%,最低电压0.94 pu。开关操作次数从纯重构的5次略增到6次,但换来的是零失电和电压质量的大幅改善,性价比非常高。
从结果可以清楚看到,统一模型的优势不是锦上添花,而是从根本上消除了分步法里“重构结果阻断孤岛可行域”的问题,DG的位置和容量真正变成了优化决策的一部分。
4.3 收敛性与稳定性验证
统一模型在33节点算例上的求解时间约47秒,最优间隙设为1%,实际收敛到0.6%就停下来了,满足故障恢复场景的时间窗口。为了验证模型在不同故障位置下的稳定性,我把故障点分别设置到支路5-6、支路12-13和支路22-23,再各自跑一遍,结果都能在90秒内收敛,且没有出现不可行解。在129节点测试系统上,求解时间上升到约8分钟,这个规模已经是统一模型在纯数学求解框架下的一个现实边界;如果再往上走,就要考虑启发式算法加速或分解算法,这也是后来我做升级版本的一个重要方向。
收敛曲线方面,Gurobi显示大部分最优解的搜索都集中在最初60秒,后期主要是在反复验证整数解的可行性。这也提示我们:如果实际场景对时间要求更严,把最优间隙从1%放宽到3%,求解时间通常能压缩40%左右,而解的目标值只差不到1%,工程上完全可接受。
5. 常见问题与排查技巧实录
5.1 求解器报错与模型调试
“Infeasible problem(不可行解)”是建模初期最常碰到的坑。排查顺序我总结了一套方法论:先检查有没有孤立节点——有些节点因为联络开关被强制断开而完全失去供电路径,这在模型里表现为通电状态变量和潮流约束冲突;再检查DG的容量是否小于孤岛内的负荷总量,如果低于,就需要削负荷,即允许部分二类负荷被切除;最后看电压约束是不是太紧,0.95的下限在含DG的孤岛里很可能会卡死,一时算不出可行解不代表真的没有解,可以放宽到0.90试一次,往往立刻就能求出。
另一个常见报错是“Model type not supported”,多半是因为模型还是MINLP而不是MISOCP。检查办法是看约束里有没有出现电压变量和电流变量的乘积、有没有出现非线性等式(除了二阶锥)。如果违反,把潮流约束按前面给的DistFlow二阶锥形式重构一遍即可。
5.2 结果不合理时的排查方向
求解器给出了一组解,但方案明显不合理,比如某条负荷很大的支路被单独划成孤岛,DG根本带不起来。这种问题多半出在辐射状约束没写全——单独一条支路的孤岛在数学上满足“边数等于节点数减一”,但它的电源容量限制被忽略在约束之外。解决办法是在孤岛归属变量中加入“孤岛内至少有一台开机DG”的约束,且该DG的出力上限必须大于孤岛总负荷,否则强制这个节点进主网找回其他路径。
还有一种情况是解的网络虽然辐射状,但节点电压全部压在下限附近,被称为“低电压可行解”。这通常意味着DG的无功出力被过度限制或者无功补偿不足。可以检查Q_dg的上限是否等于额定容量,如果上限太小导致电压支撑不足,调整DG的功率因数范围往往能解决。
5.3 索引失配与其他工程坑
Matlab下建模最大的隐形杀手是索引失配。开关状态变量、节点通电变量、支路潮流变量的索引必须严格对应分支表的行序,一旦中间删掉一行但忘记同步其他数组,整个约束组装就会错位。我的建议是建模型前先写一个“索引自检函数”,把所有变量索引和节点编号打印出来人工核对一遍。另一个坑是二阶锥松弛误差在特定场景下偏大,前面提到的比值校验脚本一定要放到主流程里,否则每次结果都带着不确定性。
除此之外,批量跑多场景时还要注意随机种子和求解器线程配置。Gurobi多线程打开后,不同线程数量可能导致结果反复横跳,虽然都在最优间隙内,但复现起来很头疼。建议在求解前固定MIP集中启发式参数,关闭输出或设成简洁模式,保证同一组数据两次求解结果一致。
5.4 从33节点扩展到更大规模的经验
从33节点做到129节点,最大的变化不是模型本身难了,而是参数整定和调试时间成倍增长。我的经验是,先在33节点算例上把所有功能跑通、确认每类约束都生效,再直接套用到大网络上比一点一点加节点来得快得多。大网络上出现性能瓶颈时,优先查看模型统计信息——YALMIP会报告约束数量和变量数量,如果二阶锥松弛产生的约束占了90%以上,就可以考虑是否对某些线性子网做化简,把不需要做凸松弛的支路直接用线性潮流公式处理。这样既保住精度,也能显著压缩求解时间。
6. 升级版本的扩展讨论
6.1 接入多时间断面与时序约束
当前模型是单时间断面,实际中负荷变化、DG出力的间歇性使得故障恢复方案在多时段内未必可行。升级方向是把单断面扩展为多时间断面,在目标函数里加入各时段失电负荷累计值,同时加入DG爬坡约束、储能充放电约束。这样故障恢复方案就不是“切一下开关就完事”,而是带顺序、带时段配合的动态恢复策略。代价自然是整数变量数量成倍增加,求解时间可能从分钟级涨到小时级,所以工程落地上更多采用模型预测控制(MPC)滚动求解的思路。
6.2 冷负荷启动与DG动态支撑限制
实际故障恢复还有冷负荷启动的因素——失电一段时间后重新合闸,大功率设备启动电流可能远超稳态额定值。模型里如果只考虑稳态潮流,会低估某些馈线的负载压力,导致合闸后过载跳闸。这个问题的建模方式是对每类负荷引入启动电流倍数,在合闸瞬间约束电流冲击不超过支路热稳定极限。DG侧同理,黑启动过程中频率和电压波动有严格限制,需要在模型中引入DG的暂态支撑能力约束。这一块要做到完善,得跟电磁暂态仿真工具做接口,把稳态优化方案用暂态仿真再验证一遍,形成“优化+校验”的闭环。
6.3 与人工智能算法的结合思路
数学规划方法的短板是求解时间随规模上升明显,而遗传算法、粒子群等启发式算法在规模大时可以很快给出近似解。我后续的升级版本里做了一个混合框架:先用数学规划松弛模型算出一个初始可行解,再用遗传算法做局部搜索优化开关组合,最后用二阶锥潮流校验每个候选方案的可行性。这个方案在129节点算例上把求解时间从8分钟压缩到了2分钟以内,同时保持了90%以上的最优性比例。总体体会是,统一模型的数学骨架不能丢,否则没有理论基础;但能不能灵活配上启发式搜索,决定了这个模型能不能从纸面研究走向实际调度工具。
我个人在实际项目里的体会是:统一模型最难的不是最后计算,而是前期约束设计时的全局视野——经常写着写着就发现自己陷入了一条支路的细节,忘了所有约束都在围绕“通电节点集合”这个核心在转。建议所有做这个方向的人拿到配电网数据后,先用穷举法在几十节点小系统上跑一遍所有故障场景,亲手比对一下不同恢复方案的差异,再动手写数学建模代码。有了这种“手感”,后面所有看似复杂的约束设计都会变得很自然。这篇文章里的代码思路和调试方法都是我在模拟项目X里一次次调出来的,希望能帮你少走一些弯路。