# -*- coding: utf-8 -*- import numpy as np import numpy.matlib as mt import matplotlib.pyplot as plt M = 2 N = 500 dt = 1.0 / 30. sigma_measure = 0.1 # x = 1/2 a t**2 # assume x = 0.5 in 0.5, i.e. head turns half maximal movement range in 0.5 sec. # so a = 2 x / t**2 = 4.0 sigma_accel = 4.0 x = np.zeros(N, dtype = np.float) x[N/3:] = 1.0 # step input measurement = x.copy() measurement += np.random.normal(0., sigma_measure, N) A = np.matrix([ [ 1. , dt ], [ 0. , 1. ] ]) R = np.matrix([[ sigma_measure**2 ]]) dv = sigma_accel * dt dp = sigma_accel * 0.5 * dt * dt Q = np.matrix([ [ dp*dp, dp*dv ], [ dv*dp, dv*dv ] ]) H = np.matrix([ [ 1., 0. ], ]) I = mt.identity(M, dtype = np.float) def arrayOfMatrices(n, shape): return np.asarray([mt.zeros(shape, dtype = np.float) for i in xrange(n)]) # Base on the scipy-cookbook http://scipy-cookbook.readthedocs.io/items/KalmanFiltering.html sz_state = (M, 1) sz_cov = (M, M) sz_K = (M, 1) xhat= arrayOfMatrices(N, sz_state) # a posteri estimate of x P=arrayOfMatrices(N, sz_cov) # a posteri error estimate xhatminus=arrayOfMatrices(N, sz_state) # a priori estimate of x Pminus=arrayOfMatrices(N, sz_cov) # a priori error estimate K=arrayOfMatrices(N, sz_K) # gain or blending factor P[0] = mt.ones((M,M)) * 100 xhat[0] = measurement[0] for k in range(1,N): # time update xhatminus[k] = A * xhat[k-1] Pminus[k] = A * P[k-1] * A.T + Q # measurement update K[k] = Pminus[k] * H.T * np.linalg.inv( H * Pminus[k] * H.T + R ) xhat[k] = xhatminus[k] + K[k] * (measurement[k] - H * xhatminus[k]) P[k] = ( I - K[k]*H ) * Pminus[k] t = np.arange(N) * dt plt.figure() plt.subplot(2,1,1) plt.plot(t, measurement,'k+',label='noisy measurements') plt.plot(t, xhat[:,0,0],'b-',label='position estimate') plt.plot(t, x, 'r-', label='ground truth') plt.subplot(2,1,2) plt.plot(t, xhat[:,1,0],'g-',label='velocity estimate') plt.show()