boss:整个卡尔曼滤波器的简单案例——估计机器人位置

⭐️ 卡尔曼滤波

卡尔曼滤波(Kalman Filtering)是一种用于状态估计的强大技术,常用于处理具有随机噪声的系统的状态估计问题。在目标跟踪等应用中,卡尔曼滤波常被用来预测目标的位置和速度等状态变量,并根据观测数据进行状态更新,从而实现对目标轨迹的跟踪。

在这里插入图片描述

在目标跟踪中,可能会出现假点(False Positives)的情况,即目标跟踪算法错误地将背景中的噪声或其他物体错误地识别为目标。为了减少假阳性的影响,可以使用卡尔曼滤波器进行假点过滤。下面是卡尔曼滤波的基本原理:

状态模型: 假设目标的状态变量为 x k \mathbf{x}_k xk,包括位置、速度等信息。卡尔曼滤波器会根据系统的动力学模型来预测目标的下一个状态 x ^ k − \hat{\mathbf{x}}_k^- x^k。通常采用线性动力学模型,形式为 x k = F k x k − 1 + B k u k + w k \mathbf{x}_k = \mathbf{F}_k \mathbf{x}_{k-1} + \mathbf{B}_k \mathbf{u}_k + \mathbf{w}_k xk=Fkxk1+Bkuk+wk,其中 F k \mathbf{F}_k Fk 是状态转移矩阵, B k \mathbf{B}_k Bk 是控制输入矩阵, u k \mathbf{u}_k uk 是外部控制输入, w k \mathbf{w}_k wk 是过程噪声(高斯分布)。

观测模型: 卡尔曼滤波器会根据观测数据来更新状态估计值。假设观测数据为 z k \mathbf{z}_k zk,卡尔曼滤波器会根据观测模型 z k = H k x k + v k \mathbf{z}_k = \mathbf{H}_k \mathbf{x}_k + \mathbf{v}_k zk=Hkxk+vk 来估计目标的位置。其中 H k \mathbf{H}_k Hk 是观测矩阵, v k \mathbf{v}_k vk 是观测噪声(高斯分布)。

卡尔曼滤波器更新: 卡尔曼滤波器利用预测值和观测值的差异,结合系统的动力学模型和观测模型,计算出最优的状态估计值。具体来说,卡尔曼滤波器包括两个主要步骤:

预测步骤(Predict): 根据系统的动力学模型,预测目标的状态变量,并计算预测的状态协方差矩阵 P k − \mathbf{P}_k^- Pk

更新步骤(Update): 根据观测模型,计算卡尔曼增益 K k \mathbf{K}_k Kk,并利用观测数据对预测值进行修正,得到最终的状态估计值 x ^ k \hat{\mathbf{x}}_k x^k 和状态协方差矩阵 P k \mathbf{P}_k Pk

整体过程如下图所示:
在这里插入图片描述

卡尔曼的相关资料很多,更详细的知识,读者可以自行搜索,嘻嘻!!!

小编推荐一部著作《Kalman_and_Bayesian_Filters_in_Python》和一位大神的博客 【滤波】设计卡尔曼滤波器,这位大神对前面的著作做了整体的翻译,很牛!!!

⭐️ 设计个卡尔曼滤波器,估计机器人的位置

本文参考《Kalman_and_Bayesian_Filters_in_Python》中的案例,利用函数模拟机器人的位置,然后通过简单卡尔曼滤波器利用测量数据对机器人位置进行估计。

滤波器各个参数设计如下

状态:
在这里插入图片描述

状态转移方程:
在这里插入图片描述

状态转移矩阵:
在这里插入图片描述

观测矩阵:
在这里插入图片描述

初始测量误差协方差矩阵:
在这里插入图片描述

初始状态及其协方差矩阵:
在这里插入图片描述

过程误差协方差矩阵利用白噪声获取。

整体代码如下

