Skip to content

Commit ed63358

Browse files
committed
add step_info mimo test (TransferFunction)
1 parent b98008a commit ed63358

File tree

1 file changed

+106
-68
lines changed

1 file changed

+106
-68
lines changed

control/tests/timeresp_test.py

Lines changed: 106 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ def siso_ss2(self, siso_ss1):
6666
T.initial = siso_ss1.yinitial - 9
6767
T.yimpulse = np.array([86., 70.1808, 57.3753, 46.9975, 38.5766,
6868
31.7344, 26.1668, 21.6292, 17.9245, 14.8945])
69-
return T
7069

70+
return T
7171

7272
@pytest.fixture
7373
def siso_tf1(self):
@@ -197,31 +197,98 @@ def no_pole_cancellation(self):
197197
@pytest.fixture
198198
def siso_tf_type1(self):
199199
# System Type 1 - Step response not stationary: G(s)=1/s(s+1)
200-
return TransferFunction(1, [1, 1, 0])
200+
T = TSys(TransferFunction(1, [1, 1, 0]))
201+
T.step_info = {
202+
'RiseTime': np.NaN,
203+
'SettlingTime': np.NaN,
204+
'SettlingMin': np.NaN,
205+
'SettlingMax': np.NaN,
206+
'Overshoot': np.NaN,
207+
'Undershoot': np.NaN,
208+
'Peak': np.Inf,
209+
'PeakTime': np.Inf,
210+
'SteadyStateValue': np.NaN}
211+
return T
201212

202213
@pytest.fixture
203214
def siso_tf_kpos(self):
204215
# SISO under shoot response and positive final value G(s)=(-s+1)/(s²+s+1)
205-
return TransferFunction([-1, 1], [1, 1, 1])
216+
T = TSys(TransferFunction([-1, 1], [1, 1, 1]))
217+
T.step_info = {
218+
'RiseTime': 1.242,
219+
'SettlingTime': 9.110,
220+
'SettlingMin': 0.950,
221+
'SettlingMax': 1.208,
222+
'Overshoot': 20.840,
223+
'Undershoot': 27.840,
224+
'Peak': 1.208,
225+
'PeakTime': 4.282,
226+
'SteadyStateValue': 1.0}
227+
return T
206228

207229
@pytest.fixture
208230
def siso_tf_kneg(self):
209231
# SISO under shoot response and negative final value k=-1 G(s)=-(-s+1)/(s²+s+1)
210-
return TransferFunction([1, -1], [1, 1, 1])
232+
T = TSys(TransferFunction([1, -1], [1, 1, 1]))
233+
T.step_info = {
234+
'RiseTime': 1.242,
235+
'SettlingTime': 9.110,
236+
'SettlingMin': -1.208,
237+
'SettlingMax': -0.950,
238+
'Overshoot': 20.840,
239+
'Undershoot': 27.840,
240+
'Peak': 1.208,
241+
'PeakTime': 4.282,
242+
'SteadyStateValue': -1.0}
243+
return T
211244

212245
@pytest.fixture
213246
def tf1_matlab_help(self):
214247
# example from matlab online help https://www.mathworks.com/help/control/ref/stepinfo.html
215-
return TransferFunction([1, 5, 5], [1, 1.65, 5, 6.5, 2])
248+
T = TSys(TransferFunction([1, 5, 5], [1, 1.65, 5, 6.5, 2]))
249+
T.step_info = {
250+
'RiseTime': 3.8456,
251+
'SettlingTime': 27.9762,
252+
'SettlingMin': 2.0689,
253+
'SettlingMax': 2.6873,
254+
'Overshoot': 7.4915,
255+
'Undershoot': 0,
256+
'Peak': 2.6873,
257+
'PeakTime': 8.0530,
258+
'SteadyStateValue': 2.5}
259+
return T
216260

217261
@pytest.fixture
218-
def tf2_matlab_help(self):
262+
def ss2_matlab_help(self):
219263
A = [[0.68, - 0.34], [0.34, 0.68]]
220264
B = [[0.18], [0.04]]
221265
C = [-1.12, - 1.10]
222266
D = [0.06]
223-
sys = StateSpace(A, B, C, D, 0.2)
224-
return sys
267+
T = TSys(StateSpace(A, B, C, D, 0.2))
268+
T.step_info = {
269+
'RiseTime': 0.4000,
270+
'SettlingTime': 2.8000,
271+
'SettlingMin': -0.6724,
272+
'SettlingMax': -0.5188,
273+
'Overshoot': 24.6476,
274+
'Undershoot': 11.1224,
275+
'Peak': 0.6724,
276+
'PeakTime': 1,
277+
'SteadyStateValue': -0.5394}
278+
return T
279+
280+
@pytest.fixture
281+
def mimo_tf_step(self, tf1_matlab_help,
282+
siso_tf_kpos,
283+
siso_tf_kneg,
284+
siso_tf_type1):
285+
Ta = [[tf1_matlab_help, tf1_matlab_help, siso_tf_kpos],
286+
[siso_tf_kneg, siso_tf_type1, siso_tf_type1]]
287+
T = TSys(TransferFunction(
288+
[[Ti.sys.num[0][0] for Ti in Tr] for Tr in Ta],
289+
[[Ti.sys.den[0][0] for Ti in Tr] for Tr in Ta]))
290+
T.step_info = [[Ti.step_info for Ti in Tr] for Tr in Ta]
291+
return T
225292

