kalman滤波器C++设计仿真案例

news2025/1/25 20:43:13

        很多同学看了我之前的文章,都对kalman滤波器的原理有了理解,但我发现,在具体工程设计过程中,还是很多人都感觉到无从下手,一些参数也不知道如何选取。

        这样吧。我这里举一些简单的例子,并用C++来一步一步的进行设计。然后,咱们一起看看最后实现的效果到底如何好吧。

案例1:室内温度测量

        要求用kalman滤波器对一个房间的温度进行测量估计。这个房间的温度大概是25℃,而由于空气流动、光照等影响,室内温度会有小幅的随机波动。这个波动的方差嘛,就暂定为0.01好了。然后我们 用温度计每分钟进行一次测量,温度计的测量误差大概是0.5℃,也就是方差为0.25。

        这是一个非常简单的案例,过程中所有的矩阵都是一维,也就是标量。

        先定义状态量X(k),就是房间温度。房间温度有波动,所以会有系统噪声W(k)。根据题意,W(k)的协方差矩阵Q就等于0.01。于是状态方程就是:

X(k)=X(k-1)+W(k-1)

Q(k)=0.01

再看量测方程。由于是直接测量,所以H阵等于1,而量测方差阵R根据题意,就等于0.25了。

Z(k)=X(k)+V(k)

R(k)=0.25

        由于涉及矩阵计算,所以这里用到了我自己用C++开发的矩阵类。需要的可以到我的空间,或者下面这个链接去下载:

https://download.csdn.net/download/weixin_38898944/90305952

        开始C++程序设计了啊。嗯,注意是C++11,否则我的有些写法可能会报错。

        先设计一个kalman滤波器的类。为了代码复用程度高,我把之前文章里的提到的基本型kalman滤波器拆分成两个类。一个是模型Model类,一个是kalman类。这样如果换一个需求场景,只要更改模型类就好了,kalman类不用变。先看kalman类。头文件内容:

#ifndef KALMAN_H
#define KALMAN_H

#include "matrix.h"
#include "model.h"
class Kalman
{
    size_t m_ns;    //状态维数
    size_t m_nm;    //量测维数

    Matrix Xkf;     //状态估计值
    Matrix Xpre;    //状态预测值
    Matrix Z;       //量测
    Matrix K;       //增益
    Matrix P;       //状态估计的协方差阵
    Matrix Ppre;    //状态预测的协方差阵

    Model *mp;      //模型,包含了状态方程、量测方程等
    Kalman();       //默认构造函数,私有化,不能调用
public:
    Kalman(size_t ns, size_t nm);           //构造函数,需要确定状态维数和量测维数
    void Init(const Matrix &X0, const Matrix &P0, Model *mp0);//初始化,初始化X0和P0,并与模型对象挂钩
    void SetMeasur(const Matrix &Zk);       //量测量进入滤波器
    void Iterator();                        //滤波器更新过程
    Matrix GetX() {return Xkf;}             //获取当前状态估计
};

#endif // KALMAN_H

源文件:

#include "kalman.h"

Kalman::Kalman()
{

}

Kalman::Kalman(size_t ns, size_t nm)
{
    m_ns = ns;
    m_nm = nm;
    K = Matrix(ns, nm);
    Xkf = Matrix(ns);
    P = Matrix(ns, ns);
    Ppre = Matrix(ns, ns);
    Z = Matrix(nm);
    Xpre = Matrix(ns);
}

void Kalman::Init(const Matrix &X0, const Matrix &P0, Model *mp0)
{
    Xkf = X0;
    P = P0;
    mp = mp0;
}

void Kalman::SetMeasur(const Matrix &Zk)
{
    Z = Zk;
}

