Skip to content

Commit 09de03b

Browse files
committed
Use the time axis of transposed inputs in discrete-time forced_response (fixes #931)
1 parent b4cf736 commit 09de03b

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎control/tests/timeresp_test.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,27 @@ def test_response_transpose(
12551255
assert x.shape == (T.size, sys.nstates)
12561256

12571257

1258+
@pytest.mark.parametrize("ninputs", [1, 2])
1259+
def test_forced_response_transpose_discrete(ninputs):
1260+
# Transposed inputs have time along the first axis, including when the
1261+
# time vector is computed from them (gh-931)
1262+
sys = ct.rss(3, 2, ninputs, dt=0.1)
1263+
U = np.random.default_rng(0).standard_normal((ninputs, 10))
1264+
1265+
resp = ct.forced_response(sys, U=U, squeeze=False)
1266+
resp_t = ct.forced_response(
1267+
sys, U=U.T, transpose=True, squeeze=False)
1268+
np.testing.assert_equal(resp_t.time, resp.time)
1269+
np.testing.assert_allclose(np.transpose(resp_t.outputs), resp.outputs)
1270+
1271+
# Scalar input with a given time vector
1272+
T = np.arange(10) * 0.1
1273+
resp = ct.forced_response(sys, T=T, U=1.0, squeeze=False)
1274+
resp_t = ct.forced_response(
1275+
sys, T=T, U=1.0, transpose=True, squeeze=False)
1276+
np.testing.assert_allclose(np.transpose(resp_t.outputs), resp.outputs)
1277+
1278+
12581279
@pytest.mark.pandas
12591280
def test_to_pandas():
12601281
# Create a SISO time response

‎control/timeresp.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,8 @@ def forced_response(
11121112
raise ValueError('Parameters `T` and `U` can\'t both be '
11131113
'zero for discrete-time simulation')
11141114
# Set T to equally spaced samples with same length as U
1115-
if U.ndim == 1:
1115+
# (time is along the first axis of a transposed U)
1116+
if U.ndim == 1 or transpose:
11161117
n_steps = U.shape[0]
11171118
else:
11181119
n_steps = U.shape[1]
@@ -1121,6 +1122,9 @@ def forced_response(
11211122
else:
11221123
if U.ndim == 0:
11231124
U = np.full((n_inputs, T.shape[0]), U)
1125+
if transpose:
1126+
# U gets transposed back when its shape is checked
1127+
U = U.T
11241128
else:
11251129
if T is None:
11261130
raise ValueError('Parameter `T` is mandatory for continuous '

0 commit comments

Comments
 (0)