资讯动态

基于DAE的轨迹灵敏度:电力系统暂态稳定评估与MPC减载

发布时间:2026/9/17 16:22:17 来源:尧图企业网站定制
简介这套基于轨迹灵敏度的电力系统动态安全评估方法代码及论文复现资料面向电力系统研究人员、研究生及动态安全评估工程师旨在解决暂态角度稳定、电压稳定、低频减载策略等实际工程问题。包内含1个PDF文档压缩包约1.01MB系统梳理了基于开源工具PSAT的8类灵敏度元素实现涵盖电力系统模型搭建、DAE求解器、并行集群计算、改进“非常不诚实牛顿法”、线性近似精度验证以及暂态角度稳定、电压稳定与基于模型预测控制的低频减载策略等核心代码及解释。目前已83人学习浏览。读者可获得完整可运行的Python示例理解灵敏度分析在WECC系统等实际场景中的应用还可调整参数复现不同扰动大小下的评估结果借助可视化工具深入掌握动态安全评估全流程为后续研究提供可直接改写的工程基线。1. 为什么轨迹灵敏度比“多跑几条时域曲线”更划算传统时域仿真一次只能回答“这条故障曲线稳不稳”换一个负荷水平或故障位置就要重新积分全部微分代数方程在线安全评估场景一多算力扛不住。轨迹灵敏度的思路是把状态轨迹对参数的偏导数当作额外状态与原始轨迹一起求解一次积分同时得到“轨迹”和“轨迹对每个参数的敏感度”。有了这两样既能做小扰动下的稳定裕度预估也能定位“哪台发电机出力、哪条线路阻抗、哪个负荷参数对稳定性影响最大”。这正是预防控制和低频减载这类控制策略设计所需要的输入。论文基于开源 PSAT 实现并验证了该方法在 WECC 系统上解决暂态角度稳定与电压稳定问题并给出了 MPC 减载方案。下面按 DAE 建模、灵敏度实现、并行加速、工程应用的顺序把代码链路拆开。2. 从 DAE 得到灵敏度方程偏导链与数值求解细节2.1 先理解系统的微分代数结构电力系统动态模型通常是微分方程与代数方程的耦合状态变量 x 包含发电机转子角、转速、励磁绕组磁链等代数变量 y 包含节点电压幅值和相位参数 p 可以是机械功率、励磁电压、负荷有功、网络导纳等。统一写成 DAE 形式dx/dt f(x, y, p, t) 0 g(x, y, p, t)其中第二组是网络潮流方程或定子电压方程作用是把网络约束“钉”在每一步积分上。这类系统在数值上按索引 1 的 DAE 处理暂态仿真工具的模型大多能改写成这种形式。轨迹灵敏度关心的不是某个平衡点而是整条轨迹对参数 p 的偏导数。定义状态灵敏度Sx ∂x/∂p代数灵敏度Sy ∂y/∂p对 DAE 两边同时对 p 求偏导dSx/dt ∂f/∂x · Sx ∂f/∂y · Sy ∂f/∂p 0 ∂g/∂x · Sx ∂g/∂y · Sy ∂g/∂p注意这里所有偏导数都沿当前轨迹取值所以是时变矩阵。第二个方程可以直接解出代数灵敏度Sy -(∂g/∂y)^(-1) · (∂g/∂x · Sx ∂g/∂p)把这个 Sy 代回第一个方程就得到关于 Sx 的线性微分方程。它的系数矩阵与原始系统每个时间步的雅可比矩阵共享结构所以主要的计算成本集中在雅可比矩阵的形成与分解上而不是额外开一条新轨迹。2.2 DAE 求解器代码骨架常见的做法是用 solve_ivp 的 BDF 方法处理刚性 DAE并把缺省状态与灵敏度状态拼成一个增广向量。下面这段代码把两个环节耦在一起import numpy as np from scipy.integrate import solve_ivp class DAETrajectorySensitivity: 微分代数方程 轨迹灵敏度联立求解 def __init__(self, f, g, x0, y0, p0): self.f f # dx/dt f(x, y, p, t) self.g g # 0 g(x, y, p, t) self.x0 np.atleast_1d(x0).astype(float) self.y0 np.atleast_1d(y0).astype(float) self.p np.atleast_1d(p0).astype(float) self.nx, self.ny self.x0.size, self.y0.size self.np self.p.size # 灵敏度状态初始值平衡点参数无突变时通常给 0 self.sx0 np.zeros((self.nx, self.np)) self.z0 np.concatenate([self.x0, self.sx0.ravel()]) def _solve_algebraic(self, t, x): 在当前 t, x 下迭代求 y y self.y0.copy() for _ in range(30): gv self.g(t, x, y, self.p) dy -np.linalg.solve(self._dg_dy(t, x, y), gv) y dy if np.max(np.abs(dy)) 1e-9: break return y def rhs(self, t, z): x z[:self.nx] sx z[self.nx:].reshape(self.nx, self.np) y self._solve_algebraic(t, x) dx self.f(t, x, y, self.p) fx self._numeric_partial(t, x, y, x) fy self._numeric_partial(t, x, y, y) fp self._numeric_partial(t, x, y, p) gx self._numeric_partial_g(t, x, y, x) gy self._numeric_partial_g(t, x, y, y) gp self._numeric_partial_g(t, x, y, p) # 用代数约束消去 sy再推进状态灵敏度 sy -np.linalg.solve(gy, gx sx gp) dsx fx sx fy sy fp return np.concatenate([dx, dsx.ravel()]) def simulate(self, t_span, t_eval): return solve_ivp(self.rhs, t_span, self.z0, t_evalt_eval, methodBDF, rtol1e-6, atol1e-8)这里的_numeric_partial和_numeric_partial_g用 1e-6 的有限差分近似雅可比矩阵。数值偏导的好处是不需要针对每个发电机模型重写解析表达式缺点是耗时论文后面用改进牛顿法和并行集群正是为了压住这部分成本。代码诊断的方向主要看三个点代数迭代是否收敛、有限差分步长是否合适、事件参数如故障切除时间的初始灵敏度是否给错。2.3 BDF 参数怎么调BDF 是隐式线性多步法适合刚性问题但容差参数和最大步长直接影响灵敏度曲线的质量。下表给出从简单三机系统起步的参数经验值参数经验取值影响rtol1e-6相对容差灵敏度数值振荡的主要来源atol1e-8绝对容差状态接近 0 时起主要作用max_step0.02 s超过系统振荡周期的 1/5 会漏掉摆动形态methodBDF比 RK45 更稳但每步代价更高把 rtol 放大到 1e-3 能跑得快但灵敏度曲线会出现毛刺尤其在电压稳定分析里母线电压处于临界点时微小的数值抖动会被“伪灵敏度”放大。所以第 2 章的核心结论是灵敏度方程本身不是额外负担真正的工程问题在于雅可比矩阵的求解代价和数值精度平衡。提示如果灵敏度曲线在故障清除时刻出现跳变先检查事件参数是不是被当成连续参数处理了。故障清除时间这类参数要从事件前后分别积分而不是直接放在同一段 DAE 里求导。3. 经典发电机模型与 8 类灵敏度元素状态布局到 Python 复现3.1 六状态发电机的摆放方式代码中的PowerSystemModel把每台发电机展开为 6 个状态按固定顺序排布天然适配数组切片和雅可比矩阵的块状结构下标状态符号物理含义6iδ转子角度6i1ω转速偏差6i2E’_qq 轴暂态电势6i3E’_dd 轴暂态电势6i4ψ_kdd 轴阻尼绕组磁链6i5ψ_kqq 轴阻尼绕组磁链这样打包后动态方程的 6×6 对角块对应单机电磁暂态非对角块通过网络导纳矩阵 Ybus 耦合雅可比矩阵的稀疏骨架就清晰了。电磁功率 Pe 的计算用到 Ybus 的实部和虚部代码里通过双层循环累加得到Pe np.zeros(self.n) for i in range(self.n): for j in range(self.n): Gij np.real(self.Ybus[i, j]) Bij np.imag(self.Ybus[i, j]) Pe[i] (Eq_p[i] * Eq_p[j] * Gij * np.cos(delta[i] - delta[j]) Eq_p[i] * Eq_p[j] * Bij * np.sin(delta[i] - delta[j]))注意这里只用了 E’_q 计算 Pe属于经典模型简化。如果接入完整励磁系统Pe 里还要加入 E’_d 与定子电流的分量。实际论文用的模型是完整六阶发电机加上励磁机和 PSS在 PSAT 里的状态数还会更多但这套双层循环的结构不变。3.2 灵敏度方程与雅可比矩阵实现sensitivity_equations方法的做法是把原始状态 x 与灵敏度矩阵 S 拼成一个长向量先调用dynamic_equations算出 dxdt再用有限差分算雅可比矩阵J ∂f/∂x和参数雅可比Jp ∂f/∂p最终更新规则是dSdt J S Jp这段 Python 代码的核心只有三行但参数维度决定计算量。假设 50 台发电机、每台 6 个状态、关注 20 个参数S 就是 300×20 的矩阵每次求 dSdt 都要先形成 300×300 的 J再做一个矩阵乘。这就是为什么论文要专门设计稀疏存储和并行计算的章节矩阵规模上来之后稠密运算完全不可接受。3.3 8 类灵敏度元素对照论文里强调实现了 8 类灵敏度元素从工程实现角度通常覆盖以下对象序号灵敏度对象典型用途实现要点1状态初值 x0研究初始运行点偏移的影响初始灵敏度由平衡点约束求不是一律给 02代数变量初值 y0电压相角初始条件分析需要先解一次潮流3发电机机械功率 Pm原动机出力变化对稳定的影响直接出现在转子运动方程中4励磁电压 Efd励磁系统增益与电压稳定影响 E’_q 的动态方程5负荷有功 P负荷不确定性、减载策略通过潮流方程耦合进节点电压6负荷无功 Q电压崩溃风险评估与 P 分开处理避免混叠7网络导纳 Gij/Bij线路开断、故障场景修改 Ybus 后重新形成雅可比8故障切除时间 t_c临界清除时间评估事件参数分段求灵敏度第 5、6 类在电压稳定分析中特别重要因为负荷模型本身带不确定性灵敏度能给出“负荷涨多少会逼近电压崩溃点”的量化指标。第 8 类最容易被忽略t_c 不是连续参数故障时和故障后的系统方程不一致求灵敏度要把轨迹按事件时刻切开分别积分后再拼起来。4. 并行集群计算与改进“非常不诚实牛顿法”两把性能钥匙4.1 用多进程把参数扰动拆开算论文中提到用并行集群降低计算负担。逐段复现集群计算需要 mpi4py 或分布式计算框架但核心思路可以先在单机多进程上验证把不同参数扰动分配给不同进程每个进程独立积分自己的轨迹灵敏度最后汇总。import multiprocessing as mp from functools import partial def simulate_one(system, t_span, t_eval): return system.simulate(t_span, t_eval) def run_parallel(systems, t_span, t_eval): pool mp.Pool(mp.cpu_count()) results pool.map(partial(simulate_one, t_spant_span, t_evalt_eval), systems) pool.close() pool.join() return results这段代码的并行粒度是“场景级”的每个 worker 跑一个扰动水平的完整轨迹。粒度更大单次通信开销少但内存占用高适合每台节点内存够用的情况粒度太小则进程调度频繁加速比上不去。实际做 WECC 级别计算时节点间通信用 MPI 传灵敏度的中间结果Python 侧只负责把任务切分逻辑写好。4.2 改进的“非常不诚实牛顿法”实现“不诚实牛顿法”的精髓是不是每一步都重新形成雅可比矩阵而是每隔若干步才更新一次。论文在此基础上进一步“非常不诚实”即在一条轨迹里尽量固定雅可比矩阵只有当牛顿迭代发散到阈值之外才重构。对应到代码上稀疏 LU 分解只做一次或少数几次其余迭代全部复用分解结果from scipy.sparse.linalg import splu def very_dishonest_newton(residual, x0, tol1e-6, max_iter30): J jacobian(residual, x0) # 只形成一次初始雅可比 lu splu(J) # 稀疏 LU 分解保留因子 x x0.copy() for _ in range(max_iter): F residual(x) if np.linalg.norm(F, np.inf) tol: break dx lu.solve(-F) # 复用 LU 因子不回代重建 x dx if np.linalg.norm(dx, np.inf) 1e6: # 超出可信范围被迫更新雅可比 lu splu(jacobian(residual, x)) return x这里lu.solve(-F)每次只需前代回代省掉最贵的矩阵分解。稀疏矩阵用csr_matrix存splu本质是 SuperLU 的接口。风险是固定雅可比时间过长会导致径向收敛半径缩小所以必须在迭代发散时强制更新不能无脑固定到底。4.3 两种手段的分工并行与改进牛顿法解决的问题不同并行针对“参数维度大”的场景把 8 类灵敏度元素拆到多核改进牛顿法针对“单次雅可比求解贵”的场景把每次积分的内部迭代成本降下来。两者可以叠加先按参数分块并行再在每个块内使用固定雅可比迭代。下表是几种组合策略的适用条件策略适用场景主要风险串行 全更新雅可比小型测试系统场景多时计算时间线性膨胀并行 全更新雅可比参数数量多、单参数轨迹计算耗时均衡负载不均动态调度复杂串行 非常不诚实牛顿法单次 DAE 积分刚性较强、步数多迭代发散需要收敛检查并行 非常不诚实牛顿法WECC 级系统8 类灵敏度全量计算通信开销与固定雅可比频率需调参提示固定雅可比可接受的迭代步数不是先验已知的建议用“连续 3 步残差不下降就更新雅可比”的启发式规则比固定步长更稳。这也是“非常不诚实”名号在实际工程里的真正含义。5. 在 WECC 系统上验证灵敏度排序、线性区间与 MPC 低频减载5.1 用扰动扫描确认线性近似边界轨迹灵敏度的隐式前提是扰动足够小、轨迹偏差近似线性。论文指出线性近似精度与扰动大小存在固定联系工程上可以通过对称扰动扫描来验证对参数 p 分别施加 1%、2%、5%用灵敏度预估轨迹差再与真实轨迹差分做对比pred_dx S_p * delta_p # 灵敏度预估值 true_dx trajectory(pdelta_p) - trajectory(p) # 实际轨迹差 error_ratio np.abs((pred_dx - true_dx) / true_dx)当 error_ratio 超过 5% 时说明参数扰动已超出线性区间要么缩小扰动幅值要么改用二阶轨迹灵敏度。更实用的做法是把这条扫描曲线画成图线性区间的斜率平滑非线性区间的曲线明显弯曲拐点就是安全评估的边界。5.2 把灵敏度送进 MPC 目标函数MPC 低频减载的核心是在当前频率轨迹预测下决定切多少负荷能最快恢复频率同时不超过单步切负荷上限。轨迹灵敏度直接提供“转速对负荷有功的灵敏度矩阵 S_ω,P”于是把仿真问题转成一个小规模二次规划# Δω_ref: 期望的频率偏差回调量 # ΔP: 各节点切负荷量决策变量 # S_wp: 轨迹灵敏度矩阵由上一节积分得到 # lam: 切换代价惩罚系数 objective ||Δω_ref - S_wp ΔP||² lam * ||ΔP||² subject to 0 ΔP ΔP_max这里的灵敏度矩阵可以提前算好MPC 每个控制周期只需要解一次带约束的最小二乘计算量远小于重新做时域仿真。lam 越大切负荷越保守实际应用时还要加上“同一节点不能重复切”和“单次切负荷总上限”这样的线性约束。最后一个执行细节低频减载策略设计时不要直接用额定频率做参考点而要用“当前运行点附近的稳态频率”否则初始正偏差会混入控制信息。把这个偏移量提前扣除后MPC 的动作曲线会平滑得多减载次数也更少。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价