卡尔曼滤波算法包(python)

本文写了具有普遍适用性的卡尔曼滤波(Kalman filter)算法程序包,输入参数即可进行运算。

算法可参考资料:

算法推导:

​​​​​​卡尔曼滤波的理解、推导和应用

卡尔曼滤波

 参数理解:

卡尔曼滤波的理解以及参数调整

手把手教你学-卡尔曼滤波(附代码)

\begin{aligned}predict:&\hat{x}'_{k}=A\hat{x}_{k-1}+Bu_{k-1}\\ &P'_{k}=AP_{k-1}A^{T}+Q\\ correct:&K_{k}=P'_{k}H^{T}(HP'H^{T}+R)^{-1}\\ &x_{k}=x_{k}'+K_{k}(Z_{k}-Hx'_{k})\\ &P_{k}=(I-K_{k}H)P'_{k} \end{aligned}

其中Z_{k}=Hx_{k}x_{k}为仪器观测到的状态值

输入参数:

状态矩阵x

状态转移矩阵A

输入控制矩阵B

外界对系统作用矩阵u

初始误差协方差矩阵P

预测噪声协方差矩阵Q

观测矩阵H

观测噪声协方差矩阵R

(可通过调整三个协方差矩阵大小来调整降噪效果)

可复制算法包:

def Kalmanfilter(x):
    # 需预先定义以下变量:
    # 状态转移矩阵A
    # 输入控制矩阵B
    # 外界对系统作用矩阵u
    # 误差协方差矩阵P
    # 预测噪声协方差矩阵Q
    # 观测矩阵H
    # 观测噪声协方差矩阵R
    # import numpy as np
    xr = np.shape(x)[0]                     # 调用状态矩阵行数
    xc = np.shape(x)[1]                     # 调用状态矩阵列数
    X_mat = x.copy()                        # 初始化记录系统优化状态值的矩阵(浅拷贝)
    X = x.T[0].T                            # 抽取预测优化值的初始状态值
    Z = H * x
    global P                                #初始设置为全局变量P
    for i in range(1,xc):
        # 预测
        X_predict = A * X                   # 估算状态变量
        if B!=0:
            X_predict = A * X + B * u.T[i-1].T
        P_predict = A * P * A.T + Q         # 估算状态误差协方差
        # 校正
        K = P_predict * H.T / (H * P_predict * H.T + R)  # 更新卡尔曼增益
        X = X_predict + K * (Z.T[i].T - H * X_predict)  # 更新预测优化值
        P = (np.eye(xr) - K * H) * P_predict  # 更新状态误差协方差
        # 记录系统的预测优化值
        for j in range(xr):
            X_mat[j, i] = X[j, 0]
    Z_mat = H * X_mat
    return Z_mat
kf = Kalmanfilter(x)

案例:对均加速直线运动的位置进行降噪处理,加速度为1,初始时间为0,初始位置为0,观测时间为7秒,每0.1秒观测一次,设误差为白噪声N(0,1)

方法1

设置时间跳跃系统:(s为位置,v为速度)

卡尔曼滤波算法包(python)_第1张图片

状态矩阵x:

\begin{vmatrix} x_{1} &... &x_{n} \\ v_{1} &... &v_{n} \end{vmatrix}

状态转移矩阵A:

\begin{vmatrix} 1 &\Delta t\\ 0 & 1 \end{vmatrix}

控制矩阵B:

\begin{vmatrix} \frac{1}{2}\Delta t^{2}&0\\ 0& \Delta t \end{vmatrix}

外界对系统作用矩阵u:

\begin{vmatrix} a &... &a \\ a & ...& a \end{vmatrix}

初始误差协方差矩阵P:

\begin{vmatrix} 1 &0 \\ 0& 1 \end{vmatrix}

预测噪声协方差矩阵Q:

\begin{vmatrix} 0.001&0\\ 0&0.001 \end{vmatrix}

观测矩阵H:

\begin{vmatrix} 1\\ 0 \end{vmatrix}

观测噪声协方差矩阵R:

\begin{vmatrix} 1 \end{vmatrix}

