资讯动态

EKF和UKF电力系统动态状态估计的Matlab实现与对比解析

发布时间:2026/10/9 6:50:27 来源:尧图企业网站定制
最近把基于EKF扩展卡尔曼滤波和UKF无迹卡尔曼滤波的电力系统动态状态估计在Matlab上从建模到滤波循环完整实现了一遍测试系统用的IEEE 14节点跑了多组噪声和初始偏差的仿真精度、耗时、发散情况都做了对比。这两类算法在电力系统动态状态估计里属于绕不开的经典路线研究生课题、毕业设计、工程预研基本都会碰到。这篇文章就把整个实现过程拆开来讲先说明为什么动态状态估计非做不可再分别拆EKF和UKF的原理和代码最后把我在调参和debug时踩过的坑全部列出来你可以直接照着跑通自己的仿真。1. 为什么电力系统偏偏需要动态状态估计1.1 静态状态估计的天然盲区传统上大家提到电力系统状态估计第一反应都是静态加权最小二乘WLS。它在SCADA系统里用得最多目标是基于某一时刻的冗余量测解算出该断面的节点电压幅值和相角。这个思路本身没有错但它有两个隐含假设一是系统处于稳态二是量测数据比较稀疏且有延迟。在这两个假设下WLS给出的状态对监控调度是够用的。但现在的电网情况变了。新能源占比上来之后出力波动性明显增大扰动不再只是偶发的短路或切机而是频繁的小幅功率振荡、风电场出力波动、光伏云层遮挡导致的出力变化。这些动态过程意味着发电机功角、角速度、暂态电动势等变量时刻都在变化而且是强非线性变化。如果还拿静态估计去拍一个断面照片拍出来的时点滞后不说许多动态中间过程根本捕捉不到。1.2 动态状态估计要解决的到底是什么动态状态估计本质上是在做一件事把卡尔曼滤波那一套预测-校正闭环用到电力系统状态变量上。上一时刻我们有一个状态估计值通过发电机转子运动方程等动态模型可以预测当前时刻状态会变成什么样然后利用当前时刻的PMU量测做校正把预测误差修回来。这里有个关键点需要明确动态状态估计估计的不是节点电压本身而是系统的真实动态状态最常见的就是发电机转子功角δ和角速度ω。功角是系统暂态稳定分析中最核心的物理量它能直接反映发电机之间的相对摆动趋势。电压幅值相角这些量更多体现在量测方程里是观测状态的窗口。PMU同步相量测量单元的出现给动态状态估计提供了数据基础。PMU能以50Hz甚至100Hz的采样率输出带时标的电压、电流相量这意味着状态估计器可以从秒级更新进入毫秒级更新。没有这个时间分辨率动态状态估计根本跑不起来。1.3 为什么EKF和UKF是主流入门选择电力系统的动态模型是非线性的这就把线性卡尔曼滤波挡在了门外。处理非线性状态估计的算法很多但EKF和UKF占据了绝大多数研究场景原因很实际EKF通过对非线性函数做一阶泰勒展开把问题线性化之后继续沿用卡尔曼滤波框架思路直观实现代码量小计算速度快。缺点是需要显式求雅可比矩阵而且精度只有一阶截断。UKF用一组确定性采样点Sigma点直接经过非线性函数传播再统计传播后样本的均值和协方差从原理上避免了求导而且精度至少达到二阶对强非线性场景更稳。在Matlab里这两种算法的代码量其实都不大核心循环几十行就能写完。但代码能跑和仿真结果可信之间还隔着模型离散化、参数匹配、噪声设置等一系列坑下面逐一展开。2. 从发电机模型到可计算的离散状态空间2.1 发电机动态方程是滤波器的心脏做动态状态估计第一步不是写滤波算法而是先确定状态方程和量测方程。状态方程描述状态量如何随时间演化量测方程描述量测与状态之间的映射关系。在经典二阶模型下第i台发电机的状态变量取为功角δi和电角速度ωi连续时间动态方程为dδi/dt ωi - ω0 Mi * dωi/dt Pmi - Pei - Di*(ωi - ω0)其中ω0是同步转速角频率工频50Hz对应的314.159 rad/sMi2Hi是发电机惯性时间常数单位秒Di是阻尼系数Pmi是机械功率Pei是电磁功率。需要注意Pei并不是状态的简单代数函数它取决于发电机内电势、机端电压以及整个网络的潮流分布。在单机无穷大模型下Pei可以写成Eq*V/xsin(δ)这种简单形式但到了IEEE 14节点这种多机系统Pei必须通过网络方程求解通常要结合潮流计算或者事先化简出的网络导纳矩阵来算。2.2 量测方程状态如何被观测到量测方程h(x)描述的是给定一组功角、角速度状态PMU在母线上应该看到什么。以IEEE 14节点系统为例PMU一般布置在发电机出口母线附近量测通常包括母线电压幅值Vi和相角θi发电机注入母线的有功功率Pi和无功功率Qi部分关键线路的潮流值这些量测和状态之间的关系是非线性的本质上是潮流方程的反向映射由发电机内电势和功角出发通过网络方程求出各母线电压再进一步得到线路功率。所以h(x)的实现通常会复用潮流计算的函数逻辑把它封装成一个给定状态输出量测的黑盒函数。量测噪声按典型PMU精度来设就够电压幅值标准差0.001~0.002 pu相角标准差0.01~0.02 rad功率标准差0.01 pu左右。这个范围是根据PMU实际测量精度和多次仿真经验得出来的设得过大过小都会直接影响滤波器收敛性。2.3 离散化很多人跳过但最影响结果的一步动态状态估计用的是离散卡尔曼滤波框架但电力系统动态模型是连续时间微分方程所以必须做离散化。这一步在不少论文里被一句话带过实际实现时它直接影响滤波精度。最省事的做法是前向欧拉法δ(k1) δ(k) Δt*(ω(k) - ω0) ω(k1) ω(k) Δt*(Pm - Pe(k) - D*(ω(k) - ω0))/M当采样间隔Δt取0.01s对应100Hz PMU时欧拉法的离散误差通常可以接受。如果追求更高精度可以用四阶Runge-Kutta代码也不复杂。我建议至少在状态预测这一步用RK4因为EKF/UKF的性能上限很大程度取决于状态预测准不准。量测方程h(x)不涉及时间离散直接是代数计算。状态方程离散化之后还要给过程噪声建模。过程噪声w(k)代表模型误差和外部扰动协方差矩阵Q通常在仿真里设为对角阵。它的物理意义是你有多相信状态方程。Q设太大滤波器会过度信任量测估计值噪声大Q设太小滤波器跟不上真实动态出现滞后误差。3. EKF和UKF的核心逻辑拆解3.1 EKF一阶线性化的成与败EKF的思路一句话就能说清既然系统非线性那就把它在当前状态附近线性化。具体做法是求f和h的雅可比矩阵F和H然后完全套用线性卡尔曼滤波的公式。EKF的滤波循环包含五步1. 状态预测x_pred f(x_est_prev) 2. 协方差预测P_pred F*P_est_prev*F Q 3. 卡尔曼增益K P_pred*H*(H*P_pred*H R)^(-1) 4. 状态更新x_est x_pred K*(z - h(x_pred)) 5. 协方差更新P_est (I - K*H)*P_pred这里面F是状态方程对x的雅可比矩阵H是量测方程对x的雅可比矩阵。在电力系统场景下H矩阵某种意义上和你熟悉的潮流雅可比矩阵是一家人——都是功率/电压对相角的偏导数。如果你有潮流计算的灵敏度矩阵甚至可以改造复用来校验H的准确性。值得注意的是EKF的线性化有两个隐患。第一雅可比矩阵是在预测点x_pred处计算的如果预测值和真值偏差太大线性化误差会被放大第二强非线性函数的一阶泰勒展开本身就丢掉了高阶信息在系统状态剧烈变化时精度会明显下降。实现EKF时我强烈建议用数值微分代替解析求导来算雅可比矩阵。电力系统状态方程和量测方程的解析导数推导繁琐且容易错用中心差分法在代码层面做灵敏度估计足够可靠F_ij (f_i(x h_ij) - f_i(x - h_ij)) / (2*h_j)扰动步长h_j的经验取法是h_j sqrt(eps)*max(abs(x_j), 1)其中eps是Matlab的浮点精度。这个取值兼顾了数值截断误差和计算机舍入误差不容易踩到坑。3.2 UKF用Sigma点绕开所有求导UKF的核心是无迹变换Unscented Transform。它不再对非线性函数做泰勒展开而是构造一组带权重的Sigma点让这些点经过非线性函数传播后用统计方法恢复出传播后分布的均值和协方差。Sigma点生成方式有很多种最常用的是对称采样。假设状态维度是n通过参数α、β、κ构造缩放参数λλ α^2*(n κ) - n然后对协方差矩阵P做Cholesky分解生成2n1个Sigma点X(0) x_mean X(i) x_mean sqrt((nλ)*P)_i 的列i1..n X(in) x_mean - sqrt((nλ)*P)_i 的列i1..n对应权重为Wm(0) λ/(nλ) Wc(0) λ/(nλ) (1 - α^2 β) Wm(i) Wc(i) 1/(2*(nλ))这里的α控制Sigma点围绕均值的散布程度通常取1e-3到1之间κ一般取0或者3-nβ根据先验分布特性取值高斯分布下β2是最优的。UKF滤波循环就是Sigma点生成-状态传播-统计还原-量测传播-互协方差-增益更新这条链路。代码里最重要的一步是所有Sigma点都要分别经过状态方程f和量测方程h得到一组传播后的样本点然后加权求和还原均值和协方差再和EKF一样计算卡尔曼增益。3.3 EKF和UKF的差异该怎么选用一张表把关键差异收敛起来方便你做选择对比维度EKFUKF线性化方式一阶泰勒展开Sigma点无迹变换精度一阶截断至少二阶雅可比矩阵需要解析或数值不需要计算量小滤波循环两次函数求值较大2n1个点到f和h各传播一次强非线性表现可能出现线性化失效更稳定实现复杂度简单中等适用场景模型较平滑、实时性要求高扰动剧烈、追求稳定性、离线分析在我实测的IEEE 14节点场景中两者精度差距并不夸张但如果故意把初始状态偏差调大或者把量测噪声调高EKF出现发散的概率明显高于UKF。这也符合理论预期初始偏差大时预测点的线性化误差更大一阶近似容易失效。4. Matlab实现从数据构造到完整滤波循环4.1 准备IEEE 14节点算例与真值轨迹我采用的是IEEE 14节点系统包含5台发电机。在Matlab里建议配合Matpower使用它可以方便地计算出稳态潮流结果。需要强调一个容易出错的细节Matpower中bus和gen数据结构里的列索引要和发电机编号正确对应否则组装状态向量时发电机顺序错位后面全盘皆错。真值轨迹的生成可以采用稳态初值扰动激励的方式。先计算稳态潮流得到初始功角、角速度角速度稳态为ω0功角来自潮流结果然后在机械功率或负荷上施加一个短时扰动比如在1s时刻给某台发电机的机械功率阶跃上升4%用数值积分生成一段时间内的真实状态轨迹。这样得到的轨迹就是滤波器要估计的真值。量测数据由真值轨迹套用量测方程h(x)生成再叠加高斯噪声。这样的好处是给真值轨迹加噪声时我们确切知道噪声统计特性后面评估EKF和UKF精度才有依据。仿真参数我建议这样设采样间隔Δt 0.01s100Hz PMU量测频率仿真时长10s共1000个采样点状态维度n 105台发电机每台2个状态过程噪声协方差Q 1e-6 * eye(n)后续根据结果微调量测噪声协方差R按前面提到的PMU典型精度设4.2 EKF核心循环Matlab代码EKF的代码重点在两个地方数值雅可比矩阵和滤波主循环。下面是数值雅可比计算的辅助函数function J numericalJacobian(func, x, params) n length(x); J zeros(n, n); for i 1:n h sqrt(eps) * max(abs(x(i)), 1); x_plus x; x_plus(i) x(i) h; x_minus x; x_minus(i) x(i) - h; J(:, i) (func(x_plus, params) - func(x_minus, params)) / (2*h); end end注意H矩阵的数值雅可比维度是量测维度 × 状态维度和F矩阵维度不同要分别计算。EKF主循环代码如下x_est x0; P_est P0; for k 1:N % 状态预测 x_pred stateFunc(x_est, params); F numericalJacobian(stateFunc, x_est, params); P_pred F * P_est * F Q; % 量测预测 z_pred hxFunc(x_pred, params); H numericalJacobian(hxFunc, x_pred, params); % 卡尔曼更新 S H * P_pred * H R; K P_pred * H / S; x_est x_pred K * (z_meas(:, k) - z_pred); P_est (eye(n) - K * H) * P_pred; % 保存估计序列 x_est_seq(:, k) x_est; end这里stateFunc就是离散化的状态方程hxFunc是量测方程。两步都封装成输入状态向量系统参数输出结果向量的形式这样数值雅可比才能统一复用。4.3 UKF核心循环Matlab代码UKF没有求导步骤核心在Sigma点生成和权重计算。先把这两个独立函数写出来function [Xi, Wm, Wc] sigmaPoints(x, P, alpha, beta, kappa) n length(x); lambda alpha^2 * (n kappa) - n; 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) Wm(2:end); S chol((n lambda) * P, lower); Xi zeros(n, 2*n1); Xi(:, 1) x; for i 1:n Xi(:, i1) x S(:, i); Xi(:, in1) x - S(:, i); end end采样间隔、Q、R的设置和EKF保持一致方便公平对比。UKF主循环x_est x0; P_est P0; for k 1:N % 生成Sigma点 [Xi, Wm, Wc] sigmaPoints(x_est, P_est, alpha, beta, kappa); % 状态传播 Xi_pred zeros(n, 2*n1); for i 1:2*n1 Xi_pred(:, i) stateFunc(Xi(:, i), params); end x_pred Xi_pred * Wm; P_pred Q; for i 1:2*n1 d Xi_pred(:, i) - x_pred; P_pred P_pred Wc(i) * (d * d); end % 量测传播 Zi_pred zeros(m, 2*n1); for i 1:2*n1 Zi_pred(:, i) hxFunc(Xi_pred(:, i), params); end z_pred Zi_pred * Wm; % 协方差与增益 Pzz R; Pxz zeros(n, m); for i 1:2*n1 dz Zi_pred(:, i) - z_pred; dx Xi_pred(:, i) - x_pred; Pzz Pzz Wc(i) * (dz * dz); Pxz Pxz Wc(i) * (dx * dz); end K Pxz / Pzz; % 更新 x_est x_pred K * (z_meas(:, k) - z_pred); P_est P_pred - K * Pzz * K; x_est_seq(:, k) x_est; endUKF代码量比EKF大但逻辑线性化程度高里面所有传播Sigma点的循环都是并行的。在Matlab里如果状态维度比较大建议把这些循环向量化或改用parfor否则计算时间会明显拖后腿。4.4 性能评价指标怎么算只画轨迹图不够量化指标才是写论文和评估算法的核心。我建议至少统计三类指标均方根误差RMSE对每个状态变量分别统计RMSE画出随时间变化曲线直观反映滤波器的动态跟踪能力。稳态平均绝对误差MAE在扰动平息后的后半段统计反映滤波器的稳态精度。单步平均耗时用tic/toc包围滤波主循环除以总步数比较EKF和UKF的计算效率。这个数据在工程预研时很有说服力。5. 实测对比精度、速度与鲁棒性5.1 不同噪声水平下的估计精度我按前面参数跑完两组仿真后典型结果如下具体数值会因扰动场景和噪声随机种子不同而略有浮动看趋势就好场景功角RMSE度角速度RMSErad/s滤波器小噪声PMU标准精度0.420.0084EKF小噪声0.360.0072UKF大噪声噪声放大3倍1.050.0221EKF大噪声0.610.0138UKF初始偏差较大功角偏5度发散/大幅震荡—EKF初始偏差较大0.890.0172UKF在小噪声且初始值准确时EKF和UKF的性能差距不大这一点和很多文献结论一致——不要指望UKF在所有场景都碾压EKF。但把初始偏差拉大或者强扰动出现时UKF的稳定性优势就体现得很明显EKF容易在预测点附近产生过大的线性化误差导致协方差矩阵失去正定性。5.2 计算代价的取舍速度方面EKF的优势是实实在在的。由于每次循环只需算两次函数求值一次预测、一次量测外加两组数值雅可比在状态维度等于10时EKF单步耗时大约在0.5~1ms量级UKF要传播21个Sigma点每个点都要过一次状态方程和量测方程单步耗时大约在EKF的2到4倍。这个差距在离线仿真中完全不是问题但如果后面要接实时闭环或硬件在环EKF仍然是更务实的选择。研究场景里如果更关注稳定性UKF多出来的那点算力成本是值得的。5.3 一个容易被忽略的对比维度对协方差初值的敏感度不少人在仿真里把P0设成单位阵或者很小的对角阵觉得滤波器总会自己收敛。实际跑下来EKF对P0的敏感度比UKF高不少。原因是EKF线性化依赖预测点质量而预测点质量又受到协方差传播的影响。P0设得过小滤波器过于相信初值头几步修正能力被严重削弱P0设得过大增益会先大后小容易在初始段产生明显超调。UKF因为Sigma点在整个分布范围内传播对P0的病态程度相对更耐受。所以如果你只有一次调参机会我建议把P0设成比你对初值的置信度略保守一点的对角阵比如功角对应的方差取(2度)^2角速度取(0.05 rad/s)^2而不是随便给个归一化数值。6. 实操中的坑与调试经验6.1 Q和R不是随便拍脑袋写的Q和R的比例直接决定了滤波器偏向信任模型还是信任量测。我在调试中最典型的失败经历是为了追求响应速度把Q设成1e-2量级结果量测噪声直接透过滤波器估计轨迹毛刺严重反过来把Q设成1e-9滤波器对突变扰动完全没有反应跟着模型走出一条滞后轨迹。比较靠谱的调参路径是先用稳态数据估计R——把PMU量测方差算出来按实测噪声水平设R然后从较小的Q开始逐渐加大观察新息序列innovation即z - h(x_pred)的变化。如果新息均值持续偏离零说明Q太小或者模型有偏如果新息方差远大于理论值S则说明Q相对R偏小滤波器没有跟上真实动态。6.2 数值雅可比扰动步长和角度单位用数值雅可比虽然省了推导但步长选不对照样翻车。步长太大函数非线性导致偏导数失真步长太小舍入误差主导。我用的经验公式是前面提到的sqrt(eps)*max(abs(x),1)并用中心差分。另一个大坑是角度单位不统一摇摆方程里角速度用rad/s功角用rad但很多潮流计算习惯用度。如果stateFunc里混入度数雅可比计算和协方差传播的数值量级都会出现病态滤波器会莫名其妙发散。建议全程用rad只在最后画图时转成度。6.3 滤波器突发散怎么排查发散是动态状态估计仿真里最常见的焦虑来源。我的排查顺序是固定的先检查模型本身单独调stateFunc用初始状态积分几步看输出是否符合物理规律功角因扰动增大、随后回转等。检查量测方程实现给出一组已知状态手动算出量测对比hxFunc输出确认没有符号或矩阵索引错位。检查协方差对称性每经过一次P_pred或P_est计算马上检查P - P的范数是否几乎为零。数值噪声会让P失去对称正定性必要的时候加一行P (P P)/2做对称化再配合P nearestSPD(P)之类处理。看新息序列把新息画出来正常应该围绕零小幅波动如果持续偏移或爆发式跳变说明预测和量测之间存在系统性偏差。还有一个藏得很深的坑量测向量维度和量测方程内部计算不一致。比如你声明量测有12维但hxFunc里数组拼错少了一行Matlab矩阵运算大概率不会报错而是在某个循环里悄悄广播错误值滤波结果可能整体偏移。这种问题靠肉眼很难看出来我的办法是在仿真前加一个assert维度检查。6.4 量测和状态的量级差异怎么处理IEEE 14节点里电压幅值大约在1.0 pu量级功角在十几度也就是0.2~0.3 rad量级角速度只在ω0附近波动偏差通常是0.01 rad/s量级。这三个量级放在同一个状态向量和协方差矩阵里很容易出现数值问题。处理办法有两个方向一是对量测做归一化把单位量纲差异通过R矩阵的缩放吸收掉二是更推荐的方案保持物理单位但在设Q和R时严格按物理量的量级来构造对角元素。例如功角的过程噪声方差可以设在(1e-4)^2角速度在(1e-3)^2而电压幅值量测噪声在(1e-3)^2相角在(2e-2)^2。这样既不损失物理意义矩阵条件数也在可控范围。我个人在实际操作中的一个体会是动态状态估计90%的精力都在模型和噪声统计上算法本身反而是最不需要反复折腾的部分。EKF和UKF的代码量在一百五十行以内但状态方程、量测方程、初值和噪声协方差这一套组合拳需要对电力系统动态过程有足够的理解才能配合到位。如果你刚开始做这类仿真建议先在一个单机无穷大系统上把EKF跑通再扩展到IEEE 14节点直接在多机系统上起步遇到发散很难分清是模型问题还是算法问题。最后一个小技巧所有滤波结果先不要看估计轨迹先画量测残差时间序列残差正态就说明滤波器状态健康残差有明显的结构模式那滤波器的模型一定还有没榨干的问题。

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

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

免费获取报价 →
↑