溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

python實(shí)現(xiàn)kalman濾波的方法

發(fā)布時(shí)間:2021-06-30 16:13:42 來源:億速云 閱讀:2663 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要講解了“python實(shí)現(xiàn)kalman濾波的方法”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“python實(shí)現(xiàn)kalman濾波的方法”吧!

卡爾曼濾波的本質(zhì)是對最小二乘法的迭代運(yùn)算,可以給出時(shí)間序列的狀態(tài)估計(jì)。假設(shè)其要估計(jì)的過程如下:

x[k+1] = A[k]*x[k] + B*u[k] + w[k]  // 狀態(tài)方程
z[k] = H[k]*x[k] + v[k]             // 測量值
p(w) ~ N(0, Q)
p(v) ~ N(0, R)

其中w和v代表滿足正態(tài)分布的噪音項(xiàng),該正態(tài)分布均值為0,協(xié)方差矩陣分別為Q和R。u代表對x的控制項(xiàng),z代表測量值,k+1和k代表不同時(shí)刻的值。A,B,H分別為相應(yīng)的關(guān)聯(lián)矩陣??柭鼮V波將該過程的預(yù)測值分為兩部分,一是通過模型對先驗(yàn)值的推斷,稱為時(shí)間更新;二是通過測量值進(jìn)行修正,稱為測量更新。其核心方程為:

// 時(shí)間更新
xb[k+1] = A[k]*x[k] + B*u[k]
Pb[k+1] = A[k]*P[k]*transverse(A[k]) + Q[k]
// 測量更新
K[k] = Pb[k]*transverse(H[k])*inverse(H[k]*Pb[k]*transverse(H[k])+R[k])
x[k] = xb[k] + K*(z[k] - H[k]*xb[k])
P[k] = (I - K[k]*H[k])*Pb[k]

其中xb為狀態(tài)先驗(yàn)估計(jì)值,Pb為先驗(yàn)誤差協(xié)方差矩陣,P為后驗(yàn)誤差協(xié)方差矩陣。在每次時(shí)間更新中,利用前一個(gè)后驗(yàn)估計(jì)值給出下一時(shí)刻的先驗(yàn)估計(jì)值xb,并給出下一個(gè)時(shí)刻的先驗(yàn)誤差協(xié)方差估計(jì)。在每次測量更新中,先計(jì)算出卡爾曼增益K,然后利用測量值z和先驗(yàn)估計(jì)值xb計(jì)算出當(dāng)前的后驗(yàn)估計(jì)值x,最后再給出當(dāng)前的后驗(yàn)誤差協(xié)方差估計(jì)。

這兩個(gè)更新過程融合了先驗(yàn)估計(jì)(從過去的數(shù)據(jù)和模型推斷的系統(tǒng)狀態(tài))和可能存在噪音的測量值,從而給出了系統(tǒng)最有可能的狀態(tài)(分布)。該方法的優(yōu)點(diǎn)在于,在測量和控制都不夠精確的情況下,給出結(jié)合二者數(shù)據(jù)的最佳估計(jì)。下面給出簡單的python代碼及運(yùn)行結(jié)果供參考。

import numpy

class Kalman_Filter:
    def __init__(self, A, H, Q, R, z, B = None, impulse = None):
        self._A = A
        self._H = H
        self._Q = Q
        self._R = R
        self._z = z

        self.m = len(z)
        self.n = len(z[0])
        self._identity = numpy.ones([self.n, self.n])

        if (B is None):
            self._B = numpy.zeros([self.n, self.n])
        else:
            self._B = B
        if (impulse is None):
            self._impulse = numpy.zeros([self.m, self.n])
        else:
            self._impulse = impulse

    def __del__(self):
        return

    def _kalman(self, xb, Pb, z, impulse):
        # 測量更新
        tmp = numpy.matmul(Pb, self._H.T)
        K = numpy.matmul(tmp, numpy.linalg.inv(numpy.matmul(self._H, tmp) + self._R))
        x = xb + numpy.matmul(K, (z - numpy.matmul(self._H, xb)))
        P = numpy.matmul((self._identity - numpy.matmul(K, self._H)), Pb)
        # 時(shí)間更新
        xb = numpy.matmul(self._A, x) + numpy.matmul(self._B, impulse)
        Pb = numpy.matmul(numpy.matmul(self._A, P), self._A.T) + self._Q
        return x, xb, Pb

    def _kalman1d(self, xb, Pb, z, impulse):
        # 測量更新
        tmp = Pb*self._H
        K = tmp/(self._H*tmp + self._R)
        x = xb + K*(z - self._H*xb)
        P = (1 - K*self._H)*Pb
        # 時(shí)間更新
        xb = self._A*x + self._B*impulse
        Pb = self._A*P*self._A + self._Q
        return x, xb, Pb

    def get_filtered_data(self, xb, Pb):
        xx = []
        for i in range(0, self.m):
            if (self.n == 1):
                (x, xb, Pb) = self._kalman1d(xb, Pb, self._z[i], self._impulse[i])
            else:
                (x, xb, Pb) = self._kalman(xb, Pb, self._z[i], self._impulse[i])
            xx.append(x)
        return xx



