☰
粒子群算法在分布式电源选址定容中的工程化应用
2026/10/20 19:13:21 网站建设 项目流程

1. 为什么分布式电源选址定容这么难缠

1.1 问题本质:不是“装在哪”这么简单

分布式电源选址定容,说白了就是回答两个问题:在配电网的哪个节点接入分布式电源?接入多大容量最合适?这两个问题单独拆开都不难,难就难在它们必须同时解决,而且相互影响。你选了一个好位置,但容量定得不对,电压可能越限;你容量算得很漂亮,但位置选在馈线末端,网损反而会增大。所以这是一个典型的组合优化问题,位置变量是离散的,容量变量是连续的,还被一堆潮流方程和运行约束死死绑住。

我最早接触这个方向时,以为就是套一个优化算法跑一下完事,后来发现完全不是那么回事。你面对的是一个非线性的、多峰的、带约束的优化问题,而且每评估一次方案就要算一次潮流。配电网少则几十个节点,多则几百个节点,搜索空间大得离谱,传统枚举法和解析法根本扛不住。这时候粒子群算法的价值就体现出来了。

1.2 传统方法为什么容易翻车

传统上有几条路可以选。第一条是枚举法,把所有可能的位置组合和容量组合全部试一遍,思路简单但计算量是指数级增长。一个33节点的配电网,如果允许安装5个分布式电源,候选位置就有几十个,容量还有若干档,组合数量轻松过万,每个组合还要跑潮流,工程上根本没法接受。

第二条是解析法,比如线性规划或者非线性规划。问题在于配电网潮流本质是非线性的,目标函数和约束条件也不是光滑的凸函数,很多解析方法会卡在局部最优解上。而且分布式电源的接入还涉及离散决策(装或者不装、装几台),经典解析法处理这种混合整数非线性规划非常别扭。

第三条是传统启发式算法,比如遗传算法、模拟退火。遗传算法能用,但参数一堆,交叉率、变异率、种群规模稍微没调好,收敛速度就慢得让人抓狂。模拟退火对初始温度和降温曲线很敏感,容易得到“差不多”的方案但离最优差很远。我实际用下来的感受是,粒子群算法在这类问题上收敛快、参数少、实现简单,综合体验最舒服。

1.3 粒子群算法凭什么能啃这块硬骨头

粒子群算法的思路特别直观,就是把每个候选方案想象成一只在解空间里飞行的“粒子”,它一边记住自己历史上找到的最好位置,一边参考整个群体共享的最好位置,然后不断调整自己的飞行方向。这种“个体经验+群体信息”的机制,让粒子群算法在全局搜索和局部开发之间能保持一个相对平衡。

更关键的是,粒子群算法对目标函数的连续性要求很低。你只要把目标函数写出来,能算数值,就能塞进去跑。配电网选址定容的目标函数往往非常“不友好”,包含网损、电压偏差、投资成本、碳排放等多个维度,可能还有惩罚项,这种乱七八糟的曲面恰恰是粒子群算法擅长的战场。再加上它的速度更新公式简单,几行代码就能实现,工程上改起来也方便,所以很多实际项目里都能见到它的影子。

2. 把问题翻译成算法能懂的语言

2.1 决策变量怎么编码:选址+容量两种思路

用粒子群算法求解之前,第一件事是把方案变成向量。最常见的做法是分两种思路。

第一种是“二进制选址+连续定容”。假设某个待选节点,位置是否安装用0/1表示,装在哪个节点就是一个离散量。容量可以用连续变量表示,比如0到额定上限之间的任意实数值。然后把所有待选节点的状态拼接成一长串向量,一个粒子就是一个完整的候选方案。这种编码直观,但容易产生“违反直觉”的粒子,比如半台机组,所以决策变量需要合理映射。

第二种更工程化,直接准备一个候选节点池。比如说配电网上有20个允许接入分布式电源的位置,每个位置对应一个连续容量变量,如果容量为0就表示不装。这样粒子就是一个20维的连续向量,天然避开了二进制离散搜索的麻烦。我项目里用的最多的就是这个方案,因为把离散问题转换成了连续优化问题,粒子群算法的速度更新公式可以直接用,不用额外处理二进制更新逻辑。

