Skip to content

Commit 052edec

Browse files
committed
added preliminary version of lqe function, which calculates the gain for a steady-state Kalman filter.
1 parent a4b4c43 commit 052edec

1 file changed

Lines changed: 73 additions & 1 deletion

File tree

control/statefbk.py

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,11 @@
4343
import numpy as np
4444
import scipy as sp
4545
from . import statesp
46+
from .mateqn import care
4647
from .statesp import _ssmatrix
4748
from .exception import ControlSlycot, ControlArgument, ControlDimension
4849

49-
__all__ = ['ctrb', 'obsv', 'gram', 'place', 'place_varga', 'lqr', 'acker']
50+
__all__ = ['ctrb', 'obsv', 'gram', 'place', 'place_varga', 'lqr', 'lqe', 'acker']
5051

5152

5253
# Pole placement
@@ -219,6 +220,73 @@ def place_varga(A, B, p, dtime=False, alpha=None):
219220
# Return the gain matrix, with MATLAB gain convention
220221
return _ssmatrix(-F)
221222

223+
# contributed by Sawyer B. Fuller <minster@uw.edu>
224+
def lqe(A, G, C, QN, RN, NN=None):
225+
"""lqe(A, G, C, QN, RN, [, N])
226+
227+
Linear quadratic estimator design (Kalman filter) for continuous-time
228+
systems. Given the system
229+
230+
Given the system
231+
.. math::
232+
x = Ax + Bu + Gw
233+
y = Cx + Du + v
234+
235+
with unbiased process noise w and measurement noise v with covariances
236+
237+
.. math:: E{ww'} = QN, E{vv'} = RN, E{wv'} = NN
238+
239+
The lqe() function computes the observer gain matrix L such that the
240+
stationary (non-time-varying) Kalman filter
241+
242+
.. math:: x_e = A x_e + B u + L(y - C x_e - D u)
243+
244+
produces a state estimate that x_e that minimizes the expected squared error
245+
using the sensor measurements y. The noise cross-correlation `NN` is set to
246+
zero when omitted.
247+
248+
Parameters
249+
----------
250+
A, G: 2-d array
251+
Dynamics and noise input matrices
252+
QN, RN: 2-d array
253+
Process and sensor noise covariance matrices
254+
NN: 2-d array, optional
255+
Cross covariance matrix
256+
257+
Returns
258+
-------
259+
L: 2D array
260+
Kalman estimator gain
261+
P: 2D array
262+
Solution to Riccati equation
263+
.. math::
264+
A P + P A^T - (P C^T + G N) R^-1 (C P + N^T G^T) + G Q G^T = 0
265+
E: 1D array
266+
Eigenvalues of estimator poles eig(A - L C)
267+
268+
269+
Examples
270+
--------
271+
>>> K, P, E = lqe(A, G, C, QN, RN)
272+
>>> K, P, E = lqe(A, G, C, QN, RN, NN)
273+
274+
See Also
275+
--------
276+
lqr
277+
"""
278+
279+
# TODO: incorporate cross-covariance NN, something like this,
280+
# which doesn't work for some reason
281+
#if NN is None:
282+
# NN = np.zeros(QN.size(0),RN.size(1))
283+
#NG = G @ NN
284+
285+
#LT, P, E = lqr(A.T, C.T, G @ QN @ G.T, RN)
286+
P, E, LT = care(A.T, C.T, G @ QN @ G.T, RN)
287+
return _ssmatrix(LT.T), _ssmatrix(P), _ssmatrix(E)
288+
289+
222290
# Contributed by Roberto Bucher <roberto.bucher@supsi.ch>
223291
def acker(A, B, poles):
224292
"""Pole placement using Ackermann method
@@ -307,6 +375,10 @@ def lqr(*args, **keywords):
307375
>>> K, S, E = lqr(sys, Q, R, [N])
308376
>>> K, S, E = lqr(A, B, Q, R, [N])
309377
378+
See Also
379+
--------
380+
lqe
381+
310382
"""
311383

312384
# Make sure that SLICOT is installed

0 commit comments

Comments
 (0)