Skip to content

Commit 2870432

Browse files
committed
allow T=None with sys.dt=None in forced_response
1 parent 1f51526 commit 2870432

1 file changed

Lines changed: 15 additions & 12 deletions

File tree

control/timeresp.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
210210
211211
T : array_like, optional for discrete LTI `sys`
212212
Time steps at which the input is defined; values must be evenly spaced.
213+
If None, `U` must be given and and `len(U)` time steps of sys.dt are
214+
simulated. If sys.dt is None or True (undetermined time step), a dt
215+
of 1.0 is assumed.
213216
214217
U : array_like or float, optional
215218
Input array giving input at each time `T`
@@ -245,7 +248,7 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
245248
squeeze=True, remove single-dimensional entries from the shape of
246249
the output even if the system is not SISO. If squeeze=False, keep
247250
the output as a 2D array (indexed by the output number and time)
248-
even if the system is SISO. The default value can be overruled by
251+
even if the system is SISO. The default value can be overridden by
249252
config.defaults['control.squeeze_time_response'].
250253
251254
Returns
@@ -310,10 +313,11 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
310313
if U is not None:
311314
U = np.asarray(U)
312315
if T is not None:
316+
# T must be array-like
313317
T = np.asarray(T)
314318

315319
# Set and/or check time vector in discrete time case
316-
if isdtime(sys, strict=True):
320+
if isdtime(sys):
317321
if T is None:
318322
if U is None:
319323
raise ValueError('Parameters ``T`` and ``U`` can\'t both be'
@@ -323,29 +327,28 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
323327
n_steps = U.shape[0]
324328
else:
325329
n_steps = U.shape[1]
326-
T = np.array(range(n_steps)) * (1 if sys.dt is True else sys.dt)
330+
dt = 1. if sys.dt in [True, None] else sys.dt
331+
T = np.array(range(n_steps)) * dt
327332
else:
328333
# Make sure the input vector and time vector have same length
329334
# TODO: allow interpolation of the input vector
330335
if (U.ndim == 1 and U.shape[0] != T.shape[0]) or \
331336
(U.ndim > 1 and U.shape[1] != T.shape[0]):
332337
ValueError('Pamameter ``T`` must have same elements as'
333338
' the number of columns in input array ``U``')
339+
else:
340+
if T is None:
341+
raise ValueError('Parameter ``T`` is mandatory for continuous '
342+
'time systems.')
334343

335344
# Test if T has shape (n,) or (1, n);
336-
# T must be array-like and values must be increasing.
337-
# The length of T determines the length of the input vector.
338-
if T is None:
339-
if not isdtime(sys, strict=True):
340-
errmsg_ctime = 'is mandatory for continuous time systems, '
341-
raise ValueError('Parameter ``T`` ' + errmsg_ctime + 'must be '
342-
'array-like, and contain (strictly monotonic) '
343-
'increasing numbers.')
344345
T = _check_convert_array(T, [('any',), (1, 'any')],
345346
'Parameter ``T``: ', squeeze=True,
346347
transpose=transpose)
348+
349+
# equally spaced also implies strictly monotonic increase
347350
dt = T[1] - T[0]
348-
if not np.allclose(T[1:] - T[:-1], dt):
351+
if not np.allclose(np.diff(T), np.full_like(T[:-1], dt)):
349352
raise ValueError("Parameter ``T``: time values must be "
350353
"equally spaced.")
351354
n_steps = T.shape[0] # number of simulation steps

0 commit comments

Comments
 (0)