☰
基于二阶锥规划的配电网无功优化:IEEE33节点Matlab实现详解
2026/10/21 8:50:35 网站建设 项目流程

配电网无功优化这个题目,很多做配网规划或者刚接触电力系统优化的同学应该都不陌生。我在某实验室做分布式电源接入研究时,最开始拿到的课题就是“基于二阶锥规划的配电网无功优化算法”,算例用的是IEEE33节点系统,工具是Matlab。这个组合在科研和工程验证里非常经典:IEEE33节点是配电网最常用的标准算例,二阶锥规划(SOCP)是近年求解配电网优化问题的主流方法,而Matlab加上Yalmip建模工具箱,可以大大缩短从数学模型到可运行代码的距离。

这篇文章我想把这套东西从头到尾拆开来讲。不光是告诉你代码怎么写,更想讲清楚几个容易被忽略的点:为什么要做无功优化、为什么选二阶锥而不是传统非线性规划、IEEE33节点数据怎么整理、建模时哪些约束必须保留、求解器报错又该怎么排查。无论你是要复现论文、做毕设,还是准备把这套方法迁移到实际馈线上,这篇文章应该都能让你少走一些弯路。

1. 项目整体思路与技术选型

1.1 无功优化到底在优化什么

先聊一个基础问题:配电网为什么要做无功优化。很多初学者会把“无功优化”理解成纯粹降低网损,其实它做的事情更综合:通过调节无功电源和无功补偿设备的出力,让全网电压保持在合理范围内,同时尽可能降低网络损耗。

配电网的特点是R/X比值大,也就是线路电阻相对于电抗来说更明显,这导致有功功率在线路上流动时会产生较大的电压降落,而无功功率对电压的影响也非常灵敏。如果馈线末端接了大量负荷,而没有任何无功补偿,末端电压很容易跌破允许下限,网损也会同步上升。加装电容器组、接入分布式电源并让它们参与无功调节,本质上是就地平衡无功,减少无功在长线路上的“长途运输”,这是在配电网层面最经济、最有效的电压治理手段之一。

用IEEE33节点算例来说,这个系统本身是辐射状网络,无功不足时末端节点电压通常会跌到0.93标幺值左右,网损也比较大。通过无功优化,把末端节点的电容器组投切量和分布式电源无功出力当作决策变量,就可以在满足潮流方程和电压约束的前提下,找到一个网损最小的运行点。目标函数一般是网损最小,当然也可以根据需求加电压偏差项、无功补偿成本项,形成多目标优化。

1.2 为什么选二阶锥规划而不是传统方法

配电网无功优化在数学上本质是非线性、非凸的优化问题。传统做法是用潮流方程直接代入,然后用内点法这类非线性规划求解器去解,但这种方法有几个痛点:一是初值敏感,给定的初始点不好可能收敛不到全局最优;二是求解速度不稳定,网络规模一大,计算时间上升得很快;三是非凸问题很难保证解的最优性,做研究写论文时说服力不够。

二阶锥规划的优势在于,它把原本非凸的潮流方程通过变量替换和凸松弛,转化为一组二阶锥约束,整个问题就变成了凸优化问题。凸优化最重要的性质是局部最优就是全局最优,而且求解算法成熟,计算效率高。现在主流的配电网优化研究,不管是无功优化还是网络重构、分布式电源定容选址,很多都会优先考虑SOCP或者SDP松弛。

SOCP和SDP(半定规划)都属于凸优化,但SOCP在配电网里更受欢迎。原因很直接:SDP的变量是半定矩阵,对配电网这种大网络来说内存占用大、求解速度慢;而SOCP是把每个支路潮流单独建立锥约束,问题规模更小、结构更清晰,配合现代求解器处理起来非常快。IEEE33节点这种规模的系统,从建模到求解通常只需要几秒。

1.3 为什么用IEEE33节点来验证

IEEE33节点系统可以说是配电网研究里的“小白鼠”,几乎每个做配网的人都跑过这个算例。它由33个节点、32条支路构成,有5条联络开关支路,正常运行时候联络开关是打开的,系统保持辐射状。基准电压12.66kV,总负荷大概在5083.26 kW加2546.32 kvar。系统本身电压水平偏低,无功补偿之后效果又特别明显,非常适合用来验证算法。

