From 04ef02dfec7a4b449f71712bc50cafe633d0f6ba Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Mon, 6 Jun 2022 21:48:39 -0700 Subject: [PATCH] handle t_eval for static systems in input_output_response (addresses #742) --- control/iosys.py | 13 +------------ control/tests/iosys_test.py | 31 ++++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/control/iosys.py b/control/iosys.py index e3719614b..6008cf43d 100644 --- a/control/iosys.py +++ b/control/iosys.py @@ -1762,19 +1762,8 @@ def input_output_response( warn("initial state too short; padding with zeros") X0 = np.hstack([X0, np.zeros(sys.nstates - X0.size)]) - # Check to make sure this is not a static function + # Compute the number of states nstates = _find_size(sys.nstates, X0) - if nstates == 0: - # No states => map input to output - u = U[0] if len(U.shape) == 1 else U[:, 0] - y = np.zeros((np.shape(sys._out(T[0], X0, u))[0], len(T))) - for i in range(len(T)): - u = U[i] if len(U.shape) == 1 else U[:, i] - y[:, i] = sys._out(T[i], [], u) - return TimeResponseData( - T, y, None, U, issiso=sys.issiso(), - output_labels=sys.output_index, input_labels=sys.input_index, - transpose=transpose, return_x=return_x, squeeze=squeeze) # create X0 if not given, test if X0 has correct shape X0 = _check_convert_array(X0, [(nstates,), (nstates, 1)], diff --git a/control/tests/iosys_test.py b/control/tests/iosys_test.py index ecb30c316..825cec5c5 100644 --- a/control/tests/iosys_test.py +++ b/control/tests/iosys_test.py @@ -1763,27 +1763,40 @@ def test_input_output_broadcasting(): resp_bad = ct.input_output_response( sys, T, (U[0, :], U[:2, :-1]), [X0, P0]) - -def test_nonuniform_timepts(): +@pytest.mark.parametrize("nstates, ninputs, noutputs", [ + [2, 1, 1], + [4, 2, 3], + [0, 1, 1], # static function + [0, 3, 2], # static function +]) +def test_nonuniform_timepts(nstates, noutputs, ninputs): """Test non-uniform time points for simulations""" - sys = ct.LinearIOSystem(ct.rss(2, 1, 1)) + if nstates: + sys = ct.rss(nstates, noutputs, ninputs) + else: + sys = ct.ss( + [], np.zeros((0, ninputs)), np.zeros((noutputs, 0)), + np.random.rand(noutputs, ninputs)) # Start with a uniform set of times unifpts = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - uniform = [1, 2, 3, 2, 1, -1, -3, -5, -7, -3, 1] - t_unif, y_unif = ct.input_output_response(sys, unifpts, uniform) + uniform = np.outer( + np.ones(ninputs), [1, 2, 3, 2, 1, -1, -3, -5, -7, -3, 1]) + t_unif, y_unif = ct.input_output_response( + sys, unifpts, uniform, squeeze=False) # Create a non-uniform set of inputs noufpts = [0, 2, 4, 8, 10] - nonunif = [1, 3, 1, -7, 1] - t_nouf, y_nouf = ct.input_output_response(sys, noufpts, nonunif) + nonunif = np.outer(np.ones(ninputs), [1, 3, 1, -7, 1]) + t_nouf, y_nouf = ct.input_output_response( + sys, noufpts, nonunif, squeeze=False) # Make sure the outputs agree at common times - np.testing.assert_almost_equal(y_unif[noufpts], y_nouf, decimal=6) + np.testing.assert_almost_equal(y_unif[:, noufpts], y_nouf, decimal=6) # Resimulate using a new set of evaluation points t_even, y_even = ct.input_output_response( - sys, noufpts, nonunif, t_eval=unifpts) + sys, noufpts, nonunif, t_eval=unifpts, squeeze=False) np.testing.assert_almost_equal(y_unif, y_even, decimal=6)