天天看点

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

当系统状态方程不符合线性假设时,采用卡尔曼滤波无法获得理想的最优估计。扩展卡尔曼滤波与卡尔曼滤波主要区别在于:对状态方程的泰勒展开。

  1. 快速回顾几个知识点:

Gaussian Distribution of

Univariate

:

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

Gaussian Distribution of

Multivariate

:

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

Bayes Filter Reminder:

Prediction:

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

Observation:

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
2. 基于系统状态方程的非线性,扩展卡尔曼滤波提出线性化过程如下:

大部分的状态估计问题都包含非线性方程:

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

其中个

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

均包含非线性成分。

Prediction的线性化:
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
Correction的线性化:
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
3. 扩展卡尔曼滤波公式(具体公式推导待更新) Prediction:
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
Correction:
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

通过对比EKF和KF的公式会发现,主要区别在于

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

对于计算雅克比矩阵,假设状态向量为

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

,观测向量为

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

。根据

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

对于

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

矩阵的求取方法类似(写出函数

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波

,然后求取对应的偏导数)。

代码(代码来自于Atsushi Sakai)实现才是目的,光写理论的都是理论家;关于代码,每一行的注释将会在这段时间加上。关于代码实现的简单介绍:

This is a sensor fusion localization with Extended Kalman Filter(EKF).

The blue line is true trajectory, the black line is dead reckoning trajectory,

the green point is positioning observation (ex. GPS), and the red line is estimated trajectory with EKF.

The red ellipse is estimated covariance ellipse with EKF.

扩展卡尔曼滤波_无人车定位系列之:扩展卡尔曼滤波
"""
Extended kalman filter (EKF) localization sample

"""

import numpy as np
import math
import matplotlib.pyplot as plt

# Estimation parameter of EKF
Q = np.diag([0.1, 0.1, np.deg2rad(1.0), 1.0])**2
R = np.diag([1.0, np.deg2rad(40.0)])**2

#  Simulation parameter
Qsim = np.diag([0.5, 0.5])**2
Rsim = np.diag([1.0, np.deg2rad(30.0)])**2

DT = 0.1  # time tick [s]
SIM_TIME = 50.0  # simulation time [s]

show_animation = True


def calc_input():
    v = 1.0  # [m/s]
    yawrate = 0.1  # [rad/s]
    u = np.matrix([v, yawrate]).T
    return u


def observation(xTrue, xd, u):

    xTrue = motion_model(xTrue, u)

    # add noise to gps x-y
    zx = xTrue[0, 0] + np.random.randn() * Qsim[0, 0]
    zy = xTrue[1, 0] + np.random.randn() * Qsim[1, 1]
    z = np.matrix([zx, zy])

    # add noise to input
    ud1 = u[0, 0] + np.random.randn() * Rsim[0, 0]
    ud2 = u[1, 0] + np.random.randn() * Rsim[1, 1]
    ud = np.matrix([ud1, ud2]).T

    xd = motion_model(xd, ud)

    return xTrue, z, xd, ud


def motion_model(x, u):

    F = np.matrix([[1.0, 0, 0, 0],
                   [0, 1.0, 0, 0],
                   [0, 0, 1.0, 0],
                   [0, 0, 0, 0]])

    B = np.matrix([[DT * math.cos(x[2, 0]), 0],
                   [DT * math.sin(x[2, 0]), 0],
                   [0.0, DT],
                   [1.0, 0.0]])

    x = F * x + B * u

    return x


def observation_model(x):
    #  Observation Model
    H = np.matrix([
        [1, 0, 0, 0],
        [0, 1, 0, 0]
    ])

    z = H * x

    return z


def jacobF(x, u):
    """
    Jacobian of Motion Model
    motion model
    x_{t+1} = x_t+v*dt*cos(yaw)
    y_{t+1} = y_t+v*dt*sin(yaw)
    yaw_{t+1} = yaw_t+omega*dt
    v_{t+1} = v{t}
    so
    dx/dyaw = -v*dt*sin(yaw)
    dx/dv = dt*cos(yaw)
    dy/dyaw = v*dt*cos(yaw)
    dy/dv = dt*sin(yaw)
    """
    yaw = x[2, 0]
    v = u[0, 0]
    jF = np.matrix([
        [1.0, 0.0, -DT * v * math.sin(yaw), DT * math.cos(yaw)],
        [0.0, 1.0, DT * v * math.cos(yaw), DT * math.sin(yaw)],
        [0.0, 0.0, 1.0, 0.0],
        [0.0, 0.0, 0.0, 1.0]])

    return jF