选这个算例还有一个实际原因:它的参数是公开的,所有研究者用的都是同一组数据,你算出来的网损、节点电压可以跟别人的论文对齐。我当时复现时特别看重这一点,因为论文里说“网损降低13.5%”,我用同样的数据和约束,应该能复现出接近的结果。如果差得太多,往往是约束条件或者目标函数写法和原文不一致,而不是算法本身有问题。

2. 核心建模过程与数学原理

2.1 DistFlow方程与二阶锥松弛的由来

配电网SOCP建模的基础是DistFlow支路潮流方程。它的核心思想是在辐射状网络中,每条支路的潮流可以用首端有功、无功和末端电压来描述。写成通俗的形式就是三条方程:

第一条描述有功功率的平衡:流过某条支路末端的有功功率,等于首端注入有功减去线路上的有功损耗,再减去该节点负荷消耗的有功。

第二条描述无功功率的平衡:同理,末端无功等于首端无功减去线路无功损耗和节点无功负荷。

第三条描述电压降落关系:末端节点电压的平方,等于首端电压平方减去线路电阻和电抗上的“压降”项。

直接写成这些方程时,里面带有电流平方项、电压平方项,是典型非线性项。标准做法是引入变量替换:用U表示电压幅值的平方,用y表示电流幅值的平方。这样改写之后,前两条有功无功平衡方程就变成线性方程了,电压降落方程也变成线性关系。

问题出现在最后一个关系上:电流平方与有功无功之间存在一个等式约束,形式上是y等于(P平方加Q平方)除以U,这个约束会造成非凸。二阶锥松弛的核心就是把这里面的等式关系松弛成不等式,同时用二阶锥约束的形式表达。通俗说,原本物理上要求电流平方必须严格等于某个数值,现在我们放松为“至少达到”或者“不超过某数值”,在数学上把这个可行性域从一个非凸曲线变成凸锥。

2.2 目标函数与约束条件的取舍

目标函数我通常选择网损最小,表达式就是所有支路的电阻乘以该支路电流平方的总和。在引入变量y之后,这个目标变成了线性函数,求解起来非常友好。

如果还想兼顾电压质量,可以在目标函数里加一个惩罚项:各节点电压偏离参考值的平方和再乘以一个权重系数。这种做法在工程上很常见,因为只求网损最小的时候,求解器可能会把电压推到接近限值的边界上,得到的结果“经济”但并不“健康”。加了电压偏差项之后,解会更均衡一些。

约束条件方面,下面几类是必须写进去的:

  • 潮流约束:即上面说的DistFlow方程和锥约束,保证任何一组解在物理上可行。
  • 根节点电压约束:变电站母线电压通常是固定值或给定上下限,这决定了整个馈线的电压基准。
  • 节点电压上下限:配电网一般要求0.95到1.05标幺值之间,算例中也可以适当放宽到0.93到1.07。
  • 支路电流上限:线路能承载的容量有限,这个约束对应y的上限。
  • 无功源的出力范围:分布式电源无功出力受逆变器容量限制,电容器组投切量也有最大最小值限制。

一个值得讨论的取舍是电容器组的处理。实际电容器是分组投切,变量是离散的,完整建模要做混合整数二阶锥规划MISOCP,求解难度更高。如果阶段目标是把优化框架跑通,我建议先把电容器容量当作连续变量处理,等流程验证无误后,再把连续结果就近取整成离散档位,或者再用整数变量做一次精确求解。

2.3 分布式电源和电容器组的模型处理

IEEE33节点算例本身不包含分布式电源,需要手动接入。我常用的做法是在18、22、25等末端电压偏低的节点上接入光伏或风机模型,单台容量一般取300到500kVA,逆变器容量限制其视在功率,因此无功出力就有一个随有功变化的范围。

光伏和风机在潮流计算里通常是PQ节点,有功由外界条件决定,无功可以根据优化需要在允许范围内调节。更精细的模型会考虑功率因数约束,比如功率因数限制在0.95到1之间,这时无功有一个超前的上限。给定了这些范围之后,分布式电源的无功出力就成为一个连续决策变量,优化器会决定它在每个时刻应该发无功还是吸收无功。

