从EKF到UKF的电力系统动态状态估计:Matlab实现与调参实战

📅 发布时间:2026/10/5 4:38:43
从EKF到UKF的电力系统动态状态估计:Matlab实现与调参实战
做电力系统动态状态估计这个方向有几年了最早接触EKF时我最大的困惑不是算法本身而是“动态”这两个字到底动态在哪。后来做PMU数据驱动的暂态稳定监测时才算彻底明白——SCADA上那套平均几秒才刷新一次的静态状态估计应付稳态监控绰绰有余但到了故障后的暂态过程你看到的永远是“过去式”。把扩展卡尔曼滤波EKF和无迹卡尔曼滤波UKF用在发电机动态状态估计上本质上就是利用PMU高频采样的量测以20~50毫秒为递推步长逐拍在线估计发电机的转子角、转速这些真正描述“动态”的状态量。这篇文章围绕这套方法在Matlab里的完整落地展开内容包括发电机模型搭建、两种滤波器的原理拆解、核心代码框架、大小扰动场景的仿真对比、Q/R参数调优以及我实际调试中踩过的坑。目标很直接给你一套改参数就能跑的SMIB单机无穷大系统算例并讲清楚每一步为什么这么做。1. 为什么说动态状态估计和静态状态估计是两回事1.1 静态状态估计的固有局限电力系统里传统的状态估计大家最熟悉的是EMS里的加权最小二乘WLS法。它的状态量是各母线的电压幅值V和相角θ每个断面独立求解一次非线性优化问题估计结果反映的是某个“准稳态”时刻的系统运行状态。SCADA系统本身扫描周期就在秒级EMS刷新周期更是以分钟计算这套逻辑处理缓慢的负荷变化没有问题。但暂态过程不是这个节奏。一个220kV线路三相短路保护动作切除故障整个过程可能只有几百毫秒发电机的转子角、转速在这段时间里快速摆动。用秒级、分钟级刷新率的静态估计去“看”这种过程等于用相机拍慢动作电影每一帧都是模糊的。1.2 动态状态估计到底“估”什么动态状态估计的状态量不再是母线电压幅值和相角而是发电机内部的机电暂态状态量最经典的是转子角δ和转子转速ω。对于更精细的发电机模型还可能包括暂态电势Eq、Ed等电磁变量。δ和ω直接决定了发电机之间的相对摇摆是暂态稳定分析、失步预测、低频振荡监测的核心输入。举个例子功角δ接近或超过稳定极限时发电机可能失去同步如果能通过动态状态估计提前几十毫秒捕捉到这种趋势就能为紧急控制争取宝贵的窗口时间。这正是动态状态估计区别于静态估计的核心价值——它不是描述系统“在哪”而是描述系统“正在往哪去”。1.3 PMU补上了最后一环动态状态估计真正能落地还得感谢同步相量量测装置PMU。PMU基于GPS授时同步能够以30帧/秒甚至60帧/秒的速率输出带时标的电压、电流相量以及频率、频率变化率。没有这种高频同步量测递推形式的滤波器根本没有足够的“观测材料”可用。所以近十年动态状态估计的文献爆发式增长和PMU的大规模部署是直接相关的。2. 从摆动方程到状态空间模型先把数学基础打牢2.1 经典二阶发电机模型动态状态估计的前提是写出发电机的动态方程。这里用经典的二阶模型也就是常说的“摇摆方程”。对于单机无穷大系统SMIB发电机经暂态电抗和线路电抗接入无穷大母线其动态方程可以写成dδ/dt ω_s · (ω - 1) 2H/ω_s · dω/dt P_m - P_e - D·(ω - 1)其中δ是转子角radω是转子转速p.u.ω_s是同步转速rad/sH是惯性时间常数sD是阻尼系数p.u.P_m是机械功率p.u.P_e是电磁功率p.u.。电磁功率由功角特性决定P_e (E·V / x_Σ) · sin(δ) P_emax · sin(δ)这里E是发电机暂态电动势V是无穷大母线电压x_Σ是暂态电抗与线路电抗之和。P_emax EV/x_Σ就是该发电机的功率极限。稳态时δ₀ arcsin(P_m/P_emax)转速ω₀ 1.0 p.u.。这个模型看起来简单却是理解一切滤波器设计的基础。实际工程中即使用更高阶的发电机模型状态方程的骨架依然脱胎于摇摆方程——转子角、转速的动态是主干电磁变量是分支。2.2 量测模型功角和转速怎么“看”出来有了状态方程还要有量测方程。PMU装设在发电机并网母线附近能够直接或间接提供如下量测量测量物理含义与状态量的关系P_e发电机电磁功率P_e P_emax · sin(δ)ω转子转速可由频率推算ω 本身就是状态量V_t, θ_t机端电压幅值/相角经网络方程与δ关联最直接也最常用的做法是把P_e和ω作为量测量。量测方程写为z [P_e; ω] [P_emax·sin(δ); ω]对应的量测雅可比矩阵H如下供EKF使用H [P_emax·cos(δ), 0; 0, 1]有一点要说清楚PMU直接测到的是机端电压相量和电流相量P_e其实是由电压电流相量推算出来的派生量。分清楚“直接量测”和“派生量测”对理解误差来源有帮助——P_e的误差里既有互感器误差也有相量算法误差所以R矩阵里对应P_e的方差不能给得太乐观。2.3 离散化与噪声建模动态方程是连续的而滤波器递推是离散的需要用数值积分把连续方程离散化。最简单而有效的办法是前向欧拉法δ_{k1} δ_k Δt·ω_s·(ω_k - 1) ω_{k1} ω_k Δt·(ω_s/(2H))·(P_m - P_emax·sin(δ_k) - D·(ω_k - 1))当PMU采样间隔Δt 0.02s50Hz时欧拉法的离散化误差对这个慢变机电过程是够用的。如果采样率更低或者模型更刚硬建议改用RK4这部分后面会提到。系统的过程噪声和量测噪声分别用Q和R矩阵建模。Q反映模型失配和外部扰动比如机械功率的缓慢波动R反映量测误差。滤波器的行为很大程度上由Q和R的相对大小决定第五节我会专门讲怎么调。3. EKF与UKF的算法拆解3.1 贝叶斯递推的统一框架EKF和UKF表面上很不一样但它们都遵循同一个贝叶斯递推框架。假设系统为x_{k1} f(x_k) w_k z_k h(x_k) v_k滤波器的每一步都做两件事一步是预测用状态方程把上一时刻的状态估计推到当前时刻另一步是更新用当前时刻的量测对预测结果进行修正。预测给出先验均值和协方差更新给出后验均值和协方差。EKF和UKF的区别仅仅在于“如何把均值和协方差穿过非线性函数f和h”——也就是非线性逼近的方式。3.2 EKF雅可比矩阵与一阶线性化EKF的做法是对非线性函数做一阶泰勒展开用雅可比矩阵代替函数本身。预测步x_pred f(x_est) P_pred F · P_est · F Q其中F ∂f/∂x是状态转移雅可比矩阵。更新步S H·P_pred·H R K P_pred·H·S⁻¹ x_est x_pred K·(z - h(x_pred)) P_est (I - K·H)·P_predH ∂h/∂x是量测雅可比矩阵。对于第二节的SMIB模型雅可比矩阵是:F [1, Δt·ω_s; -Δt·ω_s·P_emax·cos(δ)/(2H), 1 - Δt·ω_s·D/(2H)]EKF的实现难点在于每个时刻都要计算雅可比矩阵。二维模型还好如果状态升到十几维多机系统推导和调试雅可比矩阵的工程量会急剧上升而且很容易出错。3.3 UKFsigma点绕过求导UKF换了一条路不再求导而是用2n1个“sigma点”来代表当前状态的概率分布让每个sigma点分别穿过非线性函数再从穿过后的点集里重新统计均值和协方差。n是状态维数。sigma点按以下方式生成λ α²·(n κ) - n X⁰ x̄ Xⁱ x̄ sqrt((nλ)·P)的第i列, i 1...n Xⁱ x̄ - sqrt((nλ)·P)的第i-n列, i n1...2n对应的权重为Wm⁰ λ/(nλ) Wc⁰ λ/(nλ) (1 - α² β) Wmⁱ Wcⁱ 1/(2·(nλ)), i 1...2n通常取κ 0β 2高斯分布最优。α控制sigma点偏离均值的程度这个参数的选取有个大坑第六节会详细说。生成sigma点之后预测步就是把sigma点分别通过f统计得到x_pred和P_pred更新步则是把预测的sigma点再通过h统计出量测预测值、量测协方差S和状态-量测交叉协方差Pxz然后按标准卡尔曼增益公式更新。3.4 一张表说清差异对比维度EKFUKF非线性逼近方式一阶泰勒展开求雅可比无损变换sigma点采样是否需要推导导数需要多机系统导数推导繁琐不需要只需函数求值近似精度一阶强非线性下误差大对高斯分布可达二阶精度单步计算量较小约为EKF的2~3倍2n1次函数求值强非线性/大初值误差容易发散相对稳健实现与调参难度难在求导难在参数α等选择我个人的经验结论是不要神化UKF也不要低估EKF。在模型线性度尚可、初始化合理的小扰动场景里两者估计精度差距很小但当故障引起大功角摆动、初值误差较大时UKF的稳健性优势会明显体现。4. Matlab实现代码级拆解4.1 代码文件组织一套干净的实现建议分成四个部分避免所有逻辑挤在一个脚本里smib_parameters.m % 系统参数定义 true_simulation.m % 真实系统仿真生成量测数据 ekf_filter.m % EKF滤波函数 ukf_filter.m % UKF滤波函数 main_dse.m % 主程序跑两种滤波器、画图、算RMSE这种结构的好处是每个部分可以单独调试。滤波器函数只负责“输入量测和参数输出状态估计”主程序只负责数据流和结果统计后续换多机模型时改动面最小。4.2 真值仿真与量测生成要评估滤波器性能首先得有“真值”。做法是给定一个扰动场景用状态方程推出一条真实的δ和ω轨迹然后在量测上叠加高斯噪声模拟PMU量测%% 真实系统动态仿真前向欧拉 x_true zeros(2, N); x_true(:,1) [asin(Pm / P_emax); 1.0]; % 稳态初值 for k 1:N-1 x_true(:,k1) f_disc(x_true(:,k), Pm, dt, params); end %% 生成含噪量测 R diag([1e-4, 1e-6]); % P_e方差0.01^2, ω方差0.001^2 Z zeros(2, N); for k 1:N Z(:,k) h_meas(x_true(:,k), params) mvnrnd([0;0], R); end这里P_e的噪声标准差取0.01 p.u.大约是1%额定功率ω的噪声标准差取0.001 p.u.对应0.05Hz的频率偏差基本符合PMU频率量测的精度水平。离散状态方程函数f_disc和量测函数h_meas建议写成独立函数function x_next f_disc(x, Pm, dt, params) delta x(1); omega x(2); Pe params.P_emax * sin(delta); delta_next delta dt * params.omega_s * (omega - 1); omega_next omega dt * (params.omega_s / (2*params.H)) ... * (Pm - Pe - params.D * (omega - 1)); x_next [delta_next; omega_next]; end function z h_meas(x, params) z [params.P_emax * sin(x(1)); x(2)]; end4.3 EKF滤波器函数EKF的核心循环如下。预测步先算雅可比矩阵F再更新协方差更新步算量测雅可比H、增益K和协方差修正function [x_est, P_est] ekf_filter(Z, x0, P0, Q, R, Pm, dt, params) n 2; N size(Z, 2); x_est zeros(n, N); P_est zeros(n, n, N); x_est(:,1) x0; P_est(:,:,1) P0; for k 2:N % --- 预测 --- F state_jacobian(x_est(:,k-1), Pm, dt, params); x_pred f_disc(x_est(:,k-1), Pm, dt, params); P_pred F * P_est(:,:,k-1) * F Q; % --- 更新 --- H meas_jacobian(x_pred, params); S H * P_pred * H R; K P_pred * H / S; innov Z(:,k) - h_meas(x_pred, params); x_est(:,k) x_pred K * innov; P_est(:,:,k) (eye(n) - K * H) * P_pred; end end状态雅可比和量测雅可比函数function F state_jacobian(x, Pm, dt, params) delta x(1); omega x(2); F zeros(2,2); F(1,1) 1; F(1,2) dt * params.omega_s; F(2,1) -dt * params.omega_s * params.P_emax * cos(delta) / (2*params.H); F(2,2) 1 - dt * params.omega_s * params.D / (2*params.H); end function H meas_jacobian(x, params) H [params.P_emax * cos(x(1)), 0; 0, 1]; end注意这里“/”是矩阵右除等价于乘以逆矩阵Matlab里建议用“/”而不是inv再乘数值稳定性更好也更简洁。4.4 UKF滤波器函数UKF的代码核心是sigma点生成和两个统计环节。我这里给的是非增广形式——对加性高斯噪声这种形式和增广形式等价但计算量小很多function [X_sigma, Wm, Wc] sigma_points(x, P, alpha, beta, kappa) n length(x); lambda alpha^2 * (n kappa) - n; sqrtP sqrtm((n lambda) * P); % 注意用sqrtm而非chol原因见第6节 X_sigma zeros(n, 2*n1); X_sigma(:,1) x; for i 1:n X_sigma(:,i1) x sqrtP(:,i); X_sigma(:,ni1) x - sqrtP(:,i); end Wm [lambda/(nlambda), 0.5/(nlambda)*ones(1,2*n)]; Wc Wm; Wc(1) Wc(1) (1 - alpha^2 beta); end滤波主循环function [x_est, P_est] ukf_filter(Z, x0, P0, Q, R, Pm, dt, params, alpha, beta, kappa) n 2; N size(Z, 2); x_est zeros(n, N); P_est zeros(n, n, N); x_est(:,1) x0; P_est(:,:,1) P0; for k 2:N % --- 预测sigma点穿过状态方程 --- [X, Wm, Wc] sigma_points(x_est(:,k-1), P_est(:,:,k-1), alpha, beta, kappa); X_pred zeros(n, 2*n1); for i 1:2*n1 X_pred(:,i) f_disc(X(:,i), Pm, dt, params); end x_pred X_pred * Wm; P_pred Q; for i 1:2*n1 d X_pred(:,i) - x_pred; P_pred P_pred Wc(i) * (d * d); end % --- 更新量测预测与增益 --- Z_pred zeros(2, 2*n1); for i 1:2*n1 Z_pred(:,i) h_meas(X_pred(:,i), params); end z_pred Z_pred * Wm; Pzz R; for i 1:2*n1 d Z_pred(:,i) - z_pred; Pzz Pzz Wc(i) * (d * d); end Pxz zeros(n, 2); for i 1:2*n1 dx X_pred(:,i) - x_pred; dz Z_pred(:,i) - z_pred; Pxz Pxz Wc(i) * (dx * dz); end K Pxz / Pzz; innov Z(:,k) - z_pred; x_est(:,k) x_pred K * innov; P_est(:,:,k) P_pred - K * Pzz * K; end end这段代码虽然比EKF多了一些循环但结构非常模式化生成点、穿函数、统计前两阶矩、算增益。唯一需要动脑的地方就是sigma点和权重。4.5 主程序与结果输出主程序负责把两套滤波器接到同一个量测序列上并计算性能指标%% 滤波器初始化 x0 [asin(Pm/P_emax) 0.05; 1.0]; % 初始功角偏差5度 P0 diag([0.1^2, 0.01^2]); % 初值不确定性 Q diag([1e-6, 1e-6]); % 过程噪声基线 %% 运行EKF和UKF [x_ekf, P_ekf] ekf_filter(Z, x0, P0, Q, R, Pm, dt, params); alpha 0.1; beta 2; kappa 0; [x_ukf, P_ukf] ukf_filter(Z, x0, P0, Q, R, Pm, dt, params, alpha, beta, kappa); %% 计算RMSE rmse_ekf sqrt(mean((x_ekf - x_true).^2, 2)); rmse_ukf sqrt(mean((x_ukf - x_true).^2, 2));主程序里建议把RMSE结果打印出来同时画三张图功角估计轨迹对比、转速估计轨迹对比、估计误差与正负2σ包络线。第三张图特别重要——它直接反映滤波器协方差是否自洽估计误差持续落在2σ带之外说明协方差给“虚”了。5. 仿真对比与参数调优实战5.1 小扰动场景两者差异不大先看稳态附近的小扰动。比如P_m从0.8突然阶跃到0.85功角从稳态值附近开始小幅摆动。这种场景下非线性函数在运行点附近的线性化误差很小EKF和UKF的估计轨迹几乎重叠RMSE差异通常在10%以内。我实测的典型结果是功角RMSE都在0.05度到0.2度之间转速RMSE都在0.0002 p.u.到0.0005 p.u.之间。这个结论给了一个很重要的工程提示如果你的应用场景基本是稳态微扰完全没必要上UKFEKF简单、快、调试成本低足够胜任。5.2 大扰动场景EKF的线性化劣势显现换成三相短路故障场景比如在0.5s发生短路导致P_e突降1.0s故障切除。这期间功角可能从30度摆到70度以上转速偏差达到0.01~0.02 p.u.。此时EKF在每个递推点用运行点的一阶近似去逼近强非线性函数线性化误差会被放大。更极端的情况是滤波器初始化不准。比如初值功角偏差拉到10度以上EKF在最初的几个递推步里增益方向会偏收敛速度明显变慢如果把初值偏差拉到20度以上EKF甚至可能出现发散——协方差矩阵元素异常膨胀估计轨迹飞出物理合理范围。UKF因为sigma点本身携带了分布的非线性信息在同样初始化条件下仍然能快速拉回到真值附近。我实际跑大扰动场景时UKF在暂态初期的功角RMSE通常比EKF低一个数量级。这不是偶然而是两种算法对非线性逼近精度差异的直接体现。5.3 Q、R矩阵怎么调创新序列检查调Q和R是所有初学者最容易卡住的地方。我的建议是按“从R出发、以Q微调、用创新序列验证”的顺序来做。R可以从量测设备的精度指标直接推算。比如PMU频率量测误差按0.001 p.u.标准差P_e推算误差按0.01 p.u.标准差R diag([1e-4, 1e-6])就是合理起点。Q则需要根据模型可信度来试。Q太小滤波器过度信任模型量测修正作用弱遇到未建模扰动时估计会滞后Q太大滤波器过度跟随量测估计噪声大起不到滤波作用。验证手段是“创新序列”的一致性检查。定义创新量为实际量测与预测量测之差innov z - z_pred。理论上如果滤波器协方差设置合理创新序列应当满足零均值、白噪声且归一化创新平方和NIS服从均值等于量测维数的卡方分布。在二维量测情况下平均NIS应接近2NIS zeros(1, N); for k 2:N S H * P_pred * H R; % EKF场景UKF则用Pzz NIS(k) innov(:,k) / S * innov(:,k); end mean_NIS mean(NIS);如果mean_NIS远大于2说明滤波器协方差不匹配——通常是Q给得太小或者模型误差没有被充分表达如果远小于2说明R给得过大或者滤波器过度自信需要回调。这个数值化的指标比肉眼盯着曲线调整要靠谱得多。5.4 RMSE与滤波器一致性评价滤波器的最终指标有两个层面。第一层面是估计精度用RMSE衡量第二层面是协方差一致性用误差是否落在2σ带内衡量。RMSE容易理解但很多人在实际项目里只盯RMSE忽略了第二个层面。一个RMSE“好看”但协方差虚高的滤波器在后续做置信度分析、坏数据检测时会产生严重误导。我在项目里的习惯是先保证一致性再追求精度。也就是先粗调Q和R让误差大比例落在2σ带内、平均NIS接近量测维数再微调参数压低RMSE。6. 踩坑记录从协方差崩溃到角度缠绕6.1 协方差矩阵非正定sqrtm还是cholUKF的sigma点生成需要对协方差矩阵做矩阵平方根Matlab里最常用的命令是chol。但我强烈建议在这里用sqrtm而不是chol。原因很简单递推过程中P_pred可能因为数值舍入而失去严格正定性chol遇到非正定矩阵直接报错程序崩溃sqrtm对轻微非正定的矩阵仍然能给出结果鲁棒性高很多。如果发现P矩阵对角线出现负值或者严重非对称可以做一次“整形处理”P (P P) / 2; % 强制对称 [V, D] eig(P); D(D 1e-10) 1e-10; % 特征值下限截断 P V * D * V;这种处理对协方差一致性影响很小但能避免滤波器中途崩溃。多机系统状态下尤其值得写上这行保护代码。6.2 alpha参数被低估的一个坑UKF的α参数控制sigma点的散布范围。很多综述论文里推荐α 1e-3这个取值在高维状态比如10维以上里没问题但放在二维的功角-转速模型里就会出大问题λ α²(nκ) - n ≈ -2nλ ≈ 0sigma点几乎全部压在均值上UKF退化成比EKF还弱的一阶线性近似。我在二维模型上实测的经验是α取0.01~0.1比较合适。状态变量尺度差异大时功角在0.5 rad量级转速偏差在0.001 p.u.量级小α会让转速方向的sigma点分布过密估计转速时对噪声不敏感。调整α后记得重新观察NIS指标别让滤波器在“看着在跑其实没跑对”的状态下空转。6.3 角度单位与连续化最常见的隐性错误功角δ和转速ω的单位体系非常容易搞混。摆动方程里的ω_s·(ω-1)是rad/s如果ω不经换算直接按rad/s填进矩阵δ的递推一步就飞了。我处理这个问题的习惯是全程使用p.u.制ω用p.u.P_e、P_m、D都用p.u.只有ω_s这个常数带着rad/s的物理单位。量测噪声方差、初始协方差全部跟这个单位体系保持一致。另一个容易忽视的是角度连续化。摆动方程天然产生连续的功角轨迹但PMU给出的相角量测通常是包裹在[-π, π]区间的。如果把包裹后的角度直接喂给滤波器功角跨过±π边界时会制造一个巨大的虚假跳变滤波器直接“炸掉”。解决方法是先对角度序列做unwrap处理delta_meas_unwrapped unwrap(delta_meas_wrapped);在单机无穷大模型里我们要估计的是相对无穷大母线的绝对功角它会自然摆动不会一直增加但一旦研究多机系统机间功角差可能持续增长unwrap就更加必不可少。6.4 从二维模型泛化到多机系统单机模型跑通之后向多机系统的扩展思路值得提前梳理。多机经典模型的状态量变为所有发电机的δ_i和ω_i维数2n_g。量测方程不再是一个简单的sin函数而是对应各机组电磁功率的网络耦合方程P_ei Σ_j E_i·E_j·B_ij·sin(δ_i - δ_j)这时EKF需要推导整个系统的耦合雅可比矩阵手推的出错率极高我见过很多项目在此处调bug耗时几天。UKF的优势在这里彻底释放——只需要写好向量化的量测函数sigma点会自动处理所有交叉耦合项不需要为每个耦合项单独求偏导。实际工程中还有一个常用技巧如果目的是监测单台机组可以把互联网架等值成戴维南等效把多机问题拆成单机处理再用UKF逐台估计。这种做法在PMU覆盖不全时尤其实用。另外如果把机械功率P_m当成随机游走状态扩进状态向量x [δ; ω; P_m]滤波器就能在线跟踪调速器动作而不必假设P_m恒定。这是动态状态估计从“仿真复现”走向“工程应用”非常关键的一步推荐大家在基本模型跑通后拓展尝试。写在最后的一点实际体会这套EKF/UKF动态状态估计代码从模型到调参我前后迭代了好几个版本。最大的体会是滤波器本身并不难写难的是模型和噪声统计是否真实反映了物理过程。很多人把精力花在比较EKF和UKF谁更“高级”却忽略了Q、R这些真正决定滤波器行为的东西结果就是算法换了又换精度始终上不去。如果你现在从头开始做这块我建议按这个顺序走先用欧拉法离散化跑通二维SMIB模型确认EKF和UKF代码逻辑正确再用innovation序列把R定准、把Q调稳最后再考虑RK4离散、增广状态、多机扩展这些进阶内容。每一步都验证清楚了再往下一步走比一上来就搞大系统要快得多。等这套基础代码沉淀成了自己的工具再去面对真实PMU数据时你会发现最难的部分其实已经解决了。