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
from __future__ import (absolute_import, division, print_function,
19
unicode_literals)
20
21
import numpy as np
22
from scipy.linalg import inv
23
from numpy import dot, zeros, eye
24
from filterpy.common import dot3, dot4, dotn
25
26
27
class FixedLagSmoother(object):
28
""" Fixed Lag Kalman smoother.
29
30
Computes a smoothed sequence from a set of measurements based on the
31
fixed lag Kalman smoother. At time k, for a lag N, the fixed-lag smoother
32
computes the state estimate for time k-N based on all measurements made
33
between times k-N and k. This yields a pretty good smoothed result with
34
O(N) extra computations performed for each measurement. In other words,
35
if N=4 this will consume about 5x the number of computations as a
36
basic Kalman filter. However, the loops contain only 3 dot products, so it
37
will be much faster than this sounds as the main Kalman filter loop
38
involves transposes and inverses, as well as many more matrix
39
multiplications.
40
41
Implementation based on Wikipedia article as it existed on
42
November 18, 2014.
43
44
45
**Example**::
46
47
fls = FixedLagSmoother(dim_x=2, dim_z=1)
48
49
fls.x = np.array([[0.],
50
[.5]])
51
52
fls.F = np.array([[1.,1.],
53
[0.,1.]])
54
55
fls.H = np.array([[1.,0.]])
56
57
fls.P *= 200
58
fls.R *= 5.
59
fls.Q *= 0.001
60
61
zs = [...some measurements...]
62
xhatsmooth, xhat = fls.smooth_batch(zs, N=4)
63
64
65
**References**
66
67
Wikipedia http://en.wikipedia.org/wiki/Kalman_filter#Fixed-lag_smoother
68
69
Simon, Dan. "Optimal State Estimation," John Wiley & Sons pp 274-8 (2006).
70
71
|
72
|
73
74
**Methods**
75
"""
76
77
78
def __init__(self, dim_x, dim_z, N=None):
79
""" Create a fixed lag Kalman filter smoother. You are responsible for
80
setting the various state variables to reasonable values; the defaults
81
below will not give you a functional filter.
82
83
**Parameters**
84
85
dim_x : int
86
Number of state variables for the Kalman filter. For example, if
87
you are tracking the position and velocity of an object in two
88
dimensions, dim_x would be 4.
89
90
This is used to set the default size of P, Q, and u
91
92
dim_z : int
93
Number of of measurement inputs. For example, if the sensor
94
provides you with position in (x,y), dim_z would be 2.
95
96
N : int, optional
97
If provided, the size of the lag. Not needed if you are only
98
using smooth_batch() function. Required if calling smooth()
99
"""
100
101
self.dim_x = dim_x
102
self.dim_z = dim_z
103
self.N = N
104
105
self.x = zeros((dim_x,1)) # state
106
self.x_s = zeros((dim_x,1)) # smoothed state
107
self.P = eye(dim_x) # uncertainty covariance
108
self.Q = eye(dim_x) # process uncertainty
109
self.F = 0 # state transition matrix
110
self.H = 0 # Measurement function
111
self.R = eye(dim_z) # state uncertainty
112
self.K = 0 # kalman gain
113
self.residual = zeros((dim_z, 1))
114
115
self.B = 0
116
117
# identity matrix. Do not alter this.
118
self._I = np.eye(dim_x)
119
120
self.count = 0
121
122
if N is not None:
123
self.xSmooth = []
124
125
126
127
def smooth(self, z, u=None):
128
""" Smooths the measurement using a fixed lag smoother.
129
130
On return, self.xSmooth is populated with the N previous smoothed
131
estimates, where self.xSmooth[k] is the kth time step. self.x
132
merely contains the current Kalman filter output of the most recent
133
measurement, and is not smoothed at all (beyond the normal Kalman
134
filter processing).
135
136
self.xSmooth grows in length on each call. If you run this 1 million
137
times, it will contain 1 million elements. Sure, we could minimize
138
this, but then this would make the caller's code much more cumbersome.
139
140
This also means that you cannot use this filter to track more than
141
one data set; as data will be hopelessly intermingled. If you want
142
to filter something else, create a new FixedLagSmoother object.
143
144
**Parameters**
145
146
z : ndarray or scalar
147
measurement to be smoothed
148
149
150
u : ndarray, optional
151
If provided, control input to the filter
152
"""
153
154
# take advantage of the fact that np.array are assigned by reference.
155
H = self.H
156
R = self.R
157
F = self.F
158
P = self.P
159
x = self.x
160
Q = self.Q
161
B = self.B
162
N = self.N
163
164
k = self.count
165
166
# predict step of normal Kalman filter
167
x_pre = dot(F, x)
168
if u is not None:
169
x_pre += dot(B,u)
170
171
P = dot3(F, P, F.T) + Q
172
173
# update step of normal Kalman filter
174
y = z - dot(H, x_pre)
175
176
S = dot3(H, P, H.T) + R
177
SI = inv(S)
178
179
K = dot3(P, H.T, SI)
180
181
x = x_pre + dot(K, y)
182
183
I_KH = self._I - dot(K, H)
184
P = dot3(I_KH, P, I_KH.T) + dot3(K, R, K.T)
185
186
self.xSmooth.append(x_pre.copy())
187
188
#compute invariants
189
HTSI = dot(H.T, SI)
190
F_LH = (F - dot(K,H)).T
191
192
if k >= N:
193
PS = P.copy() # smoothed P for step i
194
for i in range (N):
195
K = dot(PS, HTSI) # smoothed gain
196
PS = dot(PS, F_LH) # smoothed covariance
197
198
si = k-i
199
self.xSmooth[si] = self.xSmooth[si] + dot(K, y)
200
else:
201
# Some sources specify starting the fix lag smoother only
202
# after N steps have passed, some don't. I am getting far
203
# better results by starting only at step N.
204
self.xSmooth[k] = x.copy()
205
206
self.count += 1
207
self.x = x
208
self.P = P
209
210
211
212
def smooth_batch(self, zs, N, us=None):
213
""" batch smooths the set of measurements using a fixed lag smoother.
214
I consider this function a somewhat pedalogical exercise; why would
215
you not use a RTS smoother if you are able to batch process your data?
216
Hint: RTS is a much better smoother, and faster besides. Use it.
217
218
This is a batch processor, so it does not alter any of the object's
219
data. In particular, self.x is NOT modified. All date is returned
220
by the function.
221
222
**Parameters**
223
224
225
zs : ndarray of measurements
226
227
iterable list (usually ndarray, but whatever works for you) of
228
measurements that you want to smooth, one per time step.
229
230
N : int
231
size of fixed lag in time steps
232
233
us : ndarray, optional
234
235
If provided, control input to the filter for each time step
236
237
238
**Returns**
239
240
(xhat_smooth, xhat) : ndarray, ndarray
241
242
xhat_smooth is the output of the N step fix lag smoother
243
xhat is the filter output of the standard Kalman filter
244
"""
245
246
247
# take advantage of the fact that np.array are assigned by reference.
248
H = self.H
249
R = self.R
250
F = self.F
251
P = self.P
252
x = self.x
253
Q = self.Q
254
B = self.B
255
256
if x.ndim == 1:
257
xSmooth = zeros((len(zs), self.dim_x))
258
xhat = zeros((len(zs), self.dim_x))
259
else:
260
xSmooth = zeros((len(zs), self.dim_x, 1))
261
xhat = zeros((len(zs), self.dim_x, 1))
262
for k, z in enumerate(zs):
263
264
# predict step of normal Kalman filter
265
x_pre = dot(F, x)
266
if us is not None:
267
x_pre += dot(B,us[k])
268
269
P = dot3(F, P, F.T) + Q
270
271
# update step of normal Kalman filter
272
y = z - dot(H, x_pre)
273
274
S = dot3(H, P, H.T) + R
275
SI = inv(S)
276
277
K = dot3(P, H.T, SI)
278
279
x = x_pre + dot(K, y)
280
281
I_KH = self._I - dot(K, H)
282
P = dot3(I_KH, P, I_KH.T) + dot3(K, R, K.T)
283
284
xhat[k] = x.copy()
285
xSmooth[k] = x_pre.copy()
286
287
#compute invariants
288
HTSI = dot(H.T, SI)
289
F_LH = (F - dot(K,H)).T
290
291
if k >= N:
292
PS = P.copy() # smoothed P for step i
293
for i in range (N):
294
K = dot(PS, HTSI) # smoothed gain
295
PS = dot(PS, F_LH) # smoothed covariance
296
297
si = k-i
298
xSmooth[si] = xSmooth[si] + dot(K, y)
299
else:
300
# Some sources specify starting the fix lag smoother only
301
# after N steps have passed, some don't. I am getting far
302
# better results by starting only at step N.
303
xSmooth[k] = xhat[k]
304
305
return xSmooth, xhat
306
307