无论哪种编码,都要注意一个坑:分布式电源的总容量通常不能超过系统总负荷的一定比例,否则会对继电保护和电压调节产生负面影响。所以粒子生成和更新的过程中,必须对总容量做一个约束检查。

2.2 目标函数:网损、电压、成本怎么取舍

目标函数是优化问题的灵魂,选错了后面全白搭。分布式电源选址定容的目标函数大致分三类。

第一类是技术性目标,最常见的是最小化系统有功网损。接入分布式电源的初衷之一就是减少电能传输距离、降低网损,所以很多论文和项目都用网损最小作为核心目标。计算网损需要跑潮流,然后汇总所有支路损耗,这部分是每次适应度评估的重头戏。

第二类是电压质量目标,典型做法是节点电压偏差最小化。分布式电源如果选址合理,能起到支撑电压的作用,但位置和容量不对,也可能导致电压越上限。所以通常会把所有节点电压与参考电压的偏差绝对值加权求和,甚至用最大电压偏差来代表系统电压水平。

第三类是经济性目标,包括分布式电源的投资成本、维护成本、燃料成本(如果是燃气轮机)以及折算后的发电收益。实际项目里,很少有人只优化一个目标,更多是做成多目标加权,或者用约束法把一个目标设为主要目标,其他目标转成约束。比如把投资成本设一个上限,然后在这个上限内最小化网损。

我自己的习惯是,初期先用“网损最小+电压不越限”作为目标函数,把经济性放在后面做敏感性分析。这样既能快速得到技术可行的方案,又能避免不同目标量纲不对等导致的权重调参困难。等项目需要出正式报告时,再把经济性加权进去,做成一个综合目标。

2.3 约束条件:等式约束和不等式约束一个都不能少

选址定容问题的约束条件很多,漏一个算出来的方案就可能根本不能落地。

等式约束主要是潮流约束。每个节点要满足有功和无功功率平衡,配电网的潮流方程必须成立。粒子群算法本身不会自动满足潮流约束,所以每次迭代都要调用潮流计算器,把当前粒子的DG注入功率代进去,算出各节点电压和支路功率,然后才能评估适应度。

不等式约束更是五花八门。节点电压上下限约束,一般要求在0.95到1.05倍额定电压之间;支路电流或功率不能超过导线热稳定极限;分布式电源的接入容量不能超过节点能承载的最大容量;系统整体的DG渗透率要控制在一定范围。这些约束如果直接用“罚函数”处理,比较容易实现,但罚因子太大容易导致粒子群在可行域边缘震荡,罚因子太小又会让大量不可行解混进来。我建议先用罚函数粗筛,再用可行性修复机制把明显不合理的粒子拉回可行域,具体做法后面章节会展开。

3. 粒子群算法的工程化改造

3.1 标准PSO流程回顾

先快速过一遍标准粒子群算法,免得后面讲改造时大家跟不上。假设我们要最小化一个目标函数f(x),粒子维度为D。每个粒子i在迭代t时的位置是x_i(t),速度是v_i(t)。粒子自身历史最优位置是pbest_i,群体历史最优位置是gbest。速度和位置更新公式如下:

v_i(t+1) = w * v_i(t) + c1 * r1 * (pbest_i - x_i(t)) + c2 * r2 * (gbest - x_i(t)) x_i(t+1) = x_i(t) + v_i(t+1)

其中w是惯性权重,c1和c2是学习因子,r1和r2是[0,1]之间的随机数。标准流程是:

  1. 初始化粒子群:随机生成每个粒子的位置和速度。
  2. 计算每个粒子的适应度。
  3. 更新pbest和gbest。
  4. 更新速度和位置。
  5. 检查终止条件,不满足就回到第2步。

整个过程不需要求导,不需要知道目标函数的具体数学形式,只需要能算适应度,这是它作为“黑盒优化器”最大的好处。

3.2 参数调优:惯性权重、学习因子、种群规模

粒子群算法参数不多,但每个都能影响最终结果。实践中最容易上手的调参方案是这样的。