226293
@pytest.fixture
227294
def tsystem(self,
@@ -233,7 +300,7 @@ def tsystem(self,
233300
mimo_dss1, mimo_dss2, mimo_dtf1,
234301
pole_cancellation, no_pole_cancellation, siso_tf_type1,
235302
siso_tf_kpos, siso_tf_kneg, tf1_matlab_help,
236-
tf2_matlab_help):
303+
ss2_matlab_help, mimo_tf_step):
237304
systems = {"siso_ss1": siso_ss1,
238305
"siso_ss2": siso_ss2,
239306
"siso_tf1": siso_tf1,
@@ -255,7 +322,8 @@ def tsystem(self,
255322
"siso_tf_kpos": siso_tf_kpos,
256323
"siso_tf_kneg": siso_tf_kneg,
257324
"tf1_matlab_help": tf1_matlab_help,
258-
"tf2_matlab_help": tf2_matlab_help,
325+
"ss2_matlab_help": ss2_matlab_help,
326+
"mimo_tf_step": mimo_tf_step,
259327
}
260328
return systems[request.param]
261329

@@ -312,73 +380,43 @@ def test_step_nostates(self, dt):
312380
# tolerance for all parameters could be wrong for some systems
313381
# discrete systems time parameters tolerance could be +/-dt
314382
@pytest.mark.parametrize(
315-
"tsystem, info_true, tolerance",
316-
[("tf1_matlab_help", {
317-
'RiseTime': 3.8456,
318-
'SettlingTime': 27.9762,
319-
'SettlingMin': 2.0689,
320-
'SettlingMax': 2.6873,
321-
'Overshoot': 7.4915,
322-
'Undershoot': 0,
323-
'Peak': 2.6873,
324-
'PeakTime': 8.0530,
325-
'SteadyStateValue': 2.5}, 2e-2),
326-
("tf2_matlab_help", {
327-
'RiseTime': 0.4000,
328-
'SettlingTime': 2.8000,
329-
'SettlingMin': -0.6724,
330-
'SettlingMax': -0.5188,
331-
'Overshoot': 24.6476,
332-
'Undershoot': 11.1224,
333-
'Peak': 0.6724,
334-
'PeakTime': 1,
335-
'SteadyStateValue': -0.5394}, .2),
336-
("siso_tf_kpos", {
337-
'RiseTime': 1.242,
338-
'SettlingTime': 9.110,
339-
'SettlingMin': 0.950,
340-
'SettlingMax': 1.208,
341-
'Overshoot': 20.840,
342-
'Undershoot': 27.840,
343-
'Peak': 1.208,
344-
'PeakTime': 4.282,
345-
'SteadyStateValue': 1.0}, 2e-2),
346-
("siso_tf_kneg", {
347-
'RiseTime': 1.242,
348-
'SettlingTime': 9.110,
349-
'SettlingMin': -1.208,
350-
'SettlingMax': -0.950,
351-
'Overshoot': 20.840,
352-
'Undershoot': 27.840,
353-
'Peak': 1.208,
354-
'PeakTime': 4.282,
355-
'SteadyStateValue': -1.0}, 2e-2),
356-
("siso_tf_type1", {'RiseTime': np.NaN,
357-
'SettlingTime': np.NaN,
358-
'SettlingMin': np.NaN,
359-
'SettlingMax': np.NaN,
360-
'Overshoot': np.NaN,
361-
'Undershoot': np.NaN,
362-
'Peak': np.Inf,
363-
'PeakTime': np.Inf,
364-
'SteadyStateValue': np.NaN}, 2e-2)],
383+
"tsystem, tolerance",
384+
[("tf1_matlab_help", 2e-2),
385+
("ss2_matlab_help", .2),
386+
("siso_tf_kpos", 2e-2),
387+
("siso_tf_kneg", 2e-2),
388+
("siso_tf_type1", 2e-2)],
365389
indirect=["tsystem"])
366-
def test_step_info(self, tsystem, info_true, tolerance):
390+
def test_step_info(self, tsystem, tolerance):
367391
"""Test step info for SISO systems"""
368-
info = step_info(tsystem)
392+
info = step_info(tsystem.sys)
369393

370-
info_true_sorted = sorted(info_true.keys())
394+
info_true_sorted = sorted(tsystem.step_info.keys())
371395
info_sorted = sorted(info.keys())
372396
assert info_sorted == info_true_sorted
373397

374398
for k in info:
375-
np.testing.assert_allclose(info[k], info_true[k], rtol=tolerance,
376-
err_msg=f"key {k} does not match")
399+
np.testing.assert_allclose(info[k], tsystem.step_info[k],
400+
rtol=tolerance,
401+
err_msg=f"{k} does not match")
377402

378-
def test_step_info_mimo(self, tsystem, info_true, tolearance):
403+
@pytest.mark.parametrize(
404+
"tsystem, tolerance",
405+
[('mimo_tf_step', 2e-2)],
406+
indirect=["tsystem"])
407+
def test_step_info_mimo(self, tsystem, tolerance):
379408
"""Test step info for MIMO systems"""
380-
# TODO: implement
381-
pass
409+
info_dict = step_info(tsystem.sys)
410+
from pprint import pprint
411+
pprint(info_dict)
412+
for i, row in enumerate(info_dict):
413+
for j, info in enumerate(row):
414+
for k in info:
415+
np.testing.assert_allclose(
416+
info[k], tsystem.step_info[i][j][k],
417+
rtol=tolerance,
418+
err_msg=f"{k} for input {j} to output {i} "
419+
"does not match")
382420

383421
def test_step_pole_cancellation(self, pole_cancellation,
384422
no_pole_cancellation):

0 commit comments

Comments
 (0)