void Kalman::Iterator()
{
    static Matrix I(Matrix::unit(m_ns));
    Matrix F(mp->GetF());
    Matrix H(mp->GetH());
    Matrix Q(mp->GetQ());
    Matrix R(mp->GetR());
    Xpre = mp->StateTrans(Xkf);
    Ppre = F*P*F.Trans() + Q;
    K = Ppre*H.Trans()*((H*Ppre*H.Trans() + R).Inv());
    Xkf = Xpre + K*(Z - H*Xpre);
    P = (I - K*H)*Ppre;
}

        这几个成员函数都非常直观,尤其注意那个Iterator()函数,滤波器运行需要的转移矩阵F,量测矩阵H以及状态协方差阵 Q和量测方差阵R都是从模型里获取的。所以模型变了该模型就好了,不需要改这个滤波器。一步预测那里并没有写成Xpre=H*X,而是让模型对象去更新,这样写是为了适应以后扩展成非线性kalman滤波器,也就是ekf的时候方便一些。

        下面就来设计模型类。头文件:

#ifndef MODEL_H
#define MODEL_H

#include "matrix.h"
class Model
{
    Matrix Q;
    Matrix R;
public:
    Model(): Q(Matrix::unit(1)*0.01), R(Matrix::unit(1)*0.25){}
    Matrix StateTrans(Matrix &X);         //状态转移,这里就是Xpre=H*Xkf
    void StateUpdate(Matrix &X);          //状态转移后还加入噪声,这里就是X=H*X+w
    Matrix MeasurPre(const Matrix &X);    //量测预测,没有加入量测噪声
    Matrix Measur(const Matrix &X);       //量测,加入量测噪声

    Matrix GetF();                        //获取状态转移矩阵,如果是ekf,可以改写这个函数,
                                          //获取状态方程的雅各比矩阵

    Matrix GetH();                        //获取量测矩阵,如果是ekf,改写这个函数,
                                          //获取量测方程的雅各比矩阵

    Matrix GetQ() {return Q;}                //获取模型的状态方程协方差阵
    Matrix GetR() {return R;}                //获取模型的量测方程的协方差阵
};


#endif // MODEL_H

        Q和R都是一维矩阵,且值分别是0.01和0.25。然后是源文件:

#include "model.h"


Matrix Model::StateTrans(Matrix &X)
{
    Matrix F(Matrix::ones(1, 1));
    return F*X;
}

void Model::StateUpdate(Matrix &X)
{
    X = StateTrans(X);
    X = X + Sqrtm(Q)*Matrix::randn(1, 1);
}

Matrix Model::MeasurPre(const Matrix &X)
{
    Matrix H(Matrix::ones(1, 1));
    return  H*X;
}

Matrix Model::Measur(const Matrix &X)
{
    return MeasurPre(X) + Sqrtm(R)*Matrix::randn(1, 1);
}

Matrix Model::GetF()
{
    return Matrix::ones(1, 1);
}

Matrix Model::GetH()
{
    return Matrix::ones(1, 1);
}

        我的矩阵类里已经实现了矩阵的各类运算,包括矩阵加减乘,矩阵与标量的加减乘以及矩阵转置、矩阵求逆、矩阵元素开根号。并能够生成全零矩阵、全1矩阵、单位矩阵、(0,1)正态分布的随机矩阵等。所以以上代码看上去还是很好理解的。

        有了这两个类,主程序就非常简单了:

#include "model.h"
#include "kalman.h"
#include <stdio.h>
int main()
{
    FILE *fp;
    fp = fopen("F:/data/data.txt", "w");
    Model M;
    Kalman kf(1, 1);
    Matrix X(Matrix::ones(1, 1)*25.0);
    Matrix Z(1);

    Matrix P0(Matrix::ones(1, 1)*0.01);
    kf.Init(X, P0, &M);
    for(size_t i = 0; i < 100; i++)
    {
        M.StateUpdate(X);
        Z = M.Measur(X);
        kf.SetMeasur(Z);
        kf.Iterator();
        fprintf(fp, "%lf,%lf,%lf\n", X(0), kf.GetX()(0), Z(0));
    }
    fclose(fp);
    return 0;
}

        初值就设定为25℃,P的初值也取的跟Q一样。用kf.Init()函数初始化,并与模型对象挂钩。

        主程序在运行kalman的同时也对室内温度实际值进行了仿真,并将温度实际值(X),kalman滤波值(kf.GetX()),和量测值(Z)保存到文件里。

        来看看效果吧

        蓝线为实际温度,绿线为测量值,红线为滤波输出。喏,看出效果了吧。

        先这样吧。最近有些忙,回头我再写一个状态变化情况的kalman滤波仿真。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2281569.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2025.1.21——六、BUU XSS COURSE 1 XSS漏洞|XSS平台搭建