惯性权重w决定粒子维持原来运动趋势的能力。w过大,粒子飞得远,全局探索能力强但容易漏掉最优解;w过小,粒子容易被拉向群体中心,局部开发能力强但容易早熟。常用做法是让w从0.9线性降到0.4,迭代前期多探索,后期多挖掘。我用这个策略在很多算例里都得到过稳定结果,比固定w好不少。

学习因子c1和c2分别代表粒子向自身经验和群体经验学习的强度。经典取值c1=c2=2,但实际中如果发现算法容易陷入局部最优,可以适当增大c1,让粒子更相信自己;如果发现收敛太慢,可以增大c2,让粒子更跟着群体走。我见过一些改进版用“压缩因子”来控制这两个参数,效果也不错,但工程上线性递减w已经够用了。

种群规模不用迷信“越大越好”。对于几十维的选址定容问题,30到50个粒子就足够了。再大计算量翻倍,但解的质量提升非常有限。最大迭代次数可以先设成100到300,然后观察收敛曲线,如果后期适应度不再变化可以提前终止。还有一个容易被忽略的点:每个粒子初始位置最好用“随机种子 + 可行域范围”来生成,不要让初始粒子全部挤在搜索空间的一个角落,否则前期探索效率很低。

3.3 离散变量与连续变量混合处理的三个技巧

选址定容问题里,离散变量(选哪个节点)和连续变量(容量多大)混合在一起,直接套用标准PSO会产生一些“四不像”的解。我整理了三个技巧,实测很有用。

技巧一:速度-位置映射到离散量。如果编码用的是二进制选址,可以把速度更新后的连续位置通过sigmoid函数转成0到1之间的概率,再按概率确定取0还是1。这本质上是把粒子群算法当作概率采样器在用,效果不错,但要注意阈值最好在0.5附近加入一点随机扰动,避免粒子过快地全部收敛到同一个二进制模式。

技巧二:惰性粒子修复。当一个粒子的某个容量值低于某一个很小的阈值,比如容量的5%,直接把这个值置为0,表示该候选节点不装DG。这样能避免算法用一大堆“象征性小容量”来蒙混过关,也让最终方案在工程上更清晰,方便施工人员理解。

技巧三:两段式优化。先固定容量为最大值的某一比例,只优化选址,等找到几个有潜力的候选节点组合后,再对这些组合优化容量。这样可以大幅缩小搜索空间,特别适合节点数多的大型配电网。当然,两段式可能丢失全局最优,所以我会在第二段用多次随机重启来弥补。

4. 实操:手写一个PSO选址定容Demo

4.1 算例设定与数据准备

我拿一个典型的33节点配电网简化模型来演示,这个算例经常出现在网络规划相关技术讨论中,节点参数、线路阻抗都可以引用公开的测试数据(为避免涉及具体来源,按行业通用方式构造一套相近数据即可)。

系统参数设定如下:

  • 基准电压10kV,基准功率10MVA。
  • 系统共有33个节点,32条支路,总负荷约3.7MW,无功约2.3Mvar。
  • 候选取址节点设定为第6、10、17、21、28、32号节点,共6个。
  • 每个候选节点允许安装的分布式电源容量范围为0到800kW。
  • 单个节点电压限值:0.95~1.05pu。

目标函数选择最小化系统网损,暂不考虑投资成本。约束条件包括潮流方程、节点电压上下限、DG总容量不超过总负荷的25%。

这个算例规模不大,适合用来验证算法逻辑。粒子群参数设置为:种群规模30,迭代次数200,惯性权重从0.9到0.4线性递减,学习因子c1=c2=1.8,速度上限设为容量范围的20%。

4.2 核心代码实现(适应度函数+PSO主循环)

我用Python写一个简化版,重点展示适应度函数和粒子群主循环的结构。实际工程里潮流计算一般用成熟的第三方库,或者自己实现前推回代法。