import numpy as np
import matplotlib.pyplot as plt
delta_t = 0.1                               # 每秒钟采一次样
end_t = 7                                   # 时间长度
time_t = end_t * 10                         # 采样次数
t = np.arange(0, end_t, delta_t)            # 设置时间数组
v_var = 1                                   # 测量噪声的方差
v_noise = np.round(np.random.normal(0, v_var, time_t), 2)# 定义测量噪声
a=1                                         #加速度
vn=np.add((1 / 2*a * t ** 2) , v_noise)     # 定义仪器测量的位置
v=a*t  #定义速度数组

x = np.mat([vn,v])                          # 定义状态矩阵
xc = np.shape(x)[1]                         #调用状态矩阵列数
u1=np.linspace(a,a,xc)
u = np.mat([u1,u1])                         # 定义外界对系统作用矩阵
A = np.mat([[1, delta_t], [0, 1]])          # 定义状态转移矩阵
B = [[1 / 2 * (delta_t ** 2),0],[0,delta_t]]# 定义输入控制矩阵
P = np.mat([[1, 0], [0, 1]])                # 定义初始状态协方差矩阵
Q = np.mat([[0.001, 0], [0, 0.001]])        # 定义状态转移(预测噪声)协方差矩阵
H = np.mat([1, 0])                          # 定义观测矩阵
R = np.mat([1])                             # 定义观测噪声协方差矩阵

def Kalmanfilter(x):
    # 需预先定义以下变量:
    # 状态转移矩阵A
    # 输入控制矩阵B
    # 外界对系统作用矩阵u
    # 误差协方差矩阵P
    # 预测噪声协方差矩阵Q
    # 观测矩阵H
    # 观测噪声协方差矩阵R
    # import numpy as np
    xr = np.shape(x)[0]                     # 调用状态矩阵行数
    xc = np.shape(x)[1]                     # 调用状态矩阵列数
    X_mat = x.copy()                        # 初始化记录系统优化状态值的矩阵(浅拷贝)
    X = x.T[0].T                            # 抽取预测优化值的初始状态值
    Z = H * x
    global P                                #初始设置为全局变量P
    for i in range(1,xc):
        # 预测
        X_predict = A * X                   # 估算状态变量
        if B!=0:
            X_predict = A * X + B * u.T[i-1].T
        P_predict = A * P * A.T + Q         # 估算状态误差协方差
        # 校正
        K = P_predict * H.T / (H * P_predict * H.T + R)  # 更新卡尔曼增益
        X = X_predict + K * (Z.T[i].T - H * X_predict)  # 更新预测优化值
        P = (np.eye(xr) - K * H) * P_predict  # 更新状态误差协方差
        # 记录系统的预测优化值
        for j in range(xr):
            X_mat[j, i] = X[j, 0]
    Z_mat = H * X_mat
    return Z_mat

kf=Kalmanfilter(x)
plt.rcParams['font.sans-serif'] = ['SimHei']    # 设置正常显示中文
plt.plot(t,np.array(kf)[0], "g", label='预测优化值')
plt.plot(t,np.array(x[0])[0], "r--", label='测量值')
plt.xlabel("时间")                               # 设置X轴的名字
plt.ylabel("位移")                               # 设置Y轴的名字
plt.title("卡尔曼滤波示意图")                     # 设置标题
plt.legend()                                     # 设置图例
plt.show()                                       # 显示图表

卡尔曼滤波算法包(python)_第2张图片

 方法2

设置时间跳跃系统:(s为位置,v为速度)

x_{k}=Ax_{k-1}+Bu_{k-1}\\ then, \\ s_{k}=(s_{k-1}+\Delta tv_{k-1}+\frac{1}{2}\Delta t^{2}*a)+0\\ v_{k}=(0*s_{k-1}+v_{k-1}+\Delta t*a)+0\\ a_{k}=(0*s_{k-1}+0*v_{k-1}+a)+0 \\and, \\ Z_{k}=Hx_{k}\\ Z_{k}=1*s_{k}+0*v_{k}+0*a_{k}

状态矩阵x:

\begin{vmatrix} x_{1} &... &x_{n} \\ v_{1} &... &v_{n}\\a&...&a \end{vmatrix}

状态转移矩阵A:

\begin{vmatrix} 1 &\Delta t&\frac{1}{2}\Delta t^{2}\\ 0 & 1& \Delta t\\0&0&1\end{vmatrix}

控制矩阵B:

