极端天气下电网韧性提升策略代码:从故障场景到恢复决策的完整推演 简介本资源面向电力系统与新能源并网方向的研究生、科研人员及工程技术人员聚焦极端天气条件下电网韧性提升策略的仿真与评估。包内提供完整的代码实现与配套数据可用于分析风电出力在气候情景下的波动特征支撑韧性指标计算、策略对比与敏感性分析等研究任务。资源共148个文件以140个csv数据文件和8个py脚本为主csv文件承载不同气候模式、不同年份的容量因子与情景数据py脚本负责数据处理、指标计算与策略求解压缩包整体约240.14MB目录结构便于按气候情景与年份检索。目前已有136人学习下载。读者可据此复现极端天气下的电网韧性评估流程理解风电出力不确定性建模思路并在此基础上调整参数、替换数据或扩展策略模块快速搭建自己的研究实验框架。1. 极端天气下电网韧性提升策略代码从故障场景到恢复决策的完整推演台风过境那天某区域电网在 40 分钟内连续跳闸 17 条线路调度中心的值班人员盯着屏幕上不断扩大的失电区域手里能用的只有一份静态的应急预案。这个场景暴露的问题很典型极端天气下的电网故障不是单点故障而是多点并发、级联演化的复杂过程靠人工经验和固定预案根本来不及响应。这份「极端天气下电网韧性提升策略代码」要解决的正是这个问题——它把电网韧性评估、故障场景生成、恢复策略优化串成一条可执行的代码链路让开发者能在仿真环境中复现极端天气下的电网演化过程并测试不同的韧性提升策略。适合电力系统方向的研究生、做电网调度仿真的工程师以及想切入能源韧性领域的算法开发者。代码本身不依赖真实调度系统用标准测试系统就能跑通全流程。2. 技术栈与整体架构从场景生成到策略评估的四层链路2.1 核心依赖与运行环境这个项目的技术选型走的是「电力系统仿真 优化求解 数据分析」的经典组合。核心依赖分三块电力系统计算用 pandapower 或 PyPSA 做潮流计算和网络建模优化求解用 PuLP 或 Gurobi 处理恢复策略的整数规划问题数据处理和可视化用 pandas、numpy、matplotlib 这套标配。Python 版本建议 3.9 以上因为部分依赖对 3.8 以下的支持已经不太稳定了。# 创建虚拟环境并安装核心依赖 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install pandapower2.14.0 pip install pulp2.7.0 pip install pandas numpy matplotlib networkx pip install jupyter # 如果要用 notebook 跑示例这里有个血泪经验pandapower 的版本和 numpy 版本有绑定关系装最新版 pandapower 时如果 numpy 是 2.x大概率会报np.float_已移除的错误。稳妥做法是先装 numpy 1.24.x再装 pandapower。Gurobi 是商业求解器有学术 license 的话可以用没有就用 PuLP 自带的 CBC 求解器小规模测试系统完全够用。2.2 四层架构拆解整个项目的代码结构按数据流分成四层每层职责清晰层与层之间通过标准数据结构传递。第一层场景生成层。负责把「极端天气」这个模糊概念转成具体的故障场景。核心思路是基于线路的故障概率模型用蒙特卡洛采样生成大量故障组合。每条线路的故障概率跟风速、线路老化程度、地理暴露度相关代码里用一个可配置的概率函数来描述。第二层状态评估层。拿到故障场景后用潮流计算判断当前电网状态——哪些节点失电、哪些线路过载、系统频率是否稳定。这一层会输出一个韧性指标通常用失负荷比例或系统韧性三角形面积来量化。第三层策略优化层。这是项目的核心。给定故障后的电网状态决策变量包括哪些线路需要修复、修复顺序如何、是否切负荷、分布式电源如何调度。目标函数是最小化失负荷量和恢复时间。第四层评估对比层。把不同策略在同一个故障场景集上跑一遍输出韧性指标的统计对比包括均值、方差、最坏情况。# 项目核心数据流示意简化版 class ResiliencePipeline: def __init__(self, network, weather_config): self.network network # pandapower 网络对象 self.weather weather_config # 极端天气参数 self.scenarios [] # 故障场景集 self.results {} # 策略评估结果 def generate_scenarios(self, n1000): 蒙特卡洛生成故障场景 for _ in range(n): fault_set self._sample_faults() self.scenarios.append(fault_set) return self.scenarios def evaluate_strategy(self, strategy): 在全部场景上评估一个恢复策略 metrics [] for scenario in self.scenarios: state self._apply_faults(scenario) recovery strategy.optimize(state) metrics.append(self._calc_resilience(state, recovery)) return np.mean(metrics), np.std(metrics)这段代码的关键在于_sample_faults和strategy.optimize两个方法。前者决定了场景的覆盖度后者决定了策略的优劣。实际项目中_sample_faults会根据线路的脆弱性曲线做加权采样而不是均匀随机——因为极端天气下地理上相邻的线路往往同时故障均匀采样会低估级联风险。2.3 目录结构说明项目目录按功能模块划分方便二次开发时快速定位resilience_grid/ ├── config/ # 配置文件 │ ├── ieee33.yaml # IEEE 33 节点测试系统参数 │ └── weather.yaml # 极端天气场景参数 ├── src/ │ ├── scenario/ # 场景生成模块 │ │ ├── fault_model.py # 线路故障概率模型 │ │ └── sampler.py # 蒙特卡洛采样器 │ ├── evaluation/ # 状态评估模块 │ │ ├── powerflow.py # 潮流计算封装 │ │ └── metrics.py # 韧性指标计算 │ ├── strategy/ # 策略优化模块 │ │ ├── restoration.py # 恢复策略基类 │ │ ├── greedy.py # 贪心恢复策略 │ │ └── milp.py # 混合整数规划策略 │ └── utils/ # 工具函数 ├── notebooks/ # 示例 notebook │ ├── 01_scenario_demo.ipynb │ └── 02_strategy_compare.ipynb ├── tests/ # 单元测试 └── requirements.txt这个结构的好处是策略模块可以插拔——想对比贪心策略和 MILP 策略只需要在配置里换一个类名不用改评估代码。config目录用 YAML 管理参数改测试系统或天气参数不用动代码。3. 核心模块拆解故障采样、潮流计算与恢复策略的实现细节3.1 故障场景生成从风速到线路故障概率极端天气下线路故障不是独立事件。台风场景中一条线路断了之后潮流会转移到相邻线路导致过载跳闸形成级联故障。代码里的故障模型分两步先算每条线路的初始故障概率再模拟级联过程。import numpy as np class FaultModel: def __init__(self, line_data, weather_params): self.lines line_data self.wind_speed weather_params[wind_speed] # 风速 m/s self.rainfall weather_params[rainfall] # 降雨量 mm/h self.exposure line_data[exposure] # 地理暴露度 0-1 def line_failure_prob(self, line_id): 计算单条线路的故障概率 line self.lines[line_id] # 基础故障率正常运行状态 base_rate line[base_failure_rate] # 风速超过设计阈值后的加速因子 wind_factor max(0, (self.wind_speed - line[design_wind_speed]) / 10) # 降雨影响 rain_factor self.rainfall / 100 # 综合概率用指数模型避免超过 1 prob 1 - np.exp(-base_rate * (1 wind_factor rain_factor) * self.exposure[line_id]) return min(prob, 0.95) # 截断避免数值问题 def sample_initial_faults(self): 采样初始故障集 faults [] for line_id in self.lines: p self.line_failure_prob(line_id) if np.random.random() p: faults.append(line_id) return faultsline_failure_prob里的指数模型是关键设计。用1 - exp(-λ)而不是直接线性叠加是为了保证概率始终在 0 到 1 之间而且当基础故障率很低时天气因素的影响会被自然放大——这符合实际观察正常天气下线路几乎不出事但极端天气下故障率会陡增。design_wind_speed是线路的设计风速一般架空线取 25-30 m/s超过这个值后wind_factor开始起作用。级联故障的模拟在sampler.py里逻辑是初始故障后跑一次潮流检查有没有线路过载过载线路按过载倍数决定是否跳闸跳闸后重新跑潮流循环直到没有新故障或达到最大迭代次数。3.2 潮流计算与韧性指标状态评估层用 pandapower 做潮流计算。这里有个容易翻车的地方故障后电网可能解列成多个孤岛每个孤岛要单独跑潮流不能直接对整个网络跑——否则会报不收敛。import pandapower as pp import pandapower.topology as top class StateEvaluator: def __init__(self, net): self.net net def evaluate(self, faulted_lines): 评估故障后的电网状态 # 复制网络避免修改原始数据 net self.net.deepcopy() # 断开故障线路 for line_id in faulted_lines: net.line.at[line_id, in_service] False # 检查孤岛 mg top.create_nxgraph(net, respect_switchesTrue) islands list(top.connected_components(mg)) total_load net.load.p_mw.sum() served_load 0 for island in islands: # 每个孤岛单独跑潮流 island_net self._extract_island(net, island) try: pp.runpp(island_net, algorithmnr, max_iteration50) if island_net.converged: served_load island_net.res_load.p_mw.sum() except Exception: # 潮流不收敛该孤岛全部失电 pass # 失负荷比例 loss_ratio 1 - served_load / total_load if total_load 0 else 0 return { loss_ratio: loss_ratio, n_islands: len(islands), converged: served_load 0 }_extract_island方法需要根据节点集合重建一个子网络包括子网内的线路、负荷和发电机。这一步比较繁琐但必须做——pandapower 没有内置的孤岛提取函数得手动处理。韧性指标用失负荷比例loss_ratio是最直观的也可以换成韧性三角形面积把失负荷随时间的变化曲线画出来曲线下的面积就是韧性损失。3.3 恢复策略贪心与 MILP 的取舍恢复策略模块提供两个实现贪心策略和 MILP 策略。贪心策略适合快速评估MILP 适合小规模系统的精确求解。import pulp class MILPRestoration: def __init__(self, net, faulted_lines, crews3): self.net net self.faulted faulted_lines self.crews crews # 可用抢修队数量 def optimize(self, time_horizon24): 用 MILP 求解最优恢复顺序 prob pulp.LpProblem(restoration, pulp.LpMinimize) # 决策变量每条故障线路的修复开始时间 start pulp.LpVariable.dicts(start, self.faulted, lowBound0, upBoundtime_horizon) # 二进制变量线路是否在某个时段被修复 repair pulp.LpVariable.dicts(repair, self.faulted, catBinary) # 目标最小化加权恢复时间重要负荷优先 weights {l: self.net.line.at[l, priority] for l in self.faulted} prob pulp.lpSum(weights[l] * start[l] for l in self.faulted) # 约束1抢修队数量限制 for t in range(time_horizon): prob pulp.lpSum( repair[l] for l in self.faulted if start[l] t start[l] 1 ) self.crews # 约束2修复时间必须大于等于线路修复时长 for l in self.faulted: duration self.net.line.at[l, repair_time] prob start[l] duration * repair[l] prob.solve(pulp.PULP_CBC_CMD(msg0)) return {l: start[l].varValue for l in self.faulted}MILP 的目标函数里priority是线路重要度权重重要负荷医院、供水的权重设高普通居民负荷设低。约束1 保证同时抢修的线路数不超过抢修队数量约束2 保证修复时间不小于实际修复时长。这个模型在 IEEE 33 节点系统上求解很快但节点数超过 100 后 CBC 求解器会明显变慢这时候要么换 Gurobi要么退回贪心策略。贪心策略的逻辑简单得多按重要度排序每次选当前可修复线路中重要度最高的修复后重新评估状态直到所有线路修复或达到时间上限。虽然不保证全局最优但在大规模系统上速度快几个数量级。4. 避坑与常见问题跑通代码前必须知道的五件事4.1 潮流不收敛孤岛处理是最大坑点现象跑evaluate方法时报LoadflowNotConverged或者结果里converged为 False。原因故障后电网解列孤岛内没有发电机或者发电机容量不足潮流方程无解。pandapower 默认对整个网络跑潮流遇到孤岛直接报错。解决先做连通性分析把网络拆成孤岛每个孤岛单独跑。孤岛内如果没有发电机直接标记为全失电不要尝试跑潮流。代码里_extract_island方法就是干这个的注意提取子网时要同步处理bus、line、load、gen、ext_grid这几张表。4.2 蒙特卡洛采样效率低场景数不是越多越好现象生成 10000 个场景跑了一下午还没跑完。原因每个场景都要跑潮流计算10000 次潮流计算在 Python 里就是很慢。而且很多场景的故障集高度相似重复计算浪费资源。解决用拉丁超立方采样替代均匀随机采样同样精度下场景数可以减少 60% 以上。另外对故障集做去重——如果两个场景的故障线路集合相同只跑一次潮流。实际测试中1000 个采样场景去重后通常只剩 300-400 个独立场景。4.3 线路参数缺失测试系统数据不完整现象跑示例时报KeyError: design_wind_speed或exposure。原因标准测试系统如 IEEE 33只提供电气参数不提供天气相关的脆弱性参数。这些参数需要额外配置。解决在config/weather.yaml里给每条线路补上design_wind_speed、exposure、base_failure_rate三个字段。没有实测数据时design_wind_speed统一取 27 m/sexposure按线路长度归一化base_failure_rate取 0.001/小时。这些默认值不影响代码跑通但会影响结果的绝对值做定量分析时要替换成实际数据。4.4 MILP 求解器报错CBC 的整数变量上限现象故障线路超过 50 条时MILP 求解报Problem is infeasible或直接卡死。原因CBC 求解器对整数变量数量有限制而且分支定界在大规模问题上效率急剧下降。解决故障线路超过 30 条时把问题拆成两个阶段先按区域分组每组单独求解 MILP再在组间用贪心协调。或者直接换 Gurobi学术 license 免费求解速度比 CBC 快 10 倍以上。代码里MILPRestoration类预留了solver参数换成pulp.GUROBI_CMD()即可。4.5 结果不可复现随机种子没固定现象同样的代码跑两次韧性指标差了 5%。原因蒙特卡洛采样用了np.random.random()没有设种子。每次运行采到的故障场景不同结果自然有波动。解决在采样器初始化时固定种子np.random.seed(42)或者在配置文件里加random_seed参数。做策略对比时所有策略必须在同一组场景上评估否则对比没有意义。代码里ResiliencePipeline的generate_scenarios方法接受seed参数跑对比实验时传同一个种子。5. 二次开发与策略扩展从替换策略类到接入真实数据5.1 自定义恢复策略的接入方式项目的策略模块用了基类 实现的模式扩展新策略只需要继承RestorationStrategy基类并实现optimize方法。基类定义了策略的输入输出接口输入是故障后的网络状态和故障线路列表输出是每条线路的修复时间字典。from src.strategy.restoration import RestorationStrategy class MyStrategy(RestorationStrategy): def optimize(self, net, faulted_lines, **kwargs): 自定义恢复策略 返回: {line_id: repair_start_time} # 示例按线路长度排序短的先修 sorted_lines sorted( faulted_lines, keylambda l: net.line.at[l, length_km] ) schedule {} current_time 0 for line in sorted_lines: schedule[line] current_time current_time net.line.at[line, repair_time] return schedule接入时只需要在配置里把strategy字段改成MyStrategy的类路径评估流程会自动调用。这个设计的好处是策略和评估解耦——你可以用同一个场景集对比十种策略不用改评估代码。5.2 接入真实数据的三个关键映射如果手头有真实电网的 SCADA 数据或 GIS 数据接入项目需要做三个映射。第一把真实线路的电气参数映射到 pandapower 的line表关键是r_ohm_per_km、x_ohm_per_km、c_nf_per_km和max_i_ka四个字段。第二把地理信息映射到exposure参数沿海线路、山区线路的暴露度要设高。第三把历史故障记录映射到base_failure_rate用泊松回归从历史数据里拟合。# 从历史故障记录拟合基础故障率 import pandas as pd from scipy.stats import poisson def fit_failure_rate(history_df, line_id, years5): history_df: 包含 line_id, fault_time 的故障记录 返回: 该线路的年故障率 line_faults history_df[history_df[line_id] line_id] n_faults len(line_faults) # 泊松分布的 MLE 就是均值 rate_per_year n_faults / years return rate_per_year / 8760 # 转成每小时故障率这个拟合方法假设故障服从泊松分布实际中极端天气下的故障是过离散的更严谨的做法是用负二项分布。但作为二次开发的起点泊松拟合够用了跑通之后再换更复杂的模型。5.3 一个实用的改造技巧增量式场景评估做策略对比时最耗时的环节是场景生成和潮流计算。如果每次改策略都要重新生成场景、重新跑潮流开发效率会很低。我一般会加一个缓存层把场景和对应的故障后状态存成 pickle 文件策略评估时直接读缓存。import pickle import hashlib def cache_scenarios(scenarios, net_params, cache_dir./cache): 把场景和网络参数哈希后缓存 key hashlib.md5(str(net_params).encode()).hexdigest()[:8] cache_file f{cache_dir}/scenarios_{key}.pkl with open(cache_file, wb) as f: pickle.dump(scenarios, f) return cache_file def load_cached_scenarios(net_params, cache_dir./cache): key hashlib.md5(str(net_params).encode()).hexdigest()[:8] cache_file f{cache_dir}/scenarios_{key}.pkl try: with open(cache_file, rb) as f: return pickle.load(f) except FileNotFoundError: return None这个技巧在调策略参数时特别有用——改一次策略跑一次全流程可能要 10 分钟加了缓存后降到 30 秒。注意缓存 key 要包含网络参数和天气参数否则改了参数还用旧缓存会得到错误结果。从那以后我每次做策略对比实验都强制先检查缓存命中率低于 80% 就说明参数改动太频繁该重新审视实验设计了。希望帮到你。本文还有配套的精品资源点击获取