zoukankan      html  css  js  c++  java
  • 卡尔曼滤波

          卡尔曼滤波的基本思想是,给定一个假设的合理期望值后,结合系统历史的测量情况下,为系统建立当前的测量模型,是一个概率最大化预测。结合历史测量数据并不是保留了漫长的历史数据后给出的结果,而是在系统迭代更新只保留最近的估计模型供下一次迭代使用,但是最近的估计模型都是跟前面的数据有一定的关系,是前面数据的不断迭代实现的预测结果。单就看当时的结果的话,只与上一次模型的预测结果有关,这样的思想简化了计算机的计算能力。卡尔曼滤波的核心是信息融合,包括系统受到的干扰及测量传感器的噪声。根据这些信号预测当前的状态模型,说白了就是一个估计器,下面是它的原理:

          对于离散线性时不变系统:${{ m{vec x}}_k} = F{{ m{vec x}}_{k - 1}} + B{vec u_k} + {vec w_k}$(基于先前的数据进行预测) ${{ m{vec z}}_k} = H{vec x_k} + {vec v_k}$(调整最新的测量)。其中 ${{ m{vec x}}_k}$为系统在k时刻输入的n维矢量,使系统接受外部控制F为n $ imes $n转移矩阵,建立上一个状态控制量和当前状态的关系,表示系统的动态特性,B为n$ imes $c是系统输入与系统状态之间的耦合关系,${vec w_k}$代表随机事件的干扰噪声,是一个高斯随机变量分布,体现模型(F,B)中的误差及未被考虑的干扰成份, ${{ m{vec w}}_k} sim N(0,V)$零均值高斯分布,V为协方差矩阵,${vec u_k}$为系统k时刻新的输入值(给定量)。 ${{ m{vec z}}_k}$为传感器测得的系统输出,H为传感器的测量模型,在传感器测量时也可能存在误差,因此用 ${vec v_k}$表示引入的不确定误差, ${vec v_k} sim N(0,{ m{W}})$W同为测量值的误差协方差矩阵。

          因此卡尔曼滤波器的应用应该满足系统在时间k处的状态可以表示为向量,且在时间变化中任然保持着向量中的变量;噪声是随机的,在时间上不相关,可以被平均协方差精确建模。只看公式可能一头雾水,接下来,引用OpenCV的一个例子将一个小的应用示例引入进去再对照着公式想一下,假设有一个车围绕着圆的跑道匀速移动,但由于司机对油门的控制不是很理想(即存在过程噪声),我们用视觉跟踪的方式来确定汽车位置,但是由于视觉的硬件、畸变、光照及分辨率不是很理想等造成误差(即测量噪声)。模型如下:汽车在时间k处有一个位置和一个速度,且在后面的时间K+i中任然会有一个位置量和速度量,构成${{ m{vec x}}_k}$,假设$ {{ m{vec x}}_k}{ m{ = }}left[ {egin{array}{*{20}{c}}
    { m{s}}\
    omega
    end{array}} ight]$s为位置=0.2, $omega $为角速度为0.3,(在下面程序中用0.0-0.1之间的随机数表示,此处先忽略这句话)由于司机对油门的控制不是很理想产生的噪声 ${{ m{vec w}}_k} = left[ {egin{array}{*{20}{c}}
    {{delta _1}}\
    {{delta _2}}
    end{array}} ight]{delta _1},{delta _2}$为过程噪声,状态转移矩阵 $F = left[ {egin{array}{*{20}{c}}
    1&{dt}\
    0&1
    end{array}} ight]$, $F*{{ m{vec x}}_k} = left[ {egin{array}{*{20}{c}}
    {s + dt*omega }\
    omega
    end{array}} ight]$假设dt=1,则表示汽车的角速度不变,位置随着时间增加,此例中我们先不引入给定量,(如果要给定量则表示期望到达的位置和角速度,而不是油门的大小), ${{ m{vec z}}_k}$为视觉测量矩阵,这个简单例子中只测量位置,为1 $ imes $1,即一个矢量,H为测量模型为1$ imes $2为[1,0],在示例中由程序产生, ${vec v_k}$为视觉产生的随机误差为 1$ imes $1,在下面例程中由程序产生。

          在例程效果中看到小红圈(小车当前实际位置)围绕着圆形轨道运动,黄色的圆圈在红色周围跳来跳去(代表着我们进行的测量),白色的圈收敛到红圈周围,代表我们最后通过卡尔曼滤波后预测的位置。如图所示:new

    #include<opencv2/opencv.hpp>
    #include<iostream>

    using namespace std;
    using namespace cv;

    #define phi2xy(mat)
    Point(cvRound(img.cols/2+img.cols/3*cos(mat.at<float>(0))),
    cvRound(img.rows / 2 - img.cols / 3 * sin(mat.at<float>(0))))

    int main(int argc, char** argv)
    {
         Mat img(500,500,CV_8UC3);
         KalmanFilter kalman(2,1,0);
         //代表输入的位置、角速度2*1二维矢量
         Mat x_k(2,1,CV_32F);
         randn(x_k,0.0,0.1);
         //司机对油门的控制不是很理想造成的干扰2*1二维矢量
         Mat w_k(2, 1, CV_32F);
         //视觉系统测量的位置,1维矢量
         Mat z_k = Mat::zeros(1,1,CV_32F);
         //状态转移矩阵2*2,dt=1
         float F[] = { 1,1,0,1 };
         kalman.transitionMatrix = Mat(2,2,CV_32F,F).clone();
         //状态转移矩阵
         setIdentity(kalman.transitionMatrix,Scalar(1));
         //过程噪声
         setIdentity(kalman.processNoiseCov, Scalar(1e-5));
         //测量噪声
         setIdentity(kalman.measurementNoiseCov, Scalar(1e-1));
         setIdentity(kalman.errorCovPost, Scalar(1));
         //初始状态赋值
         randn(kalman.statePost,0.0,0.1);
         namedWindow("result", WINDOW_AUTOSIZE);
         //循环预测
         for (;;)
         {
             //预测小车位置
             Mat y_k = kalman.predict();
             randn(z_k,0.0,sqrt((double)kalman.measurementNoiseCov.at<float>(0,0)));
             //测量值的产生,此处不太标准,实际由传感器传入
             z_k = kalman.measurementMatrix * x_k + z_k;
             img = Scalar::all(0);
             circle(img, phi2xy(z_k), 4, Scalar(128, 255, 255));
             circle(img, phi2xy(y_k), 4, Scalar(255, 255, 255),2);
             circle(img, phi2xy(x_k), 4, Scalar(0, 0, 255));
             putText(img,"red: actual position",Point(10,150), FONT_HERSHEY_PLAIN,2, Scalar(0, 0, 255),1,8);
             putText(img, "yellow: measur value", Point(10, 275), FONT_HERSHEY_PLAIN, 2, Scalar(128, 255, 255), 1, 8);
             putText(img, "white: predictive position", Point(10, 400), FONT_HERSHEY_PLAIN, 2, Scalar(255, 255, 255), 1, 8);
             imshow("result",img);
             kalman.correct(z_k);
             randn(w_k, 0.0, sqrt((double)kalman.processNoiseCov.at<float>(0,0)));
             x_k = kalman.transitionMatrix * x_k + w_k;
             if ((waitKey(100)&255)==27) break;
         }
         return 0;
    }


  • 相关阅读:
    ASP.NET Core应用程序容器化、持续集成与Kubernetes集群部署(二)
    ASP.NET Core应用程序容器化、持续集成与Kubernetes集群部署(一)
    2018年9月15日上海MVP线下技术交流活动简报
    在.NET中使用机器学习API(ML.NET)实现化学分子式数据格式的判定
    使用Roslyn的C#语言服务实现UML类图的自动生成
    ASP.NET Core应用程序的参数配置及使用
    微软最有价值专家(Microsoft MVP)项目经验分享
    漫谈单体架构与微服务架构(上):单体架构
    ASP.NET Core Web API下事件驱动型架构的实现(五):在微服务中使用自我监听模式保证数据库更新与消息派发的可靠性
    使用C#读写结构化的二进制文件
  • 原文地址:https://www.cnblogs.com/fuzhuoxin/p/11983165.html
Copyright © 2011-2022 走看看