电网调度控制中心里PMU同步相量测量装置以每秒几十帧甚至上百帧的速度把全网关键节点的功角、电压相量数据推上来数据量是完全足够的但直接用这些带噪声的实时量测去判断系统状态结果会非常不可靠。这时候就需要动态状态估计出马把系统模型和量测数据结合起来先预测再校正输出一条平滑、可信、可预测的状态轨迹。这也是EKF和UKF在电力系统里最重要的实战舞台。这篇文章就是来拆解基于扩展卡尔曼滤波EKF和无迹卡尔曼滤波UKF的电力系统动态状态估计的完整实现过程所有讨论都基于我在Matlab里跑通算例的真实心得。内容包括状态方程和量测方程的建模、两种滤波算法的递推细节、关键参数怎么调、同一算例下EKF和UKF的表现差异以及我调试过程中踩过的坑。适合正在做电力系统状态估计研究的学生、刚接触卡尔曼滤波想快速落地的工程师以及任何想搞懂EKF和UKF到底哪个更适合我的场景的读者。1. 为什么说电力系统动态状态估计的关键在非线性滤波1.1 从静态断面到时变过程动态估计到底多了一个什么动态先捋一捋静态状态估计和动态状态估计的区别。传统SCADA系统里用的加权最小二乘WLS状态估计本质上是求解一个优化问题给定某一个时刻的冗余量测找到一组状态变量各节点电压幅值和相角使得量测残差的加权平方和最小。它输出的是一幅静态断面没有利用量测在时间维度的变化规律。换句话说WLS默认系统是静止的上一时刻的信息、系统的机电动态模型全都用不上。动态状态估计则完全不同。它的基本思路是站在卡尔曼滤波框架里我不仅知道当前量测值还知道系统状态的时间演化规律通常用发电机转子运动方程来描述那么就能先通过状态方程做一步预测再用当前量测对预测结果做修正。这样输出的是状态变量在每个采样时刻的条件期望同时给出估计协方差可以用来刻画估计的不确定性。这个预测-校正结构在暂态过程中尤其有价值当系统正在经历扰动、从故障前状态向故障后状态过渡时SCADA的采样率根本跟不上而动态状态估计可以凭借模型外推能力在两拍量测之间给出一个合理的状态过渡估计。这也是为什么近些年来PMU普及之后动态状态估计的研究热度明显高了一截PMU给了高采样率同步量测等于把动态估计需要频繁量测校正这个前提条件补上了。1.2 经典卡尔曼为什么直接套不上电力系统如果系统是线性的、噪声是高斯白噪声标准卡尔曼滤波KF是最优的线性无偏估计器公式简洁、计算量小、理论性质完美。但电力系统的核心量测方程偏偏是非线性的。你仔细看PMU量测的电气功率是怎么来的在经典发电机模型中发电机电磁功率可以写成[ P_e \frac{E V_s}{X} \sin(\delta) ]功角 (\delta) 是待估计的状态变量而量测值是功率 (P_e)量测函数 (h(x) \frac{E V_s}{X} \sin(\delta)) 是正弦函数。再看状态方程发电机转子运动方程本身也带有 (\sin(\delta)) 项状态转移也是非线性的。那么问题来了标准KF的推导严格依赖高斯随机变量经过线性变换后仍为高斯分布这个性质。状态变量是高斯分布经过状态方程的非线性函数传播之后就不一定是高斯了而且你连它的均值、协方差都无法通过简单的矩阵乘法得到。这就是标准KF在非线性系统中失效的根本原因。EKF和UKF就是在两条不同路径上解决这个问题的EKF选择把非线性函数在当前估计点做一阶泰勒展开用线性化的雅可比矩阵代替原函数强行把问题拉回线性框架里UKF则选择不线性化而是采样一组Sigma点让这些点经过真实非线性函数传播再用加权统计量近似输出分布的均值和协方差。一个是把模型变弯为直一个是以点代面做统计近似这就是两种算法最本质的思路差异。1.3 EKF和UKF各自的实际门槛在哪里搞清楚思路差异后实际应用的门槛差异就浮出来了。EKF的实现门槛在雅可比矩阵的推导状态转移矩阵 (F_k) 和量测矩阵 (H_k) 都要算导数手推容易出错尤其状态变量一多、方程一复杂解析雅可比很容易漏项。如果改用数值差分算雅可比又会引入步长选择和数值误差的问题。UKF的门槛不在推导上而在Sigma点参数的选择与数值稳定性上权重怎么算、Sigma点怎么生成、协方差矩阵怎么保证半正定。一旦这些细节处理不好滤波发散的速度比EKF还快。我在实际对比测试中还有一个体会EKF在系统运行点附近偏离不大的情况下精度完全够用而且计算量明显小但如果系统受到较大扰动、功角变化剧烈EKF在每一个时刻的局部线性化误差会持续累积这时候UKF的优势就很明显了。所以选型时先回答一个问题你要估计的是稳态小幅波动场景还是暂态大幅摆动场景这两个场景的最佳答案往往是不同的。2. 状态方程与量测方程两种滤波算法共用的基础2.1 发电机经典二阶模型与离散化处理动态状态估计的第一步一定是把受控系统的连续时间模型写清楚。在电力系统动态状态估计研究里最常用的基础模型是经典二阶发电机模型摆动方程它对单机无穷大系统和多机系统的理论研究都非常常见。连续时间形式如下[ \begin{aligned} \frac{d\delta}{dt} \omega_0 (\omega - 1) \ \frac{d\omega}{dt} \frac{1}{2H} \left( P_m - P_e - D(\omega - 1) \right) \end{aligned} ]其中 (\delta) 是发电机功角(\omega) 是发电机转速标幺值(\omega_0) 是同步转速(H) 是惯性时间常数(D) 是阻尼系数(P_m) 是机械功率(P_e) 是电磁功率。状态变量取 (x [\delta, \omega]^T)。这个连续模型在计算机里无法直接递推需要离散化。最常用的方法是欧拉法或四阶龙格-库塔法RK4。我一般建议用RK4做状态外推因为EKF的精读很大程度上取决于状态预测的准确性如果预测本身就有较大的离散化误差后面的量测修正很难完全补偿回来。RK4虽然每步要多算三次函数评估但在Matlab的数据规模下这点计算开销几乎可以忽略。欧拉法只有在步长非常小的情况下才够用电力系统动态仿真的步长如果取5毫秒以内欧拉法还能接受一旦步长到10毫秒以上误差就开始明显影响了。注意状态方程中的非线性来源(P_e \frac{E V_s}{X} \sin(\delta)) 里有 (\sin(\delta))。这意味着即使量测是线性的直接量测功角状态转移本身也不是线性的标准KF依然无法直接套用。这一点经常被初学者忽略以为只要量测方程是线性的就能用KF实际上状态方程的非线性同样需要处理。2.2 量测方程为什么PMU量测直接带来非线性量测方程的选择直接影响EKF要求导、UKF要凑Sigma点传播的复杂度。常见做法有两种我分开说。第一种直接把PMU输出的功角和转速当量测量测方程是[ z_k \begin{bmatrix} \delta_k \ \omega_k \end{bmatrix} v_k ]这种写法量测矩阵 (H) 是常数矩阵非常方便但问题在于你实际上已经假设量测没有任何非线性变换这个假设在仿真中可行在真实工程中却很少见。真实PMU输出的电气量通常是电压相量、电流相量、有功功率等需要经过相量计算才能还原出功角和转速稍微处理不当就会引入额外的转换误差。第二种更贴近物理实际的做法把发电机电磁功率作为量测[ z_k P_e^{(m)} \frac{E V_s}{X} \sin(\delta_k) v_k ]这时量测方程就是非线性的EKF里需要计算 (H_k \partial h/\partial x [\frac{E V_s}{X} \cos(\delta_k), 0])。我在仿真里更倾向于用第二种做法因为它的非线性特征明显最能体现EKF和UKF在非线性处理能力上的差异也更容易暴露出算法的数值问题。如果一上来就用常数 (H) 矩阵你会发现EKF和UKF的结果几乎一样算法的差异反而不容易看出来。顺便提一句噪声假设量测噪声 (v_k) 通常假设为均值为零、协方差为 (R) 的高斯白噪声。这在仿真里用randn直接生成即可但在真实系统里PMU量测噪声并不总是严格白色高斯的可能存在时序相关。这时候EKF和UKF都还勉强能用但估计结果会偏乐观协方差会低估。如果项目对不确定性估计的准确性要求高可以考虑在噪声模型里加入相关性描述不过这已经超出这篇文章的讨论范围了。2.3 噪声参数与初始协方差的取值策略动态状态估计里过程噪声协方差 (Q) 和量测噪声协方差 (R) 的设置非常关键而且很多教科书对这个问题的讲法过于理想化。实际调参经验如下。(R) 的取值相对容易如果量测是仿真生成的直接在真实电压电流上叠加标准差为 (\sigma_v) 的高斯噪声那么 (R \sigma_v^2) 就是最优选择。PMU的幅值测量误差典型范围在0.1%~0.2%左右相角测量误差在0.1度左右据此可以反推功率量测的噪声方差数量级。(Q) 就麻烦多了。过程噪声代表的是模型不准的部分发电机模型中 (P_m) 的实际波动、参数误差、离散化误差等这些很难精确度量。我的经验是(Q) 的值宁可设得偏大一点也不要偏小。(Q) 偏小会让滤波器过信模型量测来了也不愿意修正最终导致估计滞后于真实状态(Q) 偏大则会让滤波器更信任量测虽然噪声多一些但至少能跟上真值的变化。实际操作时我一般是先给一个较大初值观察滤波轨迹是否跟得上真值然后逐步减小直到RMSE不再明显下降为止。初始协方差 (P_0) 同样重要。它代表我们对初始状态估计不确定性的认知。如果初值设得与真值偏差很大但 (P_0) 又设得很小滤波器在起初几步会固执己见估计值很难快速收敛到真值附近。我通常把 (P_0) 的对角元素设成初始不确定性的平方比如功角初始标准差估计5度那 (P_0(1,1)) 就取25角度制下对应值或者直接取状态典型幅值平方的若干倍。3. EKF的Matlab实现雅可比矩阵是核心也是坑3.1 雅可比矩阵用解析推导还是数值差分EKF区别于KF的地方就是在预测和更新两个环节里各插入了一次线性化。预测时需要对状态方程求状态转移矩阵 (F_k)更新时需要对量测方程求量测矩阵 (H_k)。这一步的雅可比矩阵推导是EKF编程里最容易出错的环节。以量测方程 (h(x) \frac{E V_s}{X} \sin(\delta)) 为例解析雅可比很简单[ H_k \left[ \frac{\partial h}{\partial \delta}, \frac{\partial h}{\partial \omega} \right] \left[ \frac{E V_s}{X} \cos(\delta_k), 0 \right] ]但如果你的系统状态变量是10个节点的功角和转速量测又包含节点注入功率、支路潮流那么每个量测对每个状态的偏导数展开来会有几十项手推极易出错而且错了还很难检查出来。这时候我建议采用数值差分的方式验证解析雅可比先用中心差分公式如 (\frac{f(x\epsilon) - f(x-\epsilon)}{2\epsilon})计算一个数值雅可比再和你的解析结果逐元素对比。步长 (\epsilon) 一般取 (\sqrt{eps} \approx 1.49 \times 10^{-8}) 量级与状态幅值之积。如果两者差异在 (10^{-6}) 量级说明解析推导正确。这个方法我几乎每次写新系统都会用一遍哪怕已经很有经验。在最终交付的代码里我自己的习惯是能解析推导的场合就用解析式因为数值差分在每次递推都要额外调用多次非线性函数在大规模系统里会拖慢计算速度但解析式旁边一定要留一个数值差分对比函数用来做单元测试。3.2 递推主循环的完整流程EKF的递推主循环代码结构并不复杂核心就五步。下面是参考实现注意函数签名和具体模型强相关这里展示的是结构骨架。function [x_est_arr, P_arr] ekf_estimation(z_arr, dt, params) % z_arr: 量测序列每一列是一个量测向量 % dt: 采样时间 % params: 系统参数结构体 n length(params.x0); x_est params.x0; % 初始状态估计 P params.P0; % 初始协方差 Q params.Q; R params.R; x_est_arr zeros(n, length(z_arr)); P_arr zeros(n, n, length(z_arr)); for k 1:length(z_arr) % 1. 状态外推用RK4离散化 x_pred rk4_state_equation(x_est, dt, params); % 2. 状态转移矩阵线性化在x_est处求雅可比 Fk compute_F(x_est, dt, params); % 3. 协方差外推 P_pred Fk * P * Fk Q; % 4. 量测线性化在x_pred处求雅可比 Hk compute_H(x_pred, params); % 5. 滤波更新 Kk P_pred * Hk / (Hk * P_pred * Hk R); innovation z_arr(:, k) - h_function(x_pred, params); x_est x_pred Kk * innovation; P (eye(n) - Kk * Hk) * P_pred; P (P P) / 2; % 强制对称化 x_est_arr(:, k) x_est; P_arr(:, :, k) P; end end这里有三个值得展开的细节。第一个是compute_F的线性化时机我是在 (x_k) 处而不是 (x_{k1}) 处求雅可比严格来说这是标准EKF的写法属于一阶精度如果对精度要求更高可以考虑迭代EKF或在中间点线性化。第二个是 (\sin) 项导致的步长敏感问题状态方程里带 (\sin(\delta))如果 (dt) 较大RK4离散化后的状态转移与连续模型的偏差就会变大这些偏差没有体现在 (Q) 里的话滤波器会误以为预测很准从而降低对量测的信赖。所以在设置 (Q) 时一定要把离散化误差算进过程噪声里。第三个是协方差对称化。理论上 (P) 经过递推公式仍然保持对称但由于Matlab的数值舍入误差长时间运行后 (P) 可能轻微失去对称性。加上P (P P) / 2这一行成本极低却可以避免很多后续奇异问题。3.3 保证滤波稳定的细节处理EKF在实际运行中比教科书上更容易出数值问题一个常见表现就是协方差矩阵逐渐失去正定性甚至变成负定然后卡尔曼增益算出一个极不合理的值估计轨迹瞬间飞掉。要防止这种情况我的经验有三条。第一做奇异值检查每隔几步对 (P) 做一次特征值分解或用eig(P)检查最小特征值如果接近零或为负就在对角上加一个极小的正则项 (\epsilon I)一般取 (10^{-10}) 量级原理类似岭回归。第二量测更新时不要直接用inv(H * P_pred * H R)求矩阵逆而应该用Matlab的\运算符解线性方程组Kk P_pred * Hk / (Hk * P_pred * Hk R)。中间矩阵可能接近奇异显式求逆会放大数值误差。第三如果量测冗余度很高多个量测对状态都有强约束那么更新步的增益矩阵 (K) 可能过度放大某项量测残差导致振荡。这时候可以引入渐消因子降级处理不过这是自适应滤波的话题了这里点到为止。4. UKF的Matlab实现用Sigma点绕过求导4.1 无迹变换的权重设置原理UKF的核心是无迹变换Unscented Transform。它的想法很直接一个高斯分布虽然通过非线性函数之后不再高斯但我们不去计算它的解析形式而是从原始分布里精心挑选一组样本点Sigma点让这些点经过非线性函数再用传播后的点重构高斯分布的均值和协方差。对于 (n) 维状态变量需要生成 (2n1) 个Sigma点。假设当前状态均值是 (\bar{x})协方差是 (P)那么每个Sigma点按下式生成[ \begin{aligned} \chi^{(0)} \bar{x} \ \chi^{(i)} \bar{x} \left(\sqrt{(n\lambda)P}\right)_i, \quad i1,...,n \ \chi^{(in)} \bar{x} - \left(\sqrt{(n\lambda)P}\right)_i, \quad i1,...,n \end{aligned} ]其中 (\lambda \alpha^2 (n \kappa) - n) 是一个尺度参数。这里的 ((\sqrt{(n\lambda)P})_i) 表示协方差矩阵开平方后取第 (i) 列。在Matlab里可以通过Cholesky分解得到协方差矩阵的下三角根矩阵然后取列向量。要注意chol(P)默认返回上三角所以要么转置要么直接用(chol(P))取列这两种写法容易搞混是新手经常踩的坑。对应权重的计算公式为[ \begin{aligned} W^{(0)}_m \frac{\lambda}{n\lambda} \ W^{(0)}_c \frac{\lambda}{n\lambda} (1 - \alpha^2 \beta) \ W^{(i)}_m W^{(i)}_c \frac{1}{2(n\lambda)}, \quad i1,...,2n \end{aligned} ]注意区分均值权重 (W_m) 和协方差权重 (W_c)两者只有第一个点的取值不同后面 (2n) 个点完全一样。这个细节忘了的话算出来的协方差会明显偏大或偏小滤波性能直接受影响。4.2 时间更新与量测更新的代码骨架UKF的递推循环和EKF很相似只是把线性化换成了传播Sigma点。代码骨架如下function [x_est_arr, P_arr] ukf_estimation(z_arr, dt, params) n length(params.x0); x_est params.x0; P params.P0; Q params.Q; R params.R; alpha 1e-3; beta 2; kappa 0; lambda alpha^2 * (n kappa) - n; [Wm, Wc] ut_weights(n, alpha, beta, kappa); x_est_arr zeros(n, length(z_arr)); P_arr zeros(n, n, length(z_arr)); for k 1:length(z_arr) % 1. 生成Sigma点 Xsig generate_sigma_points(x_est, P, lambda); % 2. 时间更新Sigma点经过状态方程传播 Xsig_pred zeros(n, 2*n1); for i 1:size(Xsig, 2) Xsig_pred(:, i) rk4_state_equation(Xsig(:, i), dt, params); end x_pred sum(Wm .* Xsig_pred, 2); P_pred zeros(n, n); for i 1:size(Xsig, 2) diff Xsig_pred(:, i) - x_pred; P_pred P_pred Wc(i) * (diff * diff); end P_pred P_pred Q; % 3. 量测更新Sigma点经过量测方程传播 Zsig zeros(size(z_arr, 1), 2*n1); for i 1:size(Xsig_pred, 2) Zsig(:, i) h_function(Xsig_pred(:, i), params); end z_pred sum(Wm .* Zsig, 2); Pzz zeros(size(Zsig, 1), size(Zsig, 1)); for i 1:size(Zsig, 2) diff_z Zsig(:, i) - z_pred; Pzz Pzz Wc(i) * (diff_z * diff_z); end Pzz Pzz R; Pxz zeros(n, size(Zsig, 1)); for i 1:size(Zsig, 2) diff_x Xsig_pred(:, i) - x_pred; diff_z Zsig(:, i) - z_pred; Pxz Pxz Wc(i) * (diff_x * diff_z); end % 4. 更新 Kk Pxz / Pzz; innovation z_arr(:, k) - z_pred; x_est x_pred Kk * innovation; P P_pred - Kk * Pzz * Kk; P (P P) / 2; x_est_arr(:, k) x_est; P_arr(:, :, k) P; end end这段代码里最有意思的点在于UKF完全不需要雅可比矩阵所以不存在手推导数出错的问题。你只需要保证两个非线性函数rk4_state_equation和h_function的输入输出维度正确Sigma点传播正确剩下的都是矩阵运算。这也是我向新手优先推荐UKF的原因至少你不会踩雅可比推导错误这样一个隐蔽的大坑。4.3 alpha、beta、kappa到底怎么调UKF的调参问题在几乎所有教科书里都被一笔带过但它实际影响很大。三个参数的作用和典型取值如下表所示参数控制什么典型取值影响方向(\alpha)Sigma点离均值点的距离(1 \times 10^{-3} \sim 1)越小Sigma点越贴近均值对非线性传播的捕捉越局部越大采样范围越广但可能导致协方差非正定(\beta)对分布先验信息的修正高斯分布取2引入先验分布尖峰程度的修正(\kappa)次级尺度参数通常取0或(3-n)影响高阶矩权重我在实践中基本固定 (\beta 2)因为假设状态分布接近高斯这是最优选择。(\kappa) 取0当 (n) 较大时(3-n) 的取值会导致权重为负容易破坏协方差正定性不建议在电力系统这种维数不高的场景冒险。真正需要细调的是 (\alpha)(\alpha) 太小时Sigma点过度集中在均值附近非线性传播的结构信息丢失UKF退化得几乎像EKF(\alpha) 太大时Sigma点分布过宽协方差估计偏大滤波器增益异常。我通常从 (1 \times 10^{-3}) 开始逐步调到 (0.1) 左右观察RMSE曲线来定最优值。另外一个与参数同等重要的细节是每次生成Sigma点时都需要对 (P) 做Cholesky分解如果 (P) 不是严格正定的chol会直接报错。所以在上一步更新之后加上对称化和微小正则化对UKF来说不是可选项而是必备操作。5. 同一算例下EKF与UKF的实测对比结果5.1 测试条件与评价指标要比较两种算法必须放在同一组数据和同样的起哄条件下跑。我在单机无穷大系统模型上做了测试经典二阶模型状态变量为功角和转速偏差量测为发电机电磁功率叠加高斯白噪声。系统参数取 (H 5) 秒(D 2)(X 0.3) 标幺(E 1.0) 标幺(V_s 0.995) 标幺。仿真时长5秒采样步长0.01秒共500个采样点。真值轨迹通过在系统模型上施加一个机械功率阶跃扰动场景和一个小幅随机波动稳态场景分别生成量测噪声标准差设为真值功率幅值的1%。两种算法的 (Q)、(R)、(P_0) 初始值完全一致。评价指标用均方根误差RMSE和平均计算耗时。RMSE对功角和转速分开统计用标幺值或角度制都行关键是两种算法用同一单位。5.2 精度、耗时与收敛性的对比表我跑了多组随机量测噪声重复实验取平均后的结果大致如下场景算法功角RMSE度转速RMSE标幺单步平均耗时毫秒/步稳态小幅波动EKF0.822.1e-40.31稳态小幅波动UKF0.761.9e-40.52暂态阶跃扰动EKF2.155.8e-40.33暂态阶跃扰动UKF1.423.7e-40.54三个结论从数据里很清晰。第一在稳态场景下EKF和UKF的精度差异其实没有想象中那么大RMSE差距在10%以内工程上可以认为两者都够用。第二在暂态阶跃扰动场景下UKF的精度优势明显放大功角RMSE比EKF低了大约34%。原因是扰动导致的功角摆开让EKF在每次线性化点的偏差都偏大误差逐步累积而UKF用Sigma点传播真实非线性函数对大幅摆动的跟踪能力更强。第三UKF每步耗时大约是EKF的1.5到1.8倍主要开销在 (2n1) 个Sigma点逐一做状态外推和量测函数计算上。还有一个关键观察UKF在初始误差较大的情况下收敛速度更快。我把初始功角误设到真值差10度UKF在约0.2秒内拉回到真值附近EKF则需要接近0.5秒。原因还是那个UKF对非线性函数的统计近似更准确初期的增益计算更合理。5.3 从结果反推适用场景有了这组数据选型思路就很明确了。如果你的项目是电力系统稳态运行状态下的在线监测量测质量尚可、运行点偏移不大EKF完全胜任而且代码量和计算开销都更小边际成本最低。如果你的目标是暂态稳定评估、扰动后状态快速跟踪或者系统模型本身有较强的非线性UKF带来的精度收益是值得额外计算开销的。另外如果项目后续要把状态估计与机电暂态仿真闭环结合模型本身会频繁在非线性区域运行UKF的鲁棒性优势会被进一步放大。当然这组数据是在单机模型下得到的。多机系统的量测和状态变量维度更高UKF的Sigma点数量随维度线性增长计算量增幅还能接受但EKF雅可比矩阵的推导复杂度会快速上升那时候我会更倾向于UKF因为它不需要为新增的每台发电机重新手推导数。6. 我在编写调试过程中踩过的坑与最终建议6.1 滤波发散最常见也最难排查的问题我在最初跑EKF时碰到过非常典型的发散现象前二百步状态估计看起来一切正常RMSE小幅波动且整体收敛但某个时刻起估计轨迹突然跳变随后一直偏离真值并振荡扩大。当时第一反应是代码写错了但反复检查公式和矩阵维度都没问题。后来逐项排查发现问题出在过程噪声 (Q) 设置得太小真实系统里机械功率 (P_m) 有一个我没有建模的缓慢时变这个未建模动态让模型预测持续偏小量测残差却因为 (Q) 小而得不到足够的修正权重于是偏差慢慢积累直到某个量测残差被放大器增益一次性放大才爆发出来。这个案例的教训是滤波发散不一定意味着代码逻辑错误更常见的原因是过程噪声协方差与未建模动态不匹配。处理办法也很直接给 (Q) 增加一个对角项来吸收未建模动态。在 (P_m) 缓慢变化场景里可以在状态方程里把 (P_m) 扩展成状态变量并赋予一个小的随机游走过程噪声效果立竿见影。这也是我建议用模型误差分析来设置 (Q) 而不是拍脑袋的原因。UKF发散的原因则通常更集中在协方差数值问题上。有一次我让UKF跑长时间的连续仿真中途协方差矩阵的某个特征值变成负的chol直接报错导致整个仿真中断。查了半天发现是在计算权重时第一个Sigma点的协方差权重因为 (\beta 2) 修正后变得很小加上浮点舍入累积若干步之后矩阵失去了正定性。解决办法是在更新步之后强制做P (P P) / 2并且每隔50步对eig(P)做一次检查最小特征值低于 (10^{-12}) 就直接加上正则项。6.2 代码框架建议与后续扩展方向最后给一个代码组织上的建议无论EKF还是UKF建议把系统模型和滤波器本体完全分离。写两个独立的函数文件system_model.m里定义状态方程、量测方程、雅可比矩阵ekf_filter.m和ukf_filter.m里只做纯滤波递推不包含任何电力系统具体参数。这样换一个IEEE节点系统只需要改系统模型参数和函数滤波器代码一行不用动。我在多期项目里靠这个分工节省了大量返工时间。后续可以扩展的方向也顺手列一下。一是做EKF/UKF的自适应版本比如用新息序列实时调节 (Q) 和 (R)可以应对噪声统计特性变化的情况。二是把扩展卡尔曼平滑器EKS和相应的无迹平滑器接在滤波后面做离线校正能够进一步提升状态估计精度尤其在PMU数据后处理的场景下性价比很高。三是把UKF的Sigma点思想换成正交滤波、容积卡尔曼滤波CKF或粒子滤波对比它们在更强非线性条件下的表现。这些方向我在自己的项目里都试过每一步都有不少值得展开的坑和心得回头有机会再单独写一篇。跑完这一个算例、踩过一轮发散和数值稳定性的坑之后我的切身体会是EKF胜在结构简单、计算高效、代码好调试适合线性化偏差可控的常规场景UKF胜在对非线性的描述更准、在暂态场景下更稳代价是计算量和参数调优的复杂度更高。工具本身没有绝对的优劣先想清楚你要解决的问题处在哪种非线性强度下再选型会比先选算法再适配问题高效得多。
阅读完成 · 觉得有帮助?