电容器组我一般放在馈线末端,比如节点18、33,容量根据该节点负荷的无功需求来选。如果节点无功缺口在300kvar左右,电容器组就选三组各100kvar。连续化建模时,只需要定义这个变量在0到300kvar之间;离散化建模时,则可以定义三个0/1变量来控制投切。

3. Matlab实现过程与关键细节

3.1 数据准备与程序结构

拿到IEEE33节点系统之后,第一件事不是写代码,而是先把数据整理好。我的做法是把节点参数和支路参数各存成一份矩阵,方便后面索引。节点参数包括节点编号、有功负荷、无功负荷;支路参数包括首端节点、末端节点、电阻、电抗、是否有联络开关。

跑优化之前还要确定基准值:电压基准12.66kV,功率基准10MVA。把有名值换算成标幺值之后,数据的数值范围会落在0.001到10之间,这是求解器最喜欢的尺度。如果直接拿欧姆值和瓦值去算,潮流结果可能因数值病态而无法收敛。

程序结构上我会分四块:

  1. 参数初始化脚本:定义网络参数、基准值、约束上下限、DG和电容器位置及容量。
  2. 模型构建脚本:用Yalmip定义变量、写约束和目标函数。
  3. 求解脚本:设置求解器选项,调用optimize函数求解。
  4. 后处理脚本:把结果还原成有名值,计算网损、电压,画图。

整个计算流程是:首先初始化数据和变量,然后逐条支路构造DistFlow约束,再对每个节点构造功率平衡约束,加入DG出力上下限和电压约束,设置目标函数,最后调用求解器。对IEEE33来说,约束数量很小,性能完全不是问题。

3.2 用Yalmip建模的思路与关键代码

Yalmip是一个Matlab建模层,它可以屏蔽底层求解器的差异,让你用接近数学语言的方式写优化模型。对配电网SOCP建模来说,Yalmip最大的优势是能直接写二阶锥约束,不需要手动把问题转换成求解器需要的标准格式。

变量的定义很直接:

% 支路有功、无功、电流平方,按支路数定义 P = sdpvar(32, 1); Q = sdpvar(32, 1); I2 = sdpvar(32, 1); % 节点电压平方,按节点数定义 U = sdpvar(33, 1);

DistFlow三条方程分别对应三条约束,我习惯用for循环逐条支路写:

constraints = []; for k = 1:32 i = branch(k, 1); % 首端节点 j = branch(k, 2); % 末端节点 r = branch(k, 3); x = branch(k, 4); % 有功平衡:节点j注入上级支路的有功 + 本地负荷消耗 constraints = [constraints, P(j) == P(i) - r * I2(k) - load_P(j)]; % 无功平衡 constraints = [constraints, Q(j) == Q(i) - x * I2(k) - load_Q(j)]; % 电压降落 constraints = [constraints, U(j) == U(i) - 2*(r*P(i) + x*Q(i)) + (r^2 + x^2) * I2(k)]; % 二阶锥约束 constraints = [constraints, norm([2*P(i); 2*Q(i); U(i) - I2(k)], 2) <= U(i) + I2(k)]; end

这段代码里的二阶锥约束是核心。它的物理含义是:电流平方必须大于等于由有功无功和电压决定的数值,同时通过锥的形式保证凸性。目标函数和约束写好后,只需要一行调用求解器:

objective = sum(r_all .* I2); ops = sdpsettings('solver', 'sedumi', 'verbose', 2); result = optimize(constraints, objective, ops);

有一点要特别提醒:上面的代码是核心思路示意,具体运行时需要根据全局变量编号做调整,因为负荷和支路功率的关系取决于你对支路方向的统一约定。我自己的习惯是把所有支路方向统一为从根节点指向末端节点,这样在循环里首末端不会搞反。

3.3 求解器选择与结果后处理

在Matlab里跑SOCP,求解器是关键一环。Yalmip自带的接口可以调用多种求解器,我比较常用免费的开源求解器主要有两类:一类适合中小规模问题,稳定性和精度都不错;另一类则是商业求解器,在更大规模、混合整数问题上有明显优势。如果你手头有商业求解器许可证,可以直接在sdpsettings里替换求解器名称,代码不需要做其他改动。