# =========== test ===============
import matplotlib.pyplot

t = numpy.linspace(0,10,100)   # 橫坐標(biāo),時(shí)間
# ================= 2d ==================
A = numpy.array([[1,0.1], [0,1]])
H = numpy.array([[1,0],[0,1]])
Q = 0.5*numpy.array([[1,0],[0,1]])
R = 0.5*numpy.array([[1,0],[0,1]])
noise = numpy.random.randn(2, 100)
real = numpy.vstack((10*numpy.sin(t), 10*numpy.cos(t)))   # 真實(shí)值
z = real + noise   # 測量值
kf = Kalman_Filter(A, H, Q, R, z.T)
xb = numpy.array([0,10])
Pb = numpy.array([[1,0],[0,1]])
x = kf.get_filtered_data(xb, Pb)

fig = matplotlib.pyplot.figure(figsize=(10.24,7.68))
matplotlib.pyplot.plot(t, z.T, 'r')
matplotlib.pyplot.plot(t, real.T, 'g')
matplotlib.pyplot.plot(t, x, 'b')
matplotlib.pyplot.show()

# =================== 1d =================
A = 1
H = 1
Q = 0.5
R = 0.5
B = -1     # 根據(jù)反饋進(jìn)行修正
noise = numpy.random.randn(1, 100)
real = 10*numpy.exp(-t*t)
z = real + noise
kf1 = Kalman_Filter(A, H, Q, R, z.T)   # 不加反饋
kf2 = Kalman_Filter(A, H, Q, R, z.T, B, noise.T)   # 反饋修正
xb = 10
Pb = 1
x1 = kf1.get_filtered_data(xb, Pb)
x2 = kf2.get_filtered_data(xb, Pb)

fig = matplotlib.pyplot.figure(figsize=(10.24,7.68))
matplotlib.pyplot.subplot(3,1,1)  # 下面畫第一個(gè)圖,不帶反饋修正
matplotlib.pyplot.plot(t, z.T, 'r')
matplotlib.pyplot.plot(t, real.T, 'g')
matplotlib.pyplot.plot(t, x1, 'b')
matplotlib.pyplot.subplot(3,1,2)    # 下面畫第二個(gè)圖,帶反饋修正
matplotlib.pyplot.plot(t, z.T, 'r')
matplotlib.pyplot.plot(t, real.T, 'g')
matplotlib.pyplot.plot(t, x2, 'b')
matplotlib.pyplot.subplot(3,1,3)     # 下面畫第三個(gè)圖,比較帶反饋和不帶反饋的結(jié)果
matplotlib.pyplot.plot(t, x1, 'r')
matplotlib.pyplot.plot(t, real.T, 'g')
matplotlib.pyplot.plot(t, x2, 'b')
matplotlib.pyplot.show()

計(jì)算結(jié)果如下。可以看到,在大部分情況下,藍(lán)線(Kalman濾波結(jié)果)要比紅線(測量值)更加接近綠線(真實(shí)值)。在第二個(gè)圖中,對比了加入外部反饋以根據(jù)測量結(jié)果進(jìn)行修正和不加的情況??梢钥吹?,增加反饋后在某些較大的值處給出比較好的結(jié)果,在0點(diǎn)附近震蕩更加均勻。但反饋無法在所有位置都改善結(jié)果。

python實(shí)現(xiàn)kalman濾波的方法

python實(shí)現(xiàn)kalman濾波的方法

感謝各位的閱讀,以上就是“python實(shí)現(xiàn)kalman濾波的方法”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對python實(shí)現(xiàn)kalman濾波的方法這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI