@@ -313,14 +313,52 @@ def test_combine_time_responses():
313313 combresp6 = ct .combine_time_responses ([resp1 , resp ])
314314
315315
316- @pytest .mark .xfail (
317- reason = "step responses for multiple systems not yet implemented" )
318- def test_list_responses ():
319- sys1 = ct .rss (2 , 2 , 2 )
320- sys2 = ct .rss (2 , 2 , 2 )
316+ @pytest .mark .parametrize ("resp_fcn" , [
317+ ct .step_response , ct .initial_response , ct .impulse_response ,
318+ ct .forced_response , ct .input_output_response ])
319+ def test_list_responses (resp_fcn ):
320+ sys1 = ct .rss (2 , 2 , 2 , strictly_proper = True )
321+ sys2 = ct .rss (2 , 2 , 2 , strictly_proper = True )
322+
323+ # Figure out the expected shape of the system
324+ match resp_fcn :
325+ case ct .step_response | ct .impulse_response :
326+ shape = (2 , 2 )
327+ kwargs = {}
328+ case ct .initial_response :
329+ shape = (2 , 1 )
330+ kwargs = {}
331+ case ct .forced_response | ct .input_output_response :
332+ shape = (4 , 1 ) # outputs and inputs both plotted
333+ T = np .linspace (0 , 10 )
334+ U = [np .sin (T ), np .cos (T )]
335+ kwargs = {'T' : T , 'U' : U }
336+
337+ resp1 = resp_fcn (sys1 , ** kwargs )
338+ resp2 = resp_fcn (sys2 , ** kwargs )
339+
340+ # Sequential plotting results in colors rotating
341+ plt .figure ()
342+ out1 = resp1 .plot ()
343+ out2 = resp2 .plot ()
344+ assert out1 .shape == shape
345+ assert out2 .shape == shape
346+ for row in range (2 ): # just look at the outputs
347+ for col in range (shape [1 ]):
348+ assert out1 [row , col ][0 ].get_color () == 'tab:blue'
349+ assert out2 [row , col ][0 ].get_color () == 'tab:orange'
321350
322- resp = ct .step_response ([sys1 , sys2 ]).plot ()
323- assert resp .ntraces == 2
351+ plt .figure ()
352+ resp_combined = resp_fcn ([sys1 , sys2 ], ** kwargs )
353+ assert isinstance (resp_combined , ct .timeresp .TimeResponseList )
354+ assert resp_combined [0 ].time [- 1 ] == max (resp1 .time [- 1 ], resp2 .time [- 1 ])
355+ assert resp_combined [1 ].time [- 1 ] == max (resp1 .time [- 1 ], resp2 .time [- 1 ])
356+ out = resp_combined .plot ()
357+ assert out .shape == shape
358+ for row in range (2 ): # just look at the outputs
359+ for col in range (shape [1 ]):
360+ assert out [row , col ][0 ].get_color () == 'tab:blue'
361+ assert out [row , col ][1 ].get_color () == 'tab:orange'
324362
325363
326364@slycotonly
@@ -421,6 +459,12 @@ def test_errors():
421459 out = stepresp .plot ('k-' , ** propkw )
422460 assert out [0 , 0 ][0 ].get_color () == 'k'
423461
462+ # Make sure TimeResponseLists also work
463+ stepresp = ct .step_response ([sys , sys ])
464+ with pytest .raises (AttributeError ,
465+ match = "(has no property|unexpected keyword)" ):
466+ stepresp .plot (unknown = None )
467+
424468if __name__ == "__main__" :
425469 #
426470 # Interactive mode: generate plots for manual viewing
@@ -519,3 +563,28 @@ def test_errors():
519563 input_props = [{'color' : c } for c in ['red' , 'green' ]],
520564 trace_props = [{'linestyle' : s } for s in ['-' , '--' ]])
521565 plt .savefig ('timeplot-mimo_step-linestyle.png' )
566+
567+ sys1 = ct .rss (4 , 2 , 2 )
568+ sys2 = ct .rss (4 , 2 , 2 )
569+ resp_list = ct .step_response ([sys1 , sys2 ])
570+
571+ fig = plt .figure ()
572+ ct .combine_time_responses (
573+ [ct .step_response (sys1 , resp_list [0 ].time ),
574+ ct .step_response (sys2 , resp_list [1 ].time )]
575+ ).plot (overlay_traces = True )
576+ ct .suptitle ("[Combine] " + fig ._suptitle ._text )
577+
578+ fig = plt .figure ()
579+ ct .step_response (sys1 ).plot ()
580+ ct .step_response (sys2 ).plot ()
581+ ct .suptitle ("[Sequential] " + fig ._suptitle ._text )
582+
583+ fig = plt .figure ()
584+ ct .step_response (sys1 ).plot (color = 'b' )
585+ ct .step_response (sys2 ).plot (color = 'r' )
586+ ct .suptitle ("[Seq w/color] " + fig ._suptitle ._text )
587+
588+ fig = plt .figure ()
589+ ct .step_response ([sys1 , sys2 ]).plot ()
590+ ct .suptitle ("[List] " + fig ._suptitle ._text )
0 commit comments