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
18
19
from __future__ import (absolute_import, division, print_function,
20
unicode_literals)
21
22
23
from numpy import array, zeros, vstack, eye
24
from scipy.linalg import expm, inv
25
26
27
def Q_discrete_white_noise(dim, dt=1., var=1.):
28
""" Returns the Q matrix for the Discrete Constant White Noise
29
Model. dim may be either 2 or 3, dt is the time step, and sigma is the
30
variance in the noise.
31
32
Q is computed as the G * G^T * variance, where G is the process noise per
33
time step. In other words, G = [[.5dt^2][dt]]^T for the constant velocity
34
model.
35
36
**Paramaeters**
37
38
dim : int (2 or 3)
39
dimension for Q, where the final dimension is (dim x dim)
40
41
dt : float, default=1.0
42
time step in whatever units your filter is using for time. i.e. the
43
amount of time between innovations
44
45
var : float, default=1.0
46
variance in the noise
47
"""
48
49
assert dim == 2 or dim == 3
50
if dim == 2:
51
Q = array([[.25*dt**4, .5*dt**3],
52
[ .5*dt**3, dt**2]], dtype=float)
53
else:
54
Q = array([[.25*dt**4, .5*dt**3, .5*dt**2],
55
[ .5*dt**3, dt**2, dt],
56
[ .5*dt**2, dt, 1]], dtype=float)
57
58
return Q * var
59
60
def Q_continuous_white_noise(dim, dt=1., spectral_density=1.):
61
""" Returns the Q matrix for the Discretized Continuous White Noise
62
Model. dim may be either 2 or 3, dt is the time step, and sigma is the
63
variance in the noise.
64
65
**Paramaeters**
66
67
dim : int (2 or 3)
68
dimension for Q, where the final dimension is (dim x dim)
69
70
dt : float, default=1.0
71
time step in whatever units your filter is using for time. i.e. the
72
amount of time between innovations
73
74
spectral_density : float, default=1.0
75
spectral density for the continuous process
76
"""
77
78
assert dim == 2 or dim == 3
79
if dim == 2:
80
Q = array([[(dt**4)/3, (dt**2)/2],
81
[(dt**2)/2, dt]])
82
else:
83
Q = array([[(dt**5)/20, (dt**4)/8, (dt**3)/6],
84
[ (dt**4)/8, (dt**3)/3, (dt**2)/2],
85
[ (dt**3)/6, (dt**2)/2, dt]], dtype=float)
86
87
return Q * spectral_density
88
89
90
def van_loan_discretization(F, G, dt):
91
92
""" Discretizes a linear differential equation which includes white noise
93
according to the method of C. F. van Loan [1]. Given the continuous
94
model
95
96
x' = Fx + Gu
97
98
where u is the unity white noise, we compute and return the sigma and Q_k
99
that discretizes that equation.
100
101
102
**Example**::
103
104
Given y'' + y = 2u(t), we create the continuous state model of
105
106
x' = | 0 1| * x + |0|*u(t)
107
|-1 0| |2|
108
109
and a time step of 0.1:
110
111
112
>>> F = np.array([[0,1],[-1,0]], dtype=float)
113
>>> G = np.array([[0.],[2.]])
114
>>> phi, Q = van_loan_discretization(F, G, 0.1)
115
116
>>> phi
117
array([[ 0.99500417, 0.09983342],
118
[-0.09983342, 0.99500417]])
119
120
>>> Q
121
array([[ 0.00133067, 0.01993342],
122
[ 0.01993342, 0.39866933]])
123
124
(example taken from Brown[2])
125
126
127
**References**
128
129
[1] C. F. van Loan. "Computing Integrals Involving the Matrix Exponential."
130
IEEE Trans. Automomatic Control, AC-23 (3): 395-404 (June 1978)
131
132
[2] Robert Grover Brown. "Introduction to Random Signals and Applied
133
Kalman Filtering." Forth edition. John Wiley & Sons. p. 126-7. (2012)
134
"""
135
136
137
n = F.shape[0]
138
139
A = zeros((2*n, 2*n))
140
141
# we assume u(t) is unity, and require that G incorporate the scaling term
142
# for the noise. Hence W = 1, and GWG' reduces to GG"
143
144
A[0:n, 0:n] = -F.dot(dt)
145
A[0:n, n:2*n] = G.dot(G.T).dot(dt)
146
A[n:2*n, n:2*n] = F.T.dot(dt)
147
148
B=expm(A)
149
150
sigma = B[n:2*n, n:2*n].T
151
152
Q = sigma.dot(B[0:n, n:2*n])
153
154
return (sigma, Q)
155
156
157
def linear_ode_discretation(F, L=None, Q=None, dt=1):
158
n = F.shape[0]
159
160
if L is None:
161
L = eye(n)
162
163
if Q is None:
164
Q = zeros((n,n))
165
166
A = expm(F*dt)
167
168
phi = zeros((2*n, 2*n))
169
170
phi[0:n, 0:n] = F
171
phi[0:n, n:2*n] = L.dot(Q).dot(L.T)
172
phi[n:2*n, n:2*n] = -F.T
173
174
zo = vstack((zeros((n,n)), eye(n)))
175
176
CD = expm(phi*dt).dot(zo)
177
178
C = CD[0:n,:]
179
D = CD[n:2*n,:]
180
q = C.dot(inv(D))
181
182
return (A, q)
183
184
185
186
187
188
189
190
191