Skip to content

Commit 114890f

Browse files
authored
Merge pull request #336 from adm78/bugfix/forced_response
Fixing bug in timeresp.forced_response for discrete MIMO sys and T=None
2 parents 129a053 + 8b08481 commit 114890f

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

control/tests/timeresp_test.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -252,14 +252,14 @@ def test_forced_response(self):
252252
# first system: initial value, second system: step response
253253
u = np.array([[0., 0, 0, 0, 0, 0, 0, 0, 0, 0],
254254
[1., 1, 1, 1, 1, 1, 1, 1, 1, 1]])
255-
x0 = np.matrix(".5; 1; 0; 0")
255+
x0 = np.array([[.5], [1], [0], [0]])
256256
youttrue = np.array([[11., 8.1494, 5.9361, 4.2258, 2.9118, 1.9092,
257257
1.1508, 0.5833, 0.1645, -0.1391],
258258
[9., 17.6457, 24.7072, 30.4855, 35.2234, 39.1165,
259259
42.3227, 44.9694, 47.1599, 48.9776]])
260260
_t, yout, _xout = forced_response(self.mimo_ss1, t, u, x0)
261261
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
262-
262+
263263
# Test discrete MIMO system to use correct convention for input
264264
sysc = self.mimo_ss1
265265
dt=t[1]-t[0]
@@ -270,6 +270,17 @@ def test_forced_response(self):
270270
np.testing.assert_array_equal(youtc.shape, youtd.shape)
271271
np.testing.assert_array_almost_equal(youtc, youtd, decimal=4)
272272

273+
# Test discrete MIMO system without default T argument
274+
u = np.array([[0., 0, 0, 0, 0, 0, 0, 0, 0, 0],
275+
[1., 1, 1, 1, 1, 1, 1, 1, 1, 1]])
276+
x0 = np.array([[.5], [1], [0], [0]])
277+
youttrue = np.array([[11., 8.1494, 5.9361, 4.2258, 2.9118, 1.9092,
278+
1.1508, 0.5833, 0.1645, -0.1391],
279+
[9., 17.6457, 24.7072, 30.4855, 35.2234, 39.1165,
280+
42.3227, 44.9694, 47.1599, 48.9776]])
281+
_t, yout, _xout = forced_response(sysd, U=u, X0=x0)
282+
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
283+
273284
def test_lsim_double_integrator(self):
274285
# Note: scipy.signal.lsim fails if A is not invertible
275286
A = np.mat("0. 1.;0. 0.")

control/timeresp.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
200200
sys: LTI (StateSpace, or TransferFunction)
201201
LTI system to simulate
202202
203-
T: array-like
203+
T: array-like, optional for discrete LTI `sys`
204204
Time steps at which the input is defined; values must be evenly spaced.
205205
206206
U: array-like or number, optional
@@ -260,20 +260,31 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
260260
n_inputs = B.shape[1]
261261
n_outputs = C.shape[0]
262262

263+
# Convert inputs to numpy arrays for easier shape checking
264+
if U is not None:
265+
U = np.asarray(U)
266+
if T is not None:
267+
T = np.asarray(T)
268+
263269
# Set and/or check time vector in discrete time case
264270
if isdtime(sys, strict=True):
265271
if T is None:
266272
if U is None:
267273
raise ValueError('Parameters ``T`` and ``U`` can\'t both be'
268274
'zero for discrete-time simulation')
269275
# Set T to equally spaced samples with same length as U
270-
T = np.array(range(len(U))) * (1 if sys.dt is True else sys.dt)
276+
if U.ndim == 1:
277+
n_steps = U.shape[0]
278+
else:
279+
n_steps = U.shape[1]
280+
T = np.array(range(n_steps)) * (1 if sys.dt is True else sys.dt)
271281
else:
272282
# Make sure the input vector and time vector have same length
273283
# TODO: allow interpolation of the input vector
274-
if len(U) != len(T):
275-
ValueError('Pamameter ``T`` must have same length as'
276-
'input vector ``U``')
284+
if (U.ndim == 1 and U.shape[0] != T.shape[0]) or \
285+
(U.ndim > 1 and U.shape[1] != T.shape[0]):
286+
ValueError('Pamameter ``T`` must have same elements as'
287+
' the number of columns in input array ``U``')
277288

278289
# Test if T has shape (n,) or (1, n);
279290
# T must be array-like and values must be increasing.
@@ -288,7 +299,7 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
288299
if not np.allclose(T[1:] - T[:-1], dt):
289300
raise ValueError("Parameter ``T``: time values must be "
290301
"equally spaced.")
291-
n_steps = len(T) # number of simulation steps
302+
n_steps = T.shape[0] # number of simulation steps
292303

293304
# create X0 if not given, test if X0 has correct shape
294305
X0 = _check_convert_array(X0, [(n_states,), (n_states, 1)],

0 commit comments

Comments
 (0)