题目来源&#xff1a;buuctf BUU XSS COURSE 1 目录 一、打开靶机&#xff0c;整理信息 二、解题思路 step 1&#xff1a;输入框尝试一下 step 2&#xff1a;开始xss注入 step 3&#xff1a;搭建平台 step 4&#xff1a;利用管理员cookie访问地址 三、小结 二编&#…

微信小程序使用上拉加载onReachBottom。页面拖不动。一直无法触发上拉的事件。

1&#xff0c;可能是原因是你使用了scroll-view的标签&#xff0c;用onReachBottom触发加载事件。这两个是有冲突的。没办法一起使用。如果页面的样式是滚动的是无法去触发页面的onReachBottom的函数的。因此&#xff0c;你使用overflow:auto.来使用页面的某些元素滚动&#xf…

Linux-arm(1)ATF启动流程

Linux-arm(1)ATF启动流量 Author&#xff1a;Once Day Date&#xff1a;2025年1月22日 漫漫长路有人对你微笑过嘛… 全系列文章可查看专栏: Linux实践记录_Once_day的博客-CSDN博客 参考文档&#xff1a; ARM Trusted Firmware分析——启动、PSCI、OP-TEE接口 Arnold Lu 博…

docker 部署 java 项目详解

在平常的开发工作中&#xff0c;我们经常需要部署项目&#xff0c;开发测试完成后&#xff0c;最关键的一步就是部署。今天我们以若依项目为例&#xff0c;总结下部署项目的整体流程。简单来说&#xff0c;第一步&#xff1a;安装项目所需的中间件&#xff1b;第二步&#xff1…

ARM64平台Flutter环境搭建

ARM64平台Flutter环境搭建 Flutter简介问题背景搭建步骤1. 安装ARM64 Android Studio2. 安装Oracle的JDK3. 安装 Dart和 Flutter 开发插件4. 安装 Android SDK5. 安装 Flutter SDK6. 同意 Android 条款7. 运行 Flutter 示例项目8. 修正 aapt2 报错9. 修正 CMake 报错10. 修正 N…

MySQL5.7安装超详细步骤(图文教程)

一.下载MySQL 1.在浏览器搜索MySQL&#xff0c;进入MySQL官网&#xff0c;点击下载&#xff0c;选下面的社区版本。 官网地址&#xff1a;MySQL :: Download MySQL Installer (Archived Versions) 二.安装MySQL 1.双击下载好的文件&#xff0c;选择自定义安装&#xff0c;然…

Tomcat下载配置

目录 Win下载安装 Mac下载安装配置 Win 下载 直接从官网下载https://tomcat.apache.org/download-10.cgi 在圈住的位置点击下载自己想要的版本 根据自己电脑下载64位或32位zip版本 安装 Tomcat是绿色版,直接解压到自己想放的位置即可 Mac 下载 官网 https://tomcat.ap…

语音转文字的先驱-认识Buzz的前世今生

Buzz 是一款基于 OpenAI Whisper 模型开发的开源语音转文字工具&#xff0c;其历史可以追溯到 Whisper 模型的推出&#xff0c;并在之后逐渐发展为一个功能强大且广泛使用的工具。以下是关于 Buzz 的详细历史介绍&#xff1a; 1. Whisper 模型的背景 Buzz 的核心是 OpenAI 开…

WPF5-x名称空间

1. x名称空间2. x名称空间内容3. x名称空间内容分类 3.1. x:Name3.2. x:Key3.3. x:Class3.4. x:TypeArguments 4. 总结 1. x名称空间 “x名称空间”的x是映射XAML名称空间时给它取的名字&#xff08;取XAML的首字母&#xff09;&#xff0c;里面的成员&#xff08;如x:Class、…

JavaWeb开发学习笔记——MySQL

跟着黑马程序员学习MySQLDay06-04. MySQL-DDL-数据库操作_哔哩哔哩_bilibili 注意&#xff0c;以下笔记中[ ]中都是可省略内容&#xff0c;如果不省略&#xff0c;那么直接写即可&#xff0c;不带[ ] MySQL-DDL 数据库操作 连接MySQL服务器&#xff1a;mysql -uroot -p密码…