import numpy as np # 假设配电网节点导纳矩阵、负荷数据等已就绪 # 这里只给出 PSO 选址定容的主体框架 class DGPlacementPSO: def __init__(self, nodes, candidates, pop_size=30, max_iter=200): self.nodes = nodes # 节点数量 self.candidates = candidates # 候选节点索引列表 self.dim = len(candidates) # 决策变量维度 self.pop_size = pop_size self.max_iter = max_iter self.w_max = 0.9 self.w_min = 0.4 self.c1 = 1.8 self.c2 = 1.8 self.low = 0.0 self.high = 0.8 # 单位:MW # 初始化粒子群 self.position = np.random.uniform(self.low, self.high, (self.pop_size, self.dim)) self.velocity = np.random.uniform(-0.1, 0.1, (self.pop_size, self.dim)) self.pbest_position = self.position.copy() self.pbest_score = np.full(self.pop_size, np.inf) self.gbest_position = self.position[0].copy() self.gbest_score = np.inf def power_flow(self, dg_power_mw): # 这里省略具体潮流计算 # 返回网损(MW),并且检查电压是否越限 # 如果不收敛或电压越限,返回一个很大的值 loss_mw = 0.123 # 占位返回值,实际由潮流计算得到 return loss_mw def fitness(self, x): # x 是一个维度为 dim 的容量向量 # 容量小于阈值则视为不安装 dg_real = np.where(x < 0.05, 0.0, x) total_dg = dg_real.sum() if total_dg > 0.25 * 3.7: # 超过总负荷25%则罚 return 1e6 + 1000 * (total_dg - 0.25 * 3.7) loss = self.power_flow(dg_real) # 如果电压越限,返回惩罚项 # 这里用返回值占位,实际应检测电压数组 return loss def optimize(self): for t in range(self.max_iter): w = self.w_max - (self.w_max - self.w_min) * t / self.max_iter for i in range(self.pop_size): score = self.fitness(self.position[i]) if score < self.pbest_score[i]: self.pbest_score[i] = score self.pbest_position[i] = self.position[i].copy() if score < self.gbest_score: self.gbest_score = score self.gbest_position = self.position[i].copy() for i in range(self.pop_size): r1 = np.random.random(self.dim) r2 = np.random.random(self.dim) self.velocity[i] = (w * self.velocity[i] + self.c1 * r1 * (self.pbest_position[i] - self.position[i]) + self.c2 * r2 * (self.gbest_position - self.position[i])) # 速度限幅 self.velocity[i] = np.clip(self.velocity[i], -0.2, 0.2) self.position[i] += self.velocity[i] self.position[i] = np.clip(self.position[i], self.low, self.high) return self.gbest_position, self.gbest_score

注意,上面的power_flow方法只是示意,真实使用时要把配电网节点数据、支路参数加载进来,然后用前推回代法或者牛顿拉夫逊法计算潮流,并把节点电压数组返回。网损计算是潮流求解的一部分,只要支路潮流和阻抗已知,就能累加得到。

4.3 结果分析与方案展示

第一次跑这个Demo时,我遇到的典型结果是:算法一路收敛,最终得到一组容量分配方案,比如6号节点装300kW,17号节点装450kW,28号节点装200kW,其余候选节点不装,网损从原始的0.21MW降到0.14MW左右。这个结果在工程上很漂亮,电压轮廓也更平稳。

但要注意,粒子群算法有一个特点:每次运行的结果可能都不一样。这不是bug,而是随机搜索算法的本性。所以我一般会连续跑10次或20次,统计最优解和平均解,如果多次运行的结果接近,说明算法稳定;如果差异巨大,说明参数设置不合适或者约束处理太弱,需要回头调整。

结果分析时还要看接入前后的对比数据,比如各节点电压曲线、支路负载率、网损变化率。我习惯把基态网损、优化后网损、DG总容量、电压最大最小值整理成一张表,这样汇报给项目相关方时一目了然,也比单纯甩一张收敛曲线有说服力得多。

5. 常见坑和排查实录

5.1 问题:结果每次都不同,且差异很大

这是初用粒子群最头疼的问题。原因通常是搜索空间太大,而粒子群一开始没有覆盖到足够广的区域,导致每次跑都可能收敛到不同的局部极值。解决方法有三个:一是增加种群规模,比如从30提到50;二是把惯性权重初始值调高,让粒子前期飞得更野;三是使用多种子初始化,每次运行用不同的随机数种子,最终取多次运行的最优值。

