
做配电网故障重构的人应该都被“开关组合怎么选”“恢复范围怎么定”这两件事折磨过。传统重构模型涉及离散开关变量和非线性潮流方程要么求解不稳定要么结果没法落地。这个项目基于MATLAB实现了一套主动配电网故障重构模型用二阶锥松弛把非凸潮流约束转成凸约束配合YALMIP和Mosek/Gurobi稳定求解再把故障场景、重构结果、电压分布用可视化图直观展示。如果你正在做主动配电网、分布式电源接入下的配网重构或者想系统学习二阶锥松弛建模这份笔记可以当作一份可复现的技术参考直接抄作业。1. 项目背景与核心思路拆解1.1 故障重构问题的本质是什么配电网重构字面意思是“改变网络拓扑结构”。正常运行时重构的目的是降低网损、均衡馈线负载故障时重构目的变成了两个——快速隔离故障和最大范围恢复非故障区供电。传统配电网中网络被动运行电源集中在变电站侧故障重构说白了就是“倒闸操作”。但主动配电网引入分布式光伏、风电、储能和可控负荷之后重构问题有了本质变化网络不再是一个只由大电网单向供电的被动网络多个分布式电源可以孤岛运行、也可以主动调整出力储能可以配合充电或放电可控负荷还能响应调度。这时候的故障重构实际上是一个“拓扑决策 电源出力调整 储能充放电策略”的联合优化问题。很多人一开始会把配电网故障重构当成一个简单的“路径搜索”问题觉得只要找到一条从变电站到失电区域的通路就行。但实际做下来会发现问题远不止于此。重构后的网络必须满足辐射状无环、电压不越限、线路不过载、DG出力在允许范围内等一堆约束而且还要尽量恢复重要负荷、降低网损、减少开关操作。这么一来问题就是一个典型的混合整数非线性规划数学性质很差直接求解非常吃力。这也是为什么这个项目选择数学规划路线而不是启发式算法。启发式算法遗传、粒子群上手快但每次评估都要做潮流计算计算量随网络规模增长很快而且很难保证最终方案是全局最优的尤其是故障场景多变、网络参数变化频繁的时候工程上更希望能在合理时间内得到一个可量化的可靠解。基于凸优化的数学模型一旦建模正确、松弛有效求解器能够给出全局最优解还带有对偶间隙等信息辅助判断结果质量这些特性在调度场景里非常有用。1.2 为什么二阶锥松弛会成为主动配电网重构的主流工具主动配电网重构的数学模型潮流方程是最麻烦的部分。经典的DistFlow潮流方程是二次非凸的比如支路有功、无功和电压、电流之间是乘除关系直接用求解器处理几乎没有求解器能稳定收敛到全局最优。二阶锥松弛的核心思路是先把电压幅值平方和电流幅值平方设为新的连续变量把支路功率约束通过一个不等式松弛掉。这个不等式不是随便放掉的它对应着一个旋转二阶锥是一个凸集合。于是原本头痛的非凸潮流约束被替换成一个凸约束整个模型变成了混合整数二阶锥规划MISOCP这类模型在现代求解器里已经有非常成熟的算法。有人可能会问松弛出来的解还靠谱吗这就要看“精确松弛”是否成立。对于绝大多数正常运行范围的辐射状配电网只要电压幅值在合理区间这个松弛在最优解处总是取等号的。换句话说松弛后的最优解和原非凸问题的最优解在关键指标上是一致的。这也是该技术能在配电网领域大规模应用的基础。实际项目里我会在求解后主动检查每个支路的松弛间隙如果某个支路间隙过大就需要检查是不是负荷过重、DG出力过激、或者网络参数给出了超出物理可解的范围。1.3 整体建模框架与设计思路这个项目把模型拆成三个层次逐层叠加避免一开始就陷入复杂非线性方程。第一层是潮流约束层用DistFlow分支潮流方程描述每个节点和每条支路的电压、功率、电流关系第二层是拓扑决策层用一组布尔变量表示开关状态并加入辐射状连通性约束第三层是主动性资源层包括DG的有功无功出力、储能的充放电状态、节点是否恢复供电等变量这些变量与拓扑层、潮流层相互耦合最终形成一个整体优化模型。设计时如果把所有约束一次性全写出来出错后很难排查。所以我习惯先用一个简单的小网络把模型跑通再扩展到33节点甚至更大系统。这个项目的可视化模块也承担了调试功能把拓扑状态画出来、把电压分布画出来模型哪里有错一眼就能看到比盯着矩阵数字强太多。2. 模型构建的关键细节2.1 DistFlow潮流方程怎么用DistFlow是配电网重构中最常用的潮流模型尤其在主动配电网优化里几乎是标准选择。它把潮流关系写成支路视角的递推式。为了处理电压和电流的乘积关系通常引入 (U_i V_i^2) 和 (L_{ij} I_{ij}^2) 两个辅助变量。这样节点 (j) 的有功和无功平衡可以写为流入支路功率之和减去流出支路功率之和等于该节点负荷功率减去注入功率。电压方程则描述了节点 (j) 电压平方如何由上游节点 (i) 电压平方、支路功率和电流平方决定。这些方程本身不是凸的因为在电压方程里带有电流平方项在支路功率表达式中还存在 (P_{ij}^2Q_{ij}^2) 与 (U_i L_{ij}) 的等式耦合。我在实际建模中会先把潮流的物理含义搞清楚再动手写代码。以一条支路 i-j 为例有功功率从 i 流向 j传输过程中有电阻损耗所以节点 j 的注入功率加上损耗之后等于节点 i 的注入功率电压则在经过阻抗时产生压降压降大小与支路功率和电流有关。理解了这些就算忘了公式也能从原理推出来。DistFlow潮流方程在使用时要注意一个前提适用于辐射状网络。而主动配电网重构恰恰要求最终拓扑必须是辐射状所以这和重构约束是天然匹配的。如果网络存在环DistFlow的递推关系就不成立这也是为什么大多数配电网优化文献都直接用DistFlow。2.2 二阶锥松弛的数学原理与MATLAB实现现在来说最核心的松弛。支路潮流中的原始等式是[ P_{ij}^2 Q_{ij}^2 L_{ij} U_i ]这个等式把支路功率、电流和节点电压耦合在一起非凸。二阶锥松弛把它替换成不等式[ P_{ij}^2 Q_{ij}^2 \leq L_{ij} U_i ]然后利用旋转锥形式等价写成[ \left| \begin{bmatrix} 2P_{ij} \ 2Q_{ij} \ U_i - L_{ij} \end{bmatrix} \right|2 \leq U_i L{ij} ]这样做以后模型里不再有“平方等于乘积”的非凸等式而是变成一系列“一个向量的二范数小于等于另一个线性表达式”的凸约束。Mosek、Gurobi、SDPT3等求解器对这类约束都有原生支持求解效率非常高。在MATLAB中YALMIP提供了非常友好的锥约束接口不需要手动做二阶锥变换。代码写起来非常直接% 每条支路的二阶锥约束 for k 1:nBranch i branch(k, 1); j branch(k, 2); Constraints [Constraints, cone([2*P(k); 2*Q(k); U(i) - L(k)], U(i) L(k))]; end这里的cone(x, y)就是 (|x|_2 \leq y)。YALMIP会自动把约束传递给求解器。需要注意U(i) L(k)也就是y必须是线性表达式U和L不能有非线性项所以在建模时不要把L(k)再乘上某个变量。2.3 故障场景建模与辐射状约束故障在模型中不是一个特别复杂的部分但要处理得干净。故障支路可以预先设为一个强制断开的开关状态并在该支路的潮流约束上做特殊处理。比如支路2-3故障那么直接固定z(i)0同时用大M约束把该支路的功率强制为0。这种方式的好处是模型统一不需要单独改写潮流方程。辐射状约束是重构模型里最容易翻车的地方。单纯要求“闭合支路数等于节点数减1”不够因为可能出现“多个不连通子图但各自无环”的情况。所以工程上常用虚拟流量法想象每个恢复供电的负荷节点需要消耗1个单位虚拟流量变电站根节点产生虚拟流量每条闭合支路上虚拟流量单向流动断开支路虚拟流量为0。这样如果网络中有两个不相连的环虚拟流量一定无法同时满足所有节点的消耗约束就会被打破。这个方法本质上是一种松弛的单商品流约束优点是它是一组线性约束非常容易被求解器处理。在实现时虚拟流量变量f(k)也需要跟随开关状态支路断开时f(k)0闭合时可以让f(k)在0到较大值之间变化。由于有向变量和节点功率平衡方程方向有关建模时要小心流量方向约定我习惯把支路起点设为潮流上游终点为下游虚拟流的方向也与此一致。2.4 目标函数与权重设计目标函数直接决定了重构结果会偏向什么。最常见的目标包含失电负荷最小和网损最小。如果只追求恢复负荷总量有可能为了一个很大的普通负荷而牺牲了某条线路上的重要用户。所以项目中常给不同节点配上加权系数 (w_i)把失电功率写成[ \sum_{i} w_i \cdot (1 - \alpha_i) \cdot P_i^D ]其中 (\alpha_i) 表示该节点是否成功恢复供电。权重设计可以根据负荷类型、用户等级、停电损失等因素制定。比如医院、数据中心的权重可以设为5或10普通居民区设为1次要农业负荷设为0.5。这样求解器会优先恢复重要负荷。网损项在目标中建议用支路电流平方乘电阻也就是 (r_{ij} L_{ij})而不是用P^2Q^2除以电压的形式否则目标函数中会出现非线性项也会给求解带来额外压力。把网损作为次要目标乘以一个较小的系数例如 (\lambda0.1)这样既不会影响恢复负荷的主目标又能让结果在多个可行方案中偏优。3. MATLAB代码实现与求解流程3.1 环境准备与求解器配置这个项目的代码依赖MATLAB、YALMIP以及一个支持二阶锥规划的求解器。YALMIP是一个免费的MATLAB建模工具箱在网上就能下载安装方法很简单把整个文件夹加入MATLAB路径运行一下yalmip的install脚本即可不涉及复杂配置。求解器方面我强烈建议优先使用Mosek或Gurobi。它们对混合整数二阶锥规划支持很完善求解速度快数值稳定性也好。如果实验室没有商业求解器授权可以找学术授权用起来也方便。免费备选方案是SDPT3或SeDuMi它们在纯连续SOCP问题上还行但一旦遇到0-1整数变量求解速度会成倍下降33节点系统可能就要等很久所以不推荐作为主要求解器。配置完成后可以用一个很小的测试模型快速验证环境是否正常建立一个简单的锥约束比如 (|x|_2 \leq 1)查看求解器能否正常返回。3.2 数据准备IEEE 33节点算例我平时做配电网重构验证最常用的是IEEE 33节点标准算例。不过为了演示方便下面用简化的数据结构说明。MATLAB中可以用数组保存支路信息每一行是[起点终点电阻R电抗X初始状态故障标志]。节点信息则保存负荷有功和无功。例如% branch格式: [from, to, R, X, closed, fault] branch [ 1 2 0.0922 0.0470 1 0; 2 3 0.4930 0.2511 1 0; 3 4 0.3660 0.1864 1 0; ... 8 21 0.3410 0.5362 1 0; % 联络开关 ]; % bus负荷: P_load, Q_load Pload [0; 100; 90; 120; ...]; Qload [0; 60; 40; 80; ...];故障场景设置示例faultBranch 3; % 假设支路3故障 branch(faultBranch, 5) 0; % 强制断开在实际项目中我通常把网络参数封装成一个结构体方便后续变量索引。用结构体mpc保存节点和支路信息代码可读性会高很多。这里为了篇幅用简单数组演示读者自己实现时可以根据需要调整。3.3 核心建模代码与约束组装这里给出一个完整的YALMIP建模骨架。先定义决策变量nBus size(bus, 1); nBranch size(branch, 1); z binvar(nBranch, 1); % 支路开关状态1闭合0断开 alpha binvar(nBus, 1); % 节点是否恢复供电 P sdpvar(nBranch, 1); % 支路有功 Q sdpvar(nBranch, 1); % 支路无功 U sdpvar(nBus, 1); % 节点电压平方 L sdpvar(nBranch, 1); % 支路电流平方 f sdpvar(nBranch, 1); % 虚拟流然后组装约束。首先固定根节点电压rootIdx 1; Constraints [Constraints, U(rootIdx) 1.02^2];接下来是功率平衡约束。为了方便我用了一个辅助函数getInOut根据branch数组生成每个节点的注入支路索引和流出支路索引。这里不展开函数实现核心是保证所有支路功率方向与潮流方向一致for j 1:nBus inIdx find(branch(:,2) j); outIdx find(branch(:,1) j); if ismember(j, genBus) Constraints [Constraints, sum(P(inIdx)) - sum(P(outIdx)) alpha(j)*Pload(j) - Pg(j)]; else Constraints [Constraints, sum(P(inIdx)) - sum(P(outIdx)) alpha(j)*Pload(j)]; end end注意这里没有直接写“支路断开功率为0”的等式而是用开关变量通过大M约束强制M 1e5; Constraints [Constraints, -M*z P M*z, -M*z Q M*z];接着是电压降落约束。当支路闭合时上下游电压满足DistFlow方程支路断开时这个关系不再成立所以使用大M把等式放宽for k 1:nBranch i branch(k,1); j branch(k,2); r branch(k,3); x branch(k,4); Constraints [Constraints, U(j) U(i) - 2*(r*P(k) x*Q(k)) (r^2 x^2)*L(k) (1-z(k))*M]; Constraints [Constraints, U(j) U(i) - 2*(r*P(k) x*Q(k)) (r^2 x^2)*L(k) - (1-z(k))*M]; end然后是二阶锥约束和电压上下限for k 1:nBranch i branch(k,1); Constraints [Constraints, cone([2*P(k); 2*Q(k); U(i) - L(k)], U(i) L(k))]; end Constraints [Constraints, 0.95^2 U 1.05^2, U 0, L 0];辐射状约束用虚拟流实现。这里需要约定方向每条支路的起点为上游虚拟流最大的值为闭合支路数相关所以用M做上限即可Constraints [Constraints, -M*z f M*z]; for j 1:nBus inIdx find(branch(:,2) j); outIdx find(branch(:,1) j); if j rootIdx Constraints [Constraints, sum(f(inIdx)) - sum(f(outIdx)) -sum(alpha)]; else Constraints [Constraints, sum(f(inIdx)) - sum(f(outIdx)) alpha(j)]; end end这一段等式的含义是非根节点每恢复一个单位就必须收到一个单位的虚拟流根节点则相应流出所有节点的虚拟流总和。这个技巧很经典理解之后可以用于各种辐射状配网优化问题。目标函数与求解如下weight ones(nBus, 1); % 可自定义权重 lambda 0.1; Objective sum(weight .* (1-alpha) .* Pload) lambda * sum(branch(:,3) .* L); ops sdpsettings(solver, mosek, verbose, 2); sol optimize(Constraints, Objective, ops);求解完成后取结果zopt round(value(z)); alphaopt round(value(alpha)); Popt value(P); Qopt value(Q); Uopt value(U);这里要提醒一句value返回的是数值但整数变量在数值误差下可能得到0.9999所以用round取整再参与后续分析和显示。3.4 求解结果整理与指标计算求解完之后不要直接跳到可视化先把几个关键指标算出来后面分析才有依据。失电负荷总量可以这样计算lostPower sum((1 - alphaopt) .* Pload); recoverRate 1 - lostPower / sum(Pload);网损则通过支路电流平方乘电阻汇总loss sum(branch(:,3) .* Lopt);开关操作数可以对比初始状态和重构后状态统计有多少支路的开关状态发生了翻转switchChange sum(abs(zopt - branch(:,5)));这三个指标几乎可以覆盖绝大多数重构方案的评价维度。如果要发文章还可以加一个“电压越限节点数”的指标这些数据在后面的可视化报告里也很实用。4. 可视化展示与结果分析4.1 配电网拓扑绘制从数据到图可视化听起来是锦上添花但对这个项目来说是刚需。模型求解完之后如果只是看一堆变量根本没法确认结果对不对。我一般第一步先把网络拓扑画出来用颜色和线型区分开关状态。最简单的画法是用MATLAB的graph对象G graph(branch(:,1)1, branch(:,2)1); fig figure; p plot(G, Layout, force); axis off;不过force自动布局每次运行都会变不方便对比。我用得更顺手的方式是给节点提前设好坐标xy再配合plot画线for k 1:nBranch if zopt(k) 1 line([xy(branch(k,1),1) xy(branch(k,2),1)], ... [xy(branch(k,1),2) xy(branch(k,2),2)], Color, b, LineWidth, 1.5); else line([xy(branch(k,1),1) xy(branch(k,2),1)], ... [xy(branch(k,1),2) xy(branch(k,2),2)], Color, r, LineStyle, --); end end把故障支路用更粗的红色线条单独高亮把恢复路径用绿色粗线绘制这样一次图就能看清故障在哪里、恢复到哪里、哪些开关被断开了。我建议在论文或报告里直接使用这样的图比一张大表格更直观。4.2 重构前后对比图怎么摆更有说服力很多读者拿到的可视化结果是三个子图并列故障前、故障隔离后、重构恢复后。这个做法很朴素但非常有效。用subplot(1,3,1)等可以并排展示多个状态。关键是要让三个子图中网络布局保持一致才能看出拓扑变化。所以节点坐标必须固定不能让MATLAB自动重排。在每个子图下方标注当前状态的统计指标比如带电节点个数、负荷恢复率、网损值。这样评审人或导师一眼就能看出重构效果。对比图的信息量非常大远比只画一张最终网络图更有说服力。4.3 电压分布图与负荷恢复可视化电压分布是判断重构方案是否安全的核心指标。求解后Uopt实际上是电压幅值平方要画电压幅值需要开方V sqrt(Uopt); bar(0:nBus-1, V); yline(0.95, --r); yline(1.05, --r);用bar或plot stairs都可以。我习惯用带数据点的折线图因为能直接看出哪个节点电压最低。在主动配电网中电压问题往往比潮流过载更常触发边界所以这个图对结果验证非常重要。负荷恢复情况可以用饼图或者堆叠柱状图展示figure; pie([recoverLoad, lostLoad], {已恢复负荷, 未恢复负荷});如果节点权重差异大也可以按失电量加权展示这样更贴合实际停电损失。4.4 结果分析表格模板为了把方案讲清楚我习惯在代码最后自动生成一张汇总表内容类似指标故障前故障隔离后重构恢复后带电节点数331832负荷恢复率100%40%97%网损 (kW)202.597.1142.3最低电压 (p.u.)0.9680.9520.961这张表配合拓扑图基本就是一篇完整技术报告的核心内容。具体数值需要根据实际算例运行得到但表格结构可以直接套用。5. 常见问题与实操心得5.1 求解器报错与收敛问题排查用YALMIP调用求解器最常遇到的是Mosek error: primal infeasible或者Gurobi error: unbounded。这两类问题九成是模型本身出了问题不是求解器的问题。第一件事是检查变量范围。电压平方U是否设置了下限如果某个节点电压平方被允许降到0潮流约束可能无法满足导致不可行。第二件事是检查大M约束M值太大会破坏数值稳定性太小又会错误地把可行解排除掉。我会先用1e4到1e5之间试如果求解报数值问题就改用1e3。第三件事是检查功率平衡特别是根节点注入功率有没有上限没有上限时模型可能为了让某个节点恢复而不惜提高根节点出力这是允许的但如果根节点功率受线路容量约束需要确认线路容量是否足够。如果求解时间太长优先检查是不是整数变量太多。33节点的开关变量加节点恢复变量大概有60多个0-1变量对Gurobi和Mosek来说问题不大。如果扩展到上百个节点可以考虑加初始解或者用热启动。YALMIP可以给assign初始值一定程度上能提升求解速度。5.2 辐射状约束失效的坑我之前第一次写这个模型时只加了一个“闭合支路数等于节点数减1”的约束结果画出来的拓扑出现了多个环。后来补上虚拟流约束才解决问题。这里有一个排查技巧求解后把zopt传给graph然后运行cyclebasis或者直接画图看有没有环。如果没有环但还有孤立节点说明连通性约束没写对。虚拟流约束的方向是重灾区。我在这里踩过坑把inflow和outflow算反了导致等式变成了负数求解器直接不可行。建议用一个小网络比如5个节点手算每个节点的虚拟流方向先验证约束表达式对再扩到33节点。5.3 可视化调试的独门经验给节点设定固定坐标时如果节点数较多手工排布坐标很累。我的做法是先跑一次自动布局然后把得到的xy坐标保存下来手动微调后再固定使用。这样既省时又能保证图形可读性。另一个经验是颜色不要用太多。故障支路用红色、闭合支路用蓝色、恢复路径用绿色、断开支路用灰色虚线超过四种颜色就会显得乱。可以在图例中写清楚不要靠颜色暗示。此外建议把所有关键数据写在图上比如“恢复率97.3%”“网损142.3 kW”这样做成报告时非常加分。MATLAB的text或annotation都能做到。5.4 模型扩展方向与后续优化这个模型做出来后扩展路径很清晰。第一加入储能系统用连续变量表示充放电功率同时增加SOC状态转移约束重构就升级成“故障恢复与储能调度”联合问题。第二考虑多时段重构故障期间每个时段可以有不同的DG出力和负荷需求模型需要变成多时段MISOCP结果更有工程意义。第三考虑DG出力不确定性用鲁棒优化或机会约束这需要引入分布鲁棒等高级方法但基础模型不变。如果只是给课堂作业或项目答辩做展示把上述可视化做丰富一些再附加敏感性分析比如改变负荷水平、DG出力最大值观察恢复率变化曲线效果就非常好了。最后说一点个人体会。二阶锥松弛在主动配电网重构里并不是什么玄学它就是一种很“实用主义”的数学工具面对非凸问题与其硬碰硬不如找到一种既能保持精度、又能被高效求解器处理的松弛方式。但建模时最费时间的通常不是SOCP本身而是辐射状约束、0-1变量和潮流约束的耦合调整。我建议每一个做类似项目的人都先花时间把节点坐标和拓扑图准备好然后在写约束的同时不断可视化验证而不是等模型跑完再画图。模型收敛的那一刻看到重构后的拓扑图清晰地展示出失电区域恢复、电压曲线平稳那种满足感是值得的。希望这份笔记能帮你少踩一些我踩过的坑。