ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Python实现配电网经济性与可靠性双目标协同优化规划

Python实现配电网经济性与可靠性双目标协同优化规划 搞配电网规划的朋友应该都体会过经济性和可靠性打架的感觉。传统工作流里这两个维度往往是串行处理先按年费用最小去定线路和容量再用N-1准则或可靠性导则去校核不够就加设备、加大截面来回推倒重来。这种反复试算的方式不仅低效还常常顾此失彼——过度投资的方案可靠性指标很好看经济账却惨不忍睹省钱方案又总在可靠性校核环节被一票否决。这次分享的项目就是要把经济性和可靠性同时放进目标函数在混合配电系统场景下做规划方案寻优并且用Python把整套流程完整跑通。这里说的混合配电系统是指配电网中接入了光伏、风机、储能、微型燃气轮机等多种分布式电源主网和分布式电源共同供电的格局。项目最终输出一条年总费用—电量不足期望ENS双目标的Pareto前沿以及配套的配电系统可靠性评估结果所有代码基于Python实现可以复现、可以改参数、可以二次扩展。这个项目适合三类人一是研究配电网规划、分布式电源接入的电气工程学生或科研人员二是需要把可靠性评估和优化算法落到工程项目中的规划工程师三是想系统学习NSGA-II、潮流计算、可靠性分析三者完整联动的Python开发者。无论你处于哪个阶段跟着代码把流程跑通一遍对规划问题怎么从数学建模走向工程落地会有很直观的理解。1. 项目核心思路为什么要把双目标放进同一个框架1.1 混合配电系统规划到底在规划什么传统配电网规划的核心决策变量是网架——线路怎么走、变电站建在哪、导线截面选多大。到了分布式电源高渗透的混合配电系统阶段规划的内涵明显扩大还得决定光伏、风机、储能、微燃机在哪些节点接入、每处装多大容量、储能充放电策略怎么配合。这些决策与原有网架参数高度耦合因为DG接入位置和容量直接改变了系统潮流分布而网架结构又决定了DG出力能否可靠送出。做模型抽象时我把规划问题拆成两层投资决策层和运行模拟层。投资决策层回答在哪里装、装多少运行模拟层回答装完之后系统怎么运行、可靠性水平如何。两层通过潮流计算和可靠性评估耦合在一起。这个拆分也是整个代码框架的模块划分依据后续所有功能都围绕这两层展开。在具体算例里我选了IEEE 33节点系统作为基础网络。这是一个经典的放射状配电网算例基准电压12.66kV总负荷约3.72MVA由一条主干馈线和三条分支组成非常适合用来验证DG接入方案。候选接入点覆盖了商业区、居民区、工业区三类负荷节点保证优化结果能反映不同负荷特性的差异。1.2 单目标规划为什么不够如果只做经济性目标最典型的做法是年费用最小化把DG投资等年值、运维成本、网损费用拼在一起。优化器会本能地往负荷中心节点塞大容量DG网损压得很低经济指标非常漂亮。但问题在于这种方案在面对线路故障或DG检修时非常脆弱——因为DG集中接入一旦关键线路跳闸大片负荷直接失电可靠性指标很难看。反过来只做可靠性目标优化器会倾向于到处装DG、大量配储能甚至把关键线路双回路化可靠性自然很高但投资回收期可能长到完全不符合工程实际。项目里我做过一次测试纯可靠性优化方案的总投资是折中方案的1.7倍可靠性却只提升了不到10%。这就是典型的边际收益递减。这两个目标本质上是冲突的可靠性提升需要额外投资支撑压低投资必然牺牲部分可靠性裕度。单目标优化只能映射到Pareto前沿上的一个极端点双目标优化才能给出完整的权衡关系让决策者看清楚多花多少钱、买到多少可靠性。1.3 整体技术路线我采用的技术路线分四步也是代码框架的四大模块网络建模层把33节点系统的拓扑、线路参数、负荷数据读入内存构建节点—支路关联矩阵为潮流计算做准备。方案生成层用NSGA-II不断生成候选DG配置方案每个方案是一组接入节点容量等级的整数编码。评估层对每个候选方案做潮流计算和可靠性评估输出两个目标值——年总费用和ENS。决策后处理层从Pareto前沿中筛选代表性方案输出对应DG配置、可靠性指标并绘制前沿散点图。整套架构里评估层最耗时因为每个方案都要枚举大量故障工况做潮流计算。优化能否收敛、速度是否可接受核心瓶颈就卡在这一层。所以我在第4节会专门讲计算效率的优化手段。2. 数学建模两个目标函数和四个关键约束2.1 经济性目标年等值总费用最小经济性目标我用等年值总费用来量化避免一次性投资和年运行费用不可比的问题。计算式如下[ C_{total} C_{inv}^{DG} C_{om}^{DG} C_{loss} C_{interruption} ]其中(C_{inv}^{DG})是DG投资的等年值等于投资现值乘以资金回收系数 [ C_{inv}^{DG} \sum_{i} c_{dg} \cdot S_i \cdot \frac{r(1r)^Y}{(1r)^Y - 1} ] 这里 (S_i) 是节点i接入的DG容量(r) 是折现率取8%(Y) 是设备寿命取20年。(C_{om}^{DG})是年运行维护费用按投资额比例估算光伏约2%、风机约3%、储能约5%。(C_{loss}) 是年网损费用通过潮流计算得到年总网损电量后乘以电价折算。(C_{interruption}) 是停电损失费用等于各负荷点年失电量和单位电量停电损失产电比的乘积。停电损失费用这一项最关键它把可靠性和经济性直接挂钩——系统优化时会主动规避可靠性短板比约束条件里硬卡指标要自然得多也更能反映规划方案的真实社会效益。2.2 可靠性目标用ENS做主指标可靠性评估的常规指标有SAIFI平均停电频率、SAIDI平均停电持续时间、ENS年电量不足期望、ASAI系统平均可用率。做规划寻优时我建议主目标用ENS原因是SAIFI和SAIDI只反映次数和时间没有体现负荷量级。工业负荷集中的节点停1小时和普通居民节点停1小时损失完全不同。ENS把失电量和负荷权重都带进来且与停电损失费用线性相关更适合和经济目标配对。当然输出结果时SAIFI、SAIDI、ASAI我也会一并计算方便对照工程标准。但优化目标就锁定一个ENS最小。可靠性目标函数写作[ F_2 \min \ ENS \sum_{h} P_{load,h} \cdot U_h ]其中 (U_h) 是负荷点h的年停电小时期望值由可靠性评估模块计算得到。2.3 关键约束条件怎么设约束条件我重点卡了四类潮流平衡约束节点注入功率与流出功率满足KCL/KVL实际通过前推回代法迭代收敛来表达。节点电压约束各节点电压幅值保持在0.95p.u.到1.05p.u.之间工程上通常允许±5%偏差。DG渗透率约束DG总容量不超过系统峰值负荷的30%~40%避免倒送功率过大影响上级电网。DG容量离散约束每个节点的DG容量从候选集合里选例如0、200kW、400kW、600kW、800kW更贴合设备型号的实际选择。电压约束要特别小心——DG接入后末端电压会被抬升在长馈线末端接大容量DG时电压上限比下限更容易被突破。很多新手只盯着低压校验结果算出来电压合格率虚高实际方案根本过不了运检关。3. 可靠性评估的Python实现状态枚举与Monte Carlo3.1 解析法枚举故障场景计算ENS可靠性评估我用了两种方法先用解析法做优化主循环里的评估再用序贯Monte Carlo做最终方案的验证。解析法核心是状态枚举。把每条馈线、每个主变当成可失效元件做N-1枚举。对单个故障场景判断哪些负荷失电、失电规模多大、持续多久再乘以元件故障频率得到该场景的年期望停电时间。对所有故障场景累加就得到系统级ENS。实现时要注意电源侧和DG侧分开处理。主网故障时如果DG具备孤岛运行能力可以带着局部负荷继续供电默认并网运行且允许孤岛切换的工况更贴近当前微电网技术背景。代码里我会用一个孤岛检测函数判断故障隔离后的子网络是包含DG的孤岛还是纯失电区域。3.2 序贯Monte Carlo仿真的思路序贯Monte Carlo的思路更直观给每个元件生成一条按时间推进的状态序列正常持续时间和故障修复时间都从指数分布采样也可以换Weibull分布把元件的正常—故障—正常状态序列叠加在系统时间轴上对每个时间切片做拓扑分析和潮流校验统计全年停电次数、停电时间和失电量。这个方法最大的优点是能模拟时序相关性比如光伏夜间不出力、负荷冬夏曲线不同都能通过多状态时序模型放进仿真。缺点也明显需要大量抽样才能把ENS估计得稳定计算量非常大。所以我把序贯Monte Carlo放在优化收敛之后的验证环节对选出的最优方案做高精度复核。3.3 关键代码实现潮流计算与故障分析可靠性评估离不开潮流计算。我选用的潮流算法是前推回代法Backward-Forward Sweep处理放射状配电网非常稳定。33节点系统通常迭代几十次就能收敛比Newton-Raphson方法更适合配电网这种R/X值高、节点数多的网络。核心代码结构是三层def power_flow(voltage, load_power, dg_power, branch_data): # 1. 初始化节点电压为额定值 # 2. 后推从末端向首端累加支路功率 # 3. 前推从首端向末端更新节点电压 # 4. 判断收敛max(|V_new - V_old|) epsilon # 返回各节点电压和支路潮流故障分析时对每个枚举出的故障支路从branch_data里移除它重新构建拓扑用networkx库做连通性分析判断哪些节点依然在通电回路上哪些已经失电。用现成的图论库比自己手写DFS要省心得多还能直接得到孤岛内的连通子图。提示做配电网规划枚举计算时不要用全网Newton-Raphson。配电网拓扑频繁变化每次切掉一条故障支路都要重算前推回代法每次迭代开销小且对放射状网络天然收敛速度优势非常明显。3.4 可靠性指标计算逻辑可靠性评估流程可以概括成一个双层循环外层循环枚举每个元件的故障内层循环对每个故障场景做潮流和拓扑分析。统计内容有三项失负荷节点集合失负荷功率总量故障持续期等值于元件修复时间如果存在转供或孤岛切换能力则取切换时间。最后把所有场景的失电量累加得到ENS。SAIFI和SAIDI按节点停电次数和时间汇总后除以用户总数在缺少用户明细数据时可以用负荷功率比例近似折算。4. NSGA-II双目标优化搜索Pareto前沿的实现要点4.1 为什么选NSGA-II而不是加权法有人会问把两个目标线性加权组合成单目标不是更简单吗加权法实现确实简单但有两个致命问题一是权重怎么定没有理论依据拍脑袋定的权重很容易把搜索方向带偏二是对非凸的Pareto前沿线性加权法根本找不到中间区域的解只能找到两个端点解。NSGA-II的核心优势在于不用预先设置权重。它通过非支配排序把种群按Pareto支配关系分层再借拥挤度距离保持解在空间中的散布程度一次性逼近整条Pareto前沿。后端再用Knee Point或TOPSIS等方法选最终方案决策空间比加权法大得多。4.2 编码设计与遗传算子这里每个个体就是一个DG配置方案。假设有10个候选接入节点每个节点可选6种容量等级我用整数编码染色体长度为10每个基因取值0~5# 个体示例 [2, 0, 4, 5, 0, 1, 3, 0, 2, 0] # 表示节点1装400kW节点3装800kW节点6装200kW节点7装600kW节点9装400kW遗传算子设计上选择锦标赛选择tournament size取2同时保留精英个体2个。交叉整数编码下我不建议SBX改用两点交叉破坏优秀基因块的概率更低。变异随机替换某个基因值变异率0.1~0.2。太保守容易早熟。4.3 NSGA-II主循环的代码结构主循环本身不复杂关键在非支配排序和拥挤度计算。DEAP库提供了现成的tools.selNSGA2但自己实现一遍能加深理解代码量也不大def fast_non_dominated_sort(values): # values: 每个个体的目标函数值形状 [n, 2]) # 返回每个个体所属的Pareto层级 ...主循环的伪码逻辑for gen in range(max_gen): # 1. 评估种群所有个体的 (cost, ens) # 2. 非支配排序 拥挤度计算 # 3. 锦标赛选择生成父代 # 4. 交叉、变异生成子代 # 5. 父子代合并按层排序并截断为pop_size # 6. 记录第gen代的Pareto前沿4.4 计算效率优化三个立竿见影的手段可靠性评估是最大的性能瓶颈。一个个体做一次完整状态枚举评估要跑几百次潮流计算而NSGA-II一代就要评估50~100个个体迭代100代就是上万次评估。纯Python循环跑起来非常痛苦。我用了三个优化手段矢量化潮流计算把多个负荷水平下的潮流计算塞进numpy矩阵运算避免逐节点Python循环。典型场景削减用K-means把全年8760小时负荷和DG出力聚类成12个典型场景可靠性评估跑在典型场景上精度损失控制在3%以内速度提升超过一个数量级。早停机制Pareto前沿连续20代无显著变化就终止迭代避免无效算力浪费。5. 算例实战IEEE 33节点系统的完整复现5.1 算例参数设置我在标准33节点系统基础上做了扩展。候选接入节点选了10个覆盖三类负荷区域商业负荷节点、居民负荷节点、工业负荷节点。DG类型包含光伏时序出力不可控和微型燃气轮机可控出力两类DG的成本和运维系数不同。把所有参数整理成三个文件节点数据表、支路阻抗表、负荷曲线表。用pandas读入后各模块共享DataFrame调试维护都很方便。表结构是这样的数据表字段说明节点表id, 类型, 基准电压, 峰值负荷节点类型区分商业/居民/工业支路表首端, 末端, 电阻, 电抗, 容量用于潮流计算负荷曲线时刻, 商业负荷, 居民负荷, 工业负荷典型日或全年时序5.2 运行流程与主入口程序运行入口很简单python run_planning.py --nodes 33 --pop_size 60 --max_gen 200流程依次为读数据、构建网络对象、初始化NSGA-II种群、迭代优化、输出Pareto前沿、对最优解执行Monte Carlo验证、生成结果图表。主函数代码如下if __name__ __main__: network DistributionNetwork(node_data, branch_data, load_data) optimizer NSGAII(pop_size60, max_gen200) pareto_front optimizer.run(network) plot_pareto_front(pareto_front) verify_by_monte_carlo(network, pareto_front)5.3 结果解读Pareto前沿长什么样仿真收敛后横轴是年总费用万元纵轴是ENSMWh/年会得到一条经典的向左下凹的曲线。看一下极端点和折中点的差异方案类型DG总容量(kW)年总费用(万元)ENS(MWh/年)SAIDI(h/年)电压合格率经济最优1200158.246.713.296.8%折中方案2400183.921.36.999.1%可靠最优4200245.612.84.599.7%折中方案对比经济最优年费用只多了约25.7万元ENS却下降了54%性价比非常突出。这就是双目标规划相比单目标的价值所在——能看到钱花在哪里、可靠性买到了多少、再往右投入是否已经到达边际收益递减区。注意上表数值是示例级别实际跑完会因负荷曲线和DG成本参数不同而变化。真正重要的是分析方法——投资曲线拐点、可靠性收益递减规律这些结构特性在工程上具有普适性。5.4 存储与复现建议为了让项目可复现代码里把随机种子固定为numpy.random.seed(42)所有负荷曲线和DG出力的随机生成都在该种子约束下进行。别人拿到代码跑出来的结果完全一致这非常便于学术交流和工程评审。输出文件按四类归档Pareto前沿数据CSV、各代表性方案DG配置表、可靠性指标汇总表、图件前沿散点图、电压分布图、ENS对比柱状图。按这个结构即便半年后回头翻项目也能快速定位到任意结果对应的参数和代码版本。6. 常见问题与排查技巧实录6.1 潮流计算不收敛怎么办前推回代法在正常放射状网络下几乎不会翻车但故障枚举阶段切掉某条支路后网络可能分裂成多个孤岛甚至间接形成环网算法就开始出问题。我的处理方式是先做连通性分析每个孤岛单独判断是否含平衡节点如果不含平衡节点就把孤岛内DG视作电压源改用孤岛独立前推回代的变体计算。另一个常见问题是DG渗透率过高导致潮流方向反转收敛变慢。把收敛阈值从1e-6放宽到1e-5或者把最大迭代次数从100次提到500次通常就能解决。遇到始终不收敛的个体直接让它返回一个很大的ENS作为惩罚反正这类方案在后续非支配排序中也会被淘汰。6.2 NSGA-II早熟收敛我在前几版代码里遇到过Pareto前沿聚集在局部、多样性极差的情况根源有三个种群太小。配电网规划的搜索空间不小种群数低于30很容易早熟我最终调到60~80。交叉变异参数太保守。变异率低于0.05基本跳不出局部区域推荐0.1~0.2。拥挤度计算错误。按拥挤度排序时如果忘记先按每个目标分别排序再差分得到的距离值是错的会打乱选择压力。排查技巧是把每代Pareto前沿的分布范围打印出来看它是否随代数单调外扩。如果前20代范围就不再变大果断加大变异率或者随机重新初始化部分种群。6.3 两个目标数值量级相差过大经济目标动辄百万级别ENS却可能只有几十。在非支配排序里如果两个目标尺度不一致会天然偏向量级大的目标导致支配关系判断失真。我建议在评估函数内部对两个目标做归一化或者更直接地把停电损失费用并入经济目标让两个目标的数值量级都落在万元/年附近这样NSGA-II的选择压力才是均衡的。6.4 运行时间过长怎么办完整跑完一次33节点规划优化在32核机器上实测约2~4小时取决于枚举故障数和场景数。如果只想快速验证算法有效性可以把典型场景从8760小时削减到24小时取最恶劣日或者关闭Monte Carlo验证只跑解析法。想充分利用多核用multiprocessing把种群评估并行化每个进程负责一批个体加速比能接近物理核心数。这里唯一要留意的是随机种子分配——各进程必须用不同的子种子避免并行分支产生重复随机序列。6.5 Python环境与依赖库配置整个项目依赖numpy、pandas、matplotlib、networkx、scikit-learn。强烈建议用conda建一个干净的虚拟环境再做pip install别一上来就在系统全局环境里装库。版本方面numpy和pandas版本不匹配时会报很奇怪的矩阵运算错误这类问题排查起来极其耗时间。顺带补充一句运行前先在小规模算例上把流程跑通确认评估函数和排序逻辑没有bug再上完整33节点算例。这个习惯能帮你省下大量调试时间。这次项目整体做下来我最大的体会是规划方案的代码实现难点往往不在优化算法本身而在评估环节能不能算得准、算得快。NSGA-II的框架到处可以找到现成实现真正的工程壁垒是每一次评估背后都包含几十上百次潮流计算和故障枚举这个底层计算效率决定了整个优化流程能否跑起来。如果后续扩展我建议往三个方向走一是加入储能系统容量配置把时序耦合特性带进模型二是用代理模型替代可靠性评估中的大量潮流计算进一步压缩时间三是把光伏出力随机性、负荷增长不确定性从确定性场景扩展到概率场景。最后再分享一个个人小技巧——调参前先在小规模算例上验证数据可视化别只盯着Pareto前沿把电压剖面和孤岛拓扑也打出来看很多隐蔽bug都是靠这些细节图暴露的。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进