from numpy.random import randn
import matplotlib.pyplot as plt
import numpy as np
from filterpy.kalman import KalmanFilter
from scipy.linalg import block_diag
from filterpy.common import Q_discrete_white_noise
from filterpy.stats import plot_covariance_ellipse


# 模拟传感器,返回robot的位置信息
class PosSensor(object):
    def __init__(self, pos=(0, 0), vel=(0, 0), noise_std=1.):
        self.vel = vel
        self.noise_std = noise_std
        self.pos = [pos[0], pos[1]]
        
    def read(self):
        self.pos[0] += self.vel[0]
        self.pos[1] += self.vel[1]
        
        return [self.pos[0] + randn() * self.noise_std,
                self.pos[1] + randn() * self.noise_std]

# 绘制过滤器输出数据
def plot_filter(xs, ys=None, dt=None, c='C0', label='Filter', var=None, **kwargs):
    if ys is None and dt is not None:
        ys = xs
        xs = np.arange(0, len(ys) * dt, dt)
    if ys is None:
        ys = xs
        xs = range(len(ys))

    lines = plt.plot(xs, ys, color=c, label=label, **kwargs)
    if var is None:
        return lines

    var = np.asarray(var)
    std = np.sqrt(var)
    std_top = ys+std
    std_btm = ys-std

    plt.plot(xs, ys+std, linestyle=':', color='k', lw=2)
    plt.plot(xs, ys-std, linestyle=':', color='k', lw=2)
    plt.fill_between(xs, std_btm, std_top, facecolor='yellow', alpha=0.2)

    return lines

# 测量误差方差
R_std = 0.35
# 过程误差方差
Q_std = 0.04

def tracker():
    # 创建卡尔曼滤波器
    tracker = KalmanFilter(dim_x=4, dim_z=2)
    # 时间步伐
    dt = 1.0
    # 状态转移矩阵
    tracker.F = np.array([[1, dt, 0,  0],
                          [0,  1, 0,  0],
                          [0,  0, 1, dt],
                          [0,  0, 0,  1]])
    # 过程输入值
    tracker.u = 0.
    # 观测矩阵
    tracker.H = np.array([[1/0.3048, 0, 0, 0],
                          [0, 0, 1/0.3048, 0]])
    # 测量误差协方差矩阵
    tracker.R = np.eye(2) * R_std**2
    # 白噪声
    q = Q_discrete_white_noise(dim=2, dt=dt, var=Q_std**2)
    # 过程噪声协方差矩阵
    tracker.Q = block_diag(q, q)
    # 初始状态
    tracker.x = np.array([[0, 0, 0, 0]]).T
    # 初始状态协方差矩阵
    tracker.P = np.eye(4) * 500.
    return tracker

# 模拟机器人移动
N = 30
sensor = PosSensor((0, 0), (2, .5), noise_std=R_std)
# 测量数据,位置信息
zs = np.array([sensor.read() for _ in range(N)])

# 运行过滤器
robot_tracker = tracker()
# 卡尔曼滤波结果
mu, cov, _, _ = robot_tracker.batch_filter(zs)

for x, P in zip(mu, cov):
    # x 和 y 的协方差
    cov = np.array([[P[0, 0], P[2, 0]], 
                    [P[0, 2], P[2, 2]]])
    mean = (x[0, 0], x[2, 0])
    # 绘制卡尔曼滤波器输出的位置信息,包括位置和方差
    plot_covariance_ellipse(mean, cov=cov, fc='g', std=3, alpha=0.5)
    
# 坐标位置转换为单位米
zs *= .3048
# 绘制测量数据和过滤器输出
plot_filter(mu[:, 0], mu[:, 2])
plt.scatter(zs[:, 0], zs[:, 1], color='k', facecolor='none', lw=2, label='Measurements'),
plt.legend(loc=2)
plt.xlim(0, 20)
plt.show()

运行结果如下
在这里插入图片描述

笔者水平有限,若有不对的地方欢迎评论指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥猪猪爸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值