Skip to content

Commit 4d878a9

Browse files
authored
Merge pull request #969 from basicmachines/main
Updated gram to support discrete-time systems
2 parents 7a70be1 + 0836ad8 commit 4d878a9

File tree

2 files changed

+78
-18
lines changed

2 files changed

+78
-18
lines changed

control/statefbk.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,18 +1119,21 @@ def gram(sys, type):
11191119
if type not in ['c', 'o', 'cf', 'of']:
11201120
raise ValueError("That type is not supported!")
11211121

1122-
# TODO: Check for continuous or discrete, only continuous supported for now
1123-
# if isCont():
1124-
# dico = 'C'
1125-
# elif isDisc():
1126-
# dico = 'D'
1127-
# else:
1128-
dico = 'C'
1129-
1130-
# TODO: Check system is stable, perhaps a utility in ctrlutil.py
1131-
# or a method of the StateSpace class?
1132-
if np.any(np.linalg.eigvals(sys.A).real >= 0.0):
1133-
raise ValueError("Oops, the system is unstable!")
1122+
# Check if system is continuous or discrete
1123+
if sys.isctime():
1124+
dico = 'C'
1125+
1126+
# TODO: Check system is stable, perhaps a utility in ctrlutil.py
1127+
# or a method of the StateSpace class?
1128+
if np.any(np.linalg.eigvals(sys.A).real >= 0.0):
1129+
raise ValueError("Oops, the system is unstable!")
1130+
1131+
else:
1132+
assert sys.isdtime()
1133+
dico = 'D'
1134+
1135+
if np.any(np.abs(sys.poles()) >= 1.):
1136+
raise ValueError("Oops, the system is unstable!")
11341137

11351138
if type == 'c' or type == 'o':
11361139
# Compute Gramian by the Slycot routine sb03md

control/tests/statefbk_test.py

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,28 @@ def testGramWc(self):
9898
Wctrue = np.array([[18.5, 24.5], [24.5, 32.5]])
9999
Wc = gram(sys, 'c')
100100
np.testing.assert_array_almost_equal(Wc, Wctrue)
101+
sysd = ct.c2d(sys, 0.2)
102+
Wctrue = np.array([[3.666767, 4.853625],
103+
[4.853625, 6.435233]])
104+
Wc = gram(sysd, 'c')
105+
np.testing.assert_array_almost_equal(Wc, Wctrue)
106+
107+
@slycotonly
108+
def testGramWc2(self):
109+
A = np.array([[1., -2.], [3., -4.]])
110+
B = np.array([[5.], [7.]])
111+
C = np.array([[6., 8.]])
112+
D = np.array([[9.]])
113+
sys = ss(A,B,C,D)
114+
Wctrue = np.array([[ 7.166667, 9.833333],
115+
[ 9.833333, 13.5]])
116+
Wc = gram(sys, 'c')
117+
np.testing.assert_array_almost_equal(Wc, Wctrue)
118+
sysd = ct.c2d(sys, 0.2)
119+
Wctrue = np.array([[1.418978, 1.946180],
120+
[1.946180, 2.670758]])
121+
Wc = gram(sysd, 'c')
122+
np.testing.assert_array_almost_equal(Wc, Wctrue)
101123

102124
@slycotonly
103125
def testGramRc(self):
@@ -106,9 +128,15 @@ def testGramRc(self):
106128
C = np.array([[4., 5.], [6., 7.]])
107129
D = np.array([[13., 14.], [15., 16.]])
108130
sys = ss(A, B, C, D)
109-
Rctrue = np.array([[4.30116263, 5.6961343], [0., 0.23249528]])
131+
Rctrue = np.array([[4.30116263, 5.6961343],
132+
[0., 0.23249528]])
110133
Rc = gram(sys, 'cf')
111134
np.testing.assert_array_almost_equal(Rc, Rctrue)
135+
sysd = ct.c2d(sys, 0.2)
136+
Rctrue = np.array([[1.91488054, 2.53468814],
137+
[0. , 0.10290372]])
138+
Rc = gram(sysd, 'cf')
139+
np.testing.assert_array_almost_equal(Rc, Rctrue)
112140

113141
@slycotonly
114142
def testGramWo(self):
@@ -120,6 +148,11 @@ def testGramWo(self):
120148
Wotrue = np.array([[257.5, -94.5], [-94.5, 56.5]])
121149
Wo = gram(sys, 'o')
122150
np.testing.assert_array_almost_equal(Wo, Wotrue)
151+
sysd = ct.c2d(sys, 0.2)
152+
Wotrue = np.array([[ 1305.369179, -440.046414],
153+
[ -440.046414, 333.034844]])
154+
Wo = gram(sysd, 'o')
155+
np.testing.assert_array_almost_equal(Wo, Wotrue)
123156

124157
@slycotonly
125158
def testGramWo2(self):
@@ -131,6 +164,11 @@ def testGramWo2(self):
131164
Wotrue = np.array([[198., -72.], [-72., 44.]])
132165
Wo = gram(sys, 'o')
133166
np.testing.assert_array_almost_equal(Wo, Wotrue)
167+
sysd = ct.c2d(sys, 0.2)
168+
Wotrue = np.array([[ 1001.835511, -335.337663],
169+
[ -335.337663, 263.355793]])
170+
Wo = gram(sysd, 'o')
171+
np.testing.assert_array_almost_equal(Wo, Wotrue)
134172

135173
@slycotonly
136174
def testGramRo(self):
@@ -142,15 +180,34 @@ def testGramRo(self):
142180
Rotrue = np.array([[16.04680654, -5.8890222], [0., 4.67112593]])
143181
Ro = gram(sys, 'of')
144182
np.testing.assert_array_almost_equal(Ro, Rotrue)
183+
sysd = ct.c2d(sys, 0.2)
184+
Rotrue = np.array([[ 36.12989315, -12.17956588],
185+
[ 0. , 13.59018097]])
186+
Ro = gram(sysd, 'of')
187+
np.testing.assert_array_almost_equal(Ro, Rotrue)
145188

146189
def testGramsys(self):
147-
num =[1.]
148-
den = [1., 1., 1.]
149-
sys = tf(num,den)
150-
with pytest.raises(ValueError):
190+
sys = tf([1.], [1., 1., 1.])
191+
with pytest.raises(ValueError) as excinfo:
151192
gram(sys, 'o')
152-
with pytest.raises(ValueError):
193+
assert "must be StateSpace" in str(excinfo.value)
194+
with pytest.raises(ValueError) as excinfo:
195+
gram(sys, 'c')
196+
assert "must be StateSpace" in str(excinfo.value)
197+
sys = tf([1], [1, -1], 0.5)
198+
with pytest.raises(ValueError) as excinfo:
199+
gram(sys, 'o')
200+
assert "must be StateSpace" in str(excinfo.value)
201+
with pytest.raises(ValueError) as excinfo:
202+
gram(sys, 'c')
203+
assert "must be StateSpace" in str(excinfo.value)
204+
sys = ct.ss(sys) # this system is unstable
205+
with pytest.raises(ValueError) as excinfo:
206+
gram(sys, 'o')
207+
assert "is unstable" in str(excinfo.value)
208+
with pytest.raises(ValueError) as excinfo:
153209
gram(sys, 'c')
210+
assert "is unstable" in str(excinfo.value)
154211

155212
def testAcker(self, fixedseed):
156213
for states in range(1, self.maxStates):

0 commit comments

Comments
 (0)