Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
96129 views
1
# -*- coding: utf-8 -*-
2
"""Copyright 2015 Roger R Labbe Jr.
3
4
FilterPy library.
5
http://github.com/rlabbe/filterpy
6
7
Documentation at:
8
https://filterpy.readthedocs.org
9
10
Supporting book at:
11
https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python
12
13
This is licensed under an MIT license. See the readme.MD file
14
for more information.
15
"""
16
17
import numpy as np
18
19
20
def unscented_transform(sigmas, Wm, Wc, noise_cov=None,
21
mean_fn=None, residual_fn=None):
22
""" Computes unscented transform of a set of sigma points and weights.
23
returns the mean and covariance in a tuple.
24
25
**Parameters**
26
27
28
sigamas: ndarray [#sigmas per dimension, dimension]
29
2D array of sigma points.
30
31
Wm : ndarray [# sigmas per dimension]
32
Weights for the mean. Must sum to 1.
33
34
35
Wc : ndarray [# sigmas per dimension]
36
Weights for the covariance. Must sum to 1.
37
38
noise_cov : ndarray, optional
39
noise matrix added to the final computed covariance matrix.
40
41
mean_fn : callable (sigma_points, weights), optional
42
Function that computes the mean of the provided sigma points
43
and weights. Use this if your state variable contains nonlinear
44
values such as angles which cannot be summed.
45
46
.. code-block:: Python
47
48
def state_mean(sigmas, Wm):
49
x = np.zeros(3)
50
sum_sin, sum_cos = 0., 0.
51
52
for i in range(len(sigmas)):
53
s = sigmas[i]
54
x[0] += s[0] * Wm[i]
55
x[1] += s[1] * Wm[i]
56
sum_sin += sin(s[2])*Wm[i]
57
sum_cos += cos(s[2])*Wm[i]
58
x[2] = atan2(sum_sin, sum_cos)
59
return x
60
61
residual_fn : callable (x, y), optional
62
63
Function that computes the residual (difference) between x and y.
64
You will have to supply this if your state variable cannot support
65
subtraction, such as angles (359-1 degreees is 2, not 358). x and y
66
are state vectors, not scalars.
67
68
.. code-block:: Python
69
70
def residual(a, b):
71
y = a[0] - b[0]
72
if y > np.pi:
73
y -= 2*np.pi
74
if y < -np.pi:
75
y = 2*np.pi
76
return y
77
78
79
**Returns**
80
81
x : ndarray [dimension]
82
Mean of the sigma points after passing through the transform.
83
84
P : ndarray
85
covariance of the sigma points after passing throgh the transform.
86
"""
87
88
kmax, n = sigmas.shape
89
90
91
if mean_fn is None:
92
# new mean is just the sum of the sigmas * weight
93
x = np.dot(Wm, sigmas) # dot = \Sigma^n_1 (W[k]*Xi[k])
94
else:
95
x = mean_fn(sigmas, Wm)
96
97
98
# new covariance is the sum of the outer product of the residuals
99
# times the weights
100
101
# this is the fast way to do this - see 'else' for the slow way
102
if residual_fn is None:
103
y = sigmas - x[np.newaxis,:]
104
P = y.T.dot(np.diag(Wc)).dot(y)
105
else:
106
P = np.zeros((n, n))
107
for k in range(kmax):
108
y = residual_fn(sigmas[k], x)
109
P += Wc[k] * np.outer(y, y)
110
111
if noise_cov is not None:
112
P += noise_cov
113
114
return (x, P)
115
116