另外,不要忽略“速度限幅”的作用。如果速度上限设得太高,粒子会在可行域外飞来飞去,适应度全部靠罚函数拉住,很容易出现“看似在收敛,实际在乱跳”的情况。把速度上限压缩到容量范围的10%到20%,稳定性会有明显提升。

5.2 问题:PSO早熟,陷入局部最优

早熟的特征是适应度收敛曲线在迭代后期变成一条直线,但得到的方案远不如预期。最常见的原因有两个。第一是群体多样性过早丧失,所有粒子都被拉到gbest附近,再也没有能力跳到其他地方。第二是目标函数过于“平坦”,很多不同方案算出来的网损差异极小,粒子分不清方向。

处理早熟,一个比较实用的办法是“粒子重启”。当检测到gbest连续很多代没有更新,就把一部分粒子的位置随机重新初始化,保留pbest和gbest的记忆,这样既不会丢掉当前最好的信息,又能注入新的搜索活力。另一个办法是在目标函数中加入轻微的随机扰动,比如给网损加一个噪声项,打破“平坦”局面,让粒子更容易找到真正的最优点。

5.3 问题:潮流计算不收敛

粒子群在搜索过程中会产生很多极端方案,比如某节点突然注入超大功率,导致潮流计算不收敛。这个问题最容易出现在迭代初期。我的处理方式是让潮流计算返回一个“安全失败”的标志,一旦检测到不收敛,就把这个粒子的适应度设为极大值,并且立刻把这个粒子拉回到初始化范围的中心附近,避免它继续把其他粒子带偏。

同时,要检查候选节点名单里是否有离电源点太远的微弱节点。有些馈线末端节点如果直接接大容量DG,可能本身就是潮流计算的死胡同。这种情况下可以在约束里单独给这些节点设置更小的容量上限,保证潮流可解。

5.4 问题:约束被破坏

最常见的是电压越限和DG总渗透率超限。如果罚函数设置得当,算法通常能找到可行解,但罚函数系数需要经验。我习惯把电压越限的惩罚设得非常高,因为电压不满足则方案无效;而总容量超限的惩罚可以相对温和,接近边界时允许算法去试探。

另一种处理方式是“可行性修复”。每次更新位置后,检查每个粒子的容量总和,如果超过上限,按比例缩小所有DG容量,使总和降到上限以内。这个方法比罚函数更直接,而且能让所有粒子都保持在可行域附近,收敛质量会更好。缺点是可能让粒子在一些边界区域反复震荡,所以我会配合约束裕度,刻意把容量上限压在规定值的98%,留一点余量。

我把几个常见问题整理成速查表,方便大家直接抄作业:

问题现象可能原因解决方案
多次运行结果差异大搜索空间覆盖不足增大种群、提高初始惯性权重、多种子运行
收敛过早,解质量差粒子多样性低粒子重启、随机扰动、适当增大c1
潮流不收敛极端DG注入失败即罚、拉回中心、限制末端节点容量
电压越限选址不合理或DG容量偏大高压罚因子、可行性修复、容量上限留余量
收敛极慢惯性权重太大或速度上限太紧改用线性递减w、放宽速度限幅

6. 最后聊点个人感受

我做了十几个选址定容相关的模拟项目之后,最大的体会是:粒子群算法只是工具,真正决定项目成败的还是问题建模。你花三个小时构造一个合理的目标函数和约束集合,比花三十分钟调参有意义得多。很多初学朋友一上来就急着调粒子群参数,结果目标函数写得一塌糊涂,算法再努力也没用。

另外,不要迷信“最优解”。工程上的最优解往往是“在一定假设下的最优”,实际施工中可能因为土地、线路走廊、上级电网消纳能力等因素被推翻。所以我的习惯是让粒子群算法输出前5个备选方案,然后结合外部条件做综合评价,选一个“最不坏”的方案落地。这个思路虽然不是标准的学术流程,但在实际项目中很受用。

如果你打算在真实配电网场景里用粒子群算法,建议先把潮流计算模块做扎实,最好能支持接入多种DG类型(光伏、风机、储能),因为不同DG的无功特性差别很大,简单把DG当成PQ节点处理,可能会导致电压评估偏差。这也是我栽过若干次跟头之后总结出来的,希望能帮大家少走弯路。

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

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

立即咨询