求解完成之后,结果还是标幺值,需要做后处理。我从value()函数取出所有变量的数值,然后把节点电压还原成有名值:电压幅值等于sqrt(U),再乘以基准电压12.66kV。网损则把所有支路电阻乘以电流平方结果加总,再乘以基准功率10MVA,得到实际网损。优化前和优化后的网损做个减法,就能算出来降损率。

画图一般是看两个关键结果:优化前后的节点电压曲线,以及DG和电容器组的无功出力柱状图。IEEE33系统优化后的典型结果是:末端节点电压从0.93左右提升到0.98以上,网损下降幅度通常在10%到30%之间,具体数字取决于DG接入位置和容量、电压上下限的取值。

4. 常见问题与排查技巧实录

4.1 模型不收敛或求解器报错怎么处理

我第一次跑这个模型的时候,求解器直接返回了“Infeasible problem”,整个模型不可行。后来排查发现是节点负荷数据发生了偏差,一个负荷值没有换算成标幺值直接填了进去,数值直接大了10倍,导致电压越限。这种问题最简单的排查方法,是不管目标函数,只做可行性校验,也就是把目标函数设成0,看约束本身能不能找到可行解。

另一类常见问题是锥约束写法不对。Yalmip对二阶锥约束有比较严格的要求,norm()里面的向量维度和左右项必须匹配。如果你少写了括号或者把维度搞错,求解器会报约束格式错误。这种时候我建议逐条支路输出约束表达式,用size()函数检查一下每一行的维度是不是符合预期。

求解器本身也可能出问题。如果开源的求解器安装不正确或者路径没配置好,Yalmip会提示找不到求解器。我一般会在Matlab里运行yalmip('clear')和checkyalmip(),确认所有求解器都正常。如果用的是商业求解器,还要留意许可证是否到期。

还有一个很容易被忽略的点:Yalmip的变量类型定义。sdpvar定义的是连续变量,binvar定义的是0/1变量。如果不小心把电容器组投切变量定义成sdpvar但后面又给它设置整数约束,会导致模型里有非线性等式,求解器直接报错。这种情况需要统一改成binvar重新建模。

4.2 结果不合理或松弛不紧怎么处理

有时求解器成功返回了最优解,但节点电压曲线出现一个明显的“跳变”,或者电流平方变量并不满足等式关系,这说明二阶锥松弛出现了“间隙”,也就是松弛不紧。配电网SOCP松弛不紧的情况在多数标准算例里很少见,但接入大量DG、重负荷场景下可能发生。

处理松弛不紧密问题的第一步,是检查你的目标函数是否愿意把电流平方“往下压”。SOCP松弛之所以在最优解处紧,是靠目标函数引导的:目标函数用电流平方的增函数,优化器才会尽量让电流平方取到锥边界上的最小值。如果目标函数和电流平方无关,或者加了奇怪的惩罚项,松弛自然不紧。

如果目标函数没有问题但松弛间隙仍然比较大,一个经验做法是迭代收紧:先求解SOCP松弛解,然后把锥约束等式化作为惩罚项加入目标函数,得到一个修正后的解。在只做IEEE33这种小规模场景时,我还试过直接用非线性规划求解器,用SOCP的解作为初值,这样收敛速度非常快,松弛间隙问题也可以绕开。

4.3 几个容易踩的细节坑

数据是标幺值还是有名值,这个问题我说多少次都不为过。IEEE33节点数据在资料里通常给的是有名值,节点电压基准是12.66kV,功率基准取10MVA时,100kVA的负荷在标幺值下是0.01,数值很小。如果你不换算直接在模型里使用,潮流约束的数值范围会跨越好几个数量级,二阶锥约束的数值条件会变得很差,求解精度也会下降。

根节点电压也是常被忽略的点。IEEE33系统的根节点是松弛节点,电压一般维持1.0标幺值不变。在模型里要给根节点电压平方赋一个固定的值,不能让它也作为自由变量参与优化,否则整个电压基准就不存在了,优化结果也没有意义。

还有支路方向的问题。我的建议是拿到算例之后,先手动画一张从节点1出发的单线图,把所有支路方向标出来。虽然IEEE33系统结构不复杂,但节点编号并不是严格按从根到末端排列的,写循环时还是容易搞错首末端。我在实际建模时是先把支路矩阵按“首端节点远离根节点”的原则重排一次,确保潮流方向始终是从根节点流向末端,这样后面写约束时逻辑会清楚很多。

