Skip to content

Commit 82f3fe3

Browse files
Merge pull request #941 from Jpickard1/main
Improved speed of ctrb and obsv functions
2 parents f08ad6c + f8ba0d9 commit 82f3fe3

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

control/statefbk.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -990,13 +990,15 @@ def _control_output(t, states, inputs, params):
990990
return ctrl, closed
991991

992992

993-
def ctrb(A, B):
993+
def ctrb(A, B, t=None):
994994
"""Controllabilty matrix.
995995
996996
Parameters
997997
----------
998998
A, B : array_like or string
999999
Dynamics and input matrix of the system
1000+
t : None or integer
1001+
maximum time horizon of the controllability matrix, max = A.shape[0]
10001002
10011003
Returns
10021004
-------
@@ -1016,22 +1018,30 @@ def ctrb(A, B):
10161018
amat = _ssmatrix(A)
10171019
bmat = _ssmatrix(B)
10181020
n = np.shape(amat)[0]
1021+
m = np.shape(bmat)[1]
1022+
1023+
if t is None or t > n:
1024+
t = n
10191025

10201026
# Construct the controllability matrix
1021-
ctrb = np.hstack(
1022-
[bmat] + [np.linalg.matrix_power(amat, i) @ bmat
1023-
for i in range(1, n)])
1027+
ctrb = np.zeros((n, t * m))
1028+
ctrb[:, :m] = bmat
1029+
for k in range(1, t):
1030+
ctrb[:, k * m:(k + 1) * m] = np.dot(amat, ctrb[:, (k - 1) * m:k * m])
1031+
10241032
return _ssmatrix(ctrb)
10251033

10261034

1027-
def obsv(A, C):
1035+
def obsv(A, C, t=None):
10281036
"""Observability matrix.
10291037
10301038
Parameters
10311039
----------
10321040
A, C : array_like or string
10331041
Dynamics and output matrix of the system
1034-
1042+
t : None or integer
1043+
maximum time horizon of the controllability matrix, max = A.shape[0]
1044+
10351045
Returns
10361046
-------
10371047
O : 2D array (or matrix)
@@ -1050,10 +1060,18 @@ def obsv(A, C):
10501060
amat = _ssmatrix(A)
10511061
cmat = _ssmatrix(C)
10521062
n = np.shape(amat)[0]
1063+
p = np.shape(cmat)[0]
1064+
1065+
if t is None or t > n:
1066+
t = n
10531067

10541068
# Construct the observability matrix
1055-
obsv = np.vstack([cmat] + [cmat @ np.linalg.matrix_power(amat, i)
1056-
for i in range(1, n)])
1069+
obsv = np.zeros((t * p, n))
1070+
obsv[:p, :] = cmat
1071+
1072+
for k in range(1, t):
1073+
obsv[k * p:(k + 1) * p, :] = np.dot(obsv[(k - 1) * p:k * p, :], amat)
1074+
10571075
return _ssmatrix(obsv)
10581076

10591077

control/tests/statefbk_test.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ def testCtrbMIMO(self):
4949
Wc = ctrb(A, B)
5050
np.testing.assert_array_almost_equal(Wc, Wctrue)
5151

52+
def testCtrbT(self):
53+
A = np.array([[1., 2.], [3., 4.]])
54+
B = np.array([[5., 6.], [7., 8.]])
55+
t = 1
56+
Wctrue = np.array([[5., 6.], [7., 8.]])
57+
Wc = ctrb(A, B, t=t)
58+
np.testing.assert_array_almost_equal(Wc, Wctrue)
59+
5260
def testObsvSISO(self):
5361
A = np.array([[1., 2.], [3., 4.]])
5462
C = np.array([[5., 7.]])
@@ -62,6 +70,14 @@ def testObsvMIMO(self):
6270
Wotrue = np.array([[5., 6.], [7., 8.], [23., 34.], [31., 46.]])
6371
Wo = obsv(A, C)
6472
np.testing.assert_array_almost_equal(Wo, Wotrue)
73+
74+
def testObsvT(self):
75+
A = np.array([[1., 2.], [3., 4.]])
76+
C = np.array([[5., 6.], [7., 8.]])
77+
t = 1
78+
Wotrue = np.array([[5., 6.], [7., 8.]])
79+
Wo = obsv(A, C, t=t)
80+
np.testing.assert_array_almost_equal(Wo, Wotrue)
6581

6682
def testCtrbObsvDuality(self):
6783
A = np.array([[1.2, -2.3], [3.4, -4.5]])

0 commit comments

Comments
 (0)