ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

配电网双目标规划:Python实现NSGA-II与蒙特卡洛可靠性评估

配电网双目标规划:Python实现NSGA-II与蒙特卡洛可靠性评估 做配电网规划项目这几年我最大的体会是方案评审会上最难回答的问题不是IEEE 33节点系统怎么算潮流而是领导轻描淡写的一句——这个方案到底比那个方案便宜多少可靠性又高了多少以前我们习惯把经济性指标和可靠性指标分开算报告里各占一章但真要比选方案时两者根本对不上。后来把基于经济与可靠性双目标的混合配电系统规划及可靠性评估整套模型用Python落地才真正解决了方案之间的可比性问题。这篇就完整记录一下我在这个课题里的建模思路、代码实现和踩过的坑适合正在做配电网规划、分布式电源接入方向研究的研究生也适合工程上想用Python做多目标方案比选的从业者。1. 混合配电系统双目标规划一张帕累托前沿解决省钱还是可靠之争1.1 混合配电系统到底混合在哪里先说清楚对象。混合配电系统这个叫法在文献里有几种指法我做的这套侧重的是交直流混合配电网交流馈线网络里接入AC/DC换流装置下面挂直流母线直流侧接光伏、储能甚至直流充电桩交流侧继续带传统负荷和分布式电源。为什么会有这种结构因为现在光伏直流发电、储能天然直流、电动车充电也有直流需求硬要全部经过DC/AC两次变换再接入交流网损耗高、控制复杂还不如在局部直接成环或成网。但规划层面就麻烦了。原来配电网规划只需要回答选哪条路、架什么型号的线、在哪建变电站现在多出来的变量包括换流器位置和容量、储能位置与容量、光伏选址定容、馈线是否要改造升级、联络开关怎么布置。决策变量里有二进制某个位置要不要新建/升级有离散整数设备容量选哪个档位还有连续量储能额定功率、能量混合整数非线性优化是跑不掉的。1.2 经济性目标和可靠性目标为什么天然打架经济性目标通常写成全寿命周期内的年均综合费用包括投资年值、运行维护费、网损购电费再算上停电损失。可靠性目标则用系统缺供电量期望值EENS或者用户平均停电时间SAIDI这类指标。这两个目标放在一起矛盾是非常直观的想让EENS变小就得提高冗余多建联络线、多装储能、增加DG备用容量投资运维成本必然上去反过来压投资砍掉冗余线路一故障就没法转供可靠性肯定下降。很多初学者会问为什么不用线性加权把两个目标合成一个这恰恰是双目标建模的核心逻辑。经济量和可靠量量纲不同万元和MWh/年强行相加必须给一个权重而这个权重本质上代表一度电的停电损失值多少钱的主观判断。不同地区、不同用户性质这个值差出几倍甚至一个数量级。加权成一个目标每调一次权重就得重跑一遍优化最后拿到的永远只是曲线上一个点看不到多花100万能把EENS压到什么水平这种边际关系。做双目标优化一次性画出整条帕累托前沿等于把决策空间完整摆到桌面上。1.3 双目标问题里的解不是一个最优方案双目标优化的结果不是唯一最优而是一组非支配解。什么叫非支配通俗讲就是A方案比B方案总投资高但EENS更低那么A和B谁更好取决于你更在意哪个目标只要没有一个方案能在两个目标上都打败另一个它们就都留在帕累托前沿上。我实际做项目时对前沿的处理方式是先算前沿再结合单位停电损失费用从前沿里挑综合费用最低点作为推荐方案同时把前沿两端的经济最优解、可靠性最优解都附在报告里给决策者参考。这套做法比单一加权法稳得多评审会上也能直观展示可靠性提升的边际成本。2. 可靠性评估不是算个概率而是把故障场景逐个跑一遍2.1 常用可靠性指标怎么选做规划层面的可靠性评估指标不需要太多但每个都要能落到可以计算的数值上。我重点用这几个指标全称含义单位SAIFI系统平均停电频率每个用户平均一年停几次电次/(户·年)SAIDI系统平均停电持续时间每个用户平均一年停多久h/(户·年)CAIDI用户平均停电持续时间每次停电平均持续多久等于SAIDI/SAIFIh/次EENS期望缺供电量一年里无法供给的电量期望值MWh/年ASAI供电可用率用户实际用电小时数占需求时间的比例%优化目标里F1经济性和F2可靠性我都用了年均口径F1是万元/年F2直接取EENS单位MWh/年。EENS的好处是它本身带有电量属性乘上单位停电损失费用就能折进经济性目标做灵敏度分析时只需要改一个系数。SAIFI和SAIDI更适合作为约束条件比如规划后SAIDI不得超过1小时/户·年在代码里作为罚项处理。2.2 解析法和蒙特卡洛我为什么选时序蒙特卡洛可靠性评估有两条传统路线。一条是解析法典型如故障模式后果分析法把每条线路、每个开关、每台变压器当成一个元件遍历所有可能故障事件按网络拓扑判断哪些负荷点受影响乘上故障率和修复时间求期望。对拓扑固定、没有分布式电源的传统辐射网这个方法快且精确工程上用了很多年。但加入光伏和储能之后解析法开始吃力。问题是时序性的DG出力一天24小时在变储能荷电状态随时间累加故障恰好发生在晚上光伏出力为零、储能又放空的时候和中午晴空高发时段相比孤岛能带起来的负荷完全两码事。解析法很难把这些时序状态塞进一个解析期望公式里。所以我的方案是序贯蒙特卡洛模拟把一年8760个小时变成仿真时间轴逐小时抽样元件运行/故障状态故障发生后模拟保护动作、故障隔离、联络转供和孤岛运行统计每个负荷点的停电事件和缺电量最后除以仿真年数得到年均指标。代价是计算量大但在Python里用numpy批量处理几十个元件的系统跑几百次评估是可以接受的。2.3 故障隔离、转供、孤岛运行这三个阶段决定EENS算得准不准EENS的精度其实不取决于抽样本身而取决于故障后恢复过程建模得细不细。我按工程实际把一次故障拆成三步隔离保护动作后故障元件两端开关断开故障段被隔离。上游恢复故障点靠电源侧的上游区域只要故障隔离完成就能第一时间恢复供电停的时间很短一般只算开关动作时间。下游处理故障点下游区域看有没有联络开关如果有且对侧变压器和线路容量够就转供恢复如果没有就只能等故障修复。如果下游含有分布式电源还能形成孤岛故障期间继续供电。建模时最容易漏的是孤岛约束。孤岛能不能成立取决于故障时刻DG出力、储能剩余电量、孤岛内负荷大小三者匹配。我一开始只判断下游有没有DG结果EENS明显偏小后来把时序功率匹配加进去结果才合理。储能SOC在故障前已经放电到很低的话孤岛撑不了一两个小时就瓦解这里必须模拟到位否则评估结果会偏乐观规划方案也就跟着冒进。3. 经济性与可靠性两个目标在Python里怎么落地成可计算函数3.1 经济性目标函数的四块成本经济性目标我用全寿命周期年均费用写出来是F1 C_inv C_om C_loss C_icC_inv设备投资的年折算值。不能用一次性建设成本直接比较因为不同方案设备寿命不同。标准做法是乘等年值系数CRF r * (1 r)^n / ((1 r)^n - 1) C_inv CRF * 一次性投资总额r是折现率n是设备寿命。电缆、变压器、换流器、储能寿命不一样我习惯分开按寿命算再累加。C_om每年运行维护费通常按设备投资的1%~3%估算。C_loss网损费用。用典型年8760时序潮流算出的总网损电量乘购电电价。规划方案里线路型号变了、电源位置变了网损差异会很大这笔钱不能省。C_ic停电损失等于EENS乘以单位停电损失费用。这里注意别和F2重复——F2是纯可靠性指标F1里把可靠性折算成钱这样决策者看前沿时能同时理解物理缺电水平和折算经济成本。3.2 可靠性目标函数的定义方式可靠性目标F2我直接用EENS但代码里还会同步统计SAIFI和SAIDI方便后面加约束条件或出报告。EENS的计算在蒙特卡洛模块里完成每次故障事件发生后把故障期间各时刻的缺供电量累加。伪代码逻辑是def evaluate_reliability(system_state, load_seq, pv_seq, soc_seq): eens 0.0 for faulted_component in sampled_faults: isolated_loads find_isolated_loads(faulted_component) restored_loads, shed_loads analyze_restoration(...) eens shed_loads * outage_duration return eens / simulation_years3.3 数据结构用图把拓扑讲清楚别用一维矩阵硬算配电网规划代码里最容易烂的是一开始把拓扑塞进高维矩阵。我用networkx的无向图描述拓扑import networkx as nx G nx.Graph() for br in branches: G.add_edge(br[from], br[to], rbr[r_ohm], xbr[x_ohm], typebr[line_type], status1)节点属性挂负荷、DG、储能候选信息支路属性挂阻抗、容量、故障率、修复时间。这样判断连通性、查转供路径都能直接调用图算法切负荷后的孤岛分割用连通分量搜索就能完成。决策变量单独用一个一维数组表示比如前N个位置存线路是否升级0/1中间M个位置存DG容量档位整数最后K个存储能容量档位。这个数组会直接作为NSGA-II的个体基因后面做适应度计算时再解码成具体的规划方案。潮流计算我用的前推回代法适合辐射状配电网代码短、收敛稳。时序评估时每个小时都要算一次潮流为了速度负荷和DG功率都预先组织成二维numpy数组形状是(8760, node_count)按列切片喂给潮流函数避免在Python循环里逐小时重建网络。4. 双目标求解的算法选型与Python环境搭建实战4.1 为什么选NSGA-II而不是穷举或单纯加权这个问题的答案从工程角度非常现实。规划问题的决策变量是混合整数目标函数带非线性潮流穷举根本不可能传统非线性规划对整数变量和拓扑约束的适配很痛苦单纯加权法前面说过一个权重对应一个点画前沿要反复求解而且前沿凹段会被漏掉。NSGA-II的核心价值在于它一次进化就能维护一整组候选解非支配排序把解按层级分开拥挤距离保证前沿分布均匀。我用的就是最经典的版本Python里通过pymoo库可以直接调用稳定可靠。4.2 Python环境配置一个干净环境能少踩一半坑这部分写给刚入门的朋友。Windows下装Python别去改系统默认环境我建议直接建虚拟环境conda create -n dsp python3.10 conda activate dsp pip install numpy pandas scipy matplotlib networkx pymoo如果还没有装Python就去Python官网下载安装包安装时记得勾选Add Python to PATH。numpy是后面所有数值计算的基础scipy用来做统计和插值matplotlib画帕累托前沿图networkx处理拓扑图pymoo提供NSGA-II。一个容易出问题的地方是pymoo的版本旧版本API和现在不一样装的时候直接pip install pymoo装最新的即可如果看到import pymoo报错多半是conda默认环境太老或者没激活虚拟环境。4.3 用pymoo把规划问题包装成标准优化问题pymoo的使用逻辑很简单继承Problem类定义变量个数、边界和目标个数在_evaluate方法里计算两个目标值然后初始化NSGA2算法调用minimize。核心代码框架from pymoo.core.problem import Problem from pymoo.algorithms.moo.nsga2 import NSGA2 from pymoo.optimize import minimize import numpy as np class DistributionPlanningProblem(Problem): def __init__(self): n_var 20 # 线路升级0/1 DG容量档位 储能容量档位 super().__init__(n_varn_var, n_obj2, xl0, xu1) # 下界上界离散解码在内部做 def _evaluate(self, X, out, *args, **kwargs): f1 np.zeros(X.shape[0]) f2 np.zeros(X.shape[0]) for i in range(X.shape[0]): f1[i], f2[i] evaluate_plan(X[i]) out[F] np.column_stack([f1, f2]) problem DistributionPlanningProblem() algorithm NSGA2(pop_size60) res minimize(problem, algorithm, (n_gen, 100), seed42, verboseTrue)注意这里evaluate_plan是我自定义的核心评估函数它需要完成编码解码、潮流计算、蒙特卡洛可靠性评估、费用统计四件事是整个代码里计算开销最大的部分。4.4 决策变量编码与约束罚函数NSGA-II本身不区分连续还是离散所以我在解码时统一处理。比如x数组里有一部分是连续的[0,1]解码时按阈值映射成0或1作为是否升级线路另一部分映射成DG容量档位例如区间[0,1)映射为档位0、[1,2)映射为档位1。这样做的好处是算法内部不用改交叉变异算子坏处是浮点编码会带来少量映射噪音但实测对规划结果影响很小。约束处理是真正决定算法能不能收敛到可行域的地方。我处理三类硬约束节点电压不越限、支路电流不越限、网络保持辐射状。每个约束都转成罚项加到目标上penalty lambda v: large_number * max(0, v)越限量越大罚得越狠。辐射状校验用numpy快速算连通性和边的数量不满足就直接加大罚项。罚函数系数要不要自适应我试过固定系数也试过慢慢加大工程上固定大系数已经够用关键是不要让约束被目标函数淹没导致进化后期大量不可行解继续繁殖。5. 跑通完整规划项目的实操流程与排坑记录5.1 从IEEE 33节点系统起步数据和代码要一次对齐我建议第一次做这个课题的读者用IEEE 33节点系统节点和支路参数在公开文献里都能查到系统是12.66kV负荷3490kW左右。构造方法是先用networkx搭建基础辐射网把IEEE标准的支路阻抗、负荷数据填进去再在几条末端线路上设置联络备用通道通常是5号线、18号线、25号线附近的联络模拟真实配电网的转供能力最后选3个候选节点装光伏1个候选位置装储能。一开始不要贪多算例规模小跑起来才快调试也容易。数据输入我统一用CSV项目里建好分支数据表、负荷数据表、DG出力时序表、储能运行参数表。每次改变决策变量后重新读基础数据太慢正确的做法是基础数据启动时加载一次决策方案作为参数传入评估函数只在评估函数内部修改图结构和分布式电源配置。5.2 时序蒙特卡洛的随机抽样固定种子是第一原则序贯蒙特卡洛的随机性会让目标函数每次计算结果不同如果同一套方案两次评估EENS差5%NSGA-II比较个体优劣时就会被噪声干扰整个前沿都会飘。我的做法是全局固定numpy随机种子比如np.random.seed(2024)但这只能保证单次进程内一致性。跨进程并行时每个进程需要不同的种子我会用进程编号加随机偏移保证不同工作进程的模拟序列不重复。抽样逻辑要点是对每个元件按小时状态转移抽样故障状态持续时间服从指数分布期望是修复时间用numpy批量生成状态序列而不是写for循环逐小时判断不然8760小时乘几十个元件会非常慢。5.3 最容易翻车的几个地方和对应排查踩坑点表现原因解决办法单位混乱EENS算出来是几千E06负荷用kW、电量却按MWh计费统一换算最后除以1e3潮流发散网损负值或电压越限离谱初始电压全0支路阻抗写错用平启动1.0j0核对IEEE参数优化不收敛前沿分散没有规律蒙特卡洛随机性太大或模拟年数太少固定种子把模拟年数提到50年以上孤岛评估偏乐观EENS偏低没考虑故障时刻DG出力和SOC在故障时刻读取时序出力加入SOC约束无可行解前沿全在罚函数区硬约束罚项太小罚项系数提到让不可行解成本差出一个数量级第一个单位坑我印象最深。EENS统计的是千瓦时但我停电损失费用表里的单位是元/千瓦时网络潮流算出来的损耗是kW乘时间后自然过渡到千瓦时偏偏在写报告时想用MWh展示换算漏了一次导致经济性目标里停电损失大得离谱。为了不再翻车我在代码里强制要求所有功率量纲写进块注释并在数据读入口加单位检查和换算。5.4 结果可视化前沿图和最终拓扑缺一不可跑完优化画帕累托前沿是最直观的验证方式import matplotlib.pyplot as plt F res.F plt.scatter(F[:, 0], F[:, 1], c#1f77b4, s30, alpha0.8) plt.xlabel(Annual total cost / 10k CNY) plt.ylabel(EENS / MWh) plt.grid(True, linestyle--, alpha0.5) plt.tight_layout() plt.savefig(pareto_front.png, dpi150)再单独画一个最优方案的网络拓扑图把升级线路、DG位置、储能位置用不同颜色标出来方便和评审人员沟通。这个组合比单纯贴数据表格有说服力得多。6. 帕累托前沿怎么看方案决策与工程落地经验6.1 前沿形态本身就是结论正常计算出来的前沿是一条单调下降的曲线总成本从低到高EENS从高到低形成L形拐点。拐点左侧意味着预算略微增加就能换来大量可靠性提升拐点右侧则是花大价钱只能换来一点点EENS下降。我在报告里一定会在前沿图上标注三个点经济最优方案、拐点附近推荐方案、可靠性最优方案对应给出各自的投资额、运维成本、网损、EENS和SAIDI。三个方案放在一张表里比讨论算法细节更能说服决策者。6.2 停电损失费用的灵敏度分析最常被问到评审会上高频问题就是单位停电损失费用你取了多少谁定的这个数确实没有全国统一标准工业用户、居民用户、商业用户差一个数量级。正确答案是不要试图给一个权威值而是把它当参数扫一遍比如取1元/kWh、5元/kWh、10元/kWh各跑一次优化看推荐方案是否稳健。如果不同取值下推荐方案都落在同一区域说明方案对停电损失费用不敏感结论就硬如果差别很大说明决策高度依赖用户对停电的主观评价这时需要把这一结论单独拿出来讨论。6.3 模型简化边界与扩展方向最后说点个人体会。这套基于经济与可靠性双目标的分析框架核心价值在于把决策问题结构化但它有明确边界故障率我按常数处理没有考虑线路老化、台风暴雨等极端天气储能运行策略是简化定则没有做完整的经济调度换流器等设备也没有建详细损耗模型。这些简化会让绝对数值有偏差但方案比选趋势是可信的。如果你后续想深挖可以扩展的方向有两个比较实际一是把时序运行模拟嵌入评估让储能在故障前按经济调度充电而不是随机SOC二是引入不确定性参数分析比如DG出力和负荷的多场景描述在双目标基础上再做鲁棒优化。我自己的习惯是搞定NSGA-II之后少花时间调算法参数把精力放在可靠性评估模块的故障场景细节上回报率最高。毕竟帕累托前沿的形状是评估模型一笔一笔刻画出来的模型粗糙算法再花哨也输出不了可信的决策支持。
返回列表