@@ -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