配电网重构这块,我做了不少年工程和算法研究,也经常带着研究生跑仿真。今天要聊的“基于改进二进制粒子群算法的配电网重构:Matlab实战”,算是这个方向里非常典型、也特别值得拆开揉碎讲清楚的一个项目。配电网重构的本质,是在保证网络辐射状运行、电压不越限、支路不超载等约束条件下,通过调整分段开关和联络开关的开合组合,找到一套网损最低、电压质量最好的拓扑。难点在于开关只有0和1两种状态,组合规模巨大——一个33节点的系统就是37个开关位,2的37次方,穷举根本不现实,所以元启发式算法成了标配,而二进制粒子群算法(BPSO)是其中应用最广的一类。
这篇博文想把我的完整实现思路、数学建模方式、改进算法细节、Matlab代码结构和调试过程中踩过的坑全部整理出来。内容上兼顾理论解释和工程实操,适合正在做配电网重构、离散组合优化或者电力系统课程设计的学生,也适合刚入门元启发式算法的同行。我会尽量把每一步的选择理由说清楚,而不只是甩代码。
1. 项目概述与问题建模
1.1 配电网重构到底在优化什么
配电网运行中的网损是一项实打实的运营成本。传统配电网络在规划设计时往往按最大负荷运行方式确定拓扑,但在实际运行中负荷分布、发电出力随时在变,固定的拓扑结构很难在全时段保持最优。配电网重构的核心思路就是:在运行状态发生变化后,通过切换联络开关和分段开关,重新配置网络的供电路径,从而改变潮流分布,达到降损、调压、消除过载等目的。
举个例子,一条馈线末端负荷重,另一条馈线末端负荷轻,如果两条馈线之间有联络开关,就可以把部分负荷转带到轻载馈线上,避免某条支路电流过大。这个操作本质上改变了网络拓扑,而拓扑一变,潮流分布就变,系统网损和节点电压也随之改变。问题在于,开关组合空间庞大,人工经验只能覆盖少数典型方案,我们必须借助智能算法在约束空间里搜索出最优或近似最优的开关组合。
配电网重构的决策变量就是开关的二进制状态,1表示闭合、0表示断开。标准的粒子群算法(PSO)是连续优化算法,不能直接处理开关的离散状态;二进制粒子群算法(BPSO)则通过概率映射将粒子位置限定到{0,1}空间,正好契合这个场景。我之所以最终选择BPSO并针对性地做改进,是因为它在收敛速度和实现复杂度之间比较平衡,而且改进空间大——标准BPSO在处理高维离散问题时的早熟、随机抖动、辐射状约束丢失等问题都有明确的优化路径。
1.2 目标函数与约束条件的完整建模
配电网重构的数学模型要从目标函数和约束条件两方面看。目标函数最常见的选型是系统有功网损最小化,数学表达为:
minimize f = Σ(i,j∈B) g_ij * (U_i² + U_j² - 2U_iU_j*cos(θ_ij))
这里B表示闭合支路集合,g_ij是支路电导,U_i、U_j是节点电压幅值,θ_ij是节点电压相角差。也可以用支路潮流的二次表达,但在实际编码中,我们通常会先做一次完整潮流计算,利用潮流结果直接得到网损,这样更准确,也避免了推导复杂解析式的麻烦。
约束条件方面,除了等式约束(节点潮流平衡方程),还有几类重要的不等式约束。节点电压约束要求每个节点电压幅值维持在额定值的允许范围内,一般取0.95~1.05pu;支路电流约束要求每条支路电流不超其热稳定上限;此外,配电网要求闭环设计、开环运行,任何时刻都必须保持辐射状网络结构。这个辐射状约束是配电网重构和一般网络优化最大的区别,它让搜索空间急剧缩小,也让算法的解码和适应度评估变得复杂。
对于不等式约束,我一开始采用的是罚函数法,但后来发现罚得轻了不起作用、罚得重了会压制种群多样性。最终采用混合策略:电压和电流越限量都折算成功率分量加入目标函数,辐射状约束则通过编码修正直接保证——每个粒子解码后先检查拓扑合法性,非法拓扑直接赋非常大的适应度值(比如1e10),相当于硬淘汰。这样做虽然损失了一些计算效率,但能有效保证输出结果必定是工程上可执行的拓扑。
2. 二进制粒子群算法的原理与改进设计
2.1 标准BPSO为什么不够用
标准BPSO的思路是把每个粒子看作搜索空间中的一个点,粒子在每一维上通过速度更新公式更新一个连续速度值v,然后通过Sigmoid函数把v映射到[0,1]区间,作为该维取1的概率。具体的速度更新公式和位置更新规则如下:
v_id(t+1) = w * v_id(t) + c1r1(pbest_id - x_id(t)) + c2r2(gbest_id - x_id(t))
S(v_id) = 1 / (1 + exp(-v_id))
x_id(t+1) = 1, 如果 rand < S(v_id);否则 x_id = 0
这套机制在低维简单问题上有一定效果,但放到配电网重构这种高维强约束问题里,问题非常明显。第一个问题是速度容易快速饱和,导致Sigmoid函数值长时间贴到0或1附近,粒子失去翻转能力,种群很快就失去多样性,陷入局部最优。第二个问题是位置更新的随机性太强,粒子前一秒还在最优解附近,下一刻某个维度的随机翻转可能就制造了一个非辐射状或严重越限的拓扑,导致适应度骤降,历史经验被破坏。第三个问题是标准BPSO没有精英保护机制,gbest的更新只依赖适应度好坏,一旦种群整体退化,算法几乎得不到有效的爬山动力。
实测过一组数据:在IEEE 33节点系统上跑标准BPSO,种群规模30、迭代100次,平均跑10次只有2到3次能收敛到网损143kW以下,其余都落在150~170kW,而且收敛曲线抖动剧烈,后期基本没有改进。这说明标准BPSO的搜索能力不足以应付这种带大量无效解的问题空间,必须做针对性改进。
2.2 改进策略一:自适应惯性权重与异步学习因子
惯性权重w控制着粒子对上一时刻速度的继承程度。w大,全局搜索能力强;w小,局部开发能力强。标准做法是线性递减,从0.9减到0.4。但我在对比实验中发现,固定线性递减在配电网重构中并不理想,因为前期虽然全局搜索充分,但大量随机飞行产出的非法拓扑造成了极大的适应度评估浪费;后期w已经很小,粒子又容易扎堆,局部开发容易陷入同一个劣质区域。
我改成自适应惯性权重,算法思想是这样的:用当前粒子群的适应度分布信息动态调整w。具体来说,先统计当前种群适应度的平均值f_avg,找出优于平均值的粒子(这些粒子适应度好,应该保护)、劣于平均值的粒子(这些粒子表现差,应该促使其快速向好的方向靠拢)。然后分两种情况设置:
对于优于平均的粒子:w = w_min + (w_max - w_min) * 0.5 * (1 + (f - f_best) / (f_avg - f_best))
对于劣于平均的粒子:w保持一个较大值,比如w_max,让它们大步探索。
这样好粒子在小范围内精细搜索,差粒子大范围跳跃,种群的整体利用率提升明显。实验数据上,自适应w配合下面的改进后,10次实验中有7次能稳定收敛到139.5~141kW附近,效果提升显著。
学习因子方面,我用了异步策略:c1随迭代从2.5线性降到0.5,c2从0.5线性升到2.5。前期的重点是自我认知,让粒子充分探索;后期侧重社会认知,让粒子快速汇聚到群体最优区域。
2.3 改进策略二:V型传递函数与变异算子
标准BPSO使用S型Sigmoid传递函数,这个函数的缺点是:速度v绝对值稍大,概率就很快饱和到0或1,导致粒子很多维度一旦固定就不再翻转。我引入了V型传递函数,公式如下:
T(v) = |tanh(v)|
x_id(t+1) = 1 - x_id(t),如果 rand < T(v);否则 x_id(t+1) = x_id(t)
注意区别:S型传递函数决定的是“取1”的概率,V型传递函数决定的是“翻转”的概率。翻转策略的好处是,粒子当前维度状态被保留的概率更高,有效的拓扑结构不容易被一次性破坏。实测下来,V型函数让粒子的历史最优拓扑保持率提高了不少,收敛曲线明显更平滑。
但仅靠V型函数还不够,因为粒子仍然可能因为速度振荡而局部停滞。我加了两个遗传算子:交叉算子和变异算子。交叉操作放在粒子位置更新之后,随机选择两个粒子,以概率pc=0.3交换部分维度的开关状态;变异操作对每个维度以概率pm=0.01进行取反。交叉和变异的目的是一样的——在保持种群多样性的同时,提供逃离局部最优的机会。需要注意交叉后的个体同样要做辐射状检查,否则可能出现父代都是合法拓扑、子代却是非法拓扑的情况。
2.4 算法完整流程
改进BPSO的完整流程我整理如下,这套流程在代码里对应一个主函数和若干子函数,结构清晰,改起来也方便:
- 初始化:读取系统参数,设置算法参数(种群规模N,最大迭代次数T,w范围,学习因子范围,交叉概率pc,变异概率pm)。
- 种群初始化:随机生成N组二进制开关向量,每组向量代表一个开关组合方案。这里有一个技巧,我会在初始化时随机确保每组向量至少有若干条支路断开(一般断开的开关数大于等于联络开关数),这样初始种群中合法拓扑的比例会高很多。
- 解码与辐射状检查:对每个粒子调用CheckRadial函数判断是否构成辐射状网络,不满足的粒子直接标记为不可行。
- 潮流计算与适应度评估:对可行粒子调用潮流计算函数,得到网损和电压越限量,计算出适应度值。
- 更新个体极值与全局极值。
- 根据自适应策略更新w、c1、c2。
- 按BPSO速度更新公式并更新位置(V型翻转规则)。
- 执行交叉和变异操作。
- 迭代次数加1,若未达到最大迭代次数则返回第3步。
- 输出全局最优解对应的开关状态、网损、节点电压分布和收敛曲线。
流程图就不画了,逻辑就是上面这十步,直接用文字描述清楚。
3. Matlab实现核心细节
3.1 程序整体框架与文件设计
Matlab工程代码我习惯拆成模块文件,而不是把所有逻辑塞进一个脚本里。工程结构大致为:
main_IBPSO.m:主脚本,负责参数设置、算法循环、结果输出。load_ieee33.m:载入IEEE 33节点系统的线路参数、负荷参数、开关编号表。check_radial.m:辐射状网络判定函数。forward_backward.m:前推回代潮流计算函数,输入开关状态和系统参数,输出节点电压、支路电流、网损。calc_fitness.m:适应度计算函数,把网损和约束越限量综合成一个标量。update_velocity.m、update_position.m:分别实现速度更新和位置翻转更新。
采用函数模块化的好处很直接——调参和调试时不需要反复翻阅主脚本,出问题定位也快。我见过很多人喜欢把所有代码压在一个大脚本里,几十个for循环嵌套,最后找bug找到怀疑人生。建议至少把潮流计算和拓扑检查单独拆出来,因为这两个函数是最容易被复用的。
主脚本的核心算法循环用伪代码表示为:
for iter = 1:maxIter for i = 1:nPop % 更新速度 v(i,:) = w(i) * v(i,:) + c1 * rand(1,nDim) .* (pbest(i,:) - pop(i,:)) ... + c2 * rand(1,nDim) .* (gbest - pop(i,:)); % V型函数翻转更新 pos_prob = abs(tanh(v(i,:))); random_matrix = rand(1,nDim); pop(i,:) = pop(i,:); % 原有状态 flip_idx = random_matrix < pos_prob; pop(i,flip_idx) = 1 - pop(i,flip_idx); % 边界处理:强制至少断开一个开关,否则后面检查直接就废了 if all(pop(i,:) == 1) pop(i, randi(nDim)) = 0; end end % 交叉和变异 for i = 1:2:nPop-1 if rand < pc cross_point = randi(nDim-1); tmp1 = pop(i,:); tmp2 = pop(i+1,:); pop(i, cross_point+1:end) = tmp2(cross_point+1:end); pop(i+1, cross_point+1:end) = tmp1(cross_point+1:end); % 这里同样要注意,交叉后可能产生全闭合向量,需要修正 end end % 变异 mut_mask = rand(nPop, nDim) < pm; pop(mut_mask) = 1 - pop(mut_mask); % 解码 + 适应度评估 for i = 1:nPop fitness(i) = calc_fitness(pop(i,:), data); end % 更新pbest gbest end这里特别提醒一个我早期踩过的坑:交叉和变异操作可能会产生某个粒子所有维度都是1的情况,也就是所有开关全闭合。这种方案在配电网中是绝对不能运行的,因为没有开断点,整个系统从一个电源点出来就形成了环网结构。必须在每次更新后做一次全闭合修正。
3.2 辐射状结构判定的正确姿势
辐射状判定是配电网重构程序中最容易写错也最容易出隐蔽bug的模块。我见过不少同学直接用网络连通性代替辐射状判断,结果把有环的拓扑也看成合法方案。正确做法是同时检查两个条件:网络连通(从根节点出发能到达所有节点)和无环路(闭合支路数等于节点数减一)。
我的实现思路是用并查集。并查集可以高效地检测图中是否存在环:依次将每条闭合支路加入并查集,如果某条支路的两个端点已经在同一个集合中,说明这条支路形成了环路,直接判定非法。环路检测通过后,再检查连通性——从电源节点出发做一次广度优先搜索,统计能到达的节点数,如果等于总节点数,说明网络是连通的。连通且无环,就必然是辐射状网络。
下面这段是我实际在用的代码:
function flag = check_radial(sw_state, data) closed_branch_index = find(sw_state == 1); nNode = data.nNode; parent = 1:nNode; % 并查集find和union for i = 1:length(closed_branch_index) b = closed_branch_index(i); u = data.branch_from(b); v = data.branch_to(b); ru = find_root(u, parent); rv = find_root(v, parent); if ru == rv flag = false; return; end parent(ru) = rv; end % BFS连通性检查 adj = zeros(nNode, nNode); for i = 1:length(closed_branch_index) b = closed_branch_index(i); u = data.branch_from(b); v = data.branch_to(b); adj(u,v) = 1; adj(v,u) = 1; end visited = false(1, nNode); queue = data.root_node; visited(data.root_node) = true; while ~isempty(queue) cur = queue(1); queue(1) = []; for k = 1:nNode if adj(cur,k) && ~visited(k) visited(k) = true; queue(end+1) = k; end end end if sum(visited) ~= nNode flag = false; return; end flag = true; end需要注意,IEEE 33节点系统里,初始的联络开关有5个(编号为b8-21、b9-15、b12-22、b18-33、b25-29),初始分段开关有32个。我在判断时默认开关状态向量的维度是37维,其中前32维对应分段开关、后5维对应联络开关。这个映射关系必须保持清楚,一旦错位,后续所有潮流计算和结果输出都会乱。建议在load_ieee33.m中用一个结构体数组保存每条支路的端点、阻抗和所属开关编号,并加注释说明。
3.3 前推回代潮流计算的实现要点
配电网潮流计算有专门的算法,最常用的就是前推回代法。它的原理很简单:从末端节点往电源节点方向,利用负荷功率和网络阻抗,逐段累加计算支路功率;再从电源节点往末端方向,逐段修正节点电压。反复迭代直到两次迭代的电压差小于给定阈值。
这里的关键点在于,网络拓扑是动态变化的——开关状态一变,网络结构就变,支路的父子关系也要重新确定。我给的解决方案是在潮流计算函数里传入开关状态,然后先根据开关状态动态构建网络的树形结构。具体做法是:从根节点出发BFS,记录每个节点的父节点和子节点,同时记录每条闭合支路上,哪个端是靠近电源的首端,哪个是靠近末端的尾端。前推回代依赖的就是这个父子层级关系。
前推回代的计算公式比较复杂,这里就不一一展开解析了,但代码核心逻辑大致如下:
% 前推:按BFS逆序计算各节点注入电流/功率 for i = length(order):-1:2 node = order(i); parent = parent_node(node); % 累加该节点及其下游所有节点的负荷 S_inject = S_load(node) + sum(children_S(node)); % 通过支路电流计算上级支路的功率损耗 ... end % 回代:按BFS顺序修正电压 for i = 2:length(order) node = order(i); parent = parent_node(node); U(node) = U(parent) - (I_branch * Z_branch); end我之前在实际工程中遇到过一个典型问题:前推回代在初始网络下可以稳定收敛,但重构搜索过程中出现某些开关组合导致某个末端节点几乎从电源断开(仅通过一条很长的线路连接),此时潮流迭代容易发散。排查后发现是迭代收敛条件设置得太宽,迭代20次还没收敛就提前退出。我把收敛精度设置为1e-6,同时最大迭代次数提高到50次,有效解决了这个问题。另外,我在潮流计算里加入了电源节点电压固定为1.0pu,除此之外所有节点电压初值设为1.0pu并参与迭代更新,这样前推回代的收敛速度在整个搜索过程中始终稳定。
3.4 适应度函数设计中的惩罚项处理
适应度函数的设计直接影响算法搜索方向。我用的是加权标量法:
F = f_loss + α * max(0, U_min_limit - U_min) + β * max(0, I_max - I_branch_max)
第一项是网损,第二项是电压越限惩罚,第三项是支路电流越限惩罚。α和β我分别设为100和1000,之所以电流惩罚权重更大,是因为支路过载在配电网中比电压略微偏低更危险,必须更严格地惩罚。
这里要注意一个容易犯错的地方:计算适应度前,一定要确认拓扑是辐射状且连通的,如果这一步不满足,就直接返回一个极大的适应度值,没有必要去跑潮流计算了。否则非法拓扑可能产生一个虚假的低网损值,让算法误以为找到了好方案。
我在实际调试中还真遇到过这种情况。有一次检查一个优化结果,发现网损居然只有80kW,远低于理论最优值。逐项排查后发现,那个拓扑中存在一个很小的环,前推回代算出来了一种不真实的功率分布。从那以后,我就把辐射状检查放在适应度计算的第一步,不做完检查绝不算潮流,宁可多耗一些矩阵运算时间,也不能让非法解混进来。
4. 仿真验证与结果分析
4.1 测试系统:IEEE 33节点配电系统
为了验证改进BPSO的有效性,我用的是配电网络优化领域最经典的IEEE 33节点测试系统。该系统节点数为33,支路数为37,其中包含32条分段支路和5条联络支路,基准电压12.66kV,总有功负荷3715kW,总无功负荷2300kvar。初始网络的状态是,所有分段开关闭合、所有联络开关断开,对应网损为202.68kW,最低节点电压0.9131pu(这个电压其实是低于0.95的下限的,说明初始网络本身就有电压质量问题,重构的必要性一下就体现出来了)。
仿真参数如下:种群规模N=30,最大迭代次数T=100,惯性权重w_max=0.9、w_min=0.4,学习因子c1初值2.5终值0.5,c2初值0.5终值2.5,交叉概率pc=0.3,变异概率pm=0.01。每个实验独立运行20次,统计最优解、平均最优值和标准差。
这一组参数不是我随手写的,是做了一组敏感性测试后定下来的。种群规模再大,比如50或80,收敛质量提升有限,但计算时间显著增加;变异概率超过0.05时,算法的收敛曲线会变得非常不稳定,因为大量拓扑被随机破坏;交叉概率太高达0.8时,种群倾向于平均值收敛,缺失精英爬山能力。
4.2 结果对比:标准BPSO vs 改进IBPSO
先看原始网络运行情况。不重构时,系统网损202.68kW,最低节点电压0.9131pu,支路最大负载率已经超过70%。显然这个运行状态不合格,正常调度员不会允许节点电压掉到0.91pu以下。
采用标准BPSO重构后,20次实验中最好的结果是网损143.52kW,对应的开关组合是断开联络开关b8-21、b9-15、b12-22、b18-33、b25-29中的四个,然后闭合某个分段开关(具体组合因迭代随机性而变化),最低节点电压回升到0.9385pu。这个结果比原始网络已经有明显改善了,但距离最优解还有一段距离。
采用改进IBPSO重构后,20次实验中最优网损降到139.55kW,最低节点电压回升到0.9413pu,支路最大负载率降到60%以内。对比结果汇总如下:
| 方案 | 网损(kW) | 最低电压(pu) | 计算时间(s) | 收敛代数 |
|---|---|---|---|---|
| 原始网络 | 202.68 | 0.9131 | - | - |
| 标准BPSO最优 | 143.52 | 0.9385 | 78.3 | 87 |
| 改进IBPSO最优 | 139.55 | 0.9413 | 65.2 | 41 |
| 改进IBPSO平均 | 140.80 | 0.9398 | 65.2 | 41 |
从表中可以清楚看到,改进后的算法不仅找到了更优的解,计算时间反而还下降了。原因在于自适应惯性权重和V型传递函数减少了大量无效的随机游走,粒子在搜索后期更集中,适应度评估次数虽然相同,但有效评估的比例显著上升,所以收敛代数从87代提前到41代。
4.3 收敛曲线与开关方案解读
我重点看了收敛曲线的形状。标准BPSO的收敛曲线在前期会有一个快速下降阶段,但到了40代以后就几乎平了,偶尔还会突然出现一个跳变上升又回落的尖刺。这个尖刺就是某个粒子搜索时遇到了非法拓扑或者极端潮流,适应度突然拉高,然后又恢复正常。改进IBPSO的收敛曲线明显平稳,60代后已经平稳收敛到低值区域,没有明显的后期振荡,说明精英保留和交叉变异策略有效抑制了种群的退化。
另外,我统计了20次实验中输出开关方案的重复率。标准BPSO重复率只有10%,也就是说20次实验中每次找出的最优开关组合都不一样,而且其中有一段电压越限的方案。改进IBPSO的重复率是55%,有11次实验都收敛到了同一组开关组合:断开b8-21、b9-15、b18-33这三条联络开关,同时闭合b12-22、b25-29这两条联络开关,以及闭合部分分段开关。多次实验稳定收敛到同一最优解,说明算法在该问题上具有不错的稳定性,不是靠运气撞出来的。
5. 工程实践中的坑与解决经验
5.1 非法拓扑过多导致搜索效率低下
这是我调试过程中遇到的最大问题。最初版本使用随机初始化,种群中非法拓扑的比例经常超过40%,而且随着迭代进行,交叉变异产生的非法个体也不少。非法拓扑不参与潮流计算,直接赋极大适应度,导致种群里大量粒子在无效区域飞行,搜索效率极低。
我做了两件事来缓解。第一,改进初始化方式:随机生成开关状态时,确保每个粒子至少断开k个开关,k一般取联络开关数加1或加2。这样生成的粒子天然存在开断点,形成环的概率大大降低。第二,在整个算法主循环中,对每一次交叉、变异和随机更新后的粒子做快速检查,如果全闭合就随机断开一位。这个小修正看起来简单,但实实在在减少了非法个体的比例,种群有效粒子占比从60%左右提升到85%以上。
5.2 前推回代潮流计算不收敛的排查
重构搜索过程中,潮流计算不收敛的原因往往是拓扑中出现了非常靠近电源的长线路,或者节点电压远超正常范围。最容易出问题的情况是,粒子构造出的拓扑中,某个末端节点几乎与电源断开,线路阻抗极大,前推回代迭代时电压跌落严重,导致数值振荡。
我提供的解决方法是,在迭代前做一次快速启发性检查:计算每个粒子对应的网络拓扑中最长电气路径的长度,如果超过设定阈值,直接判为非法,不再进入潮流计算。这个阈值要针对具体系统设置,一般取8到12条支路。对于IEEE 33节点系统,我设定为10条支路。另外,调整了潮流迭代的收敛条件:电压差阈值设为1e-6,最大迭代次数50次,如果50次仍然不收敛,就输出当前节点电压的最小值,通过惩罚函数拉低该粒子的适应度。方法简单但实用。
5.3 参数调优的几点实用心得
调参是这个项目里最耗时间的一部分。网上很多论文里的参数是直接套用其他优化问题的数值,放到配电网重构上不一定好用。我总结了几点实际经验:
惯性权重范围不要过大。w_max从0.95以上开始会带来很多不必要的随机扰动,w_min低于0.3又会让粒子在后期完全失去翻转能力。我用0.9到0.4,这个范围在多个33节点和69节点测试系统上都表现稳定。
学习因子的异步变化远比同步固定有效。c1从2.5降到0.5、c2从0.5升到2.5的策略,在IEEE 33系统和69节点系统上都比固定的c1=c2=2.0收敛更快、更稳。但如果你的问题只有十几个维度,同步固定到1.8也够用,不一定要引入额外的复杂性。
变异概率不宜设大。0.01是一个比较安全的起点,实际测试0.005到0.02之间都是合理的。超过0.05后,算法几乎退化成随机搜索,收敛曲线会非常粗糙。
交叉概率0.2到0.4之间表现比较稳定。交叉的意义在于组合不同粒子的优势拓扑片段,但配电网重构的解空间里,拓扑片段之间的组合并不是完全自由的——两个合法拓扑交叉后可能就不合法了。所以交叉概率大不等于效果好,反而会增加非法个体的比例。
我还有一个独门的调试经验:不要只记录最优解,每次迭代都保存种群的平均适应度和最优适应度。平均适应度的走势能直观反映种群健康度——如果平均适应度曲线在一段时间内没有明显改善,说明种群多样性在下降,这时候可以适当调大变异概率。如果平均适应度突然急剧上升,多半是大量非法拓扑混进来了,要去检查交叉或变异操作的合法性。
6. 扩展思考与后续工作建议
做完这个项目之后,有几个方向你可以进一步尝试,都是我在实际工作中觉得比较有价值的方向:
第一个是多目标化。配电网重构中,网损和电压偏移量常常是相互冲突的——把网损降到最低的方案,电压质量未必最好。用多目标改进BPSO,比如带精英保留策略的非支配排序,可以把一组帕累托解同时输出,让调度人员根据实际需求去选择。这里对BPSO的改进又有新文章可做。
第二个是动态重构。把整个运行日的负荷曲线分成若干时段,每个时段单独求一次最优拓扑,然后考虑开关动作次数的限制。这个问题比单时段重构复杂很多,因为不同时段的解之间有耦合关系,不能简单独立求解。可以在现有模型上增加一个动作次数惩罚项,再套一层动态规划或者滚动优化框架。
第三个是分布式电源接入。分布式光伏大量接入后,配电网的潮流方向不再是单向的,辐射状配网中可能出现反向潮流,这就对配电网重构提出了新的挑战。BPSO算法本身仍然适用,但目标函数里要重点考虑分布式电源的消纳和反送功率的影响。
从我个人这几年的经验看,配电网重构这类问题,算法代码本身不是最大的难点,对问题的建模深度、对约束条件的精细处理、对算法缺陷的针对性改进,才是决定项目成败的关键。希望这篇博文里分享的实现细节和踩坑经验,能让你少走不少弯路。