Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
96129 views
1
# -*- coding: utf-8 -*-
2
3
"""Copyright 2015 Roger R Labbe Jr.
4
5
FilterPy library.
6
http://github.com/rlabbe/filterpy
7
8
Documentation at:
9
https://filterpy.readthedocs.org
10
11
Supporting book at:
12
https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python
13
14
This is licensed under an MIT license. See the readme.MD file
15
for more information.
16
"""
17
18
19
from __future__ import (absolute_import, division, print_function,
20
unicode_literals)
21
import numpy as np
22
from scipy.linalg import inv
23
from numpy import dot, zeros, eye, asarray
24
from filterpy.common import setter, setter_scalar, dot3
25
26
27
28
class InformationFilter(object):
29
30
def __init__(self, dim_x, dim_z, dim_u=0):
31
""" Create a Information filter. You are responsible for setting the
32
various state variables to reasonable values; the defaults below will
33
not give you a functional filter.
34
35
**Parameters**
36
37
dim_x : int
38
Number of state variables for the filter. For example, if you
39
are tracking the position and velocity of an object in two
40
dimensions, dim_x would be 4.
41
42
This is used to set the default size of P, Q, and u
43
44
dim_z : int
45
Number of of measurement inputs. For example, if the sensor
46
provides you with position in (x,y), dim_z would be 2.
47
48
dim_u : int (optional)
49
size of the control input, if it is being used.
50
Default value of 0 indicates it is not used.
51
"""
52
53
assert dim_x > 0
54
assert dim_z > 0
55
assert dim_u >= 0
56
57
self.dim_x = dim_x
58
self.dim_z = dim_z
59
self.dim_u = dim_u
60
61
self._x = zeros((dim_x,1)) # state
62
self._P_inv = eye(dim_x) # uncertainty covariance
63
self._Q = eye(dim_x) # process uncertainty
64
self._B = 0 # control transition matrix
65
self._F = 0 # state transition matrix
66
self._F_inv = 0 # state transition matrix
67
self._H = 0 # Measurement function
68
self._R_inv = eye(dim_z) # state uncertainty
69
70
# gain and residual are computed during the innovation step. We
71
# save them so that in case you want to inspect them for various
72
# purposes
73
self._K = 0 # kalman gain
74
self._y = zeros((dim_z, 1))
75
self._S = 0 # system uncertainty in measurement space
76
77
# identity matrix. Do not alter this.
78
self._I = np.eye(dim_x)
79
self._no_information = False
80
81
82
def update(self, z, R_inv=None):
83
"""
84
Add a new measurement (z) to the kalman filter. If z is None, nothing
85
is changed.
86
87
**Parameters**
88
89
z : np.array
90
measurement for this update.
91
92
R : np.array, scalar, or None
93
Optionally provide R to override the measurement noise for this
94
one call, otherwise self.R will be used.
95
"""
96
97
if z is None:
98
return
99
100
if R_inv is None:
101
R_inv = self._R_inv
102
elif np.isscalar(R_inv):
103
R_inv = eye(self.dim_z) * R_inv
104
105
# rename for readability and a tiny extra bit of speed
106
H = self._H
107
H_T = H.T
108
P_inv = self._P_inv
109
x = self._x
110
111
if self._no_information:
112
self._x = dot(P_inv, x) + dot3(H_T, R_inv, z)
113
self._P_inv = P_inv + dot3(H_T, R_inv, H)
114
115
else: # y = z - Hx
116
# error (residual) between measurement and prediction
117
self._y = z - dot(H, x)
118
119
# S = HPH' + R
120
# project system uncertainty into measurement space
121
self._S = P_inv + dot(H_T, R_inv).dot (H)
122
self._K = dot3(inv(self._S), H_T, R_inv)
123
124
# x = x + Ky
125
# predict new x with residual scaled by the kalman gain
126
self._x = x + dot(self._K, self._y)
127
self._P_inv = P_inv + dot3(H_T, R_inv, H)
128
129
130
def predict(self, u=0):
131
""" Predict next position.
132
133
**Parameters**
134
135
u : np.array
136
Optional control vector. If non-zero, it is multiplied by B
137
to create the control input into the system.
138
"""
139
140
# x = Fx + Bu
141
142
A = dot3(self._F_inv.T, self._P_inv, self._F_inv)
143
try:
144
AI = inv(A)
145
invertable = True
146
if self._no_information:
147
try:
148
self._x = dot(inv(self._P_inv), self._x)
149
except:
150
self._x = dot(0, self._x)
151
self._no_information = False
152
except:
153
invertable = False
154
self._no_information = True
155
156
if invertable:
157
self._x = dot(self._F, self.x) + dot(self._B, u)
158
self._P_inv = inv(AI + self._Q)
159
else:
160
I_PF = self._I - dot(self._P_inv,self._F_inv)
161
FTI = inv(self._F.T)
162
FTIX = dot(FTI, self._x)
163
print('Q=', self._Q)
164
print('A=', A)
165
AQI = inv(A + self._Q)
166
self._x = dot(FTI, dot3(I_PF, AQI, FTIX))
167
168
169
def batch_filter(self, zs, Rs=None, update_first=False):
170
""" Batch processes a sequences of measurements.
171
172
**Parameters**
173
174
zs : list-like
175
list of measurements at each time step `self.dt` Missing
176
measurements must be represented by 'None'.
177
178
Rs : list-like, optional
179
optional list of values to use for the measurement error
180
covariance; a value of None in any position will cause the filter
181
to use `self.R` for that time step.
182
183
update_first : bool, optional,
184
controls whether the order of operations is update followed by
185
predict, or predict followed by update. Default is predict->update.
186
187
**Returns**
188
189
means: np.array((n,dim_x,1))
190
array of the state for each time step. Each entry is an np.array.
191
In other words `means[k,:]` is the state at step `k`.
192
193
covariance: np.array((n,dim_x,dim_x))
194
array of the covariances for each time step. In other words
195
`covariance[k,:,:]` is the covariance at step `k`.
196
"""
197
198
raise "this is not implemented yet"
199
200
''' this is a copy of the code from kalman_filter, it has not been
201
turned into the informatio filter yet. DO NOT USE.'''
202
203
n = np.size(zs,0)
204
if Rs is None:
205
Rs = [None]*n
206
207
# mean estimates from Kalman Filter
208
means = zeros((n,self.dim_x,1))
209
210
# state covariances from Kalman Filter
211
covariances = zeros((n,self.dim_x,self.dim_x))
212
213
if update_first:
214
for i,(z,r) in enumerate(zip(zs,Rs)):
215
self.update(z,r)
216
means[i,:] = self._x
217
covariances[i,:,:] = self._P
218
self.predict()
219
else:
220
for i,(z,r) in enumerate(zip(zs,Rs)):
221
self.predict()
222
self.update(z,r)
223
224
means[i,:] = self._x
225
covariances[i,:,:] = self._P
226
227
return (means, covariances)
228
229
230
def get_prediction(self, u=0):
231
""" Predicts the next state of the filter and returns it. Does not
232
alter the state of the filter.
233
234
**Parameters**
235
236
u : np.array
237
optional control input
238
239
**Returns**
240
241
(x, P)
242
State vector and covariance array of the prediction.
243
"""
244
raise "Not implemented yet"
245
246
x = dot(self._F, self._x) + dot(self._B, u)
247
P = dot3(self._F, self._P, self._F.T) + self.Q
248
return (x, P)
249
250
251
def residual_of(self, z):
252
""" returns the residual for the given measurement (z). Does not alter
253
the state of the filter.
254
"""
255
raise "Not implemented yet"
256
return z - dot(self._H, self._x)
257
258
259
def measurement_of_state(self, x):
260
""" Helper function that converts a state into a measurement.
261
262
**Parameters**
263
264
x : np.array
265
kalman state vector
266
267
**Returns**
268
269
z : np.array
270
measurement corresponding to the given state
271
"""
272
raise "Not implemented yet"
273
return dot(self._H, x)
274
275
276
@property
277
def Q(self):
278
""" Process uncertainty"""
279
return self._Q
280
281
282
@Q.setter
283
def Q(self, value):
284
self._Q = setter_scalar(value, self.dim_x)
285
286
@property
287
def P_inv(self):
288
""" inverse covariance matrix"""
289
return self._P_inv
290
291
292
@P_inv.setter
293
def P_inv(self, value):
294
self._P_inv = setter_scalar(value, self.dim_x)
295
296
297
@property
298
def R_inv(self):
299
""" measurement uncertainty"""
300
return self._R_inv
301
302
303
@R_inv.setter
304
def R_inv(self, value):
305
self._R_inv = setter_scalar(value, self.dim_z)
306
307
@property
308
def H(self):
309
return self._H
310
311
312
@H.setter
313
def H(self, value):
314
self._H = setter(value, self.dim_z, self.dim_x)
315
316
317
@property
318
def F(self):
319
return self._F
320
321
322
@F.setter
323
def F(self, value):
324
self._F = setter(value, self.dim_x, self.dim_x)
325
self._F_inv = inv(self._F)
326
327
@property
328
def B(self):
329
""" control transition matrix"""
330
return self._B
331
332
333
@B.setter
334
def B(self, value):
335
""" control transition matrix"""
336
self._B = setter (value, self.dim_x, self.dim_u)
337
338
339
@property
340
def x(self):
341
return self._x
342
343
344
@x.setter
345
def x(self, value):
346
self._x = setter(value, self.dim_x, 1)
347
348
@property
349
def K(self):
350
""" Kalman gain """
351
return self._K
352
353
@property
354
def y(self):
355
""" measurement residual (innovation) """
356
return self._y
357
358
@property
359
def S(self):
360
""" system uncertainy in measurement space """
361
return self._S
362
363
364
365
366