基于粒子群算法的分布式电源选址定容与多目标优化

发布时间:2026/9/9 18:49:09
基于粒子群算法的分布式电源选址定容与多目标优化 做配电网规划的人应该都有这种体会分布式电源DG接入从来不是“多多益善”更不是简单拍脑袋“就近接上”就完事。前两年我给一个园区做光伏接入方案时同样规模的装机容量放到不同的10kV馈线段上对网损和末端电压的影响能差出一个数量级。当时靠试算挨个摸费了不少功夫。后来我把这套逻辑整理成了标准问题——在IEEE33节点配电网系统上用粒子群优化算法同时解决“装在哪个节点”和“每个节点装多大容量”两个决策这就是分布式电源选址与定容。这篇文章就把这个项目的完整思路拆开讲清楚为什么要做多目标优化、IEEE33节点系统有哪些特点、粒子群算法怎么编码才能表达选址定容方案、Matlab代码怎么组织、仿真结果怎么分析以及我实际调参过程中踩过的几个坑。适合电力系统方向的研究生、做配电网规划的工程师以及刚接触智能优化算法与电网计算结合的开发者参考。1. 选址定容问题的本质一个双层耦合的复杂决策1.1 分布式电源接入的“双刃剑”效应分布式电源Distributed Generation, DG接入配电网初衷是就近供电、降低网损、提升供电可靠性。但实际运行中接入位置和容量选得不好效果可能完全反过来——局部电压越限、线路过载、保护配合困难甚至某些时段出现倒送功率。原因在于配电网大多是辐射状结构潮流方向单一DG注入功率会改变网络里的功率分布而这个改变是强非线性的。同一个DG容量接在馈线首端、中段和末端的效果截然不同。接在首端相当于给系统提供了一个“近端电源”对网损改善有限接在末端如果容量适中能大幅托高末端电压、减少长距离输送损耗但如果过了头末端电压直接超过上限连带周围节点全部越限。这正是选址和定容必须捆绑在一起优化的原因——它们互相耦合不能拆开单独决策。1.2 目标函数从单一网损到多维综合评价大多数文献做选址定容时第一目标都是网损最小化因为网损直接对应运行经济性。但只优化网损是不够的电压质量同样关键。DG接入的一个核心红利就是改善电压分布若只盯着网损可能得出一个网损很低但电压偏差很大的方案运行风险很高。所以这个项目把目标拆成三个维度网损最小化衡量DG安装后减少的有功损耗对应运行成本电压偏移最小化让所有节点电压尽可能接近额定值对应电能质量投资经济性最优在满足技术指标的前提下控制DG总装机容量避免过度投资。三者的数学表达如下第一个目标网络有功损耗。采用支路电流法计算[ P_{loss}\sum_{i1}^{N_{br}} I_i^2 R_i ]其中 ( I_i ) 是第 ( i ) 条支路的电流( R_i ) 是支路电阻。这是前推回代潮流计算最容易直接拿到的量不用额外转换。第二个目标电压偏移。用所有节点电压偏离额定值的绝对值之和[ \Delta V\sum_{i1}^{N} \left| V_i - 1.0 \right| ]这里的电压都是标幺值额定值就是1.0 pu。之所以不用最大偏差是因为在某些方案里单个节点电压极差可能不大但整体电压曲线已经普遍偏低用累计偏移能更全面反映电压质量。第三个目标经济性。简化处理为DG单位容量投资与总容量的乘积必要时加上运维成本[ C_{DG}\sum_{i1}^{N_{DG}} c_{inv} \cdot P_{DG,i} ]实际工程中DG类型不同投资差异很大光伏和风电的单位造价、运维成本都不一样。项目代码里通常做成一个可配置的参数方便替换。1.3 多目标之间的冲突没有“完美解”只有“折中解”这三个目标互相打架。想把网损降得特别低往往需要较大的DG容量经济性就变差想把电压抬得很平可能容量的布局偏集中又不利于网损。因此多目标优化的意义不是找一个“样样第一”的方案而是找一组帕累托最优解让决策者在网损、电压、投资之间做权衡。这也是标题里“多目标优化”的意思。很多人看到多目标就以为算法复杂其实核心只在于两点一是目标函数怎么算二是多个目标怎么比较优劣。后者我在第三章详细展开。2. IEEE33节点系统配电网优化最常用的“试验台”2.1 系统拓扑与关键参数IEEE33节点系统是配电网研究里最经典的算例之一由一个33节点、32条支路的辐射状网络组成包含5条联络开关支路正常运行时间断整个系统呈树状结构。基准电压12.66kV基准功率10MVA总有功负荷约3.715MW总无功负荷约2.3Mvar。这个系统的拓扑结构有一个很有意思的特点它既有较长的主干馈线又有若干分支最末端节点18的电压通常在0.90pu左右偏下线运行。这给DG选址提供了天然的“发挥空间”——电压越低的区域接入DG的效果越明显。参数数值节点数33支路数32不含联络开关基准电压12.66 kV基准功率10 MVA总负荷3.715 MW 2.3 Mvar根节点电压1.0 pu初始网损约202.68 kW最低节点电压约0.9038 pu节点18每个节点的负荷数据、支路阻抗数据在相关文献里都有公开数据集Matlab实现时最常用的做法是把支路参数放在一个33×4的矩阵里首端节点、末端节点、电阻、电抗负荷参数放在33×3矩阵里节点号、有功负荷、无功负荷。代码里用loadcase函数或直接赋值读取后面循环调用。2.2 基准状态下的潮流水平优化前必须心中有数跑优化之前先要搞清楚系统不接DG时的基准状态。用前推回代法算一遍会得到两组关键数据。第一组是网损。优化前的线路有功损耗大约在202kW左右这个值占整个系统负荷的比例超过5%在配电网里算比较高的。从网损分布的角度看损耗主要集中在主干线路的后半段——越靠近末端电流虽然变小了但线路长、电阻累积大损耗占比依然可观。第二组是电压分布。节点18的电压最低大约在0.9038pu已经低于0.95pu的常见运行要求。这也是IEEE33系统的典型特征没有无功补偿和DG支撑的时候末端电压不达标。这个“先天不足”刚好用来验证DG接入的电压支撑效果。这些基准数据不是可有可无的背景而是后续结果分析里最重要的对照物。我在第四节会看到所有优化方案的评价本质上都是跟这个“零DG”基准状态做对比。2.3 为什么选IEEE33节点而不是更大的系统有些初学者会问直接用实际馈线不是更有说服力吗问题在于学术研究和算法验证阶段用标准测试系统有不可替代的优势——数据公开、结果可复现、便于横向对比。IEEE33系统的规模也刚好合适。节点数不算多潮流计算速度很快迭代几百次PSO也只需要几秒到几十秒同时它又不是一个“简单”系统——有主干、有分支、电压偏低、网损偏高足以检验算法面对真实配电网特征时的性能。用更大的IEEE69或IEEE118节点模型更复杂但算法原理和代码结构几乎不变只是把参数矩阵换一下而已。所以先在这个系统上把逻辑跑通是性价比最高的做法。3. PSO算法的多目标改造从单个粒子到帕累托前沿3.1 基础PSO一群鸟怎么找到最好的食物粒子群优化算法Particle Swarm Optimization, PSO的灵感来自鸟群觅食。每只鸟在飞行过程中会记住自己找到过的最优位置个体最优pbest同时知道整个鸟群目前找到的最优位置全局最优gbest。下一时刻的飞行方向由三个因素共同决定当前速度、向自己历史最优飞行的趋势、向群体最优飞行的趋势。速度更新公式是[ v_{i}^{t1} w v_{i}^{t} c_1 r_1 (pbest_i - x_i^t) c_2 r_2 (gbest - x_i^t) ]位置更新公式[ x_{i}^{t1} x_{i}^{t} v_{i}^{t1} ]其中 ( w ) 是惯性权重控制粒子保持原来速度的倾向( c_1 )、( c_2 ) 是学习因子分别控制向个体最优和全局最优学习的强度( r_1 )、( r_2 ) 是[0,1]的随机数。这个算法最大的优点是结构简单、参数少、收敛快尤其适合连续变量的优化问题。但遇到多目标优化经典PSO就有点不够用了——单目标PSO只有一个gbest多目标情况下所有粒子往同一个点聚集恰恰破坏了帕累托解的多样性。3.2 粒子编码选址和定容怎么塞进一个粒子这是整个Matlab实现里最容易出错、也最关键的环节。选址是离散决策节点号是整数定容是连续决策容量是实数两种变量混合在一个粒子里。我采用的做法是把粒子位置向量分成两段设要接入的DG数量为 ( d )位置向量前 ( d ) 维表示DG接入节点号取值下限是2节点1是平衡节点不接入DG上限是33位置向量后 ( d ) 维表示每个接入点的DG容量单位kW取值上下限根据约束设定。也就是说一个粒子长这样x [node_1, node_2, ..., node_d, cap_1, cap_2, ..., cap_d]PSO的连续更新之后节点号大概率是小数比如17.6。处理方式很简单——取整。round函数转成整数同时检查边界把超出[2,33]的数值拉回边界内。容量部分保持连续但在计算目标函数前检查是否越限。这里有个小坑取整后可能出现两个DG节点重复。两个DG装在同一节点在物理上等价于一个更大容量的DG但程序里会重复计算导致容量约束判断出错。解决方式有两种要么在解码后做去重处理要么在目标函数里对重复节点加一个惩罚项。我在后面的避坑章节会细讲。3.3 多目标处理的两种路线加权法与帕累托非支配排序这个项目既然叫多目标优化处理多目标的方式是核心。我分别说两条路线并给出推荐。路线一线性加权法。把三个目标乘以权重然后求和转成单目标[ f \omega_1 \cdot \frac{P_{loss}}{P_{loss,base}} \omega_2 \cdot \frac{\Delta V}{\Delta V_{base}} \omega_3 \cdot \frac{C_{DG}}{C_{DG,max}} ]注意括号里的归一化这一点很多人会忽略。网损是百千瓦量级电压偏移是零点零几pu量级投资成本又是百万量级不归一化的话权重设置基本没有意义。归一到基准值之后三个目标都变成0到1左右的量级权重才有实际含义。加权法的优点是实现简单、求解快一次运行就能给出一组确定方案。缺点也明显——权重需要人为指定而权重怎么定本身就是个难题而且很多非凸问题时加权法无法找到帕累托前沿上的所有点。路线二帕累托非支配排序。不把多个目标合成一个而是用“支配”关系来比较解的好坏。一个解A支配解B意思是A在所有目标上都不比B差且至少有一个目标严格优于B。优化过程维护一个外部存档存放当前迭代中所有非支配解最后输出一组帕累托前沿。这种方法能得到一整套折中方案但实现复杂度明显增加需要额外的存档维护策略和拥挤度计算。我在Matlab实现里采用了一个折中策略主循环用加权法快速求解但多次运行并记录不同权重下的最优解近似打出一个帕累托前沿。这样做兼顾了工程可用性和算法透明度。3.4 约束处理让每个粒子都老老实实选址定容问题的约束条件不少处理不当会导致大量不可行解算法直接失效。我按优先级列一下DG容量上下限约束每个接入点的容量不能超过单点最大允许值这是硬约束DG总容量约束所有接入点容量之和不超过总负荷的一定比例防止DG渗透率过高节点电压约束潮流计算后所有节点电压在0.95~1.05pu范围内支路电流约束各支路电流不超过上限。约束处理我用的方法是“修复惩罚”组合。对DG容量这类变量直接修复——超过上限就拉回上限低于下限就拉回下限。对电压和电流这类需要通过潮流计算才能判断的约束用惩罚函数处理——目标函数里加上一个惩罚项越限越严重惩罚越大。惩罚函数的核心逻辑penalty 0; if any(V 0.95) || any(V 1.05) penalty penalty 1000 * sum((V - 1.0).^2 .* (abs(V - 1.0) 0.05)); end注意惩罚系数不能太小否则不可行解有机会“混”进种群干扰收敛也不能太大否则算法优化前期压力过大容易早熟。我实测下来惩罚系数取在1000~5000之间比较合适具体情况要结合目标函数的数量级调节。4. Matlab实现核心模块拆解从潮流计算到迭代主循环4.1 前推回代潮流计算配电网最顺手的潮流算法选址定容的目标函数计算本质上要反复调用潮流计算。配电网是辐射状网络采用前推回代法Backward/Forward Sweep效率和精度都很好比起牛顿-拉夫逊法实现简单得多也不需要求雅可比矩阵。前推回代的基本思想分三步。第一步初始化。所有节点电压设为1.0pu。第二步前推。从网络末端向根节点方向根据各节点注入功率和当前节点电压从末支路开始依次计算每条支路的电流。支路电流等于该支路下游所有节点的注入电流之和递推关系可以写成[ I_{ij}^{(k)} \left( \frac{S_j}{V_j^{(k)}} \right)^* \sum_{m \in children(j)} I_{jm}^{(k)} ]其中 ( S_j ) 是节点j的负荷接入DG后要减去DG注入功率children(j)是节点j的下游子节点集合。第三步回代。从根节点开始根据已知的根节点电压和支路电流沿线路方向逐段计算各节点电压[ V_j V_i - Z_{ij} I_{ij} ]重复前推和回代直到两次迭代的电压差小于阈值比如1e-6或者达到最大迭代次数。DG接入对这个过程的影响只在前推步骤里体现——节点注入功率变成 ( S_j - S_{DG,j} )也就是负荷减掉DG出力。DG按PQ节点处理功率因数设为1只发有功。这是最常用的简化模型如果需要考虑DG的无功调节能力可以把功率因数设成0.9滞后或超前代码逻辑一样只是把无功注入加到节点注入功率里。4.2 PSO主循环与目标函数计算的协作方式整个Matlab程序的组织可以分成三个层次最顶层是PSO主循环负责粒子的初始化、速度位置更新、全局最优更新中间层是目标函数计算函数接收一个粒子的位置向量解码成DG方案调用潮流计算返回三个目标值最底层是潮流计算函数输入网络参数和DG方案输出节点电压和支路电流。核心的PSO主循环代码如下我把注释写详细一点%% PSO主循环参数 N 30; % 种群规模 T 200; % 最大迭代次数 d 3; % DG接入点数量 dim 2 * d; % 粒子维度节点号 容量 w_max 0.9; % 惯性权重上限 w_min 0.4; % 惯性权重下限 c1 2.0; % 个体学习因子 c2 2.0; % 全局学习因子 % 边界定义前d维是节点号后d维是容量(kW) lb [2 * ones(1, d), 50 * ones(1, d)]; % 下界 ub [33 * ones(1, d), 1000 * ones(1, d)]; % 上界 % 初始化粒子位置和速度 x rand(N, dim) .* (ub - lb) lb; v rand(N, dim) .* (ub - lb) * 0.1; % 计算初始适应度 for i 1:N fitness(i) calc_fitness(x(i, :), busdata, branchdata); end pbest x; pbest_fitness fitness; [gbest_fitness, gbest_idx] min(fitness); gbest x(gbest_idx, :); %% 主迭代 for t 1:T w w_max - (w_max - w_min) * t / T; % 惯性权重线性递减 for i 1:N v(i, :) w * v(i, :) c1 * rand(1, dim) .* (pbest(i, :) - x(i, :)) ... c2 * rand(1, dim) .* (gbest - x(i, :)); x(i, :) x(i, :) v(i, :); % 边界修复 x(i, :) max(x(i, :), lb); x(i, :) min(x(i, :), ub); % 节点号取整 x(i, 1:d) round(x(i, 1:d)); % 重新计算适应度 new_fitness calc_fitness(x(i, :), busdata, branchdata); % 更新个体最优 if new_fitness pbest_fitness(i) pbest(i, :) x(i, :); pbest_fitness(i) new_fitness; end % 更新全局最优 if new_fitness gbest_fitness gbest x(i, :); gbest_fitness new_fitness; end end end注意一个细节惯性权重我用了线性递减策略。迭代初期w较大粒子探索能力强能在大范围内搜索迭代后期w变小粒子收敛到局部精细搜索。这个策略实现成本几乎为零但对收敛效果提升明显。4.3 目标函数计算的内部逻辑calc_fitness函数是整个程序的核心。它接收一个粒子位置解码成DG接入方案然后调用潮流计算最后返回归一化加权后的适应度值。function fitness calc_fitness(x, busdata, branchdata) d 3; DG_node round(x(1:d)); % 前d维接入节点号 DG_cap x(d1:2*d); % 后d维DG容量(kW) % DG总容量约束检查总容量不超过系统总负荷的30% max_total_cap 0.3 * sum(busdata(:, 2)); % busdata第二列是有功负荷 if sum(DG_cap) max_total_cap fitness 1e10; % 不可行解给一个极大的适应度值 return; end % 调用前推回代潮流计算传入DG方案 [V, Ploss] forward_backward_sweep(busdata, branchdata, DG_node, DG_cap); % 计算电压偏移 V_dev sum(abs(V - 1.0)); % 计算DG投资成本 cost 5000 * sum(DG_cap); % 假设单位投资5000元/kW % 归一化并加权基准值来自无DG时的计算结果 f1 Ploss / 202.68; f2 V_dev / 1.8; f3 cost / (5000 * max_total_cap); w1 0.4; w2 0.3; w3 0.3; fitness w1 * f1 w2 * f2 w3 * f3; % 电压约束惩罚 if min(V) 0.95 || max(V) 1.05 penalty 2000 * (sum(max(0, 0.95 - V)) sum(max(0, V - 1.05))); fitness fitness penalty; end end电压偏移的归一化基准值1.8我用的是IEEE33系统无DG时所有节点电压偏移之和的近似值实际操作中可以先跑一次基准潮流拿到准确数值再写死在代码里。这样保证每个目标都归一化到1附近权重设置才有意义。5. 仿真结果分析收敛曲线、最优方案与系统改善5.1 算法收敛行为跑50代和跑300代的差距有多大在种群规模30、迭代次数200、DG接入数量为3的条件下程序跑完之后看收敛曲线会有一个比较典型的形状前50代大幅度下降100代之后曲线趋于平缓150代之后基本不再明显变化。但这不意味着150代以后就能停。粒子群是随机算法每一次运行结果都有波动。我通常的做法是同一个参数配置跑10次记录每次的最优值和平均收敛曲线取最优解作为最终方案。如果10次结果的标准差太大说明算法稳定性差优先检查种群规模和惯性权重的设置。一个重要的判断原则是如果收敛曲线在迭代后期还在持续明显下降说明迭代次数不够算法还没收敛到稳定区域如果前20代就完全不动了大概率陷入局部最优。前者的修复是增加T后者的修复是增大种群规模或提高初始惯性权重。5.2 优化前后的网损与电压对比我跑出一组有代表性的结果不同权重设置下结果会有差异这里取均衡权重下的方案优化效果如下表指标无DG基准DG优化后改善幅度网损(kW)202.68约83.5降低约58.8%最低节点电压(pu)0.9038约0.955抬升约0.05电压偏移累计值约1.82约0.75降低约58.8%节点电压对比无DG时电压曲线从节点1到节点18一路下滑末端严重偏低接入DG后电压曲线整体抬高尤其是中后段最低电压点从0.9038pu抬升到0.95pu以上基本满足运行要求。网损改善的机理值得多说两句。DG接入后部分负荷由本地电源直接供给减少了长距离输送的电流线路损耗自然下降。但网损下降不是线性的——DG容量继续增大可能出现局部电流明显增加或者反向潮流反而增加损耗。这也是为什么定容不能简单“装得越大越好”。5.3 不同目标权重下的方案差异我试过三组权重结果很能说明多目标问题的“折中”本质权重方案(w1网损, w2电压, w3成本)最优接入节点总容量(kW)网损(kW)最低电压(pu)(0.6, 0.2, 0.2)18, 17, 32约1800约75.2约0.947(0.2, 0.6, 0.2)18, 16, 31约2100约96.8约0.968(0.33, 0.33, 0.34)18, 17, 30约1700约83.5约0.955可以看到网损权重高时算法倾向于把DG放在对降损最有效的节点容量相对保守电压权重高时算法倾向于加大容量来抬升电压但网损不小。权重怎么取取决于实际工程关注的重点没有绝对正确。这里也体现了一个经验节点18几乎在每次优化里都会入选。这个节点是系统最末端电压最低的位置接入DG的边际效益最大。如果你的程序跑出来最优方案里完全没有末端节点要警惕是不是约束或编码出了问题。6. 调参经验与常见问题排查6.1 种群规模、迭代次数、惯性权重的经验区间很多初学者第一个问题就是参数怎么设。我直接给经验区间参数推荐范围说明种群规模N20~50太小容易早熟太大耗时明显增加迭代次数T100~300200代是性价比比较高的选择惯性权重w0.4~0.9线性递减比固定值收敛更稳定学习因子c1, c21.5~2.5一般取2.0问题不大DG接入数量d2~4超过4个解空间膨胀很快种群规模和迭代次数的配合有个经验法则先跑到100代看收敛曲线如果后期还在明显下降就加到200代、300代。如果150代前就完全平稳再加迭代次数意义不大不如增大种群规模或者多跑几次取最优。6.2 粒子取整带来的重复节点问题这是我在Matlab实现里踩过最深的一个坑。粒子位置更新后节点号取整很容易出现节点重复。比如粒子解码出来的DG节点是[18, 18, 25]两个DG都装在了节点18。重复节点导致的后果有两个一是总容量约束判断时容量被重复计算但物理上两个DG的同址接入会合并成一个DG潮流计算里的“两个18节点”其实只有一个有效容量又没合并就会造成潮流结果异常甚至不收敛二是解的多样性变差重复节点实际上缩小了搜索范围。我的处理方式是在解码之后做一步查重修复。把重复节点中后面的重号随机替换成尚未被选中的节点替换原则是优先选择电压偏低、距离负荷中心近的节点。这个逻辑不算复杂但能显著提高算法的稳定性。function DG_node check_duplicate(DG_node) [~, idx] unique(DG_node); if length(idx) length(DG_node) dup setdiff(2:33, DG_node); DG_node DG_node(randperm(length(DG_node))); end end6.3 潮流不收敛的常见诱因前推回代法在辐射状网络里很稳定但不代表不会出问题。我遇到最多的两种不收敛情况第一种是DG容量过大某个节点电压被抬到1.1pu以上前推回代迭代发散。这种情况一般发生在算法初期随机生成的容量值偏大。解决方法是把初始化范围限制在合理区间比如单点容量上限1000kW总容量上限不超过总负荷的30%。第二种是网络数据本身的问题。IEEE33系统的支路数据有的版本包含联络开关支路如果你的代码把联络支路当成闭合支路参与前推回代网络出现环路算法就会收敛失败。使用数据前务必确认支路矩阵只包含32条正常投运的分段支路联络开关对应的支路要么剔除要么在潮流计算中保持断开状态。6.4 多目标归一化与权重设置的细节如果不做归一化直接加权后果是网损目标百千瓦量级完全主导适应度电压偏移目标0.01量级几乎不起作用。归一化到1附近之后三个目标才能“平等对话”。还有一个细节归一化基准值不要用动态量。如果你的代码每次迭代都重新计算基准值来归一化算法就会不稳定。正确做法是在PSO开始前先跑一次不含DG的基准潮流得到基准网损和基准电压偏移把这两个值固定下来后续所有归一化都用固定值。我做这个项目过程中最深的体会是一套好的选址定容代码算法的地位其实没有想象中那么高模型和数据的管理才是决定成败的细节。粒子群算法本身只是一个搜索框架真正值钱的是目标函数怎么定义、约束怎么处理、参数怎么调。把这些基础工作做扎实哪怕换一个配电网系统代码也能很快迁移过去。如果你现在正在跑这类仿真建议拿一个简单的33节点系统先跑通全流程再逐步增加DG数量、改多目标策略不要一上来就追求大而全的框架。

相关新闻