def jacobH(x):
    # Jacobian of Observation Model
    jH = np.matrix([
        [1, 0, 0, 0],
        [0, 1, 0, 0]
    ])

    return jH


def ekf_estimation(xEst, PEst, z, u):

    #  Predict
    xPred = motion_model(xEst, u)
    jF = jacobF(xPred, u)
    PPred = jF * PEst * jF.T + Q

    #  Update
    jH = jacobH(xPred)
    zPred = observation_model(xPred)
    y = z.T - zPred
    S = jH * PPred * jH.T + R
    K = PPred * jH.T * np.linalg.inv(S)
    xEst = xPred + K * y
    PEst = (np.eye(len(xEst)) - K * jH) * PPred

    return xEst, PEst


def plot_covariance_ellipse(xEst, PEst):
    Pxy = PEst[0:2, 0:2]
    eigval, eigvec = np.linalg.eig(Pxy)

    if eigval[0] >= eigval[1]:
        bigind = 0
        smallind = 1
    else:
        bigind = 1
        smallind = 0

    t = np.arange(0, 2 * math.pi + 0.1, 0.1)
    a = math.sqrt(eigval[bigind])
    b = math.sqrt(eigval[smallind])
    x = [a * math.cos(it) for it in t]
    y = [b * math.sin(it) for it in t]
    angle = math.atan2(eigvec[bigind, 1], eigvec[bigind, 0])
    R = np.matrix([[math.cos(angle), math.sin(angle)],
                   [-math.sin(angle), math.cos(angle)]])
    fx = R * np.matrix([x, y])
    px = np.array(fx[0, :] + xEst[0, 0]).flatten()
    py = np.array(fx[1, :] + xEst[1, 0]).flatten()
    plt.plot(px, py, "--r")


def main():
    print(__file__ + " start!!")

    time = 0.0

    # State Vector [x y yaw v]'
    xEst = np.matrix(np.zeros((4, 1)))
    xTrue = np.matrix(np.zeros((4, 1)))
    PEst = np.eye(4)

    xDR = np.matrix(np.zeros((4, 1)))  # Dead reckoning

    # history
    hxEst = xEst
    hxTrue = xTrue
    hxDR = xTrue
    hz = np.zeros((1, 2))

    while SIM_TIME >= time:
        time += DT
        u = calc_input()

        xTrue, z, xDR, ud = observation(xTrue, xDR, u)

        xEst, PEst = ekf_estimation(xEst, PEst, z, ud)

        # store data history
        hxEst = np.hstack((hxEst, xEst))
        hxDR = np.hstack((hxDR, xDR))
        hxTrue = np.hstack((hxTrue, xTrue))
        hz = np.vstack((hz, z))

        if show_animation:
            plt.cla()
            plt.plot(hz[:, 0], hz[:, 1], ".g")
            plt.plot(np.array(hxTrue[0, :]).flatten(),
                     np.array(hxTrue[1, :]).flatten(), "-b")
            plt.plot(np.array(hxDR[0, :]).flatten(),
                     np.array(hxDR[1, :]).flatten(), "-k")
            plt.plot(np.array(hxEst[0, :]).flatten(),
                     np.array(hxEst[1, :]).flatten(), "-r")
            plot_covariance_ellipse(xEst, PEst)
            plt.axis("equal")
            plt.grid(True)
            plt.pause(0.001)


if __name__ == '__main__':
    main()
           

参考文献:

  1. https://github.com/AtsushiSakai/PythonRobotics/blob/master/Localization/extended_kalman_filter/extended_kalman_filter.py
  2. 概率机器人——扩展卡尔曼滤波、无迹卡尔曼滤波
  3. https://www.cse.sc.edu/~terejanu/files/tutorialEKF.pdf
香港理工大学定位于导航实验室近期招聘研究助理(需有研究生学位),博士生,博士后。研究方向包括GNSS RTK定位,多传感融合定位(因子图优化,factor graph optimization)。有意联系微信:welsonpolyu