主动配电网故障恢复:重构与孤岛划分统一建模的Matlab实现

发布时间:2026/10/24 4:42:38
主动配电网故障恢复:重构与孤岛划分统一建模的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 决策变量怎么定

统一模型里最核心的决策变量有三类:

  1. 支路投运状态:每条支路对应一个0-1变量,1表示合闸投运,0表示断开。这直接表达重构动作,也是开关操作次数的计算来源。
  2. 节点供电状态:每个负荷节点对应一个0-1变量,1表示恢复供电,0表示失电。节点供电状态把“可恢复性”从支路拓扑中解耦出来,便于统计失电负荷和灵活约束。
  3. 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)重要负荷标志
10000
21006000
1890404001
22603000
33503000

支路数据结构也类似,字段包括支路编号、首端节点、末端节点、电阻、电抗、是否为联络支路、初始开合状态。原始数据要特别注意两个点:一是支路末端的编号顺序不要乱,后面生成Yalmip变量是按顺序循环的;二是故障前的开关状态一定要记录,因为目标函数里的操作次数要基于初始状态做差。

3.2 代码框架总览

整个Matlab代码按模块划分,顺序执行:

  1. 数据输入模块:加载节点、支路、DG、故障场景数据;
  2. 故障预处理模块:根据故障位置断开故障支路,标记失电区域;
  3. 模型定义模块:用Yalmip定义变量、目标函数、约束;
  4. 求解模块:调用Gurobi/Cplex求解MISOCP;
  5. 后处理模块:解析开关状态、计算恢复电量、绘图。

这种模块化分离最大的好处是便于排查问题——报错了先看是数据不对、约束写错,还是求解器不收敛。我强烈建议不要在同一个脚本里从头写到尾,做一个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)]; end

M的取值很关键。取值太小会截断有效的潮流范围,导致可行域错误;取值太大会让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 结果怎么判断可信度

判断一个恢复方案是否可信,我总结了三个准则:

  1. 拓扑必须全连通且无环,孤岛内所有节点都要有电源支撑;
  2. 每个恢复节点的电压都要满足上下限约束,不能出现恢复电压越限;
  3. 开关操作顺序在物理上可行,不能出现需要同时合闸才能带电的串联节点。

看求解器输出的最优解之前,我会先把这三条用后处理脚本做一遍自动化检查,全部通过才会画图出报告。这样既省去人工看数据的麻烦,也避免把错误结果直接拿去做演示。

5.3 这个模型还能怎么扩展

升级版的统一模型框架其实还能继续往下延伸。目前最热的方向有两个:一个是接SOP(智能软开关),用电力电子装置替代传统联络开关,故障恢复时不仅能合闸转带负荷,还能精确控制两侧有功和无功交换,这对统一模型的表达方式又是一个挑战;另一个是把分布式储能和电动汽车充电桩纳入模型,让它们在故障恢复时作为“临时电源”参与孤岛划分和功率支撑。

还有一个方向是多目标权重自适应调整。现在权重是固定值,但如果想让模型在不同故障场景下自动调整恢复策略(比如重载场景优先保供电量,轻载场景优先降网损),就可以给权重加一层模糊逻辑或者规则判断。这些都是在这个统一模型骨架上的自然延伸,代码框架不用大改,主要是扩展约束和决策变量。

回到最开始的痛点:重构和孤岛划分不该是两条道上的车。这次把两者统一建模,并用Matlab+Yalmip跑通升级版,整个项目的核心收益就是让故障恢复方案从“能算出来”变成“算出来能直接用”。后面如果再往SOP、储能、不确定性方向扩展,这个模型底座仍然能撑得住。我个人在实际操作中的体会是,统一模型最难的地方不是数学推导,而是把物理运行规则准确翻译成约束,和信息学里的说法很像——怎么让优化器真正理解配电网是怎么运行的。把这层想明白,后面调参、扩展、换算例都只是时间问题。