做配电网无功优化这个课题的时候,我最初以为就是把调度系统里的无功补偿模块“升级一下算法”而已。结果真正把风电和光伏的出力曲线塞进潮流计算之后,才发现问题比预想麻烦得多——单一方向潮流的假设完全不成立,固定电容器在分布式电源大发时段反而成了累赘,电压越限从馈线末端一路蔓延到中部。这篇文章把我从数学模型搭建、多目标粒子群优化算法(MOPSO)落地,到Matlab里跑通整套仿真的过程完整梳理一遍,重点说清楚每个环节的取舍理由,以及我在调参和工程实现中踩过的坑。内容覆盖主动配电网实时无功优化的建模思路、算法设计、代码框架和算例分析,适合正在做配电网新能源接入、分布式电源优化控制课题的研究生和工程师参考。
1. 风电光伏并网后的无功电压矛盾:为什么要做实时优化
1.1 传统配电网的补偿思路为什么开始失效
传统配电网本质上是单电源辐射状网络,变电站出口到各馈线末端的潮流方向非常明确,永远是从高压侧流向低压侧。无功补偿的思路也相对固定:在变电站母线装并联电容器,在重载的长馈线中段和末端装固定电容器组,按最大负荷方式离线整定,一次配置后基本不再调整。
这套方案在只有负荷、没有电源的配电网络里是行得通的,因为电压降落的方向固定,末端电压最低,把补偿容量放在末端效果最直接。但风电光伏接入后,情况完全变了。
光伏在午间大发时,馈线中段和末端的用户负荷往往处于低谷,分布式电源出力超过本地负荷的部分会沿着馈线倒送回变电站,潮流方向彻底反转。这时候末端电压不是降低,而是被抬高。固定电容器还在按设计容量补着无功,叠加倒送的有功功率,形成的电压抬升幅度非常可观。我实测过一组数据:某10kV馈线光伏渗透率超过40%后,晴日正午部分节点电压接近额定值的1.045倍,而按照传统方案配置的固定电容器组投着没有任何感知,问题持续到傍晚负荷增长才缓解。
1.2 “实时”二字的工程含义
实时无功优化不是每秒钟都在跑优化算法,而是要有分钟级到小时级的滚动决策能力。光伏出力受云层遮挡影响,可以在几分钟内从满发跌到20%以下;风电出力波动幅度更大,尤其阵风情况下,就地电压和无功功率需求都在快速变化。
如果沿用日前优化给出的无功补偿计划,就会出现“计划跟不上变化”的尴尬场景:早上基于天气预报制定的电容器投切方案,到了中午光伏实际出力比预测高出一大截,结果是电压越限持续几个小时,只能靠人工调度救场。我最初做这个项目时也想偷懒,直接用日前预测数据算一次全天方案,结果对照实际出力曲线一仿真,电压合格率只有89%,这个数字直接让我老老实实做实时优化。
所以这里说的实时优化,本质上是反复进行的短周期滚动优化:以最新的超短期预测数据和实时量测数据为输入,在满足设备动作次数约束的前提下,给出未来一个控制周期内的无功设备调控指令。典型控制周期是15分钟到1小时,分钟级气象预测更新就重新算一轮。控制周期太短,设备动作频繁,设备寿命和运行可靠性都会受影响;控制周期太长,又跟不上风电光伏的波动节奏。
1.3 主动配电网的“主动”到底体现在哪里
主动配电网和传统配电网的核心区别,在于接入的分布式电源、无功补偿设备以及有载调压变压器(OLTC)都可以由调度端主动协调控制,而不是被动地等待保护动作或依赖就地定值。
这个转变带来两个直接影响。第一,控制变量变多了:分布式光伏逆变器,可以在容量允许范围内发无功;风电机组,也能通过变流器调节无功出力;再加上传统电容器组和OLTC,可调手段从单一的电容器投切扩展到了多类型设备协同。第二,协调难度变大,因为连续变量和离散变量混在一起,目标之间还存在此消彼长的关系,这直接决定了后面的建模和算法选型。
我在建模型之前花了挺多时间琢磨一件事:控制变量到底有哪些、各自的时间尺度和动作约束是什么。这个问题想清楚了,后面公式和代码都好写。
2. 优化模型的数学化过程:目标函数、决策变量与约束条件
2.1 以网损和电压偏差为双目标的数学表达
标题里“以网损和……”这半句话,落点就是网损最小化和电压质量最优化两个目标。我最终采用的目标函数如下。
目标1:系统总有功网损最小化。
$$P_{loss} = \sum_{i,j \in \Omega} G_{ij} (U_i^2 + U_j^2 - 2U_i U_j cos\theta_{ij})$$
目标2:节点电压偏差最小化。
$$V_{dev} = \sum_{k=1}^{N} \left|\frac{U_k - U_{ref}}{U_{ref}}\right|$$
两个目标存在明显的冲突关系:为了把网损压到最低,可能需要把某些节点电压推到靠近上限的位置;为了让所有节点电压都贴近额定值,又可能牺牲一部分网损经济性。这就是典型的多目标优化问题,直接加权合并会丢失Pareto前沿上很多有价值的中间解,所以后面才会引入多目标粒子群算法。
2.2 决策变量:连续与离散混合的实际困难
建模阶段最需要花心思的是决策变量。我把控制变量分成了三类:
- 分布式光伏逆变器无功出力 Q_PV,连续变量,受逆变器视在容量和当前有功出力的双重约束;
- 风电机组无功出力 Q_WT,连续变量,同样要满足容量圆约束;
- 电容器组投切档位和OLTC变压器分接头档位,离散变量。
连续变量和离散变量混在一起,直接带来两个问题。第一,粒子群算法的位置更新公式天然适合连续空间,离散变量需要做取整处理;第二,离散变量动作频次有严格限制,投切次数多了设备检修周期大幅缩短,这在目标函数里必须体现出来,否则算法会把所有电容器当成无成本资源随意操作。实际工程里,一组10kV电容器一年动作次数超过几百次就会出现明显的机械疲劳问题。
2.3 约束条件的完整清单
实时无功优化模型需要同时满足以下约束。
- 潮流等式约束:各节点有功、无功必须满足潮流平衡方程;
- 节点电压上下限约束:UL ≤ Ui ≤ UU,我按配电网运行规程取0.95和1.05(标幺值),内部可以再留5%的裕度;
- 逆变器无功能力约束:-√(S²-P²) ≤ Q ≤ √(S²-P²),其中S是逆变器额定容量,P是当前有功出力,这意味着光伏有功发得越多,可调无功空间越小;
- 离散设备动作次数约束:单个控制周期内,电容器组和OLTC动作次数不超过预设上限;
- 分布式电源功率因数约束:一般要求在0.95(超前)到0.95(滞后)之间,这也是并网规程的硬性要求。
我把约束条件写成清单贴在代码注释的第一行,后面每次改模型都对照着检查一遍。说实话,这个步骤看起来不起眼,但极大减少了我后期调debug的时间。
3. 多目标粒子群算法的选型逻辑与核心实现
3.1 为什么选了MOPSO而不是其他算法
做多目标优化,主流的算法路线就那几条,我逐一试过之后才确定用多目标粒子群算法。
先说加权求和法。把两个目标按固定权重合并成单目标,理论上最简单,但有两个致命缺点:一是权重需要反复试,而且对解的质量影响很大;二是一次运行只能得到Pareto前沿上的一个点,想得到完整前沿需要跑很多次不同权重。实时场景下显然不合适。
再说非支配排序遗传算法。效果公认不错,Pareto解的分布性也很好,但实现代码量很大,非支配排序和拥挤度计算的开销也不小,在我的测试环境下一轮优化要跑到一两分钟,实时性过不去。
最后说MOPSO。它继承了粒子群算法实现简洁、收敛速度快的特点,Pareto机制通过外部档案和网格法就可以实现,代码量比NSGA-II少一大截,计算时间也基本能控制在十几秒以内。对于33节点这个规模的配电网算例,完全够用。
3.2 MOPSO的三个关键机制:外部档案、领导选择、多样性保持
MOPSO相比单目标粒子群算法,核心改动在三个地方。
第一是外部档案。每次迭代结束后,把当前所有粒子的非支配解存入一个外部档案集合,如果新解支配档案中的部分解,就把被支配的解剔除;如果存在互相不支配的解,则保留在档案中,形成对Pareto前沿的逼近。
第二是全局最优领导者的选择。单目标PSO中全局最优是唯一的全局最优解,多目标情况下不存在这个“唯一”,要由算法决定每个粒子跟着谁飞。我采用的是网格法:把目标空间划分为若干个网格,统计每个网格中的解数量,密度越低的网格被选中的概率越高,以此保持解的分散性。
第三是多样性保持。每次向档案中添加新解时,如果档案已满,就删除拥挤程度最高网格中的解,为覆盖稀疏区域的解腾出空间。
这三个机制缺一个都不行。我最初实现时偷懒,领导选择直接用档案随机抽,根本没有密度惩罚,结果跑了50次迭代Pareto前沿后段一直残缺,越往后解的分布越差。换成网格法之后才算稳定。
3.3 编码设计与约束处理的处理思路
粒子位置向量需要把连续和离散变量统一编码。我采用的做法是:
x = [Q_PV_1, ..., Q_PV_NPV, Q_WT_1, ..., Q_WT_NWT, N_C_1, ..., N_C_NC, T_OLTC]
其中连续变量直接取实际无功出力标幺值,离散变量(电容器组数和OLTC档位)在速度更新后做取整处理。取整过程要特别注意边界越限问题,我的处理方式是sigmoid函数映射到合法档位区间后按四舍五入取整。
约束处理我用了罚函数加修复策略的两层方案。对于潮流等式约束和电压上下限约束,采用罚函数项加到目标函数中,让越限严重的粒子在Pareto排序中被自然淘汰;对于逆变器无功能力约束,在更新后用投影法修复,把超界的无功出力直接拉回容量圆边界。实测下来这个组合比单纯罚函数法收敛快得多,因为投影修复能防止粒子在不可行区域浪费大量迭代次数。
4. Matlab仿真框架搭建:从潮流计算到算法闭环
4.1 算例系统与场景数据准备
仿真算例我选用了标准33节点配电网系统,这是一个在配电系统研究里被反复验证的经典算例:母线电压等级10kV,包含33个节点、32条支路,初始负荷数据完整。风电和光伏的接入位置我分别选在长馈线中段17号节点和末端32号节点,这两个位置对电压分布的影响最有代表性。
负荷曲线和新能源出力曲线是实时优化仿真的输入。我把一天分成96个时段,每15分钟一个控制周期。光伏出力采用晴天典型曲线,早6点开始爬坡,12点达到峰值,18点后衰减到零;风电出力采用长时间尺度的波动曲线,最大值约0.8(标幺值),最小值约0.2。负荷曲线按典型居民和商业混合负荷形状生成,晚高峰出现在19点到21点。
这些基础数据不需要实测,按典型曲线形状生成即可,重点是让优化算法在不同场景下都能验证有效。
4.2 核心代码结构:主循环与适应度函数
Matlab里最核心的衔接点,是粒子群算法每更新一次粒子位置,就要调用一次潮流计算来评价目标函数。我的主程序结构如下:
%% 主程序:MOPSO实时无功优化 % 初始化参数 nPop = 60; % 粒子数 MaxIt = 100; % 最大迭代次数 nVar = nPV + nWT + nC + 1; % 决策变量总数 % 初始化粒子群 for i = 1:nPop particle(i).x = InitParticle(nVar); particle(i).v = zeros(1, nVar); particle(i).f = Evaluate(particle(i).x, netData, scenData); end % 主循环 for it = 1:MaxIt w = wMax - (wMax - wMin) * it / MaxIt; % 惯性权重线性递减 for i = 1:nPop % 更新速度与位置 particle(i).v = w * particle(i).v ... + c1 * rand * (particle(i).pBestX - particle(i).x) ... + c2 * rand * (gBest.x - particle(i).x); particle(i).x = particle(i).x + particle(i).v; % 离散变量取整与边界修复 particle(i).x = RoundAndRepair(particle(i).x); % 目标函数评估 particle(i).f = Evaluate(particle(i).x, netData, scenData); % 更新个体最优与外部档案 [particle(i).pBest, rep] = UpdateArchive(particle, rep); end end适应度函数是整个仿真闭环的核心,它把粒子位置分解为具体的控制指令,执行潮流计算后返回两个目标值和罚函数结果:
function [f1, f2] = Evaluate(x, netData, scenData) % 解析决策变量 Qpv = x(1:nPV); Qwt = x(nPV+1:nPV+nWT); CapacitorOn = x(nPV+nWT+1:nPV+nWT+nC); OLTCtap = x(end); % 组装含分布式电源的潮流数据 [P_loss, V] = PowerFlow(netData, scenData, Qpv, Qwt, CapacitorOn, OLTCtap); % 目标1:有功网损 f1 = P_loss; % 目标2:电压偏差 f2 = sum(abs(V - 1.0)); % 罚函数:电压越限、动作次数越限 f2 = f2 + lambda_volt * sum(Violation(V)); f2 = f2 + lambda_act * sum(Violation(ActionCount)); end前推回代潮流函数我单独封装,输入是网络参数、当前负荷和分布式电源出力,输出节点电压和各支路功率,这样算法部分不用关心潮流细节,也方便后续替换成其他潮流计算方法。
4.3 实时性的工程取舍与加速手段
实时无功优化的一个核心指标是单轮优化耗时。我在33节点系统上,用60个粒子、100次迭代,Matlab环境下单轮耗时大约12秒到18秒,这个速度对于15分钟控制周期来说完全充裕。
如果接入的配电网规模更大,比如100个节点以上,可以做的优化有两个方向。第一个是潮流计算改用前推回代法的稀疏矩阵版本,减少重复计算;第二个是粒子群并行化,Matlab的parpool并行池可以把60个粒子的适应度评估分散给多个worker并行跑。
我还做过一次实验,把粒子数从60降到40,计算时间缩短了35%,但Pareto前沿质量明显变差,最优网损和最小电压偏差都变大了。这说明粒子数不能为了省时间无脑削减,算法参数和计算资源之间需要仔细权衡,这个我在第6章专门展开。
5. 算例测试与结果分析:多场景下的网损与电压改善效果
5.1 测试场景与算法参数设定
为了验证实时优化在不同运行工况下的有效性,我设计了三个典型场景:
- 场景A:晴天大风,光伏出力高且风电出力波动大,对应午间时段;
- 场景B:阴天微风,光伏出力低,风电出力平稳,对应下午时段;
- 场景C:晚间无光,风电出力中高,负荷处于晚高峰。
三个场景覆盖了电压越上限风险最高、电压越下限风险最高以及负荷重导致网损最突出的三种典型工况。算法参数统一设定为粒子数60、最大迭代100次、惯性权重从0.9线性递减到0.4、学习因子c1和c2均取1.5。
5.2 优化前后的关键指标对照
我把每个场景优化前后的结果整理成了表格,对比网损、最低电压、最高电压和电压合格率四项指标。
| 场景 | 项目 | 优化前 | 优化后 | 改善幅度 |
|---|---|---|---|---|
| 场景A | 有功网损(kW) | 156.4 | 121.9 | 22.1% |
| 场景A | 最低电压(p.u.) | 0.958 | 0.971 | 1.36% |
| 场景A | 最高电压(p.u.) | 1.032 | 1.019 | 降1.26% |
| 场景A | 电压合格率 | 93.8% | 99.6% | 5.8% |
| 场景B | 有功网损(kW) | 98.7 | 86.2 | 12.7% |
| 场景B | 最低电压(p.u.) | 0.967 | 0.982 | 1.55% |
| 场景B | 电压合格率 | 96.2% | 99.8% | 3.6% |
| 场景C | 有功网损(kW) | 203.8 | 152.3 | 25.3% |
| 场景C | 最低电压(p.u.) | 0.933 | 0.960 | 2.89% |
| 场景C | 电压合格率 | 91.4% | 99.1% | 7.7% |
从结果看,网损降低最明显的是晚高峰重负荷场景,电压改善最明显的是光伏大发场景。这符合物理直觉:重负荷时网损基数大,优化空间自然大;光伏大发时主要矛盾是电压抬升,通过逆变器吸收无功、调整OLTC档位就能快速把电压拉回来。
5.3 Pareto前沿的典型形态与决策方法
多目标优化跑出来的不是单一解,而是一组Pareto前沿。以场景A为例,最终得到的前沿在网损和电压偏差两个目标之间呈现明显的此消彼长趋势:最小网损解在121.9kW附近,但电压偏差较大;最平缓电压解电压偏差很小,但网损会上升到138.5kW附近。
工程中要从这组解里选一个落地执行,我常用的决策方法是距离理想点最近原则。具体做法是:把两个目标归一化后,找目标空间里到原点距离最近的解作为最终控制方案。这个方法不需要人为给权重,决策过程客观,而且实现起来就是一行代码。
5.4 与单目标优化的对比实验
为了验证多目标优化的必要性,我做了一组对比:只用网损最小作为单目标,粒子群算法跑同样场景,得到的最优网损是119.6kW,比多目标折中解的121.9kW低约2%,但对应最低电压只有0.952p.u.,直接越限。
这说明如果只盯着网损,算法会把电压推向边界“压榨”网损收益,结果根本不可运行。实时无功优化的目标必须考虑电压质量的约束或目标,多目标框架恰恰能把这个权衡过程显式化,让运行人员根据实际需求挑选合适的运行点。
6. 参数调优与工程落地中的几个关键心法
6.1 粒子数与迭代次数:实时计算的平衡方案
粒子数和迭代次数的选择,本质上是计算时间和解质量之间的权衡。我在33节点系统上的实测经验是:粒子数达到50之后,再增加粒子数对Pareto前沿质量的提升就有限了;迭代次数超过100次之后,粒子群基本收敛,继续迭代只是在最终前沿附近小幅波动。
一个我在调参时常用的判断方法是画收敛曲线。每次迭代结束后记录外部档案中最优解的目标函数变化,如果连续20代没有明显改进,说明算法已经收敛,可以提前终止。我实测最优情况下大约85代就可以收敛,把最大迭代次数设为100刚好留了余量。
6.2 离散设备动作次数约束的罚函数设置
电容器组和OLTC分接头的动作次数,直接决定设备寿命,这个约束漏掉会出大问题。我最初几次仿真,算法给出的优化方案里同一台电容器一夜之间投切了七八次,这在实际现场是不允许的。
我的做法是在适应度函数的罚函数项里加动作计费惩罚:统计每个控制周期内电容器组和OLTC相对上一周期的动作次数,超过设定上限(比如单周期内电容器最多动作2次、OLTC最多操作1次)的部分,按超出次数乘一个较大的惩罚系数累加到目标函数中。实测中惩罚系数取500到1000时效果最好,太小约束不住,太大会把解集整体推向不动作区域,反而失去优化的意义。
6.3 实时闭环里的三个细节坑
第一个坑是风电光伏出力预测误差直接传导到优化结果。我用超短期预测数据做优化,到了执行时段实际出力和预测差很多,优化方案自然失效。后来我在闭环里加了执行前的量测校验环节,如果实际出力偏差超过15%就立即触发新一轮优化,保证控制指令始终贴合真实运行状态。
第二个坑是逆变器无功能力被忽略。光伏满发时逆变器几乎把容量都用在了有功上,可调无功空间非常小,如果模型里想当然地给逆变器分配大量无功任务,结果就是根本无法执行。我在代码里专门加了容量圆约束的实时计算,光伏有功越高,允许的无功范围越窄,这个逻辑必须显式建模。
第三个坑是OLTC动作与电容器动作的时序协调。变压器分接头调节影响全局电压,电容器组影响局部电压,两者如果同一时刻动作,可能互相抵消甚至造成振荡。我在优化后处理阶段加了一条控制规则:优先调节逆变器无功,其次电容器组,最后才是OLTC,这样既保证响应速度,也减少开关设备动作。
6.4 我对这套方案的整体体会与扩展方向
整套项目做下来,最大的体会是多目标优化的价值不在于找“唯一最优解”,而在于给运行人员提供一组直观的权衡方案,让调度决策从“拍脑袋”变成“有依据”。后续如果要往工程化方向走,可以考虑两个扩展:一是把储能充放电策略纳入决策变量,和光伏风电配合实现更长时间尺度的优化;二是接入短期负荷预测模块,让实时优化方案具备更强的预判能力。
最后分享一个小技巧:在Matlab里调试MOPSO时,我习惯把每轮迭代得到的外部档案解集单独保存成结构化数据文件,跑完后再统一可视化。这样即使中间某一次仿真参数乱了,原始数据还在,可以直接回放Pareto前沿的变化过程,排查问题比只看最终结果高效得多。这个习惯帮我解决了好几次莫名其妙的收敛异常问题,值得保留下来。