信息滤波器

信息滤波器(IF)是卡尔曼滤波器(KF)的对偶滤波器。卡尔曼滤波器维护的变量包括状态均值 μ \mu μ和状态协方差 Σ \Sigma Σ。而信息矩阵维护的变量包括信息向量 ξ \xi ξ和信息矩阵 Ω \Omega Ω

从KF到IF

在KF中我们用高斯分布来描述状态变量的分布情况:
p ( x ) = d e t ( 2 π Σ ) − 1 2 e x p ( − 1 2 ( x − μ ) T Σ − 1 ( x − μ ) ) p(x) = det(2\pi\Sigma)^{-\frac{1}{2}}exp(-\frac{1}{2}(x-\mu)^T\Sigma^{-1}(x-\mu)) p(x)=det(2πΣ)21exp(21(xμ)TΣ1(xμ))

而信息矩阵和信息向量,它们与均值和方差的关系为:
Ω = Σ − 1 ξ = Σ − 1 μ \Omega=\Sigma^{-1}\\\xi=\Sigma^{-1}\mu Ω=Σ1ξ=Σ1μ
对于KF,它的预测和更新方程如下:
μ ˉ t = A t μ t − 1 + B t u t Σ ˉ t = A t Σ t − 1 A t T + R t K t = Σ ˉ t C t T ( C t Σ ˉ t C t T + Q t ) − 1 μ t = μ ˉ t + K t ( z t − C t μ ˉ t ) Σ t = ( I − K t C t ) Σ ˉ t \bar{\mu}_t = A_t\mu_{t-1}+B_tu_t\\ \bar{\Sigma}_t = A_t\Sigma_{t-1}A^T_t+R_t\\ K_t=\bar{\Sigma}_tC^T_t(C_t\bar{\Sigma}_tC^T_t+Q_t)^{-1}\\ \mu_t = \bar{\mu}_t+K_t(z_t-C_t\bar{\mu}_t)\\ \Sigma_t=(I-K_tC_t)\bar{\Sigma}_t μˉt=Atμt1+BtutΣˉt=AtΣt1AtT+RtKt=ΣˉtCtT(CtΣˉtCtT+Qt)1μt=μˉt+Kt(ztCtμˉt)Σt=(IKtCt)Σˉt
Ω \Omega Ω ξ \xi ξ代入可得,IF的预测方程为:
Ω ˉ t = ( A t Ω t − 1 − 1 A t T + R t ) − 1 ξ ˉ t = Ω ˉ t ( A t Ω t − 1 − 1 ξ t − 1 + B t u t ) \bar{\Omega}_t=(A_t\Omega^{-1}_{t-1}A^T_t+R_t)^{-1}\\ \bar{\xi}_t=\bar{\Omega}_t(A_t\Omega^{-1}_{t-1}\xi_{t-1}+B_tu_t) Ωˉt=(AtΩt11AtT+Rt)1ξˉt=Ωˉt(AtΩt11ξt1+Btut)
下面推导IF的更新方程:
Ω \Omega Ω ξ \xi ξ代入上面的高斯分布概率密度函数有:
p ( x ) = η e x p ( − 1 2 x T Ω x + x T ξ ) η = e x p ( − 1 2 μ T ξ ) d e t ( 2 π Ω − 1 ) 1 2 p(x) = \eta exp(-\frac{1}{2}x^T\Omega x+x^T\xi)\\ \eta = \frac{exp(-\frac{1}{2}\mu^T\xi)}{det(2\pi\Omega^{-1})^{\frac{1}{2}}} p(x)=ηexp(21xTΩx+xTξ)η=det(2πΩ1)21exp(21μTξ)
而根据贝叶斯公式,推出后验概率:
b e l ( x i ) = η p ( z t ∣ x t ) b e l ˉ ( x t ) = η e x p ( − 1 2 ( z t − C t x t ) T Q t − 1 ( x t − C t x t ) ) e x p ( − 1 2 ( x t − μ ˉ t ) T Σ ˉ − 1 ( x t − μ ˉ t ) ) = η e x p ( 1 2 x t T [ C t T Q t − 1 C t + Ω ˉ t ] x t + x t T [ C t T Q t − 1 z t + ξ ˉ t ] ) bel(x_i)=\eta p(z_t|x_t)\bar{bel}(x_t)\\ =\eta exp(-\frac{1}{2}(z_t-C_tx_t)^TQ_t^{-1}(x_t-C_tx_t)) exp(-\frac{1}{2}(x_t-\bar{\mu}_t)^T\bar{\Sigma}^{-1}(x_t-\bar{\mu}_t))\\ = \eta exp(\frac{1}{2}x^T_t[C_t^TQ^{-1}_tC_t+\bar{\Omega}_t]x_t+x^T_t[C^T_tQ^{-1}_tz_t+\bar{\xi}_t]) bel(xi)=ηp(ztxt)belˉ(xt)=ηexp(21(ztCtxt)TQt1(xtCtxt))exp(21(xtμˉt)TΣˉ1(xtμˉt))=ηexp(21xtT[CtTQt1Ct+Ωˉt]xt+xtT[CtTQt1zt+ξˉt])
所以,IF的更新方程为:
Ω t = C t T Q t − 1 C t + Ω ˉ t ξ t = C t T Q t − 1 z t + ξ ˉ t \Omega_t=C^T_tQ^{-1}_tC_t+\bar{\Omega}_t\\ \xi_t = C^T_tQ^{-1}_tz_t+\bar{\xi}_t Ωt=CtTQt1Ct+Ωˉtξt=CtTQt1zt+ξˉt

