diff --git a/control/iosys.py b/control/iosys.py index 2bb445bdd..df75f3b54 100644 --- a/control/iosys.py +++ b/control/iosys.py @@ -890,7 +890,7 @@ def __init__(self, syslist, connections=None, inplist=None, outlist=None, kwargs, defaults, end=True) # Initialize the system list and index - self.syslist = syslist + self.syslist = list(syslist) # insure modifications can be made self.syslist_index = {} # Initialize the input, output, and state counts, indices @@ -903,12 +903,12 @@ def __init__(self, syslist, connections=None, inplist=None, outlist=None, sysname_count_dct = {} # Go through the system list and keep track of counts, offsets - for sysidx, sys in enumerate(syslist): + for sysidx, sys in enumerate(self.syslist): # If we were passed a SS or TF system, convert to LinearIOSystem if isinstance(sys, (StateSpace, TransferFunction)) and \ not isinstance(sys, LinearIOSystem): - sys = LinearIOSystem(sys) - syslist[sysidx] = sys + sys = LinearIOSystem(sys, name=sys.name) + self.syslist[sysidx] = sys # Make sure time bases are consistent dt = common_timebase(dt, sys.dt) @@ -2850,12 +2850,12 @@ def interconnect(syslist, connections=None, inplist=None, outlist=None, inputs=inputs, outputs=outputs, states=states, params=params, dt=dt, name=name, warn_duplicate=warn_duplicate) - # check for implicity dropped signals + # check for implicitly dropped signals if check_unused: newsys.check_unused_signals(ignore_inputs, ignore_outputs) # If all subsystems are linear systems, maintain linear structure - if all([isinstance(sys, LinearIOSystem) for sys in syslist]): + if all([isinstance(sys, LinearIOSystem) for sys in newsys.syslist]): return LinearICSystem(newsys, None) return newsys diff --git a/control/tests/interconnect_test.py b/control/tests/interconnect_test.py index 3b99adc6e..2c29aeaca 100644 --- a/control/tests/interconnect_test.py +++ b/control/tests/interconnect_test.py @@ -230,3 +230,25 @@ def test_string_inputoutput(): P_s2 = ct.interconnect([P1_iosys, P2_iosys], inputs=['u1'], output='y2') assert P_s2.output_index == {'y2' : 0} + +def test_linear_interconnect(): + tf_ctrl = ct.tf(1, (10.1, 1), inputs='e', outputs='u') + tf_plant = ct.tf(1, (10.1, 1), inputs='u', outputs='y') + ss_ctrl = ct.ss(1, 2, 1, 2, inputs='e', outputs='u') + ss_plant = ct.ss(1, 2, 1, 2, inputs='u', outputs='y') + nl_ctrl = ct.NonlinearIOSystem( + lambda t, x, u, params: x*x, + lambda t, x, u, params: u*x, states=1, inputs='e', outputs='u') + nl_plant = ct.NonlinearIOSystem( + lambda t, x, u, params: x*x, + lambda t, x, u, params: u*x, states=1, inputs='u', outputs='y') + + assert isinstance(ct.interconnect((tf_ctrl, tf_plant), inputs='e', outputs='y'), ct.LinearIOSystem) + assert isinstance(ct.interconnect((ss_ctrl, ss_plant), inputs='e', outputs='y'), ct.LinearIOSystem) + assert isinstance(ct.interconnect((tf_ctrl, ss_plant), inputs='e', outputs='y'), ct.LinearIOSystem) + assert isinstance(ct.interconnect((ss_ctrl, tf_plant), inputs='e', outputs='y'), ct.LinearIOSystem) + + assert ~isinstance(ct.interconnect((nl_ctrl, ss_plant), inputs='e', outputs='y'), ct.LinearIOSystem) + assert ~isinstance(ct.interconnect((nl_ctrl, tf_plant), inputs='e', outputs='y'), ct.LinearIOSystem) + assert ~isinstance(ct.interconnect((ss_ctrl, nl_plant), inputs='e', outputs='y'), ct.LinearIOSystem) + assert ~isinstance(ct.interconnect((tf_ctrl, nl_plant), inputs='e', outputs='y'), ct.LinearIOSystem) \ No newline at end of file diff --git a/control/tests/iosys_test.py b/control/tests/iosys_test.py index 8a6ed8165..7d3b9fee9 100644 --- a/control/tests/iosys_test.py +++ b/control/tests/iosys_test.py @@ -1454,6 +1454,11 @@ def test_linear_interconnection(): inputs = ('u[0]', 'u[1]'), outputs = ('y[0]', 'y[1]'), name = 'sys2') + tf_siso = ct.tf(1, [0.1, 1]) + ss_siso = ct.ss(1, 2, 1, 1) + nl_siso = ios.NonlinearIOSystem( + lambda t, x, u, params: x*x, + lambda t, x, u, params: u*x, states=1, inputs=1, outputs=1) # Create a "regular" InterconnectedSystem nl_connect = ios.interconnect( @@ -1500,6 +1505,18 @@ def test_linear_interconnection(): np.testing.assert_array_almost_equal(io_connect.C, ss_connect.C) np.testing.assert_array_almost_equal(io_connect.D, ss_connect.D) + # make sure interconnections of linear systems are linear and + # if a nonlinear system is included then system is nonlinear + assert isinstance(ss_siso*ss_siso, ios.LinearIOSystem) + assert isinstance(tf_siso*ss_siso, ios.LinearIOSystem) + assert isinstance(ss_siso*tf_siso, ios.LinearIOSystem) + assert ~isinstance(ss_siso*nl_siso, ios.LinearIOSystem) + assert ~isinstance(nl_siso*ss_siso, ios.LinearIOSystem) + assert ~isinstance(nl_siso*nl_siso, ios.LinearIOSystem) + assert ~isinstance(tf_siso*nl_siso, ios.LinearIOSystem) + assert ~isinstance(nl_siso*tf_siso, ios.LinearIOSystem) + assert ~isinstance(nl_siso*nl_siso, ios.LinearIOSystem) + def predprey(t, x, u, params={}): """Predator prey dynamics"""