C++实现对GPS读取坐标的卡尔曼滤波

通过网上很多资料,还有例程的代码,我根据自己的需求写的笔记如下请添加图片描述
用自己的话来讲,卡尔曼滤波就是找一个权重值,我有一个测量值和一个预测值,测量值就是我通过各种传感器得到的数据,例如速度呀,加速度呀,经纬度这些,这个数据会收到外界干扰,和理论值存在一些偏差,还有一个是预测值,预测值是怎么得到的呢?第一个预测值肯定是自己想的预测的是多少,后面的预测值就要根据不断变化的系数进行修正,这个让他变化的东西就是状态转移方程,一次次的更新我们的预测值.综合以上考虑,我们需要得到一个最终结果,这个值就叫做估计值,估计值等于一定比例的测量值+预测值.我更相信测量值,那我就让测量值占0.7,预测值占0.3,如果一半一半,那就测量值占0.5,预测值也占0.5,我们需要找的就是一个这样最合适的比例.公式还是有很多数学基础知识,建议推导过程把所有不会的都查一遍,这样才能更好的理解五个卡尔曼公式,最终编写代码

我自己编写的代码如下,不过只考虑的X方向上的滤波,Y方向的没有考虑,如法炮制即可

void RasterWindow:: Kalman(std::vector<std::vector<double>> &gpspoints)
{
    const double Time = 1; //控制周期1s
    MatrixXd A(2,2); // 系数矩阵
    A(0, 0) = 1;
    A(1, 0) = 0;
    A(0, 1) = Time;
    A(1, 1) = 1;

    MatrixXd H(1,2);   //观测矩阵
    H(0, 0) = 1;
    H(0, 1) = 0;
    MatrixXd Q(2, 2);//过程激励噪声协方差,假设系统的噪声向量只存在速度分量上,且速度噪声的方差是一个常量0.01,位移分量上的系统噪声为0
    Q(0, 0) = 0;
    Q(1, 0) = 0;
    Q(0, 1) = 0;
    Q(1, 1) = 0.01;
    MatrixXd R(1, 1);//观测噪声协方差,测量值只有位移,它的协方差矩阵大小是1*1,就是测量噪声的方差本身。
        R(0, 0) = 0.00001;
        //变量定义阵,初始值均为零
    MatrixXd X_evlt = MatrixXd::Constant(2, 1, 0); //状态预测值
    MatrixXd X_pdct = MatrixXd::Constant(2, 1, 0); //状态估计值
    MatrixXd Z_meas = MatrixXd::Constant(1, 1, 0); //测量值
    MatrixXd X_real(2, 1);  //真实值

    MatrixXd Pk = MatrixXd::Constant(2, 2, 0);  //预测状态与真实状态的协方差矩阵
    MatrixXd Pk_p = MatrixXd::Constant(2, 2, 0);//估计状态和真实状态的协方差矩阵
    MatrixXd K = MatrixXd::Constant(2, 1, 0);  //kalman增益矩阵
    MatrixXd tmp(1, 1);
    std::vector<MatrixXd> x_evlt, x_pdct, z_meas, pk, pk_p, k,x_real;
    for (int i = 1; i < GPSNUM; ++i) {
            X_real(0,0)=gpspoints[i-1][0]+gpspoints[i-1][2]*Time*0.00001;
            X_real(1,0)=0;
            x_real.push_back(X_real);
        }
    x_evlt.push_back(X_evlt);
    x_pdct.push_back(X_pdct);
    z_meas.push_back(Z_meas);
    pk.push_back(Pk);
    pk_p.push_back(Pk_p);
    k.push_back(K);

    //开始迭代
       for (int i = 1; i < GPSNUM-1; i++) {
            //预测值
            X_pdct = A * x_evlt[i - 1];
            x_pdct.push_back(X_pdct);
            //预测状态与真实状态的协方差矩阵,Pk'
            Pk_p = A * pk[i - 1] * A.transpose() + Q;
            pk_p.push_back(Pk_p);
            //K:2x1
            tmp = H * pk_p[i] * H.transpose() + R;
            K = pk_p[i] * H.transpose() * tmp.inverse();
            k.push_back(K);
            //测量值z
            Z_meas = H * x_real[i];
            z_meas.push_back(Z_meas);
            //估计值
            X_evlt = x_pdct[i] + k[i] * (z_meas[i] - H * x_pdct[i]);
            x_evlt.push_back(X_evlt);
            //估计状态和真实状态的协方差矩阵,Pk
            Pk = (MatrixXd::Identity(2, 2) - k[i] * H) * pk_p[i];
            pk.push_back(Pk);
        }
        std::cout << "含噪声测量" << "  " << "后验估计" << "  " << "真值" << "  " << std::endl;
        for (int i = 0; i < GPSNUM-1; i++) {
            std::cout<<z_meas[i]<<"  "<<x_evlt[i](0,0)<<"  "<<x_real[i](0,0)<<std::endl;
            gpspoints[i][0] = x_evlt[i](0,0);

}


}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
无迹卡尔曼滤波(Unscented Kalman Filter,UKF)是一种基于卡尔曼滤波的非线性滤波方法,适用于非线性系统的状态估计问题。相比于传统的扩展卡尔曼滤波(Extended Kalman Filter,EKF),UKF不需要对非线性函数进行线性化,因此具有更好的鲁棒性和精度。 以下是一个简单的C++实现无迹卡尔曼滤波的示例: ```c++ #include <iostream> #include <Eigen/Dense> using namespace Eigen; // 状态向量维度 const int n = 2; // 观测向量维度 const int m = 1; // 系统噪声方差 const double q = 0.01; // 观测噪声方差 const double r = 0.1; // UKF参数 const double alpha = 0.001; const double beta = 2; const double kappa = 0; // 状态转移函数 VectorXd f(const VectorXd& x) { VectorXd x_next(n); x_next(0) = x(0) + x(1); x_next(1) = x(1); return x_next; } // 观测函数 VectorXd h(const VectorXd& x) { VectorXd z(m); z(0) = x(0); return z; } // 生成Sigma点 MatrixXd generate_sigma_points(const VectorXd& x, const MatrixXd& P) { MatrixXd X(n, 2*n+1); MatrixXd A = (sqrt(n+kappa)*P).transpose(); for (int i = 0; i < n; i++) { X.col(i+1) = x + A.col(i); X.col(i+n+1) = x - A.col(i); } X.col(0) = x; return X; } // UKF预测 void predict(VectorXd& x, MatrixXd& P) { // 生成Sigma点 MatrixXd X = generate_sigma_points(x, P); // 计算预测均值和协方差矩阵 VectorXd x_pred(n); MatrixXd P_pred(n, n); x_pred.setZero(); P_pred.setZero(); for (int i = 0; i < 2*n+1; i++) { x_pred += f(X.col(i)); } x_pred /= 2*n+1; for (int i = 0; i < 2*n+1; i++) { VectorXd dx = f(X.col(i)) - x_pred; P_pred += dx * dx.transpose(); } P_pred /= 2*n+1; P_pred += q * MatrixXd::Identity(n, n); x = x_pred; P = P_pred; } // UKF更新 void update(VectorXd& x, MatrixXd& P, const VectorXd& z) { // 生成Sigma点 MatrixXd X = generate_sigma_points(x, P); // 计算预测观测均值和协方差矩阵 VectorXd z_pred(m); MatrixXd Pzz(m, m); MatrixXd Pxz(n, m); z_pred.setZero(); Pzz.setZero(); Pxz.setZero(); for (int i = 0; i < 2*n+1; i++) { z_pred += h(X.col(i)); } z_pred /= 2*n+1; for (int i = 0; i < 2*n+1; i++) { VectorXd dz = h(X.col(i)) - z_pred; Pzz += dz * dz.transpose(); VectorXd dx = X.col(i) - x; Pxz += dx * dz.transpose(); } Pzz /= 2*n+1; Pzz += r * MatrixXd::Identity(m, m); Pxz /= 2*n+1; // 计算卡尔曼增益 MatrixXd K = Pxz * Pzz.inverse(); // 更新状态和协方差矩阵 x += K * (z - z_pred); P -= K * Pzz * K.transpose(); } int main() { // 初始化状态和协方差矩阵 VectorXd x(n); MatrixXd P(n, n); x << 1, 0; P << 1, 0, 0, 1; // 生成随机数据 srand(time(NULL)); std::vector<double> data; for (int i = 0; i < 100; i++) { double val = rand() / (double)RAND_MAX; data.push_back(val); } // 运行UKF for (int i = 0; i < 100; i++) { // 预测 predict(x, P); // 更新 VectorXd z(m); z << data[i]; update(x, P, z); // 输出结果 std::cout << "x(" << i+1 << "): " << x.transpose() << std::endl; } return 0; } ``` 在这个示例中,我们考虑一个只有一个状态变量的非线性系统,状态变量的状态转移函数为 $f(x_k)=[x_k+x_{k-1},x_{k-1}]^T$ ,观测函数为 $h(x_k)=x_k$ 。我们使用随机数据对系统进行观测,并使用UKF对系统状态进行估计。在程序运行过程中,我们输出每个时间步的状态估计结果。 需要注意的是,在实际应用中,需要根据具体问题进行调整和优化UKF参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值