2014-05-29 04:16:41 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
|
|
Created on Wed May 28 17:40:19 2014
|
|
|
|
|
|
|
|
@author: rlabbe
|
|
|
|
"""
|
|
|
|
|
|
|
|
from numpy import matrix, zeros, asmatrix, size
|
|
|
|
from numpy.linalg import cholesky
|
|
|
|
|
|
|
|
|
2014-06-01 02:57:33 +02:00
|
|
|
def sigma_points (mean, covariance, kappa):
|
2014-05-29 04:16:41 +02:00
|
|
|
""" Computes the sigma points and weights for an unscented Kalman filter.
|
|
|
|
xm are the means, and P is the covariance. kappa is an arbitrary constant
|
|
|
|
constant. Returns tuple of the sigma points and weights.
|
|
|
|
|
|
|
|
This is the original algorithm as published by Julier and Uhlmann.
|
|
|
|
Later algorithms introduce more parameters - alpha, beta,
|
|
|
|
|
|
|
|
Works with both scalar and array inputs:
|
|
|
|
sigma_points (5, 9, 2) # mean 5, covariance 9
|
|
|
|
sigma_points ([5, 2], 9*eye(2), 2) # means 5 and 2, covariance 9I
|
|
|
|
"""
|
|
|
|
|
2014-06-01 02:57:33 +02:00
|
|
|
mean = asmatrix(mean)
|
|
|
|
covariance = asmatrix(covariance)
|
2014-05-29 04:16:41 +02:00
|
|
|
|
|
|
|
n = size(mu)
|
|
|
|
|
|
|
|
# initialize to zero
|
|
|
|
Xi = asmatrix (zeros((n,2*n+1)))
|
|
|
|
W = asmatrix (zeros(2*n+1))
|
|
|
|
|
|
|
|
|
|
|
|
# all weights are 1/ 2(n+kappa)) except the first one.
|
|
|
|
W[0,1:] = 1. / (2*(n+kappa))
|
|
|
|
W[0,0] = float(kappa) / (n + kappa)
|
|
|
|
|
|
|
|
|
|
|
|
# use cholesky to find matrix square root of (n+kappa)*cov
|
|
|
|
# U'*U = (n+kappa)*P
|
2014-06-01 02:57:33 +02:00
|
|
|
U = asmatrix (cholesky((n+kappa)*covariance))
|
2014-05-29 04:16:41 +02:00
|
|
|
|
|
|
|
# mean is in location 0.
|
2014-06-01 02:57:33 +02:00
|
|
|
Xi[:,0] = mean
|
2014-05-29 04:16:41 +02:00
|
|
|
|
2014-06-01 02:57:33 +02:00
|
|
|
for col in range (n):
|
|
|
|
Xi[:, col+1] = mean + U[:, col]
|
2014-05-29 04:16:41 +02:00
|
|
|
|
|
|
|
for k in range (n):
|
2014-06-01 02:57:33 +02:00
|
|
|
Xi[:, n+col+1] = mean - U[:, col]
|
2014-05-29 04:16:41 +02:00
|
|
|
|
|
|
|
return (Xi, W)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def unscented_transform (Xi, W, NoiseCov=None):
|
2014-06-01 02:57:33 +02:00
|
|
|
""" computes the unscented transform of a set of sigma points 'X'
|
|
|
|
and weights 'W'.
|
|
|
|
|
|
|
|
W should be in the form:
|
|
|
|
|
|
|
|
[w0, w1, w2,...wn].T
|
|
|
|
|
|
|
|
where w0 is the mean,
|
|
|
|
|
|
|
|
Xi should be in the form:
|
|
|
|
[X_00,
|
|
|
|
|
|
|
|
|
|
|
|
returns the mean and covariance in a tuple '(mean, cov)'
|
2014-05-29 04:16:41 +02:00
|
|
|
"""
|
2014-06-01 02:57:33 +02:00
|
|
|
|
|
|
|
W = asmatrix(W)
|
2014-05-29 04:16:41 +02:00
|
|
|
Xi = asmatrix(Xi)
|
|
|
|
|
|
|
|
n, kmax = Xi.shape
|
|
|
|
|
|
|
|
# initialize results to 0
|
2014-06-01 02:57:33 +02:00
|
|
|
mean = matrix (zeros((n,1)))
|
|
|
|
cov = matrix (zeros((n,n)))
|
2014-05-29 04:16:41 +02:00
|
|
|
|
|
|
|
for k in range (kmax):
|
2014-06-01 02:57:33 +02:00
|
|
|
mean += W[0,k] * Xi[:,k]
|
2014-05-29 04:16:41 +02:00
|
|
|
|
|
|
|
for k in range (kmax):
|
|
|
|
cov += W[0,k]*(Xi[:,k]-mu) * (Xi[:,k]-mu).T
|
|
|
|
|
2014-06-01 02:57:33 +02:00
|
|
|
return (mean, cov)
|
|
|
|
|
2014-05-29 04:16:41 +02:00
|
|
|
|
2014-06-01 02:57:33 +02:00
|
|
|
if __name__ == "__main__":
|
2014-05-29 04:16:41 +02:00
|
|
|
|
2014-06-01 02:57:33 +02:00
|
|
|
xi = matrix ([[1,2,3,4,5,6,7],[1,2,3,4,5,6,7],[1,2,3,4,5,6,7]])
|
|
|
|
mu = matrix ([1,2,3,4,5,6,7])
|
2014-05-29 04:16:41 +02:00
|
|
|
|
2014-06-01 02:57:33 +02:00
|
|
|
m,c = unscented_transform(xi, mu)
|
|
|
|
print m
|
|
|
|
print c
|