ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于Matlab的EKF与UKF在电力系统状态估计中的实现与对比

基于Matlab的EKF与UKF在电力系统状态估计中的实现与对比 1. 从量测方程的非线性说起为什么状态估计绕不开EKF和UKF我在做电力系统状态估计的时候最早接触的是加权最小二乘法WLS。教科书上讲得清楚WLS在量测冗余度足够、系统运行在稳态工况下估计结果相当靠谱。但真正拿到现场数据尤其是我在仿真里引入PQ节点的功率量测时问题就来了——功率量测和状态变量节点电压幅值与相角之间的关系本来就是二次型的非线性映射WLS通过迭代线性化来逼近最优解本质上是在每次迭代中重新计算雅可比矩阵再用高斯-牛顿法求解。这套思路在常规负荷水平下没问题可一旦系统进入动态过程或者量测噪声不再是理想的高斯白噪声WLS就开始捉襟见肘。我举个例子。假设你有一个简单的两节点系统节点1是平衡节点电压幅值固定为1.0相角为0节点2是PQ节点有功和无功注入量测为P和Q。量测方程是P V1 * V2 * (G * cos(θ12) B * sin(θ12))Q V1 * V2 * (G * sin(θ12) - B * cos(θ12))这里的V2和θ12就是待估计的状态量。这个方程对V2和θ12的偏导数雅可比矩阵元素本身就含三角函数和电压项一步线性化必然带来截断误差。WLS通过迭代可以逐渐逼近但它本质上是在求一个静态优化问题的解对时序上的连续性、对状态随时间演化的规律完全不敏感。换句话说WLS做的是一次“快照”式的估计而实际系统每时每刻都在变化。这时候扩展卡尔曼滤波器EKF和无迹卡尔曼滤波器UKF的优势就体现出来了。卡尔曼滤波天然是递推结构能够把上一时刻的估计结果作为先验信息结合系统的动态模型状态转移方程来预测当前时刻的状态再用最新的量测来修正预测值。对于线性系统标准卡尔曼滤波就是最优估计对于电力系统这种典型的非线性系统EKF通过对非线性函数做一阶泰勒展开来进行局部线性化UKF则通过确定性采样Sigma点直接传播状态的统计特性绕开了雅可比矩阵的推导和计算。我在Matlab里搭了一套完整的实验平台把IEEE 14节点系统当作测试对象对比了WLS、EKF和UKF三种方法在稳态、负荷突变、量测噪声增大三种场景下的表现。结果符合预期WLS在稳态下精度最高因为它的目标函数本来就是最小化量测残差的二范数但一旦系统动态变化WLS每次都要重新从头迭代而且在噪声较大的情况下收敛速度明显变慢。EKF胜在原理简单、计算量小适合处理弱非线性问题UKF在高非线性场景下精度优势明显代价是计算量大约是EKF的三倍。这篇文章我就围绕这套Matlab仿真平台把EKF和UKF在电力系统状态估计中的实现细节、代码结构和实验对比思路完整梳理一遍。适合正在做电力系统动态估计、配电网状态感知、或者想把自己的WLS程序扩展成卡尔曼滤波形式的研究生和工程师参考。2. 仿真框架与状态空间模型搭建IEEE 14节点测试平台2.1 问题建模状态向量、量测向量与动态模型怎么定做状态估计的第一步不是写代码而是把数学问题定义清楚。电力系统状态估计的状态向量通常取所有节点的电压幅值V和相角θ平衡节点相角除外在极坐标下表示为x [θ2, θ3, ..., θN, V1, V2, ..., VN]^T对于IEEE 14节点系统平衡节点是节点1所以状态向量的维度是(14-1)14 27维。量测向量一般包含节点注入有功/无功功率、支路有功/无功潮流和节点电压幅值三种类型。在仿真中我在每个节点配置了电压幅值量测在所有支路上配置了有功和无功潮流量测还在部分节点配置了注入功率量测。总的量测数量是14个电压幅值 20条支路 × 2有功/无功潮流 6个节点的注入功率 × 2 14 40 12 66个量测。量测冗余度 66/27 ≈ 2.44这个冗余度在工程上是达标的能够保证可观测性并且给滤波器提供足够的修正信息。动态模型的选择直接决定了卡尔曼滤波的预测效果。最常用的是一阶随机游走模型x(k1) x(k) w(k)其中w(k)是过程噪声协方差矩阵为Q。这个模型的基本假设是在短时间内系统运行点不会发生剧烈跳变状态量在上一时刻的基础上叠加一个小扰动。随机游走模型虽然简单但非常实用——它不需要知道发电机的详细动态方程也不需要负荷预测模型适合做纯量测驱动的状态估计。如果你需要更精确的预测可以用准稳态模型x(k1) F * x(k) w(k)这里的F可以是单位阵对应随机游走也可以是根据历史数据辨识出来的状态转移矩阵。我在仿真里对比过F取单位阵时EKF和UKF的稳态估计精度差别不大但在负荷突变时刻带有负荷预测信息的动态模型能让滤波器更快地收敛回稳态。2.2 Matlab仿真环境设计与量测生成我要先说明一下下面展示的是一个可运行的Matlab实验框架版本是R2021a及以上都能跑不需要额外的工具箱电力系统相关的Power System Toolbox不是必需的我们自己搭雅可比矩阵。量测数据的生成是仿真中至关重要的一环。很多人喜欢直接从潮流计算程序里拿真值然后叠加高斯噪声来模拟量测。这套流程本身没有错但要注意实际量测中不同表计的精度是不一样的。电压幅值量测通常来自PMU或RTU的误差标准差大约是0.002到0.005 p.u.而有功潮流的误差标准差大约是0.01 p.u.。在仿真里如果给所有量测设置相同的噪声方差就会导致滤波结果失真——高精度的量测本该获得更大的权重却被等权处理了。我的做法是分类型设置量测噪声标准差量测类型量测误差标准差p.u.说明电压幅值0.004对应0.4%的精度PMU级别支路有功潮流0.010对应1%的精度RTU级别支路无功潮流0.012无功量测精度略低于有功节点注入功率0.015注入功率由计算得到误差偏大生成量测值的时候先用Matpower跑一遍潮流得到状态真值x_true然后根据量测方程h(x_true)计算量测真值再叠加对应标准差的高斯噪声得到量测向量z。流程图是潮流真值 → 量测方程计算真值 → 叠加噪声 → 送入滤波器。在Matlab里生成量测的代码大致长这样% 加载IEEE 14节点系统数据Matpower格式 mpc loadcase(case14); % 跑潮流得到状态真值 results runpf(mpc); V_true results.bus(:, 8); % 电压幅值 theta_true results.bus(:, 9) * pi / 180; % 相角弧度 % 构造量测真值 % h(x)是量测函数返回所有量测的真值 z_true measure_func(V_true, theta_true, mpc); % 生成量测噪声 R diag([ ... ]); % 噪声协方差矩阵维度66x66 noise mvnrnd(zeros(1, 66), R); z_meas z_true noise;这段代码里最关键的是measure_func函数它实现了潮流和注入功率的量测方程。我在仿真中直接调用了Matpower里的函数来计算这些值省去了自己推导的麻烦。不过如果你不想依赖Matpower也可以自己写一个简单的潮流计算器——无非是PQ分解法或者牛顿-拉夫逊法对于14节点系统来说收敛速度很快。2.3 为什么在仿真中要给EKF和UKF相同的初始条件这个问题看起来微不足道但实际上对实验结果的可信度影响很大。很多人做对比实验时给不同的滤波器设置不同的初始协方差矩阵结果一个收敛快、一个收敛慢得出“A方法优于B方法”的结论这是不严谨的。我的做法是两种滤波器都用潮流计算得到的初值x(0) 潮流解略微加上0.01的扰动初始协方差矩阵P(0) I × 0.01过程噪声协方差Q I × 1e-6量测噪声协方差R由量测类型决定和生成量测时使用的标准差对应。这样设置的意义在于初始不确定性相同滤波器的收敛速度差异就完全取决于算法本身的性能。有一点值得注意Q的取值对滤波器的动态跟踪能力有直接影响。Q设置得太小滤波器会过度信任预测值导致量测修正的增益变小在负荷突变时跟踪速度慢Q设置得太大滤波器又会被量测噪声牵着鼻子走稳态精度下降。我的经验是在仿真前期用大Q1e-4做系统辨识让滤波器先适应动态稳定后再切换到小Q1e-6进入稳态跟踪。这属于工程调参技巧后面我会专门展开说。3. 扩展卡尔曼滤波器的Matlab实现雅可比矩阵与递推流程3.1 EKF的预测-修正结构与线性化误差来源EKF的核心思想可以用一句话概括在每一步迭代中在上一时刻的估计点处对非线性函数做一阶泰勒展开然后套用标准卡尔曼滤波的递推公式。展开后系统模型变成x(k1) ≈ f(x̂(k)) F(k) · (x(k) - x̂(k)) w(k) z(k) ≈ h(x̂(k|k-1)) H(k) · (x(k) - x̂(k|k-1)) v(k)这里的F(k)是状态转移矩阵随机游走模型下就是单位阵H(k)是量测函数的雅可比矩阵。EKF的误差来源恰恰在于这个一阶截断当系统的非线性程度较强时泰勒展开的二阶及以上的高阶项被忽略会造成明显的估计偏差。在电力系统里状态变量与量测之间的非线性主要来自潮流方程中的三角函数和电压乘积项在小角度差假设下线性化误差尚可接受但如果系统处于重负荷或接近电压失稳区相角差变大EKF的线性化误差就会显著增加。具体实现中我按照标准的滤波递推公式来写% EKF主循环 for k 1:N % 1. 预测步骤 x_pred x_est(:, k-1); % 随机游走模型预测状态等于上一时刻估计值 P_pred P_est(:, :, k-1) Q; % 状态转移矩阵是单位阵 % 2. 计算量测函数的雅可比矩阵 H jacobian_measure(x_pred, mpc); % 3. 更新步骤 K P_pred * H / (H * P_pred * H R); innov z_meas(:, k) - measure_func(x_pred, mpc); x_est(:, k) x_pred K * innov; P_est(:, :, k) (eye(n_state) - K * H) * P_pred; end这里最耗费精力的部分就是jacobian_measure函数需要手推雅可比矩阵的解析式。你可能觉得头疼但我可以给你一个简化思路。3.2 量测雅可比矩阵的推导技巧按量测类型分块计算雅可比矩阵的维度是m×nm是量测数量n是状态数量27。咱们一行一行地对上电压幅值量测行如果量测是节点i的电压幅值Vi那么它对状态变量Vi的偏导数为1对其他状态变量的偏导数为0。这一行极其简单只有对角线上那个元素是1。支路潮流量测行支路i-j的有功潮流Pij对状态变量的偏导比较复杂。Pij的计算公式是Pij Vi²·g - Vi·Vj·(g·cosθij b·sinθij)对Vi求偏导2·Vi·g - Vj·(g·cosθij b·sinθij) 对Vj求偏导-Vi·(g·cosθij b·sinθij) 对θi求偏导Vi·Vj·(g·sinθij - b·cosθij) 对θj求偏导-Vi·Vj·(g·sinθij - b·cosθij)这四组偏导数就是这条支路潮流量测对应的雅可比行中非零元素。注入功率量测行节点i的注入有功Pi等于所有与i相连的支路潮流之和所以对每个相邻节点j其偏导数是对应支路潮流偏导数的叠加。你会发现雅可比矩阵是高度稀疏的。实际计算时没必要为每个量测单独写一个函数更高效的实现是采用按类型批量处理——先根据量测类型建立索引然后用向量化计算填充雅可比矩阵。这个方法在Matlab里能显著减少循环次数对于14节点这种小系统虽然差别不明显但如果将来你扩展到118节点、1354节点性能差距就非常大了。3.3 EKF初值敏感性与数值稳定性问题EKF在实际运行中有两个典型痛点一是对初值敏感二是协方差矩阵容易失去正定性。初值敏感性的原因在于雅可比矩阵H是在估计点处计算的。如果初值严重偏离真值H矩阵对应的也是错误工作点上的线性化可能导致滤波发散。我在仿真里做过一个极端实验把初值设为所有状态量为零V1θ0结果EKF在第一个时刻的更新就把协方差矩阵压得极小之后无论量测怎么修正估计值都很难翻身。解决办法是在滤波器启动时给P矩阵设置一个较大的初始值比如P(0) I × 0.1让滤波器在前几步具备较高的“可修正性”等收敛后再逐步收紧。数值稳定性问题多出现在P矩阵的递推更新。EKF的协方差更新公式P (I - K·H)·P_pred在计算机浮点运算中容易产生非对称现象长期运行后甚至可能出现负特征值导致滤波发散。一个简单的工程解决方案是改用Joseph形式的更新公式% Joseph form 保证数值稳定性 I_KH eye(n_state) - K * H; P_est I_KH * P_pred * I_KH K * R * K;这个形式在计算上略微复杂一些但能够保证协方差的对称性和半正定性在长时间在线估计中非常值得采用。本站的读者如果只是想快速验证EKF效果用简化形式问题不大但如果要集成到实际系统中的长期运行我强烈建议用Joseph形式。4. 无迹卡尔曼滤波器的Matlab实现Sigma点传播与权重设计4.1 无迹变换为什么不需要计算雅可比矩阵UKF的核心思想是无迹变换Unscented Transform, UT它的出发点非常朴素与其对非线性函数做线性化近似不如找一组确定性的采样点Sigma点把这组点直接通过非线性函数传播再用传播后的点来近似状态的均值和协方差。这句话听起来抽象我用个生活化的类比来解释。假设你要估计一个公园的面积你手头有一张公园的地图先验分布但你不知道公园的精确边界。EKF的做法是把公园近似成一个椭圆用地图上的某个点当前估计值做切线画出椭圆来近似整个公园的形状。UT的做法则是在地图上选若干个有代表性的点Sigma点把这些点对应的实际边界位置找出来再根据这些点重新拟合一个最接近实际形状的椭圆。对于电力系统状态估计来说UT的好处是不需要推导雅可比矩阵。我们只需要知道量测函数h(x)的input-output关系不要把数学表达式显式地写出来。这意味着你可以把任何复杂的量测函数——包括那些需要调用潮流计算程序的函数——直接嵌入UKF框架不需要为每个新量测类型重新推导偏导数。这是UKF在工程实现上最诱人的优势。4.2 Sigma点采样策略与权重公式的Matlab实现UT的采样策略有多种最常见的是对称采样。假设状态维度为n27那么总共需要2n155个Sigma点。第0个Sigma点就是当前状态的均值其余的Sigma点按如下方式生成χ(0) x̄χ(i) x̄ (√((nλ)·P))_ii 1, ..., nχ(in) x̄ - (√((nλ)·P))_ii 1, ..., n这里的(√((nλ)·P))_i表示矩阵(nλ)·P的Cholesky分解的第i列。λ α²·(nκ) - n是尺度参数其中α控制Sigma点围绕均值的散布程度通常取1e-3到1之间κ是次级尺度参数对高斯分布建议取3-n。对应权重为W_m(0) λ/(nλ)W_c(0) λ/(nλ) (1-α²β)W_m(i) W_c(i) 1/(2·(nλ))i 1, ..., 2n其中β是包含先验分布信息的参数对高斯分布最优取值为2。在Matlab里实现Sigma点采样最核心的步骤是Cholesky分解。注意Matlab的chol函数默认返回上三角矩阵而公式里需要的是下三角矩阵或者是其转置所以代码里要写成function [X_sigma, Wm, Wc] ut_sigma_points(x, P, alpha, beta, kappa) n length(x); lambda alpha^2 * (n kappa) - n; % Cholesky分解得到下三角矩阵 A chol((n lambda) * P, lower); % 生成Sigma点 X_sigma zeros(n, 2*n1); X_sigma(:, 1) x; for i 1:n X_sigma(:, i1) x A(:, i); X_sigma(:, in1) x - A(:, i); end % 权重 Wm zeros(2*n1, 1); Wc zeros(2*n1, 1); Wm(1) lambda / (n lambda); Wc(1) lambda / (n lambda) (1 - alpha^2 beta); Wm(2:end) 1 / (2 * (n lambda)); Wc(2:end) 1 / (2 * (n lambda)); end一个容易被忽视的坑是P矩阵的性质。Cholesky分解要求P必须是正定矩阵。在实际运行中由于连续多步乘法运算P矩阵可能因为数值误差而失去正定性这时候chol函数会直接报错。我常用的一个鲁棒性处理是在每次执行Cholesky分解前给P矩阵的对角线加一个极小的正则化项比如P P 1e-9 * eye(n)确保分解稳定。4.3 UKF递推主循环与量测更新细节UKF的递推流程比EKF复杂一些但结构非常清晰按照“预测-更新”两大步% UKF主循环 for k 1:N % 1. 生成Sigma点基于上一时刻的估计状态和协方差 [X_sigma, Wm, Wc] ut_sigma_points(x_est(:, k-1), P_est(:, :, k-1), alpha, beta, kappa); % 2. 预测步骤Sigma点通过状态转移函数 X_pred X_sigma; % 随机游走模型状态转移是恒等映射 % 计算预测均值和协方差 x_pred X_pred * Wm; P_pred zeros(n_state); for i 1:2*n_state1 diff X_pred(:, i) - x_pred; P_pred P_pred Wc(i) * (diff * diff); end P_pred P_pred Q; % 3. 生成新的Sigma点基于预测状态 [X_pred_sigma, ~, ~] ut_sigma_points(x_pred, P_pred, alpha, beta, kappa); % 4. 量测传播 Z_pred zeros(n_meas, 2*n_state1); for i 1:2*n_state1 Z_pred(:, i) measure_func(X_pred_sigma(:, i), mpc); end % 5. 计算量测均值、协方差和交叉协方差 z_pred Z_pred * Wm; Pzz zeros(n_meas); Pxz zeros(n_state, n_meas); for i 1:2*n_state1 diff_z Z_pred(:, i) - z_pred; diff_x X_pred_sigma(:, i) - x_pred; Pzz Pzz Wc(i) * (diff_z * diff_z); Pxz Pxz Wc(i) * (diff_x * diff_z); end Pzz Pzz R; % 6. 更新步骤 K Pxz / Pzz; innov z_meas(:, k) - z_pred; x_est(:, k) x_pred K * innov; P_est(:, :, k) P_pred - K * Pzz * K; end这段代码中有一个关键细节预测步骤之后需要重新生成一组Sigma点而不是直接使用预测前的Sigma点。原因在于过程的噪声w(k)是在预测步骤之后叠加的如果直接使用预测前的Sigma点就忽略了过程噪声对Sigma点分布的影响导致量测更新时协方差计算不准确。这个坑很多人第一版代码都会踩到是我自己调试时撞出来的教训——如果你发现UKF的估计结果对Q矩阵极其敏感先检查这里是不是写错了。4.4 UKF的性能特征与计算复杂度分析我在14节点系统上做了对比实验UKF的估计精度在各场景下略优于EKF尤其在负荷突变的动态过程中优势明显——EKF在突变后的2-3个采样周期内跟踪误差较大而UKF基本在突变后的下一个采样周期就能恢复。原因很容易理解负荷突变导致系统非线性程度增强EKF的一阶线性化产生了更大的截断误差而UT直接传播Sigma点不依赖线性化假设因此在高非线性区域依然保持较好的精度。代价是计算量。14节点系统的状态维度是27生成55个Sigma点每个点都要通过measure_func计算量测值其中涉及到多个节点的潮流计算总体耗时大约是EKF的3倍。在Matlab环境下单步UKF耗时大约在几十毫秒量级对于离线仿真来说完全不成问题但如果你将来要做实时估计需要考虑这个计算负担是否能满足控制周期要求。5. 仿真实验对比收敛性、跟踪能力与噪声鲁棒性分析5.1 实验场景设计稳态运行、负荷突变与量测噪声变化做仿真对比不能只跑一种工况得设计有区分度的场景才能让两种滤波器的性能差异真正显现出来。我设计了三个实验场景场景A稳态运行系统运行在额定工作点量测噪声水平保持在标准值模拟正常稳态监控场景。这个场景主要验证两种滤波器的基础估计精度和收敛速度。场景B负荷突变在仿真进行到第100个采样点时节点5和节点9的有功负荷同时增加30%模拟电网中的负荷突增事件。这个场景考察滤波器对动态变化的跟踪能力。场景C噪声增大将量测噪声标准差整体放大5倍模拟表计精度下降或通信干扰增强的场景。这个场景检验滤波器在恶劣量测条件下的鲁棒性。每个场景运行200个采样周期采样间隔为1秒模拟SCADA的采集周期。我分别计算了电压幅值估计误差和相角估计误差的均方根误差RMSE并记录了滤波器从启动到收敛的过渡时间。5.2 稳态场景下的精度对比EKF与UKF谁更准在稳态场景A下两种滤波器的估计结果都收敛到了真值附近但细节上略有差异。电压幅值的RMSE对比如下滤波方法电压幅值RMSEp.u.相角RMSE弧度达到稳态所需迭代数WLS0.00380.00121直接求解EKF0.00410.00153-4UKF0.00390.00143-4从数据上看三者差距不大WLS在稳态下甚至略微占优。这是因为在理想稳态工况下WLS求解的是非线性最小二乘问题的精确最优解而卡尔曼滤波是递推估计它要依赖前一步的结果不断逼近必然会引入一些累积误差。如果你只关心稳态监控精度WLS依然是最好的选择——这也是为什么实际电力系统调度中心至今仍以WLS为主流算法的原因。UKF和EKF在稳态场景下的差别不明显UKF的RMSE只比EKF低了5%左右。这说明在弱非线性区域EKF的一阶线性化截断误差足够小UKF的高阶信息并没有带来显著收益。所以仿真结果也印证了EE界的一个共识EKF并不是“比UKF差”而是“在非线性强的时候会力不从心”弱非线性下两者差距很小。5.3 负荷突变场景下的跟踪性能差异场景B的对比才真正体现了两种滤波器的本质差异。在负荷突变的第100个采样点电压幅值会发生约0.02-0.04 p.u.的跳变相角会发生约0.01-0.02弧度的变化。EKF和UKF都检测到了这个突变通过量测残差增大但反应速度不同从仿真曲线看UKF在第102个采样点就已经基本跟踪上了新的稳态值而EKF直到第104-105个采样点才完全跟上。这个差距来源于UKF的协方差传播方式——UT通过Sigma点直接传播非线性函数对状态的真实不确定性刻画更准确因此量测更新能够更恰当地调整修正增益。EKF的协方差传播在线性化截断后偏小导致滤波器过度相信模型预测对突变的反应用了更长时间。这里有一个重要的工程经验在实际系统中负荷突变通常伴随着保护动作、切机切负荷等连锁反应状态估计的响应速度直接影响后续的态势感知和辅助决策。如果你做的是在线动态安全评估系统UKF在突变场景下的快速收敛特性会带来实打实的性能提升。5.4 噪声鲁棒性对比与协方差整形技巧场景C把量测噪声标准差放大了5倍这对所有估计方法都是严峻考验。仿真结果显示UKF和EKF的估计误差都有明显增大但增幅不同EKF的电压幅值RMSE从0.0041增大到0.0087UKF从0.0039增大到0.0068。英国UKF在强噪声下的相对优势从5%扩大到22%。为什么噪声越大UKF的优势越明显我的理解是量测噪声增大意味着量测信息的不确定性更大滤波器在“相信预测”和“相信量测”之间的权衡更加敏感。EKF的雅可比矩阵是在单点处线性化的当噪声增大导致状态估计值偏离真值更远时线性化点偏离真值也更远雅可比矩阵不再能准确反映真实函数行为相当于“在错误的地方画切线”。UKF的Sigma点在估计值周围撒开一个“团”这个团内的不同点各自通过非线性函数相当于考虑了不同工作点上的函数斜率变化对噪声的抵抗能力自然更强。如果你要在工程上提升滤波器的噪声鲁棒性除了换用UKF之外还有一个“协方差整形”的技巧在量测更新之前人为对P_pred做一次扩展P_pred_scaled P_pred × c其中c是一个大于1的缩放因子我通常取1.1-1.5。这相当于承认我们对预测不确定性的估计偏乐观主动放宽预测置信区间让滤波器对量测赋予更高权重。这个技巧对EKF尤其有效能够部分补偿线性化误差造成的“过度自信”。5.5 权重系数α、β、κ的调参经验UKF的性能对UT参数非常敏感这一点我在仿真中体会很深。α是Sigma点散布范围的缩放参数直接影响UT的高阶信息近似精度。我的经验值α 1e-3Sigma点几乎贴近均值UT近似精度最高但数值稳定性变差矩阵接近奇异。α 0.1-0.3很好的中间选择我日常仿真都取这个范围。α 1.0Sigma点散布范围增大鲁棒性更好但对非线性函数的近似精度下降。β在高斯分布下的最优值是2这个参数主要是用来补偿高阶项信息一般不需要改动。κ对非高斯分布更敏感电力系统状态估计通常近似高斯取3-n即可。如果你换了一个全新的系统做UKF仿真我建议先用α0.1、β2、κ3-n跑一遍基线然后扫一遍α在0.001到1之间的取值观察RMSE的变化趋势。这个方法虽然笨但最可靠。6. 仿真代码架构与实战坑位从Matlab脚本到模块化设计6.1 完整的Matlab工程文件结构写仿真代码最容易犯的错误是把所有东西堆在一个大脚本里变量名满天飞跑完一次下次就忘。我做这套仿真时用了模块化设计把不同功能拆成独立文件power_system_estimation/ ├── main_ekf_ukf_comparison.m % 主脚本运行对比实验并绘图 ├── load_case_data.m % 加载IEEE 14节点数据 ├── measure_func.m % 量测函数计算量测值 ├── jacobian_measure.m % 量测雅可比矩阵计算EKF用 ├── run_ekf.m % EKF主循环 ├── run_ukf.m % UKF主循环 ├── ut_sigma_points.m % Sigma点生成与权重计算 ├── ut_weights.m % UKF权重计算独立模块 ├── generate_measurements.m % 生成量测数据加噪声 ├── compute_rmse.m % 计算均方根误差 ├── plot_estimation_results.m % 绘制估计结果对比图这种组织方式的优点是每个文件只负责一个独立功能修改量测模型比如从PQ量测换成PMU量测只需要改measure_func和jacobian_measure两个文件其他部分完全不用动。以后你要在这个平台上扩展其他算法比如无迹粒子滤波直接把新的算法文件加进去就行。6.2 我在Matlab实现中踩过的五个具体坑仿真过程中我踩了不少坑有些在教科书上完全找不到这里逐一列出来帮你避开坑一跑潮流时角度单位不一致。Matpower的潮流结果中电压相角默认是度degree而直接使用三角函数时需要弧度radian。我第一次写仿真时忘了把角度从度转弧度结果量测生成和雅可比计算全部错位EKF的输出结果完全发散。后来我养成习惯所有涉及三角函数的变量一律用弧度只在输出结果给人类看时才转回度。坑二Cholesky分解的返回矩阵方向搞反。前面提到过Matlab的chol返回上三角矩阵而公式里用的是下三角矩阵。如果不加lower参数Sigma点生成的方向就反了但量测更新时又不会完全崩溃只是精度轻微下降——这是一种很隐蔽的bug。我建议你在调试时打印一组Sigma点检查它们是否关于均值对称分布快速判断是否中招。坑三量测噪声协方差R和实际噪声方差不匹配。生成量测时用了标准差0.01的噪声但R矩阵里对角线却填了标准差0.01的平方1e-4这是对的但如果你手滑填成0.01滤波器会认为量测噪声很小、量测很可信对量测赋予过大权重导致估计结果抖动严重。我在代码里封装了generate_measurements函数自动从R矩阵提取标准差来生成噪声从根本上避免了这个不匹配问题。坑四过程噪声Q矩阵过大导致稳态精度下降。我在场景B中为了加快跟踪速度把Q调大了一个量级从1e-6调到1e-5结果表明跟踪速度确实改善了但稳态下的电压幅值RMSE从0.004增加到了0.005。这说明Q的调参是在快速跟踪和稳态精度之间做权衡不能盲目贪大。实际工程中可以用自适应方法——根据残差的大小在线调整Q但我建议先用固定Q跑通整个流程再考虑优化。坑五滤波器发散后的重启机制缺失。在场景C强噪声下EKF曾经出现过一次发散估计电压幅值跑到了0.85附近之后无论量测怎样修正都回不来。我排查后发现是数值问题——协方差矩阵P在连续更新后变得接近奇异Kalman增益计算数值不稳定。解决办法前面提过用Joseph form以及在P的对角线加小正则化项。如果以后你在更复杂的系统上跑我建议再加一条逻辑当新息序列innovation的绝对值连续超过3倍标准差时触发一次滤波器重启重置P矩阵。6.3 如何验证你的状态估计代码没有bug写代码容易验证代码难。尤其是状态估计算法这种没有标准答案的仿真很容易出现“输出很漂亮但其实是错误算法”的情况。我在验证滤波器实现时用了三个步骤分享给你第一步是验证量测函数。用潮流解x_true代入measure_func应该得到与潮流计算完全一致的量测值误差在1e-8以内。这一步能验证量测函数的正确性。第二步是验证雅可比矩阵。用数值差分法比如中心差分计算H和解析推导的雅可比矩阵对比两者误差应该在1e-6量级。如果误差很大说明解析式推导有误。第三步是验证滤波器的“最优性”。在理想线性系统下把量测函数强行线性化滤波器的估计误差应该符合理论协方差。具体做法是跑一组确定性仿真噪声固定为某个特定种子然后对比实际估计误差与滤波器给出的P矩阵对角线上的平方根两者应该在统计上吻合。如果滤波器给出的不确定性远小于实际误差说明滤波器“过度自信”实现中很可能有bug。我强烈建议你在正式跑对比实验之前先花一个小时完成上述三步验证。相信我这比跑完一整套仿真后才发现结果不可信要高效得多。7. 后续扩展方向PMU量测、自适应滤波与非线性模型这套Matlab仿真平台做完之后可扩展的方向非常多。我结合自己的研究心得给你列几个最值得尝试的方向。第一个方向是在量测体系中加入PMU同步相量测量单元的相角量测。目前的量测量以电压幅值和功率为主缺少相角的直接量测。PMU可以直接提供高精度的相角量测值误差标准差约0.001弧度能够显著提高状态估计的可观测性和精度。在仿真中添加PMU量测只需两步在measure_func中加入相角量测方程θ_i本身在R矩阵中对应对角线填入很小的方差即可。你会看到PMU量测的加入立刻让滤波器收敛速度翻倍稳态精度提升20%以上。第二方向是自适应噪声协方差估计。我前面提到Q矩阵调参是个麻烦事为了解决这个问题可以用新息序列的自相关来估计实际的过程噪声协方差。思路是如果滤波器运行良好新息序列应该是不相关的如果相关性明显说明预测模型有偏差需要调大Q。实现上可以写一个在线估计器用滑窗内的新息样本方差来更新R矩阵用协方差匹配法covariance matching来更新Q矩阵。这个方向对工程落地很有价值因为在真实系统里量测噪声的统计特性并不是恒定的。第三个方向是模型复杂化。随机游走模型毕竟太简单如果你想模拟更真实的电力系统动态可以用发电机二阶摇摆方程作为状态转移模型状态向量扩展为含功角、角速度、内电势等动态变量。这会大幅增加状态维度14节点系统可能扩到50维以上而且状态方程变成更复杂的微分-代数方程组。这时候EKF的实现难度会显著增加雅可比矩阵推导变得极其繁琐而UKF的优势反而更大——你只需要把状态转移函数写出来不需要推导任何偏导。这也是我做UKF仿真后最大的感悟无迹变换真正的价值在于免去雅可比矩阵推导对模型复杂度的限制。我目前正在尝试的方向是把这套仿真平台扩展到配电网比如IEEE 33节点配电网系统。配电网的R/X比值大、三相不平衡严重非线性程度远超输电网是验证滤波器鲁棒性的天然试验场。我预期UKF在配电网动态状态估计中的优势会更加明显这个方向如果你感兴趣后面我可以再单独写一篇分享。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进