Skip to content

Commit 0fa431c

Browse files
sawyerbfullermurrayrm
authored andcommitted
dare and care now use scipy routines if slycot not available. fixed bug in non-slycot care. lqr, lqe, dlqr, dlqe now get tested without slycot.
1 parent 04cfe65 commit 0fa431c

File tree

3 files changed

+27
-9
lines changed

3 files changed

+27
-9
lines changed

control/mateqn.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,8 @@ def dare(A, B, Q, R, S=None, E=None, stabilizing=True, method=None):
527527
:math:`A^T X A - E^T X E - (A^T X B + S) (B^T X B + R)^{-1} (B^T X A + S^T) + Q = 0`
528528
529529
where A, Q and E are square matrices of the same dimension. Further, Q and
530-
R are symmetric matrices. The function returns the solution X, the gain
530+
R are symmetric matrices. If R is None, it is set to the identity
531+
matrix. The function returns the solution X, the gain
531532
matrix :math:`G = (B^T X B + R)^{-1} (B^T X A + S^T)` and the closed loop
532533
eigenvalues L, i.e., the eigenvalues of A - B G , E.
533534

control/statefbk.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ def lqe(*args, **keywords):
403403
P, E, LT = care(A.T, C.T, G @ Q @ G.T, R, method=method)
404404
return _ssmatrix(LT.T), _ssmatrix(P), E
405405

406+
406407
# contributed by Sawyer B. Fuller <minster@uw.edu>
407408
def dlqe(A, G, C, QN, RN, NN=None):
408409
"""dlqe(A, G, C, QN, RN, [, N])
@@ -473,10 +474,7 @@ def dlqe(A, G, C, QN, RN, NN=None):
473474
# NN = np.zeros(QN.size(0),RN.size(1))
474475
# NG = G @ NN
475476

476-
# LT, P, E = lqr(A.T, C.T, G @ QN @ G.T, RN)
477-
# P, E, LT = care(A.T, C.T, G @ QN @ G.T, RN)
478-
A, G, C = np.array(A, ndmin=2), np.array(G, ndmin=2), np.array(C, ndmin=2)
479-
QN, RN = np.array(QN, ndmin=2), np.array(RN, ndmin=2)
477+
A, G, C, QN, RN = map(np.atleast_2d, (A, G, C, QN, RN))
480478
P, E, LT = dare(A.T, C.T, np.dot(np.dot(G, QN), G.T), RN)
481479
return _ssmatrix(LT.T), _ssmatrix(P), E
482480

@@ -574,7 +572,7 @@ def lqr(*args, **keywords):
574572
575573
See Also
576574
--------
577-
lqe
575+
lqe, dlqr, dlqe
578576
579577
Notes
580578
-----
@@ -622,6 +620,7 @@ def lqr(*args, **keywords):
622620
X, L, G = care(A, B, Q, R, N, None, method=method)
623621
return G, X, L
624622

623+
625624
def dlqr(*args, **keywords):
626625
"""dlqr(A, B, Q, R[, N])
627626

control/tests/statefbk_test.py

+21-3
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def testAcker(self, fixedseed):
166166
continue
167167

168168
# Place the poles at random locations
169-
des = rss(states, 1, 1);
169+
des = rss(states, 1, 1)
170170
poles = pole(des)
171171

172172
# Now place the poles using acker
@@ -339,6 +339,11 @@ def test_DLQR_3args(self, matarrayin, matarrayout, method):
339339
K, S, poles = dlqr(dsys, Q, R, method=method)
340340
self.check_DLQR(K, S, poles, Q, R)
341341

342+
def test_DLQR_4args(self, matarrayin, matarrayout):
343+
A, B, Q, R = (matarrayin([[X]]) for X in [0., 1., 10., 2.])
344+
K, S, poles = dlqr(A, B, Q, R)
345+
self.check_DLQR(K, S, poles, Q, R)
346+
342347
def test_lqr_badmethod(self):
343348
A, B, Q, R = 0, 1, 10, 2
344349
with pytest.raises(ControlArgument, match="Unknown method"):
@@ -469,8 +474,21 @@ def test_lqe_call_format(self):
469474
with pytest.raises(ct.ControlDimension, match="incorrect covariance"):
470475
L, P, E = lqe(sys.A, sys.B, sys.C, R, Q)
471476

477+
def check_DLQE(self, L, P, poles, G, QN, RN):
478+
P_expected = asmatarrayout(G.dot(QN).dot(G))
479+
L_expected = asmatarrayout(0)
480+
poles_expected = -np.squeeze(np.asarray(L_expected))
481+
np.testing.assert_array_almost_equal(P, P_expected)
482+
np.testing.assert_array_almost_equal(L, L_expected)
483+
np.testing.assert_array_almost_equal(poles, poles_expected)
484+
485+
def test_DLQE(self, matarrayin):
486+
A, G, C, QN, RN = (matarrayin([[X]]) for X in [0., .1, 1., 10., 2.])
487+
L, P, poles = dlqe(A, G, C, QN, RN)
488+
self.check_DLQE(L, P, poles, G, QN, RN)
489+
472490
def test_care(self, matarrayin):
473-
"""Test stabilizing and anti-stabilizing feedbacks, continuous"""
491+
"""Test stabilizing feedback, continuous"""
474492
A = matarrayin(np.diag([1, -1]))
475493
B = matarrayin(np.identity(2))
476494
Q = matarrayin(np.identity(2))
@@ -489,7 +507,7 @@ def test_care(self, matarrayin):
489507
X, L, G = care(A, B, Q, R, S, E, stabilizing=False)
490508

491509
def test_dare(self, matarrayin):
492-
"""Test stabilizing and anti-stabilizing feedbacks, discrete"""
510+
"""Test stabilizing feedback, discrete"""
493511
A = matarrayin(np.diag([0.5, 2]))
494512
B = matarrayin(np.identity(2))
495513
Q = matarrayin(np.identity(2))

0 commit comments

Comments
 (0)