5. 结果验证与代码扩展方向

5.1 怎么确认你算的结果是对的

代码跑通之后,先别急着写结论,我强烈建议做一个最简单的验证:设置所有DG和电容器组出力为0,此时模型应该退化成纯潮流计算。用Matlab里传统的潮流计算函数对比一下各个节点的电压幅值,如果SOCP结果和潮流结果一致,说明你的约束写对了。

第二步验证是优化效果的合理性。IEEE33节点系统不加任何补偿时,末端电压一定偏低,网损较大。做完无功优化后,电压曲线整体抬升,网损下降。你可以把算出来的降损率和文献上的结果对比,一般都能对得上。如果对不上,大概率是约束条件中DG容量范围设置不同,或者电压上下限范围设置不同。

第三步验证是参数灵敏度分析。我通常会扫描电容器容量,从0kvar逐步增加到1000kvar,每次记录网损,画一条网损随容量变化的曲线。这条曲线应该呈现先降后升的趋势,因为补偿过度时无功倒送会增加网损。如果曲线单调下降或者单调上升,说明模型中某处潮流方向或者目标函数定义有问题。

5.2 从单时段静态优化到全天96点动态无功优化

IEEE33节点静态无功优化是整个算法框架的“最小闭环”,但工程上往往需要做时间尺度的扩展。分布式电源出力波动性很强,一天内不同时间段的最优解可能差异很大。扩展的方式很直接:把每个时间段当作一个独立的断面,目标函数改为所有断面网损之和,约束中补充相邻时间段之间的电容器组投切次数限制。

这样修改之后,问题就变成一个大SOCP,变量数量是单时段的96倍左右,但对IEEE33节点来说仍然可以求解。如果求解时间变长,可以考虑场景缩减、聚类典型日等方法。我在这块走得比较远,后来还把三相不平衡配电网的无功优化也纳入模型,SOCP的框架同样可以扩展到三相DistFlow,只是约束表达会更复杂一些。

5.3 二阶锥方法在实际工程中的适用边界

聊了很多SOCP的优点,但也要说清楚它的适用边界。二阶锥规划处理辐射状单相配电网时非常稳定,但一旦网络不是严格的辐射状、或者存在多电源环网结构,SOCP松弛的紧性可能会变差。三相不平衡系统中,各相之间的耦合会让锥松弛的精度更难控制,这时候需要考虑更精细的模型。

DG高渗透率场景下,逆变器无功调节能力和电压控制耦合性很强,SOCP解的最优性虽然能保证,但模型本身如果忽略了逆变器实际控制逻辑,计算结果在实际工程中未必可直接执行。我的一个体会是,SOCP更适合做规划层面的工具,用来快速评估不同方案的效果边界,而不是直接作为现场实时控制的决策引擎。实际控制还需要综合通信、量测、设备响应时间等因素,这是另一个层面的事情。

6. 个人经验与最后的建议

做这个项目前前后后折腾了不少时间,踩得最深的一个坑就是在标幺值和有名值之间反复横跳,看着各种奇怪的结果,最后才发现是单位问题。所以我现在拿到任何一个配电网算例,第一件事永远是先把基准值、电压上下限、支路方向捋清楚,再开始写模型。

还有一点小技巧是“分步加约束”。第一次建模时不要一口气把所有约束写完,先只写潮流约束和电压约束,求解一次看看电压曲线是否合理。再把DG和电容器约束加进去,再求解。这样每次报错时,错误的范围已经被压缩得很小。这个习惯帮助我在很多模型上快速定位问题,比直接跑完整模型再一点点排查效率高得多。

最后想说的是,IEEE33节点配合SOCP这套组合非常适合作为配电网优化研究的入门和测试平台。它计算量小,成果容易复现,算法框架通用性又强,做熟了之后换到其他配电网算例,基本上只需要修改网络参数和约束边界。如果你准备做配网方向的研究或工程验证,把这套代码吃透,后续不管是做网络重构、分布式电源规划还是动态无功优化,都会顺很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询