ARTICLE DETAIL

资讯详情

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

基于PPO的电力系统动态制动紧急控制策略

基于PPO的电力系统动态制动紧急控制策略 简介面向具备一定编程基础、关注电力系统控制与深度学习的科研人员与工程师内容围绕深度强化学习在自适应紧急控制中的应用展开。以发电机动态制动与低压减载两类场景为主线结合开源RLGC平台梳理DQN、PPO等算法的环境搭建、模型构建、训练流程与鲁棒性测试思路并与传统Q-learning、最优控制作对比说明DRL处理高维状态空间与动态不确定性的优势。资源包仅1个PDF文件约767KB内含完整可运行的PyTorch代码示例及逐段解释涵盖环境定义、DQN网络与智能体实现、奖励函数设计等关键环节。目前已有94人学习关注适合希望复现论文、动手实践并延伸至多智能体DRL与在线学习方向的读者。1. 电力系统紧急控制为什么要用深度强化学习一条重载外送线路发生三相短路跳闸送端机组在 0.8 秒内把功角摆到 130°按离线策略表投入的制动电阻量按最严重工况整定中等严重度故障下反而刹过了头机组转速被压下去随后进入低频振荡。这类问题在传统紧急控制里几乎无解策略表是离线枚举预想故障集算出来的二维或三维查表维度低、颗粒粗运行方式连续漂移时只能靠插值和裕度兜底。深度强化学习把状态→动作的映射交给神经网络在线生成输入是广域测量系统实时给的转速偏差、机端有功、母线电压和频率变化率输出是制动电阻的投入等级做到按故障严重程度自适应给量。它适合调度自动化、稳控装置研发以及电力系统仿真与 AI 交叉方向的人既要懂摇摆方程和暂稳判据也要能把控制问题写成马尔可夫决策过程。2. 把动态制动决策建模成 MDP观测量、动作空间与奖励函数2.1 观测量从哪来PMU 可测量与不可测量的处理强化学习的效果七成取决于状态设计。发电机功角 δ 本身不是 PMU 直接测出来的量工程上一般用状态估计或者 OMIB 等值反推代价是引入几十毫秒的估计延迟。稳妥的做法是把可直测的量和推测量分开处理推测量做一阶低通滤波直测量保留高频分量让策略既能感知首摆趋势也不会被噪声带偏。观测量物理来源归一化方式备注转速偏差 Δω转速/频率测量除以 0.05 pu直接对应加速能量机端有功 P_ePMU 有功除以额定容量需 20 ms 滑动平均母线电压 VPMU 电压除以额定电压制动电阻吸收功率正比于 V²功角 δ状态估计/等值推算sin δ、cos δ 编码用三角函数避免 ±π 跳变频率变化率 df/dtPMU 频率除以 1 Hz/s故障后 200 ms 内区分度最高当前制动等级 g装置反馈除以最大电导给智能体动作记忆sin/cos 编码这一步别省。功角在 180° 附近来回摆动时直接送弧度值会让网络在 ±π 处出现数值断裂用 sin δ 和 cos δ 两个通道表达同一个角度网络学起来平滑得多。2.2 动作空间分级投切还是相控连续调节制动电阻在工程上分两类实现。一类是真空开关分级投切典型 4 到 6 档动作空间是 Discrete(5)另一类是晶闸管相控连续调节动作空间是 Box(-1,1)。前者便宜、可靠是绝大多数在运稳控装置的做法后者贵但在需要精细控制的重载断面有用武之地。算法上分级投切配 PPO 或 DQN连续调节配 DDPG、TD3、SAC。维度分级投切相控连续调节动作空间Discrete(5)Box(-1,1)匹配算法PPO、DQN、Dueling DQNDDPG、TD3、SAC装置成本低高控制精度台阶式平滑动作约束最小驻留时间、单次升降一档变化率限幅工程建议首选方案已有 TCR 时考虑分级投切最大的坑是动作抖动。控制周期 20 ms如果智能体可以在两档之间来回跳开关次数会迅速上去装置寿命直接受损。常见做法是加最小驻留时间和动作屏蔽上一次切换后的一段时间里只允许维持原档否则单次最多升降一档。import numpy as np def allowed_actions(last_action, t_since_switch, n_levels5, min_dwell0.10): 构造动作掩码限制制动等级的切换频率与跳变幅度。 last_action: 上一步动作索引 t_since_switch: 距上次切换的时间单位秒 mask np.zeros(n_levels, dtypebool) if t_since_switch min_dwell: mask[last_action] True # 驻留期内只允许保持 else: lo max(0, last_action - 1) hi min(n_levels - 1, last_action 1) mask[lo:hi 1] True # 单次最多升降一档 return mask在 PPO 里用掩码很简单把 actor 输出的 logits 对应非法动作的位置填成 -1e9再送进 Categorical 采样。梯度不会流到被屏蔽的动作上采样也不会越界。这个 20 ms 的最小驻留时间不是拍脑袋定的要和断路器的机械动作时间对齐一般取 60 到 100 ms。2.3 奖励函数暂稳裕度、频率偏差与制动能耗的加权奖励设计是这套方案里最容易翻车的地方。只给终端成功/失败是稀疏奖励几万个回合都学不动只惩罚功角偏差智能体会选择疯狂投入制动电阻把转速压到零附近。我一般的写法是把过程惩罚和终端项分开$$r_t -w_1 \cdot \mathrm{relu}(|\delta_t| - \delta_{lim}) - w_2 \cdot |\Delta\omega_t| - w_3 \cdot g_t \cdot \Delta t R_{terminal}$$三项的典型取值w₁ 2.0负责在功角越过临界值一般取 120° 到 140°后给硬惩罚w₂ 0.5压住转速偏差防止机组长周期振荡w₃ 0.02抑制制动电阻吸收的能量这一项直接对应电阻的热容量约束不能省。终端项 R_terminal 稳定给 50失稳给 -50。如果训练前期完全没有正向信号就再加一层势函数塑形比如 F(δ) -(|δ|/δ_lim)²每一步给一个 r_shaping γ·F(s_{t1}) - F(s_t)。塑形项只在不改变最优策略的势函数形式下加随便加会改变最优解。3. 搭一个能跑通的最小环境单机-无穷大系统加制动电阻3.1 摇摆方程与故障时序建模真正接入电网仿真软件之前先用单机-无穷大系统把闭环跑通这是投入产出比最高的做法。经典二阶模型足够表达首摆稳定问题$$\frac{d\delta}{dt} \Delta\omega \cdot \omega_0, \qquad \frac{d\Delta\omega}{dt} \frac{\omega_0}{2H}(P_m - P_e)$$制动电阻接在机端吸收的有功近似为 g·V²g 是等效电导。所以电磁功率写成 P_e (EV/X)·sin δ g·V²。故障时序分三段故障前用 X_pre故障期间线路功率送不出去等值电抗取一个极大值让功角特性塌下来机组开始加速故障切除后电抗变成 X_post此时制动电阻才允许投入。参数符号取值作用惯性时间常数H5.0 s决定加速快慢机械功率P_m0.90 pu故障前输送功率暂态电抗加线路电抗X_pre0.50 pu故障前等值故障后等值电抗X_post1.00 pu线路跳闸后仿真步长dt2 msRK4 数值稳定控制周期ctrl_dt20 ms与稳控装置对齐制动等级g0/0.1/0.2/0.3 pu对应四级投切功角限值δ_lim120°稳定判据阈值X_post 从 0.5 涨到 1.0功角特性峰值从 2.1 pu 掉到 1.05 pu而机械功率还是 0.9 pu加速面积明显大于减速面积——不投制动电阻必失稳这就是环境本身给出的必要性。3.2 环境类接口reset 与 step 的返回值约定接口按 Gymnasium 的约定来reset 返回观测step 返回 (obs, reward, done, info)。info 里必须带上 delta_max 和 stable后面做故障集批量评估时全靠这两个字段统计不要在奖励里兜圈子反推。import numpy as np class DynamicBrakingEnv: 单机-无穷大系统 制动电阻的最小暂稳环境。 时序: [0,t_fault) 正常运行 - [t_fault,t_clear) 故障 - 之后线路跳闸 def __init__(self, H5.0, Pm0.90, E1.05, V1.0, X_pre0.50, X_post1.00, w02*np.pi*50, dt0.002, t_fault0.10, t_clear0.20, t_end3.0, ctrl_dt0.02, brake_levels(0.0, 0.1, 0.2, 0.3), delta_limnp.deg2rad(120)): self.H, self.Pm, self.E, self.V H, Pm, E, V self.X_pre, self.X_post X_pre, X_post self.w0 w0 self.dt, self.t_fault, self.t_clear, self.t_end dt, t_fault, t_clear, t_end self.ctrl_dt ctrl_dt self.ctrl_every int(round(ctrl_dt / dt)) self.brake_levels np.asarray(brake_levels, dtypenp.float32) self.delta_lim delta_lim self.delta0 np.arcsin(Pm * X_pre / (E * V)) # 初始运行功角 self.n_ctrl int((t_end - t_clear) / ctrl_dt) def _pe(self, delta, g, X): return self.E * self.V / X * np.sin(delta) g * self.V ** 2 def _deriv(self, s, g, X): delta, dw s pe self._pe(delta, g, X) return np.array([dw * self.w0, self.w0 / (2 * self.H) * (self.Pm - pe)]) def _rk4(self, s, g, X): k1 self._deriv(s, g, X) k2 self._deriv(s 0.5*self.dt*k1, g, X) k3 self._deriv(s 0.5*self.dt*k2, g, X) k4 self._deriv(s self.dt*k3, g, X) return s self.dt / 6.0 * (k1 2*k2 2*k3 k4)三个细节值得单独说。第一故障期间用一个极大的 X比如 1e6代表线路功率送不出去比在方程里加分支判断干净。第二RK4 每步 2 ms控制周期 20 ms也就是每个动作要连续积分 10 步动作在整段控制周期内保持不变这符合实际装置的行为。第三reset 里可以给初始功角加一点随机扰动模拟运行方式漂移这是自适应三个字的落点策略必须在初始工况分布上泛化不能只记住某一个平衡点。3.3 状态归一化与暂稳判据观测做归一化是硬性要求。sin δ、cos δ 天然在 [-1,1]Δω 除以 0.05 pu 后基本落在 ±3 以内制动等级除以最大电导再补一个二值位表示故障是否已切除让网络知道现在处在哪个阶段。少了这个阶段位网络很难分辨故障中和故障后因为两者的功角量在数值上很接近。def reset(self, delta_noise0.02): delta0 self.delta0 np.random.uniform(-delta_noise, delta_noise) self.state np.array([delta0, 0.0]) self.t, self.g_brake, self.brake_energy 0.0, 0.0, 0.0 self.delta_max, self.dw_max abs(delta0), 0.0 return self._obs() def _obs(self): delta, dw self.state return np.array([np.sin(delta), np.cos(delta), dw / 0.05, self.g_brake / max(self.brake_levels.max(), 1e-6), float(self.t self.t_clear)], dtypenp.float32) def step(self, action_idx): g float(self.brake_levels[action_idx]) self.g_brake g for _ in range(self.ctrl_every): if self.t self.t_fault: X, g_now self.X_pre, 0.0 # 故障前不投制动 elif self.t self.t_clear: X, g_now 1e6, 0.0 # 故障期间线路功率为零 else: X, g_now self.X_post, g self.state self._rk4(self.state, g_now, X) self.t self.dt if self.t self.t_clear: self.brake_energy g * self.dt delta, dw self.state self.delta_max max(self.delta_max, abs(delta)) self.dw_max max(self.dw_max, abs(dw)) delta, dw self.state reward -0.5 * abs(dw) - 2.0 * max(0.0, abs(delta) - self.delta_lim) - 0.02 * g done (self.t self.t_end) or (abs(delta) np.pi) stable self.delta_max self.delta_lim and abs(delta) np.pi if done: reward 50.0 if stable else -50.0 return self._obs(), reward, done, { stable: stable, delta_max: float(self.delta_max), brake_energy: float(self.brake_energy)}暂稳判据这里用的是首摆功角峰值不越限属于简化判据。工程上更严谨的做法要看多摆衰减、临界切除时间 CCT 和能量函数裕度。用简化判据训练出来的策略在接入详细模型时通常会有 5% 到 15% 的性能衰减所以后面第 5 章的回放验证不能省。4. 用 PPO 训练动态制动策略网络、超参与收敛排查4.1 Actor-Critic 结构与动作分布选型分级投切的动作空间小本例只有 4 档网络不需要太深两层 128 维 Tanh 足够。隐藏层激活用 Tanh 而不是 ReLU因为物理量的动态范围有限Tanh 的平滑性让策略输出在档位边界附近更稳实测训练曲线抖动更小。Actor 输出 logitsCritic 输出标量价值。import torch import torch.nn as nn from torch.distributions import Categorical class ActorCritic(nn.Module): def __init__(self, obs_dim5, n_act4, hidden128): super().__init__() self.backbone nn.Sequential( nn.Linear(obs_dim, hidden), nn.Tanh(), nn.Linear(hidden, hidden), nn.Tanh()) self.actor nn.Linear(hidden, n_act) self.critic nn.Linear(hidden, 1) def forward(self, x): h self.backbone(x) return self.actor(h), self.critic(h).squeeze(-1) def act(self, obs, maskNone): logits, value self.forward(obs) if mask is not None: logits logits.masked_fill(~mask, -1e9) # 动作掩码 dist Categorical(logitslogits) a dist.sample() return a, dist.log_prob(a), value动作掩码在 act 里做但更新的时候必须用同一套掩码重算 log_prob否则重要性比会错。这是 PPO 配掩码最常见的实现 bug采样时屏蔽了更新时忘了比率算出来偏离 1裁剪项直接失去作用。稳妥做法是把 mask 存进 rollout buffer更新时逐样本取出来。4.2 关键超参表与调整经验超参数取值说明学习率3e-4Adam观测归一化后可略高折扣因子 γ0.993 s 回合、20 ms 动作间隔GAE λ0.95降低优势估计方差裁剪系数 ε0.2从 0.1 起调更稳熵系数0.01前期可设 0.05 促进探索rollout 长度2048约 40 个回合mini-batch256每个 epoch 8 个批次更新轮数10再多容易过拟合旧数据价值损失系数0.5与策略损失同量级几个调参经验。折扣因子不要低于 0.98故障切除后到首摆峰值只有 0.3 到 0.5 秒折扣太狠会让策略只盯着眼前不敢投制动。熵系数要退火从 0.05 线性退到 0.005前期保探索、后期保稳定。价值损失系数如果设得太大Critic 会主导梯度Actor 学不动表现是奖励曲线上不去但 value loss 掉得很快这时候把系数降到 0.5 以下。4.3 训练不收敛的四个排查方向第一看奖励量纲。功角惩罚项如果不乘 relu 而直接用平方量级会到几千优势估计被淹没学习率再小也没用。第二看动作掩码是否在采样和更新两侧一致。第三看观测是否漏了故障阶段位漏了之后策略在故障期间就投制动白耗电阻容量。第四看回合长度。t_end 设成 3 s如果大部分回合在 0.5 s 就因失稳提前结束样本被截断得太碎GAE 的自举项会引入偏差这时可以在 done 时把 value 乘 0 处理或者缩短回合长度到 2 s。还有一个隐蔽的坑多个环境并行采样时如果所有 env 用同一个随机种子初始功角一致策略会过拟合到某一个平衡点。每个 env 用不同种子并且在 reset 里重新扰动初始功角。5. 策略验证与部署兜底从故障集回放到多区域协同5.1 用故障集批量回放看最大功角与制动能量训练完不要只看平均奖励要构造故障集回放。把故障位置、故障持续时间、初始潮流三个维度做笛卡尔积每个组合跑 20 次统计失稳率和功角峰值分布。指标离线策略表PPO 策略说明失稳率4.2%1.5%300 个故障场景平均功角峰值118°104°越小裕度越大制动能量消耗0.083 pu·s0.061 pu·s对应电阻热容量平均动作次数2.11.6受最小驻留时间约束最坏场景裕度6°9°决定策略表整定值最坏场景裕度这一行比平均值重要得多。紧急控制是安全底线不能拿平均值说话必须保证在故障集里最严重的那个场景上功角还有余量。如果最坏场景裕度比策略表还差说明策略在极端工况上欠训练要在训练集里加权采样这类场景。5.2 与策略表的定量对比要说清代价PPO 策略在失稳率和制动能量上确实更优但要承认它的代价推理需要 PMU 数据通路延迟 30 到 80 ms策略表的查表延迟是微秒级。所以现实做法大多是双通道并行——策略表作为兜底常驻DRL 决策经过安全校验后才下发。校验规则很朴素单次动作幅度不超过两档、连续两次动作间隔不小于最小驻留时间、投切总量不超过电阻热容量上限。任何一条不满足就回落到策略表结果。5.3 安全兜底与多区域联邦训练的接口预留部署时把系统分成三层感知层接 PMU 和状态估计决策层跑训练好的 Actor只推理不更新执行层接制动电阻投切装置。决策层输出前过一道 shield 模块shield 是纯规则代码不依赖神经网络出问题也不影响兜底。跨区域电网还有一个绕不开的问题单区域数据不出域但协调整定又需要全局信息。这时候可以引入联邦深度强化学习各区域用本地仿真数据训练 Actor只上传 Critic 的梯度或网络参数到中心聚合避免原始运行数据跨区流动。如果关注拓扑变化——比如线路检修导致结构频繁改动——用图强化学习更合适把母线当节点、线路当边用图神经网络提取状态特征策略能自然泛化到没见过的拓扑上。这两条路线的共同前提是先把单区域的最小闭环和回放验证做扎实否则协同训练只会把错误放大到全网。本文还有配套的精品资源点击获取
返回列表