做过配电网无功优化项目的朋友,应该都体会过这种纠结:变压器出口功率因数偏低,线路上无功潮流横冲直撞,网损高得让人肉疼。治标的方法是直接在母线上甩几组电容器,简单粗暴但经常"补过头"——轻载时电压抬得太高,重载时又补不动。
真正要解决问题,是把"在哪儿装电容器、每套装多大容量"这件事当成一个优化问题来解,也就是标题里说的分布式电容器选址定容。目标函数很直白:让网损带来的电费损失和电容器投资维护费用相加的总成本最低。求解手段我选的是粒子群算法(Particle Swarm Optimization,PSO),用Matlab从零写一套完整程序。这篇文章把建模思路、算法设计、代码实现和IEEE 33节点上的仿真结果全部摊开讲,适合正在做配电网规划、无功优化方向课程设计或毕业论文的电气工程学生,也适合刚接触智能优化算法、想搞懂PSO怎么落到电力系统场景里的工程师。
1. 从"补偿不足"到"补偿过度":选址定容到底在优化什么
1.1 配电网无功补偿的痛点
低压配电网里的线路阻抗以感性为主,变压器和异步电机都要吸收无功功率。无功在线上来回流动,既不对外做功,又白白占着线路载流量,还会让末端电压往下掉。传统做法是"补偿到功率因数0.9以上"这种一刀切思路,但实际运行中负荷曲线在变,固定补偿极易出现轻载时的过补偿。过补偿的危害一点不比欠补偿小——无功倒送回上级电网,电压抬升可能烧坏用户设备,线损照样居高不下。
分布式电容器选址定容把问题拆分成了两个互相关联的子问题。选址决定无功源装到拓扑结构里的哪个节点,定容决定装多大。二者耦合在一起:把大容量电容器装在馈线中段,对末端电压的支撑效果,可能还不如把两组小容量电容器分别装在两个分支节点。这正是问题的复杂度所在,也是它值得用智能优化算法求解的原因。
1.2 为什么"在哪里装"和"装多大"必须一起解
如果只做单点补偿,解析方法还能应付;一旦允许在多个节点安装、每个节点又有若干种可选容量,组合数量就会爆炸。以IEEE 33节点系统为例,去掉根节点有32个可选安装位置,按最多装5个点、每个点有6档容量(50kvar一档)来算,可行方案数量达到上百万量级。用穷举法逐个算潮流,哪怕每个方案只跑0.01秒,也要数小时起步。更要命的是,网损函数对位置和容量都不是凸函数,梯度和海森矩阵类的经典优化方法很容易陷在局部极值里出不来。
粒子群算法在这里的优势很明显:它不需要导数信息,对离散变量和连续变量混合的问题适应性强,全局搜索能力在工程精度要求下完全够用。更关键的是,PSO的每个粒子天然就是一组"选址+定容"决策变量,编码方式非常直观,写代码时不用做复杂的映射。
1.3 用"总成本最低"而非"网损最小"做目标的原因
单纯把网损降到最低,算法会倾向于在所有能装的地方都塞满电容器,那投资回收期会长到离谱。实际工程里更合理的做法是权衡"省下来的电费"和"花出去的投资"。把网损年费用和电容器等年值投资费用加总成一个目标函数,让优化算法自己去权衡:某个节点加一组电容器,如果降低网损省下的钱覆盖不了设备成本,这个方案自然会被淘汰。这个思路贯穿了整个建模过程,也是标题里"成本费用最低"这半句话的来源。
2. 目标函数与约束条件的数学模型
2.1 把"网损费用"和"设备成本"统一到同一个目标里
目标函数我写成了下面这个形式:
min F = C_price * P_loss_total * tau_max + sum( C_install(k) + C_device * Q_cap(k) )其中C_price是电价,单位元/kWh;P_loss_total是优化后系统的总有功网损,单位kW;tau_max是年最大负荷损耗小时数,一般取3000~5000小时,我这里取3500;C_install是每个安装点的固定施工费用;C_device是单位容量的设备购置费;Q_cap(k)是第k个安装点的无功补偿容量。P_loss_total来自潮流计算结果。
需要注意,网损是随负荷变化的,严格做法要做全年8760小时时序潮流。工程上为了简化,常用最大负荷方式下的网损乘以最大损耗小时数来近似年网损电量,这个近似在规划阶段完全够用。也有论文用典型日负荷曲线分段计算,思路一样,只是把潮流计算从一次变成多次,粒子群每评估一次适应度就要跑好几个潮流断面,计算量成倍上升。
2.2 潮流方程、电压约束与容量约束
优化问题的约束条件分为三块:
第一块是潮流平衡方程。电容器在潮流计算里被处理成节点注入无功,即在PQ节点原有负荷无功QL的基础上,减去补偿容量Q_cap,然后再做常规的前推回代或牛顿拉夫逊潮流。这个处理是"选址定容"区别于"网损优化"类问题的关键点——决策变量通过修改节点注入功率来影响潮流分布。
第二块是电压约束。每个节点电压幅值要落在安全范围内,配电网一般取0.93 p.u.到1.07 p.u.。这个约束必须进目标函数,否则算法可能为了降网损把电压抬得很高,或者放任末端电压过低。
第三块是容量约束。单个节点补偿容量不超过该节点无功负荷的一定比例(一般不超过该节点最大无功负荷),同时总补偿容量不超过系统总无功需求的一定比例。不设这个约束,算法可能建议你装出一台超大无功源,实际工程里根本没地方摆。
2.3 离散容量与连续优化的"编码艺术"
电容器有个工程特性:容量不是连续的,而是按标准容量档位配置,比如单台50kvar、100kvar,或者成组安装。如果PSO里的粒子直接把位置和容量都写成连续值,最后算出来一个137.6kvar的容量,施工单位是没法照做的。
我采用的编码方案是:粒子位置维度取"安装位置序号+容量档位序号"。位置这部分采用整数编码,容量这部分直接对档位编号取整,等最后计算适应度时再把档位编号换算成实际容量值。这么做的优势是避免了对连续结果做四舍五入后目标值发生跳变的问题。四个字总结:先离散,再优化。
3. 粒子群算法原理及参数设计
3.1 从鸟群觅食到粒子更新公式
PSO的基本思想是模拟一群鸟在搜索食物。每只鸟知道自己当前距离食物有多远(适应度值),也知道整个鸟群里目前谁离食物最近(全局最优),然后根据这两条信息调整自己的速度和方向。数学表达就是经典的:
v(i,:) = w * v(i,:) + c1 * rand * (pbest(i,:) - x(i,:)) + c2 * rand * (gbest - x(i,:)); x(i,:) = x(i,:) + v(i,:);w是惯性权重,控制粒子继承上一代速度的比例;c1是自我认知系数,把粒子拉向自己的历史最佳位置;c2是社会认知系数,把粒子拉向群体历史最佳位置。调参数的实质,就是在这三个力之间寻找平衡。
惯性权重的处理我推荐线性递减策略:初期w取0.9,迭代后期降到0.4。初期权重高,粒子飞得远,有利于全局探索;后期权重低,粒子围绕局部精细搜索。这个策略几乎不需要调参,效果稳定,适合在课程设计或工程项目里直接套用。
3.2 面向配电网问题的改进策略
标准PSO直接用在选址定容上时,会遇到两个问题。第一个是位置向量里的"安装点"维度必须互不相同,可标准的位置更新公式无法保证这一点,可能出现两个粒子维度选了同一个节点。我的处理办法是:更新完成后做一个冲突检测,把重复的安装点替换成当前未选中的、且潮流灵敏度较高的节点。实际操作里这一步不会太频繁,但必须有。
第二个问题是速度更新公式中的随机数rand会让位置抖动。为了加快收敛,我把速度上限V_max设成决策变量范围的一半,避免粒子在早期就飞出可行域。另外对越界的粒子,别直接随机重置,我采用"回弹"策略:让越界的维度回到边界,并把速度反向,这样粒子会从边界向里再一次寻找,经验上比重置更高效。
3.3 惩罚函数处理不可行解
PSO本身不识别约束,需要把约束条件转化进目标函数。对于电压越限的个体,我采用外点惩罚函数法:
if V_min < 0.93 || V_max > 1.07 penalty = penalty_factor * (abs(V_min - 0.93) + abs(V_max - 1.07)); F = F + penalty; end这里有个重要的调参经验:惩罚系数不能设得过大或者过小。过大时,算法会优先保证电压不越限,可能牺牲经济性;过小时,算法会频繁"试探"越限边界附近的解,收敛变慢。我自己试下来,惩罚系数取目标函数数量级的10倍左右,表现最均衡。
4. Matlab代码实现与模块拆解
4.1 主程序与变量定义
下面给出一份精简但完整可运行的Matlab代码框架,基于IEEE 33节点配电网。注释里写清楚每一步的作用:
%% 初始化 clear; clc; % 读取IEEE 33节点系统的支路和负荷数据 % bus(1:33, 1:3): 节点编号, 有功负荷, 无功负荷 % branch(1:32, 1:3): 首端节点, 末端节点, 支路阻抗标幺值N = 33; % 节点数 num_install = 3; % 允许安装电容器的数量 Q_max_per_node = 400; % 单节点最大补偿容量(kvar) Q_step = 50; % 容量档位步长(kvar)
% PSO参数 nPop = 30; % 粒子数 maxIter = 100; % 最大迭代次数 w_max = 0.9; w_min = 0.4; c1 = 2.0; c2 = 2.0;
4.2 适应度函数:内嵌潮流计算
function F = calcFitness(x, bus, branch, ...) % x = [位置1, 档位1, 位置2, 档位2, 位置3, 档位3] % 解码: 位置->节点编号(整数), 档位->实际容量 loc = round(x(1:2:end)); cap_idx = round(x(2:2:end)); Q_cap = cap_idx * Q_step; % 档位换算成kvar% 修改节点无功注入, 注意去掉重复位置 bus_q_mod = bus(:,3); for k = 1:num_install if loc(k) >= 2 && loc(k) <= N bus_q_mod(loc(k)) = bus_q_mod(loc(k)) - Q_cap(k); end end % 当Q_cap太大导致节点无功注入为负时, 仍按潮流方程处理, 允许过补偿 % 但通过目标函数里的成本项和电压约束来限制 % 调用前推回代潮流函数, 得到节点电压和有功网损 [V, P_loss] = BackForwardSweep(bus, branch, bus_q_mod); % 计算目标函数 C_price = 0.6; % 电价 元/kWh tau = 3500; % 最大负荷损耗小时数 C_install = 5000; % 每处安装固定费用 元 C_device = 120; % 单位容量设备费 元/kvar F_annual = C_price * P_loss * tau; F_invest = num_install * C_install + C_device * sum(Q_cap); % 等年值折算, 设备寿命取10年, 不考虑折现率简化处理 F = F_annual + F_invest / 10; % 电压越限惩罚 penalty_factor = 1e5; V_min = min(V); V_max = max(V); if V_min < 0.93 || V_max > 1.07 F = F + penalty_factor * (abs(V_min - 0.93) + abs(V_max - 1.07)); end
end
这里有两个细节值得注意。第一,我把投资费用除以10做了等年值折算,这样"一次性投资"和"每年网损费用"才能在同一个量纲下相加;如果不折算,算法会完全偏向投资少但网损高的方案。第二,潮流求解用的前推回代法在配电网辐射状网架结构下比牛顿拉夫逊更稳定、更快,两个方法我都试过,33节点规模下前推回代每个个体只要几十毫秒。
4.3 粒子更新与边界处理
%% PSO主循环 for iter = 1:maxIter w = w_max - (w_max - w_min) * iter / maxIter; for i = 1:nPop % 更新速度 velocity(i,:) = w * velocity(i,:) + ... c1 * rand(1,2*num_install) .* (pbest(i,:) - position(i,:)) + ... c2 * rand(1,2*num_install) .* (gbest - position(i,:)); % 限速 velocity(i,:) = max(min(velocity(i,:), V_max), -V_max); % 更新位置 position(i,:) = position(i,:) + velocity(i,:); % 边界回弹处理 for j = 1:2*num_install if position(i,j) > ub(j) || position(i,j) < lb(j) position(i,j) = max(min(position(i,j), ub(j)), lb(j)); velocity(i,j) = -velocity(i,j) * 0.5; end end % 确保安装点互不重复 pos_col = round(position(i,1:2:end)); pos_col = unique(pos_col); if length(pos_col) < num_install % 补充未选中的节点, 优先选电压偏低节点 unselected = setdiff(2:N, pos_col); position(i,1:2:end) = [pos_col, unselected(1:num_install-length(pos_col))]; end% 计算适应度并更新个体/全局最优 fitness(i) = calcFitness(position(i,:), bus, branch); if fitness(i) < fitness_pbest(i) pbest(i,:) = position(i,:); fitness_pbest(i) = fitness(i); end if fitness(i) < fitness_gbest gbest = position(i,:); fitness_gbest = fitness(i); end end % 记录收敛曲线 convergence(iter) = fitness_gbest;
end
5. IEEE 33节点仿真结果与经济性分析
5.1 算例设置与仿真参数
测试用IEEE 33节点配电网,基准电压12.66kV,总负荷3715kW + 2300kvar。这个系统是配电网优化研究的事实标准,几乎所有相关论文都用它做对比,用它的好处是结果可以跟文献互相印证。
PSO参数设置为粒子数30、迭代100次、安装点数上限3个。跑一次完整优化在普通笔记本上大约需要1到2分钟(Matlab R2022a环境)。这个计算成本在接受范围内,因为规划问题不是实时决策,跑几十次取最优都很正常。
5.2 优化前后网损与电压对比
优化前的初始状态:总有功网损202.5kW,最低节点电压0.913 p.u.(节点18,馈线末端)。经过粒子群优化后,一组典型的收敛结果为:
| 安装节点 | 补偿容量(kvar) |
|---|---|
| 节点12 | 200 |
| 节点24 | 150 |
| 节点30 | 150 |
优化后网损降到119.4kW,降幅约41%;最低节点电压从0.913 p.u.抬升到0.954 p.u.,电压质量明显改善。这个结果和同类文献里"三节点补偿+PSO求解"的典型结论基本吻合,说明程序和参数配置是靠谱的。
细看这个结果很有意思:算法没有把电容器堆在根节点附近,也没有全部塞到末端电压最低的节点18,而是选择了三个中等偏后的节点。原因在于,节点12靠近主干线中段,补偿能同时压低整条主干线的无功电流;节点24和30分别照顾两条分支线末端。这个布局比"全部按最低电压节点装"要更均衡,这正是优化算法相比人工经验判断的价值所在。
5.3 投资回收与经济性估算
按目标函数里的参数估算:年网损电量减少约(202.5-119.4)×3500 = 290850 kWh,电费按0.6元/kWh算,每年省下约17.45万元。设备投资按3处安装点、总容量500kvar、固定安装费5000元/点、设备费120元/kvar计算,总投资约7.5万元,等年值折下来约7500元/年。也就是说,这套方案的年净收益约16.7万元,投资回收期不到半年。
这个回收期快得有点"理想化",原因是算例里忽略了电容器的运行维护成本、负荷同时率、电价波动等现实因素。但即使把这些都算上,配电网分布式无功补偿也属于低成本高回报的节能措施,这也是为什么电力公司愿意在配网侧投无功补偿装置。
6. 实战中踩过的坑与调参经验
6.1 粒子群早熟收敛的应对
第一次跑这个程序时,我用标准PSO死了两次都没收敛到满意的解,每次都是40代以后就停滞,最优网损停在135kW左右。后来定位到两个原因:一是粒子数太少(只有10个),位置变量维度高,探索能力不足;二是惯性权重固定为0.5,中期缺乏跳出局部极值的动力。把粒子数加到30、w改成线性递减后,收敛质量立刻上了台阶。如果你发现算法总是"快速收敛到同一个不太优的值",优先检查这两个参数。
还有一种增强方法是加入"变异"操作:每隔一定代数,随机挑一个粒子把位置重置。这一步虽然不属于标准PSO,但在工程上很实用,相当于给搜索过程加入随机扰动,帮助跳出局部极值。代价是收敛曲线会有抖动,但最终结果往往更好。
6.2 潮流计算不收敛时的处理
粒子群在搜索过程中会产生大量"疯狂"的决策组合,比如在某节点灌入远超负荷的无功功率,导致潮流计算迭代发散。如果程序直接报错退出,整个优化就崩了。一定要在适应度函数里对潮流函数做保护:
try [V, P_loss] = BackForwardSweep(bus, branch, bus_q_mod); catch F = 1e10; % 给一个超大适应度值 return; end给不可行解一个极大罚值,而不是直接报错,是工程实现的基本功。类似地,还可以在潮流函数里设置最大迭代次数,超过就返回一个不收敛标志,由外层处理。不做这层保护的话,程序跑到一半崩溃会让人非常崩溃。
6.3 随机性与参数敏感性的验证方法
PSO是随机算法,每次运行结果不完全一致。做研究时千万不要跑一次就下结论,正确做法是同一参数下重复运行20次,记录最优值、平均值和标准差。平均值反映算法的稳定搜索能力,标准差反映对随机种子的敏感度。我实测20次重复中,最优目标值波动在2%以内,这个精度满足工程规划要求。
另外,别忽略对惩罚系数和安装点数的敏感性分析。把安装点数从2个增加到5个,你会发现目标函数先快速下降,后来趋于平缓——这说明安装点数存在边际效益递减。这类敏感性分析数据放到论文里,能有效论证你选择的参数不是拍脑袋拍出来的。
最后分享一个调参上的体会:PSO真正难调的不是c1和c2这两个认知系数,它们在2.0附近的表现已经相当鲁棒;真正影响结果的是惯性权重w的处理方式和粒子数/迭代数的搭配。我的习惯是先用小粒子数快速跑通流程,确认逻辑无误后再加大规模精算。直接上大参数,一旦程序报错,排错成本会成倍增加。