IF的python实现

import numpy as np
from numpy.linalg import inv
from numpy import dot
from matplotlib import pyplot as plt
import seaborn

class BasicMovement:
    def __init__(self, maxSpeed, covariance, robotFeaturesDim):
        self.maxSpeed = maxSpeed
        self.covariance = np.atleast_2d(covariance)
        self.robotFeaturesDim = robotFeaturesDim

    #  Input the real state
    def move(self, state, covariance=None, command=None):
        move = self.__choose_command(state) if command is None else command
        noise = self.__get_noise(state, covariance)
        newState = state + move + noise
        return newState, move

    def __choose_command(self, state):  # TO CHANGE FOR 2D
        dim = self.robotFeaturesDim
        way = 1 - 2 * np.random.randint(2)
        speed = self.maxSpeed * np.random.rand()
        newCommand = np.zeros_like(state)
        newCommand[:dim] = way * speed  # TO CHANGE FOR 2D
        return newCommand

    def __get_noise(self, state, covariance):
        dim = self.robotFeaturesDim
        noise = np.zeros_like(state)
        covariance = self.covariance if covariance is None else covariance
        noise[:dim] = np.random.multivariate_normal(np.zeros(dim), covariance, 1).T
        return noise


class BasicMeasurement:
    def __init__(self, covariance, robotFeaturesDim, envFeaturesDim, measureFunction, gradMeasureFunction, detectionSize=0):
        self.covariance = np.atleast_2d(covariance)
        self.robotFeaturesDim = robotFeaturesDim
        self.envFeaturesDim = envFeaturesDim
        self.measureFunction = measureFunction
        self.gradMeasureFunction = gradMeasureFunction
        self.detectionSize = detectionSize

    #  Input the real state
    def measure(self, state):
        dim = state.shape[0]
        dimR = self.robotFeaturesDim
        dimE = self.envFeaturesDim
        rState = state[:dimR]
        envState = state[dimR:]
        nbLandmark = (dim - dimR) / dimE
        nbLandmark = int(nbLandmark)
        mes = np.zeros(nbLandmark)
        landmarkIds = np.zeros(nbLandmark).astype(int)
        j = 0
        for i, landmark in enumerate(envState.reshape((nbLandmark, dimE, 1))):
            if (np.linalg.norm(rState - landmark) < self.detectionSize) or (self.detectionSize is 0):
                mes[j] = self.measureFunction(rState, landmark)
                landmarkIds[j] = int(i)
                j += 1
        mes = mes[:j]
        landmarkIds = landmarkIds[:j]

        mes = np.array(mes)
        noise = self.__get_noise(mes)
        mes += noise  
        return mes.reshape((len(mes), 1)), landmarkIds

    def __get_noise(self, mes):
        noise = np.squeeze(np.random.multivariate_normal(np.zeros(self.envFeaturesDim), self.covariance, len(mes)))
        return noise