CSS实现实现票据效果 mask与切图方式

一、“切图”的局限性 传统的“切图”简单暴力,但往往缺少适应性。 适应性一般有两种,一是尺寸自适应,二是颜色可以自定义。 举个例子,有这样一个优惠券样式 关于这类样式实现技巧,之前在这篇文章中有详细介绍: CSS 实现优惠券的技巧 不过这里略微不一样的地方是,两个…

【二叉树的深搜】二叉树剪枝

文章目录 814. 二叉树剪枝解题思路&#xff1a;深度优先遍历 后序遍历另一种写法 814. 二叉树剪枝 814. 二叉树剪枝 ​ 给你二叉树的根结点 root &#xff0c;此外树的每个结点的值要么是 0 &#xff0c;要么是 1 。 ​ 返回移除了所有不包含 1 的子树的原二叉树。 ​ 节点…

Codeforces Round 1000 (Div. 2) A-C

链接&#xff1a;Codeforces Round 1000 (Div. 2) A:Minimal Coprime 大意&#xff1a; 给定一个区间&#xff0c;定义最小互质区间是边界互质&#xff0c;边界内无互质区间。求这个区间最小互质区间个数 思路&#xff1a; gcd(l, l 1) gcd(1, l) 1,即相邻数组成的区间互…

基于Redis实现短信验证码登录

目录 1 基于Session实现短信验证码登录 2 配置登录拦截器 3 配置完拦截器还需将自定义拦截器添加到SpringMVC的拦截器列表中 才能生效 4 Session集群共享问题 5 基于Redis实现短信验证码登录 6 Hash 结构与 String 结构类型的比较 7 Redis替代Session需要考虑的问题 8 …

校验收货地址是否超出配送范围实战3(day09)

优化用户下单功能&#xff0c;加入校验逻辑&#xff0c;如果用户的收货地址距离商家门店超出配送范围&#xff08;配送范围为5公里内&#xff09;&#xff0c;则下单失败。 提示&#xff1a; ​ 1. 基于百度地图开放平台实现&#xff08;https://lbsyun.baidu.com/&#xff09…

Vue2.0+ElementUI实现查询条件展开和收起功能组件

一、需求 el-form如果查询条件过多&#xff0c;影响页面的展示效果。查询条件表单是我们系统中非常常见的功能&#xff0c;我们需要把它封装成一个通用的组件&#xff0c;方便在系统开发中提升开发效率。除了在实现基本查询条件的功能上&#xff0c;还需要实现多条件的折叠和展…

UE求职Demo开发日志#8 强化前置条件完善,给物品加图标

1 强化前置条件完善 StrengthManager里实现一个Check前置的函数 bool CheckPreAllIsActive(int index)&#xff0c;所有的前置都已经激活就返回true&#xff0c;否则返回false 之后在强化的时候加入条件检查&#xff1a; 1.所有前置技能全部激活 2.本身没有强化过 最后测…

pinctrl子系统

目录 一、PinCtrl子系统的定义 二、明确PinCtrl子系统和我们编写驱动的关系 三、pinctrl_desc结构体引入 四、PinCtrl子系统驱动实现分析 1.芯片厂家是如何实现PinCtrl子系统的 2.linux在什么位置设置的引脚复用和电气属性 2.1 really_probe的主要功能 2.2 really_prob…

行政纠错——pycorrector学习

pycorrector是一个开源中文文本纠错工具&#xff0c;它支持对中文文本进行音似、形似和语法错误的纠正。此工具是使用Python3进行开发的&#xff0c;并整合了Kenlm、ConvSeq2Seq、BERT、MacBERT、ELECTRA、ERNIE、Transformer等多种模型来实现文本纠错功能。pycorrector官方仓库…

深入MapReduce——计算模型设计

引入 通过引入篇&#xff0c;我们可以总结&#xff0c;MapReduce针对海量数据计算核心痛点的解法如下&#xff1a; 统一编程模型&#xff0c;降低用户使用门槛分而治之&#xff0c;利用了并行处理提高计算效率移动计算&#xff0c;减少硬件瓶颈的限制 优秀的设计&#xff0c…