FEATURED · 精选文章

Matlab中kalman函数用法详解:从教科书公式到LQG状态估计

发布时间 / 2026/9/7 11:52:48
来源 / 创域科博编辑部
栏目 / 资讯中心
Matlab中kalman函数用法详解:从教科书公式到LQG状态估计 简介一份简明实用的MATLAB Kalman滤波器函数说明文档面向利用控制系统工具箱进行状态估计与噪声抑制的工程师、科研人员和相关专业学生。内容围绕kalman函数展开从离散系统状态空间模型出发讲解稳态Kalman滤波器的设计方法、语法格式和参数含义A、B、C、Q、R、kalmf、L、P、M并给出完整可运行的MATLAB代码用于构建带噪系统、并联反馈闭环、生成高斯噪声并对比滤波前后的输出与误差。文档还延伸到误差协方差计算和时变Kalman滤波器的迭代实现帮助读者掌握实际调试与验证思路。资源包为单个PDF文档共1个文件大小约180KB内容紧凑便于查阅与打印。目前已有125人浏览/学习适合正在做控制系统课程设计、仿真实验或需要快速上手Kalman滤波器的MATLAB使用者。 如果你在Matlab里打开help文档搜索kalman大概率会有一种“这和我看过的卡尔曼滤波教程怎么对不上”的错愕感。我在做LQG控制器设计时也经历过这个阶段教科书里明明是预测、更新两个公式来回迭代但Matlab却让我先给一个sys、再给两个协方差矩阵Qn和Rn最后返回一个叫kalmf的状态空间对象。这篇博文就围绕Matlab里的kalman函数展开把它和教科书卡尔曼滤波的关系、模型构造方法、参数含义一次讲清楚最后用直流电机转速估计的实例走完整个流程。无论你是刚开始学状态估计的学生还是正在写LQG、跟踪、导航融合代码的工程师应该都能从里面找到直接能用的东西。1. kalman函数到底在解决什么问题和教科书递推公式的差异1.1 先回顾教科书里的经典卡尔曼滤波递推卡尔曼滤波最常见的教学形式是离散系统的五条公式。假设系统写成x[k1] A x[k] B u[k] w[k] y[k] C x[k] v[k]其中w是过程噪声v是测量噪声它们的协方差分别为Q和R。从初始估计出发每个时刻要做两件事预测 x_pred A * x_hat(k-1) B * u(k-1) P_pred A * P(k-1) * A Q 更新 K P_pred * C * inv(C * P_pred * C R) x_hat(k) x_pred K * (y(k) - C * x_pred) P(k) (I - K * C) * P_pred这组公式你可以在任何一本现代控制理论教材里找到。它描述的是一个递推过程先根据系统模型预测状态和误差协方差再用最新测量值修正预测。滤波增益K不是固定的它在每个时刻都会随P的变化而更新。但不知道你有没有注意到一个细节如果系统是线性时不变的噪声统计特性也不随时间变化那么经过一段足够长的时间后P_pred和P会逐渐收敛到常量K也会收敛到一个固定值。这就是所谓的稳态卡尔曼滤波。1.2 控制工具箱里要的是稳态估计器不是滤波循环Matlab的kalman函数来自Control System Toolbox它的定位就是设计稳态估计器准确说叫线性二次估计器LQE是LQG控制设计的一环。它的设计目标不是帮你在每个采样周期里跑一遍预测-更新循环而是直接求解代数黎卡提方程算出稳态误差协方差P和稳态滤波增益L再把整个估计器动态封装成一个状态空间模型kalmf。也就是说你调用[kalmf, L, P] kalman(sys, Qn, Rn);拿到的kalmf不是一个函数句柄而是一个状态空间模型对象。它内部已经包含了这么一段动态dx_hat/dt A * x_hat B * u L * (y - C * x_hat - D * u)这不是什么“另一种卡尔曼滤波”它就是卡尔曼滤波的稳态形式。用教科书公式迭代很多步之后最终会收敛到和这个估计器完全一致的行为。这就解释了为什么第一次用kalman函数的人总觉得它别扭你习惯了把卡尔曼滤波当作一段“算法”去执行但Matlab把它当成一个“对象”去设计和装配。比如在Simulink里做LQG闭环时kalman函数生成的kalmf可以直接和lqr设计出的控制器K拼成一个完整的LQG控制器这种“模型对模型”的接口比手写递推循环方便得多。2. 用kalman函数之前先把噪声写进状态空间模型2.1 为什么sys必须包含噪声输入通道很多人的报错都出在这一步。kalman函数设计估计器时必须知道过程噪声从哪个通道进入系统、测量噪声又长什么样。你光给它一个ss(A, B, C, D)模型是不行的因为在这个模型里只有确定性输入u根本没有w的位置。正确的做法是把过程噪声w当作系统的一个额外输入通道和u一起拼进输入矩阵B里。比如一个连续时间系统dx/dt A x B u Bw * w y C x D u Dw * w v对应的状态空间模型应该写成sys ss(A, [B, Bw], C, [D, Dw]);其中sys的输入向量是[u; w]前几列是确定性控制输入最后一列或几列是随机噪声输入。kalman函数默认把sys输入中最后面的通道当作过程噪声w所以构造模型时一定要把噪声通道放在最后。这里有一个很多人会忽略的小点Dw矩阵。如果噪声w会直接串到测量输出y上Dw这列就不能填0。比如过程噪声通过某种物理耦合直接影响了传感器读数那么D矩阵对应的那一列必须填实际的耦合系数。如果w只影响状态更新、不影响输出那Dw填0即可。2.2 连续与离散模型的构造细节连续时间系统的构造刚才已经说了关键在于把B矩阵扩展成[B, Bw]。离散时间系统的道理完全一样只是矩阵名称看起来不同sysd ss(Ad, [Bd, Bwd], Cd, [Dd, Dwd], Ts);这里Ts是采样周期。如果你要从连续模型得到离散模型可以用c2d做离散化它会同步返回离散后的Ad、Bd、Cd、Dd。有一个工程上的坑我必须提醒你离散化时过程噪声协方差Q也会发生变化。连续系统里的Q代表噪声强度离散化后通常要乘以采样周期或做更精确的矩阵指数积分不能直接把连续Q原封不动塞给离散kalman函数。很多人在c2d离散化之后发现滤波器行为异常多半是这个原因。具体做法上如果连续系统是sys ss(A, [B Bw], C, [D Dw])在Matlab中直接sysd c2d(sys, Ts);然后调用kalman时Qn和Rn要换成离散域对应的数值。实际项目中如果噪声统计特性不明确通常的做法是先做一个粗略估算然后在仿真里微调这个调参经验后面专门讲。2.3 忽略噪声通道时会发生什么最常见的报错是矩阵维度不匹配比如Error using kalman (line 32) The plant model has no random inputs.或者类似“Q matrix must have dimension Nw-by-Nw”的提示。前者说明sys输入里没有噪声通道后者说明Qn的维度和Bw的列数对不上。遇到这种错误第一反应不要急着改Qn或Rn的维度先检查sys是不是把w写进去了。我见过不少朋友把[B, Bw]写错成[B; Bw]导致模型输入数量翻倍而不是增加一列这种低级错误只要看一眼size就能发现。3. 语法拆解kalmf、L、P和离散版本中的M、Z都是什么3.1 基本调用形式与参数含义kalman函数最常见的用法是[kalmf, L, P] kalman(sys, Qn, Rn);四个输入的用途分别是sys包含了确定性输入和随机噪声输入的状态空间模型就是前面构造的带噪声系统。Qn过程噪声w的协方差矩阵。注意它是w的协方差维度等于w的数量不是状态数量。如果只有一个噪声源Qn就是一个标量。Rn测量噪声v的协方差矩阵维度等于测量输出y的数量。单输出系统里Rn也是标量。可选参数Nn过程噪声和测量噪声的互协方差矩阵。如果两者不相关这个参数可以不传默认是0。三个输出参数的含义也要说清楚kalmf状态空间估计器模型。在Simulink里做LQG闭环时它就是你在框图中拖出来用的那个滤波器模块输入端对应u和y输出端对应状态估计x_hat和输出估计y_hat。L稳态卡尔曼滤波增益。它的物理意义是估计器动态方程里的矫正增益也就是估计状态受测量残差影响的强度。你完全可以拿它手写一个连续的估计器方程dx_hat/dt A*x_hat B*u L*(y - C*x_hat - D*u)。P稳态状态估计误差协方差矩阵就是黎卡提方程的解。它告诉你估计值可信程度对角线元素就是各状态估计方差。这里有一个容易混淆的点教科书里通常把滤波增益叫KMatlab里用L两者是一个东西。P在教科书里是随时间更新的估计误差协方差Matlab返回的是收敛后的稳态值。3.2 离散系统里的额外输出M和Z如果sys是离散时间模型调用形式变成[kalmf, L, P, M, Z] kalman(sysd, Qn, Rn, Nn);多出来的两个输出是M最优预测器增益对应状态的一步预测x[k1|k]场景下的增益。Z预测器对应的误差协方差矩阵。换句话说离散系统里会同时存在两个视角一个是滤波器filter估计的是当前时刻x[k|k]另一个是预测器predictor估计的是下一时刻x[k1|k]。滤波器的增益L和协方差P我们上面已经说了预测器的增益M和协方差Z就是额外的这两个输出。实际上你在Matlab里跑连续系统调用返回的也是L和P跑离散系统才能拿到M和Z。这算是kalman函数和教科书离散递推公式衔接得最微妙的地方教科书里每个采样周期都要算一次K和P而kalman函数直接帮你解出稳态的对应值还包括了预测器的版本。3.3 版本差异和端口顺序问题不同Matlab版本对kalmf端口顺序的定义有过调整尤其老的R2007b之前版本和现在的新版本不完全一致。我建议你在自己机器上执行一次help kalman看一眼当前版本支持哪些语法再在模型建好之后用size(kalmf)检查一下输入输出个数。这个习惯能帮你省掉很多不必要的排查时间。4. 一个完整示例对直流电机转速做卡尔曼估计4.1 建模一阶惯性系统加噪声假设有一个直流电机转速动态可以简化为一阶惯性模型dx/dt -10 x 2 V w y x vx是电机转速V是控制电压w是过程噪声v是测量噪声。取Qn0.5Rn0.2这个模型虽然简单但足够看清kalman函数从设计到仿真的完整链路。建模代码a 10; b 2; bw 1; A -a; B [b, bw]; % 第1列是控制输入V第2列是过程噪声w C 1; D [0, 0]; % w不直接串到输出 sys_plant ss(A, B, C, D);这里sys_plant有两个输入第一个是控制电压第二个是噪声w。kalman函数会默认把最后一个输入通道当作随机噪声输入所以一切都对得上。4.2 设计估计器并仿真接下来调用kalman函数并把真实系统初值设为1让估计器从0开始去追这样收敛过程会看得非常清楚Qn 0.5; Rn 0.2; [kalmf, L, P] kalman(sys_plant, Qn, Rn); t 0:0.01:10; u 2 * ones(size(t)); w sqrt(Qn) * randn(size(t)); v sqrt(Rn) * randn(size(t)); [~, ~, x] lsim(sys_plant, [u; w], t, 1); y C * x v;然后拿kalman返回的L手动实现连续估计器。这里明明有kalmf对象可以直接用但我故意写成显式循环目的是让你看清L到底用在什么地方x_hat zeros(size(t)); x_hat(1) 0; for i 2:numel(t) dt t(i) - t(i-1); x_hat(i) x_hat(i-1) dt * (A*x_hat(i-1) b*u(i-1) ... L * (y(i-1) - C*x_hat(i-1) - D(1)*u(i-1))); end plot(t, x, LineWidth, 1.5); hold on; plot(t, y, --); plot(t, x_hat, LineWidth, 1.5); legend(真实状态x, 含噪测量y, 卡尔曼估计x\_hat); xlabel(时间/s); ylabel(转速); grid on;4.3 运行结果里能看到什么运行这段代码后L大约是0.124P大约是0.025。看曲线图会有几个直观印象含噪测量y的曲线上下抖动很剧烈单看任何一个时刻的测量值都很难判断真实转速。x_hat的曲线明显平滑很多说明卡尔曼滤波器确实把测量噪声压下来了。初始阶段x_hat从0往1收敛这个收敛速度由L决定。L越大收敛越快但对噪声越敏感L越小输出越平滑但响应越迟钝。这个例子里的Qn和Rn选得相对合理所以估计器看起来很正常。实际工程里Qn和Rn往往不知道准确值这时就需要按照下一章的经验去调试。5. 手写递推和kalman函数的选择以及协方差调试经验5.1 稳态滤波适合哪些场景时变滤波又适合哪些场景kalman函数的本质是求稳态解这意味着它最适合系统线性时不变、噪声平稳、模型参数固定的场景。尤其是LQG控制设计kalman函数和lqr、lqgreg配合是最标准的做法你不需要自己写递推循环直接生成kalmf对象搭闭环即可。但如果你处理的是时变系统比如模型参数在处理过程中会变化或者你希望滤波增益K每个时刻都随协方差动态更新那就应该自己写教科书里的递推循环。此外如果你需要在每个采样周期里读取估计协方差P(k)作为输出递推形式也更直接。我个人的经验是能用kalman函数的就别自己写循环。一方面Matlab内置实现经过优化数值稳定性有保障另一方面LQG设计里它和lqr调用天然配套能少写不少代码。只有当任务明确需要时变增益时才考虑手写递推。5.2 协方差Qn和Rn怎么调最关键的两个经验调Qn和Rn是卡尔曼滤波实际工程应用中最耗时间的环节。我最深的两个体会第一Rn可以实测。把传感器放在静止场景中采集一段数据计算方差就直接得到Rn。这个方法在电机转速测量、GPS定位、温度测量上都非常有效。如果测量噪声相关还要考虑协方差矩阵但通常对角线方差够用了。第二Qn很难直接测量但从物理量级入手比盲调快得多。Qn描述的是你对系统模型的信任程度。Qn开很大意味着你觉得模型不可靠更信任测量值滤波曲线会变毛糙、噪声抑制变弱Qn开很小意味着你觉得模型很准确更信任预测值滤波曲线会变得很平滑但动态响应会明显滞后。实际调的时候先把Qn和Rn设成同一数量级跑一遍仿真再根据估计曲线是过“毛”还是过“钝”来调整比例。5.3 滤波发散时怎么排查如果估计值直接飞掉或者明显不合理按下面顺序排查检查sys的噪声通道是否构造正确w是不是放在了输入序列最后。检查Qn和Rn维度是否和w、y的维度匹配。检查系统是否可观。如果某个状态在输出里完全不可观测卡尔曼滤波对该状态的估计没有意义增益和协方差也可能表现异常。可以用rank(obsv(sys_plant))快速检查。检查Qn和Rn的数量级是否差异过大比如一个1e-8、一个1e8这种情况数值上很容易出问题。5.4 别把kalman函数和其他工具箱的卡尔曼API混用Matlab里叫“卡尔曼”的可不止kalman函数一个。vision.KalmanFilter是计算机视觉工具箱里做目标跟踪的dsp.KalmanFilter是DSP系统工具箱里做信号滤波的trackingKF、trackingUKF、trackingEKF是传感器融合与跟踪工具箱里的自适应滤波对象用于多目标跟踪insfilter系列则是惯性导航和GNSS融合的专用滤波器。它们都基于卡尔曼思想但接口和使用方式完全不一样。如果你搜kalman函数是想做图像里的目标框跟踪或者做惯性导航融合用kalman(sys, Qn, Rn)大概率不是最顺手的方案。先想清楚自己的应用场景再选对应工具箱。反过来如果你就是在做LQG控制或者线性系统状态估计那么kalman函数是首选。另外提醒一句如果你在系统辨识与自适应控制仿真里用卡尔曼滤波做参数在线估计那通常需要的是recursiveLS、recursiveAR这类递推辨识函数而不是kalman。这一点容易被忽略我一开始就走偏过一次。卡尔曼滤波的用法其实不难难点在于搞清楚自己手里函数到底是“算法”还是“设计工具”。kalman函数是后者它替你完成了稳态滤波器设计中最复杂的求解过程。只要建模时把噪声通道写对再花点心思把Qn、Rn调到合理范围剩下的工作基本就是仿真验证。看完这篇之后建议你把自己项目的系统模型代入跑一遍有报错就先用help kalman对照一下当前版本的语法很多问题其实一两分钟就能定位。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