\begin{vmatrix}0\end{vmatrix}

外界对系统作用矩阵u:

\begin{vmatrix}0\end{vmatrix}

初始误差协方差矩阵P:

\begin{vmatrix} 1 &0 &0\\ 0& 1 &0\\0&0&1\end{vmatrix}

预测噪声协方差矩阵Q:

\begin{vmatrix} 0.001&0&0\\ 0&0.001&0\\0&0&0.001 \end{vmatrix}

观测矩阵H:

\begin{vmatrix} 1\\ 0\\0 \end{vmatrix}

观测噪声协方差矩阵R:

\begin{vmatrix} 1 \end{vmatrix}

import numpy as np
import matplotlib.pyplot as plt
delta_t = 0.1                                 # 每秒钟采一次样
end_t = 7                                     # 时间长度
time_t = end_t * 10                           # 采样次数
t = np.arange(0, end_t, delta_t)              # 设置时间数组
v_var = 1                                     # 测量噪声的方差
v_noise = np.round(np.random.normal(0, v_var, time_t), 2)# 定义测量噪声
a=1                                           #加速度
vn=np.add((1 / 2*a * t ** 2) , v_noise)       # 定义仪器测量的位置
v=a*t  #定义速度数组
a1=np.linspace(a,a,time_t)

x = np.mat([vn,v,a1])                         # 定义状态矩阵
u = 0                                         # 定义外界对系统作用矩阵
A = np.mat([[1, delta_t, 1/2*delta_t], [0, 1, delta_t], [0, 0, 1]])          # 定义状态转移矩阵
B = 0                                         # 定义输入控制矩阵
P = np.mat([[1, 0,0], [0, 1,0],[0,0,1]])      # 定义初始状态协方差矩阵
Q = np.mat([[0.001, 0,0], [0, 0.001,0],[0,0,0.001]])        # 定义状态转移(预测噪声)协方差矩阵
H = np.mat([1, 0, 0])                         # 定义观测矩阵
R = np.mat([1])                               # 定义观测噪声协方差矩阵

def Kalmanfilter(x):
    # 需预先定义以下变量:
    # 状态转移矩阵A
    # 输入控制矩阵B
    # 外界对系统作用矩阵u
    # 误差协方差矩阵P
    # 预测噪声协方差矩阵Q
    # 观测矩阵H
    # 观测噪声协方差矩阵R
    # import numpy as np
    xr = np.shape(x)[0]                     # 调用状态矩阵行数
    xc = np.shape(x)[1]                     # 调用状态矩阵列数
    X_mat = x.copy()                        # 初始化记录系统优化状态值的矩阵(浅拷贝)
    X = x.T[0].T                            # 抽取预测优化值的初始状态值
    Z = H * x
    global P                                #初始设置为全局变量P
    for i in range(1,xc):
        # 预测
        X_predict = A * X                   # 估算状态变量
        if B!=0:
            X_predict = A * X + B * u.T[i-1].T
        P_predict = A * P * A.T + Q         # 估算状态误差协方差
        # 校正
        K = P_predict * H.T / (H * P_predict * H.T + R)  # 更新卡尔曼增益
        X = X_predict + K * (Z.T[i].T - H * X_predict)  # 更新预测优化值
        P = (np.eye(xr) - K * H) * P_predict  # 更新状态误差协方差
        # 记录系统的预测优化值
        for j in range(xr):
            X_mat[j, i] = X[j, 0]
    Z_mat = H * X_mat
    return Z_mat

kf=Kalmanfilter(x)
plt.rcParams['font.sans-serif'] = ['SimHei']    # 设置正常显示中文
plt.plot(t,np.array(kf)[0], "g", label='预测优化值')
plt.plot(t,np.array(x[0])[0], "r--", label='测量值')
plt.xlabel("时间")                                # 设置X轴的名字
plt.ylabel("位移")                                # 设置Y轴的名字
plt.title("卡尔曼滤波示意图")                      # 设置标题
plt.legend()                                      # 设置图例
plt.show()                                        # 显示图表

卡尔曼滤波算法包(python)_第3张图片

 在合适的协方差矩阵大小设置之下,卡尔曼滤波算法可得到需要的降噪效果,美!!

你可能感兴趣的:(算法,数据挖掘,人工智能,线性代数)