做电网规划的这几年,我越来越觉得,这个活儿的难点从来不在某一个单点上,而在“权衡”。要在经济性和可靠性之间权衡,要在投资和运行之间权衡,要在好几套备选方案里反复权衡。尤其当分布式电源和储能大规模接入之后,配电网变成真正意义上的“混合配电系统”,这种权衡的复杂度又往上跳了一个台阶。
我最近整理了一套基于经济与可靠性双目标的混合配电系统规划及可靠性评估方法,核心逻辑是把“规划方案生成”和“可靠性评估”组合成一个完整的闭环:外层用多目标进化算法搜方案,内层用序贯蒙特卡洛模拟算可靠性,最后输出一组Pareto最优解给决策者挑。整套代码用Python实现,也是我个人在多个项目里反复调整之后比较顺手的一套框架。
这篇文章适合谁看?如果你在做配电网规划相关的研究、设计或工程落地,需要把分布式电源、储能和传统配电网揉在一起做方案比选;或者你手头已经有评估算法,但不知道怎么把可靠性指标和经济成本真正放进同一个优化框架里,那这篇内容应该能帮上忙。我不打算只堆公式,而是把模型怎么建、代码怎么写、坑在哪里,都按实际操作的顺序讲清楚。
1. 混合配电系统规划到底在解决什么问题
1.1 “混合”这个词带来的规划难点
传统配电网是单向供电、辐射状结构,电源在上游,负荷在下游,规划的核心无非是线路扩容、变电站增容。但现在系统里接入了光伏、风电、储能、电动汽车充电设施,甚至微电网,情况就完全变了:潮流方向不再固定,设备利用率波动变大,可靠性评估也不能再简单按“故障—停电”的静态逻辑来算。
这种“混合”属性的直接后果是:规划人员要同时决定多个层次的问题。常规电网改不改、新增DG往哪接、储能配多大、开关和自动化设备怎么布,这些决策彼此影响。比如你在一端接入大量光伏,如果不配套储能和线路改造,可能白天电力溢出送不出,晚上又不够用。反过来,如果规划得保守,冗余装备一堆,投资回报就成问题。
所以混合配电系统规划,本质上是一个组合优化问题,决策变量类型多、约束多、目标相互冲突。这也是它比单一设备规划难一个数量级的原因。
1.2 为什么一定是“经济+可靠性”双目标
规划这件事最终要落到底层,就是两个问题:花多少钱,以及靠不靠得住。
经济性指标涵盖设备投资、运行维护、电能损耗、购电成本这些看得见的费用;可靠性指标则考核用户侧能感知到的停电频率、停电时长、缺供电量。这两个目标天然互相矛盾:提高可靠性的手段,比如增设联络开关、配置冗余线路、增加储能备用容量,每一项都要花钱;而压缩投资的最直接方式,就是砍掉那些“平时用不上、关键时刻救命”的设备。
如果只按经济性最优来规划,算出来的方案成本最低,但可靠性可能让用户无法接受;如果只按可靠性最优来规划,系统会冗余到成本失控。所以工程上需要同时优化两个目标,让决策者看到完整权衡关系,再结合实际情况选一个落地方案。
1.3 双目标如何定量描述
我把两个目标分别写成标量函数,评价一个规划方案时同时计算这两项:
- 经济目标:全生命周期等年值成本,单位万元/年,数值越低越好
- 可靠性目标:可以用SAIDI,也可以用年期望缺供电量ENS,单位小时/户·年或MWh/年,同样越低越好
这里一个很实用的建模思路是,把可靠性指标折算成缺电损失成本,塞进经济目标里。这样规划代码里就有了两个维度:一个是净经济成本,一个是纯可靠性水平。前者包含缺电损失但它是货币化的,后者是物理指标。两个目标从不同视角评价方案,比单纯混成一个总费用更有分析价值。
2. 可靠性评估的原理、选型与Python实现要点
2.1 指标体系怎么选才够用
算可靠性,第一步是选指标。我常用的四个指标是SAIFI(系统平均停电频率指标)、SAIDI(系统平均停电持续时间指标)、ENS(缺供电量)和ASAI(供电可用率)。
| 指标 | 含义 | 单位 |
|---|---|---|
| SAIFI | 系统用户平均停电次数 | 次/户·年 |
| SAIDI | 系统用户平均停电时间 | 小时/户·年 |
| ENS | 年期望缺供电量 | MWh/年 |
| ASAI | 供电可用率 | % |
规划阶段我通常重点看SAIDI和ENS。SAIDI反映的是用户的停电感受,适合用来做约束,比如“改造后SAIDI必须控制在2小时以内”;ENS则直接跟缺电损失挂钩,方便折算成经济成本放进目标函数里。
2.2 解析法和蒙特卡洛怎么选
可靠性评估有两大流派:解析法和模拟法。解析法适合电网结构固定、规模较小的场景,通过枚举故障模式或者求最小割集来计算指标,速度快、结果稳定。但混合配电系统里,DG出力的随机性、储能充放电策略、负荷转移和开关动作逻辑都带有时序特征,解析公式很难精确刻画。
所以我更推荐序贯蒙特卡洛模拟。它就是把系统一年的运行过程逐年“演”无数遍,每一年里元件的故障和修复按概率分布随机抽样,然后统计平均停电指标。这个方法的好处是能容纳各种复杂的运行策略,只要你把策略用代码写清楚,评估逻辑就能反映出来。
代价也很直观——慢。在规划优化里,每个候选方案都要做一次全系统的可靠性评估,如果蒙特卡洛采样年数不够,结果抖动还特别大,直接导致进化算法分不清两个方案谁更优。
2.3 序贯蒙特卡洛的Python实现细节
核心数据结构是元件状态时间序列。一个元件通常用两状态模型:正常运行状态和故障停运状态。故障率λ(次/年)、平均修复时间r(小时),这两个参数是基础输入。
实现时我一般这么处理:
import numpy as np def generate_component_states(years, failure_rate, repair_hours): # 将年转换为小时 total_hours = years * 8760 states = np.ones(total_hours, dtype=int) # 1表示正常,0表示故障 t = 0 while t < total_hours: # 抽样正常运行持续时间,指数分布 uptime = np.random.exponential(1.0 / failure_rate) * 8760 t += uptime if t >= total_hours: break # 抽样故障修复时间,这里假设指数分布,指定平均修复小时 downtime = np.random.exponential(repair_hours) end = min(int(t + downtime), total_hours) states[int(t):end] = 0 t = end return states这段代码的关键点有两个:一是把年故障率换算成小时尺度时,要乘以8760;二是修复时间直接用小时。单位不统一是刚开始跑这个程序时最容易出的问题,我早期有一次算出来的SAIDI离谱地小,排查半天才发现是故障率换算时少乘了一个8760。
有了每个元件的状态序列之后,下一步是逐小时判断系统哪些负荷失电。这一步要结合网络拓扑和潮流结果:某个元件故障后,先判断有没有转供路径,有的话尝试恢复部分负荷;没有的话,故障范围内的负荷全部停电。统计每一小时的失电负荷和停电用户数,累加除以总用户数和总年数,就能得到SAIFI和SAIDI。
2.4 评估速度优化的三个方向
蒙特卡洛慢是公认痛点。我在一个33节点算例里实测过,如果用纯Python循环逐小时判断,跑一个方案要一分钟以上。三个方向的优化效果最直接:
- 向量化采样:把逐小时循环改成numpy数组批量生成状态序列,避免Python循环
- 场景缓存:同一故障场景在不同采样年里重复出现,按故障模式查表,避免重复计算相同的恢复策略
- 并行评估:pymoo支持多进程并行评估种群个体,多核机器上接近线性加速
这三点做完,33节点系统跑一轮可靠性评估能压缩到几秒级别,整个优化流程才可能在实际项目中落地。
3. 经济性建模与NSGA-II多目标优化框架
3.1 经济性目标到底包含哪些钱
经济性目标我按全生命周期口径计算,一般分五块:设备投资成本、运行维护成本、网络损耗成本、向上级电网购电成本、缺电损失成本。
投资成本包括线路新建或改造、变压器增容、DG和储能设备购置费用。运行维护成本按设备类型的年维护费率计算,光伏、储能、常规配变的维护费率差异很大。网络损耗成本要基于典型日负荷曲线做潮流计算,把年损耗电量折算成购电成本。
这里必须强调,设备寿命不同,不能直接把建设总费用和年运行费用相加。要把投资成本折算成等年值——先算现值,再用资金回收系数换算成年值。资金回收系数的公式是:
CRF = r * (1 + r)^n / ((1 + r)^n - 1)其中r是贴现率,n是设备寿命。同样一笔投资,寿命15年的线路和寿命10年的储能,年化成本完全不是一回事。
3.2 为什么我不用单目标加权法
把两个目标加权合成一个单目标,逻辑上很简单,实际操作却非常难受。最核心的问题是权重不好定。经济性单位是万元,可靠性单位是小时或MWh,不同量纲、不同数量级,权重本质上代表了主观偏好,你定多少都会被人问一句“凭什么”。更麻烦的是,如果Pareto前沿是非凸的,线性加权法根本求不出全部最优解。
多目标进化算法就不存在这个问题。以NSGA-II为例,它靠着非支配排序和拥挤度距离,一次运行就能跑出一整片Pareto前沿。最终输出不是单个方案,而是一串方案,决策者可以从前沿上根据实际偏好挑点。
3.3 pymoo里的实现组织方式
Python里的多目标优化库,我推荐pymoo,它自带NSGA-II、NSGA-III等主流算法,API比较清晰。DEAP也可以,但算子灵活度要求高,更适合自己定制算法的人。
我在pymoo里的实现套路是这样的:
- 定义个体编码:线路改造状态用二进制,DG接入容量用实数,储能配置功率和容量用实数
- 在问题类里实现
_evaluate方法,输入个体矩阵,输出经济成本和可靠性指标两个目标值 - 约束写在问题类里,比如节点电压上下限、支路容量、辐射状拓扑约束
一个典型的pymoo问题定义框架:
from pymoo.core.problem import Problem import numpy as np class DistributionPlanningProblem(Problem): def __init__(self): n_var = 20 # 根据具体决策变量数量调整 super().__init__(n_var=n_var, n_obj=2, n_ieq_constr=5) def _evaluate(self, X, out, *args, **kwargs): # X是一批个体,需要逐个解码并评估 results_cost = [] results_saidi = [] for individual in X: plan = decode_individual(individual) cost = evaluate_economic(plan) reliability = evaluate_reliability(plan) results_cost.append(cost) results_saidi.append(reliability) out["F"] = np.column_stack([results_cost, results_saidi]) # 不等式约束,小于0为满足 out["G"] = np.column_stack([...])这里要提醒一个重点:评估函数里可靠性评估是最耗时的一环。NSGA-II每一代要评估整个种群,几百个个体做几十上百次蒙特卡洛,如果评估函数写得粗糙,整个优化流程会拖到无法接受。所以正式跑优化之前,一定要先单独验证评估函数的速度。
4. 33节点算例从零跑通全流程
4.1 算例设计:先小后大,别贪规模
第一次跑通这套框架,不建议直接上几百节点的实际馈线。我推荐从IEEE 33节点标准算例开始,它26条支路、32个负荷节点,规模适中,既能体现辐射状配电网的全部特征,又方便人工核对结果。
算例数据要包含几类:各节点年峰值负荷和典型日负荷曲线、线路阻抗和容量参数、上级电源位置和容量、DG候选接入节点和容量范围。负荷曲线很重要,不能只用峰值负荷做静态评估,否则蒙特卡洛无法体现负荷时序变化对可靠性的影响。
我先不加任何DG,跑一遍基础潮流和可靠性评估,得到“投资为0但缺电损失较高”的基准方案。这个基准值后面非常关键,所有优化方案的改善幅度都拿它作为对比参照。
4.2 代码结构:从第一天就分好模块
代码结构直接影响后期的调试效率。我的目录组织是这样:
project/ ├── data/ # 算例数据文件,csv或excel ├── models/ # 配电网模型、元件参数类 ├── evaluation/ # 潮流计算、可靠性评估模块 ├── optimizer/ # NSGA-II配置与主循环 ├── results/ # Pareto前沿输出与图表 └── main.py # 总入口强烈建议把评估部分独立成模块,不要和优化逻辑揉在一起。原因有两个:一是调试可靠性评估时,可以单独跑一个方案,不用启动整个进化流程;二是后续如果想替换评估逻辑,比如从序贯蒙特卡洛换成准序贯,只需要动评估模块,优化器不用改。
4.3 潮流计算和可靠性评估如何配合
潮流计算我用pandapower,它内置了牛顿法和直流潮流,读取网络参数之后直接求解。对33节点这种规模,速度和收敛性都不是问题。
可靠性与潮流的配合关系,我总结成三步:
- 对规划方案先跑正常状态潮流,检查线路负载率和节点电压是否越限
- 在蒙特卡洛模拟的每个故障场景中,先判断失电区域,然后搜索相邻的联络开关或转供路径,尝试恢复非故障区域负荷
- 恢复之后再做一次潮流校验,如果线路过载或电压不合格,就需要继续削减部分负荷,直到潮流收敛且满足约束
这一点特别重要:如果只判断“拓扑是否连通”就认定负荷恢复,不考虑容量和电压约束,评估出来的可靠性指标会明显偏乐观。我早期跑结果时发现SAIDI比文献值好很多,检查半天才发现是恢复策略里漏掉了重载校验。
4.4 NSGA-II主循环的参数设置
pymoo里跑NSGA-II,参数我一般这样设:
from pymoo.algorithms.moo.nsga2 import NSGA2 from pymoo.operators.crossover.sbx import SBX from pymoo.operators.mutation.pm import PM from pymoo.operators.sampling.real_random import RealRandomSampling from pymoo.optimize import minimize algorithm = NSGA2( pop_size=100, sampling=RealRandomSampling(), crossover=SBX(prob=0.8, eta=15), mutation=PM(prob=0.1, eta=20), eliminate_duplicates=True ) res = minimize(problem, algorithm, ('n_gen', 200), seed=42, verbose=True)种群规模100,最大代数200,交叉概率0.8,变异概率0.1,随机种子固定方便复现。这个设置在我跑过的中低压配网算例里收敛表现都不错。
跑完后,保存每一代记录的Pareto前沿。横轴画经济年成本,纵轴画SAIDI或ENS,能非常直观地看出成本和可靠性之间的权衡关系。
4.5 从Pareto前沿里挑最终方案
优化结束不是直接把第一个解交付,而是从前沿上选点。前沿上每个解都代表一种“偏好”:越靠左经济性越好但可靠性差,越靠右可靠性好但花钱多。
我常用的筛选逻辑有三个:一是看前沿上的“拐点”,也就是斜率突变的位置,这里往往是性价比最高的区域;二是先设定一个可靠性约束,比如SAIDI必须小于2小时,在前沿上圈出可行解,选成本最低的那个;三是用熵权TOPSIS这类多属性决策方法给前沿解打分,适合需要走评审流程的项目。
不过说句实在话,真正做规划项目时,最靠谱的方式还是把几套关键方案的前沿图和相关指标拿到评审会上,跟决策者一起讨论。优化算法解决的是“有哪些好方案”的问题,最终怎么定,还得结合现场条件和政策要求。
5. 常见问题与排查技巧实录
5.1 蒙特卡洛结果不稳定怎么办
蒙特卡洛指标本质上是统计估计值,不是精确值。如果你发现同一个方案跑两次,SAIDI差20%以上,那说明采样年数不够。
我的经验是用方差系数来控制采样量。每累计一定采样年数,就计算SAIDI的方差系数,低于0.02~0.05就可以停止。但注意,进化算法内部如果每个个体都动态调整采样年数,会让比较失去基准。我建议固定采样年数,比如5000年,保证方案之间可比。
为了减少计算负担,可以用两级评估:前期用1000年粗评估筛掉明显差的个体,最后对精英解再用5000年精评估。实测下来,这个策略能省掉大半计算时间,同时保住结果可信度。
5.2 不可行解太多怎么办
规划问题的约束一大堆,随机生成的个体很可能不可行,最常见的是破坏了辐射状拓扑,或者电源容量不足导致潮流不收敛。不可行解一多,进化算法大部分时间都在评估无效方案,收敛自然慢。
我的处理办法是“修复优先于惩罚”。以辐射状约束为例,检测到一个个体存在环网结构时,就随机断开一条成环支路,把拓扑修复为辐射状。惩罚函数当然也能用,但惩罚系数要反复调,调不好会让算法向不可行区域偏移。
5.3 整条流程太慢从哪里突破
整套流程最重的瓶颈就是序贯蒙特卡洛评估。所以优化性能要盯住三个点:向量化采样、场景缓存、多进程并行。
pymoo的并行评估可以设置use_gpu=False,用多进程方式同时评估多个个体。这里有一个坑:多进程模式下,如果每个子进程都重新加载算例数据和潮流模型,开销会非常大。我的解决办法是把只读数据放全局变量,子进程初始化时只加载一次。
三件事都做完以后,33节点系统跑200代NSGA-II从原来的一天压到几个小时,这个速度对研究级项目已经足够了。
5.4 一个最不起眼但最致命的问题:数据质量
最后说一个最容易被忽视、但后果最严重的坑:数据错误。算例数据里一个负荷节点编号写错、一条线路的阻抗数量级不对,可靠性评估结果会悄无声息地变形,而且很不容易察觉,因为报错很少,数值看着也“像那么回事”。
我养成的习惯有这几条。解析完算例数据先画网络拓扑图,人工核对节点编号和支路连接,这一步能拦住大部分拓扑错误。做一次“无DG、无改造”的基准可靠性评估,跟公开文献或标准算例的结果对比,偏差太大就一定有问题。最后把经济成本的各个分量单独输出,检查投资成本、网损成本、缺电损失是不是都在合理区间。
没有哪个算法能对抗脏数据。我在这套流程上踩过的所有“灵异问题”,最后追根溯源几乎都回到了数据表本身。所以我把这条放在最后讲,它是整套方法能不能复现的底线。
以上就是我个人在混合配电系统规划及可靠性评估里积累的一套完整实践。说实话,优化算法本身已经比较成熟,真正拉开方案质量差距的,是模型建得够不够贴近实际,评估逻辑有没有把恢复策略、时序出力这些细节考虑进去,以及拿到结果之后能不能做出正确的权衡判断。如果你也正在处理类似的规划问题,建议先从小算例把评估流程跑通,再逐步加实际网络数据,过程中务必把数据校验当成第一道工序。这样遇到问题的时候,你才能有底气说,结果对不上,一定不是模型和代码先出问题。