class EIFModel:
    def __init__(self, dimension, robotFeaturesDim, envFeaturesDim, motionModel, mesModel, covMes, muInitial):
        self.robotFeaturesDim = robotFeaturesDim
        self.envFeaturesDim = envFeaturesDim
        self.dimension = dimension

        self.H = np.eye(dimension)
        self.b = dot(muInitial.T, self.H)
        self.S = np.zeros(dimension * robotFeaturesDim).reshape((dimension, robotFeaturesDim))
        self.S[:robotFeaturesDim] = np.eye(robotFeaturesDim)
        self.invZ = inv(covMes)
        self.motionModel = motionModel
        self.mesModel = mesModel

    def update(self, measures, landmarkIds, command, U):
        self.__motion_update(command, U)
        for ldmIndex, ldmMes in zip(landmarkIds, measures):
            self.__measurement_update(ldmMes, ldmIndex)
        return self.H, self.b

    def __motion_update(self, command, U):
        previousMeanState = self.estimate()
        _, meanStateChange = self.motionModel.move(previousMeanState, command=command)
        self.H = inv(inv(self.H) + dot(dot(self.S, U), self.S.T))
        self.b = dot((previousMeanState + meanStateChange).T,  self.H)

    def __measurement_update(self, ldmMes, ldmIndex):
        mu = self.estimate()
        meanMes, gradMeanMes = self.__get_mean_measurement_params(mu, ldmIndex)

        z = np.atleast_2d(ldmMes)
        zM = np.atleast_2d(meanMes)
        C = gradMeanMes

        self.H += dot(dot(C, self.invZ),  C.T)
        self.b += dot(dot((z - zM + dot(C.T, mu)).T, self.invZ), C.T)

    def __get_mean_measurement_params(self, mu, ldmIndex):
        realIndex = self.robotFeaturesDim + ldmIndex * self.envFeaturesDim
        # import ipdb; ipdb.set_trace()
        ldmMeanState = mu[realIndex: realIndex + self.envFeaturesDim]
        rMeanState = mu[:self.robotFeaturesDim]

        meanMes = self.mesModel.measureFunction(rMeanState, ldmMeanState)
        gradMeanMes = self.mesModel.gradMeasureFunction(mu, ldmIndex)
        return meanMes, gradMeanMes

    def estimate(self, H=None, b=None):
        H = self.H if H is None else H
        b = self.b if b is None else b
        return dot(b, inv(H)).T
measureFunction = lambda rState, landmark: np.sign(landmark[0, 0] - rState[0, 0]) * np.linalg.norm(rState - landmark)

def gradMeasureFunction(state, ldmIndex):
    grad = np.zeros_like(state)
    grad[0] = -1
    grad[ldmIndex+1] = 1
    return grad


T = 1000  # 仿真步数
nbLandmark = 10 ## 路标个数
maxSpeed = 3 ## 最大速度
robotFeaturesDim = 1 ## 机器人状态维数
envFeaturesDim = 1 ## 环境状态维数
dimension = robotFeaturesDim + nbLandmark * envFeaturesDim ##总状态维数

# Detection parameters
spaceBetween = 100 ## 路标间隔
detectionSize = 15 ## 探测范围

covarianceMotion = np.eye(robotFeaturesDim) * 10  # 运动噪声
covarianceMeasurements = np.eye(envFeaturesDim) * 10  # 观测噪声

motionModel = BasicMovement(maxSpeed, covarianceMotion, robotFeaturesDim)
measurementModel = BasicMeasurement(covarianceMeasurements, robotFeaturesDim, envFeaturesDim, measureFunction, gradMeasureFunction, detectionSize)
state = np.zeros((dimension, 1))  # 机器人状态和路标位置
state[1:] = np.arange(0, nbLandmark * spaceBetween, spaceBetween).reshape(nbLandmark, 1)# 设置路标


muEIF = np.zeros_like(state)  # 初始状态
muEIF = state.copy()
muEIF[1:] += np.random.multivariate_normal([0], covarianceMeasurements, nbLandmark).reshape(nbLandmark, 1)


eif = EIFModel(dimension, robotFeaturesDim, envFeaturesDim, motionModel, measurementModel, covarianceMeasurements, muEIF)

mus_eif = np.zeros((T, dimension))##记录IF滤波值和真值
states = np.zeros((T, dimension))

mus_eif[0] = np.squeeze(muEIF)
states[0] = np.squeeze(state)

listStates = []
listCommands = []
listMeasures = []
listLandmarkIds = []
for t in range(1, T):
    state, motionCommand = motionModel.move(state)
    measures, landmarkIds = measurementModel.measure(state)
    listStates.append(state)
    listCommands.append(motionCommand)
    listMeasures.append(measures)
    listLandmarkIds.append(landmarkIds)


for t in range(1, T):
    state = listStates[t-1]
    motionCommand = listCommands[t-1]
    measures = listMeasures[t-1]
    landmarkIds = listLandmarkIds[t-1]

    H, b = eif.update(measures, landmarkIds, motionCommand, covarianceMotion)
    muEIF = eif.estimate()
    mus_eif[t] = np.squeeze(muEIF)
    
plt.figure()
plt.plot(states[:, 0])
plt.plot(mus_eif[:, 0])
plt.legend(['Real position', 'EIF estimate'])
plt.title("{0} landmarks".format(nbLandmark))
plt.show()

在这里插入图片描述

参考:
http://ais.informatik.uni-freiburg.de/teaching/ws12/mapping/pdf/slam06-eif.pdf
https://github.com/theevann/SLAM

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值