Skip to content

Commit 56cecc0

Browse files
authored
Merge pull request #649 from murrayrm/timeresponse_class
Time response data class
2 parents 5155dd5 + 136d6f4 commit 56cecc0

File tree

8 files changed

+1230
-189
lines changed

8 files changed

+1230
-189
lines changed

control/iosys.py

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
from warnings import warn
3333

3434
from .statesp import StateSpace, tf2ss, _convert_to_statespace
35-
from .timeresp import _check_convert_array, _process_time_response
35+
from .timeresp import _check_convert_array, _process_time_response, \
36+
TimeResponseData
3637
from .lti import isctime, isdtime, common_timebase
3738
from . import config
3839

@@ -878,7 +879,7 @@ def __init__(self, updfcn, outfcn=None, inputs=None, outputs=None,
878879
def __call__(sys, u, params=None, squeeze=None):
879880
"""Evaluate a (static) nonlinearity at a given input value
880881
881-
If a nonlinear I/O system has not internal state, then evaluating the
882+
If a nonlinear I/O system has no internal state, then evaluating the
882883
system at an input `u` gives the output `y = F(u)`, determined by the
883884
output function.
884885
@@ -907,7 +908,8 @@ def __call__(sys, u, params=None, squeeze=None):
907908

908909
# Evaluate the function on the argument
909910
out = sys._out(0, np.array((0,)), np.asarray(u))
910-
_, out = _process_time_response(sys, None, out, None, squeeze=squeeze)
911+
_, out = _process_time_response(
912+
None, out, issiso=sys.issiso(), squeeze=squeeze)
911913
return out
912914

913915
def _update_params(self, params, warning=False):
@@ -1641,14 +1643,21 @@ def input_output_response(
16411643
----------
16421644
sys : InputOutputSystem
16431645
Input/output system to simulate.
1646+
16441647
T : array-like
16451648
Time steps at which the input is defined; values must be evenly spaced.
1649+
16461650
U : array-like or number, optional
16471651
Input array giving input at each time `T` (default = 0).
1652+
16481653
X0 : array-like or number, optional
16491654
Initial condition (default = 0).
1655+
16501656
return_x : bool, optional
1657+
If True, return the state vector when assigning to a tuple (default =
1658+
False). See :func:`forced_response` for more details.
16511659
If True, return the values of the state at each time (default = False).
1660+
16521661
squeeze : bool, optional
16531662
If True and if the system has a single output, return the system
16541663
output as a 1D array rather than a 2D array. If False, return the
@@ -1657,15 +1666,27 @@ def input_output_response(
16571666
16581667
Returns
16591668
-------
1660-
T : array
1661-
Time values of the output.
1662-
yout : array
1663-
Response of the system. If the system is SISO and squeeze is not
1664-
True, the array is 1D (indexed by time). If the system is not SISO or
1665-
squeeze is False, the array is 2D (indexed by the output number and
1666-
time).
1667-
xout : array
1668-
Time evolution of the state vector (if return_x=True).
1669+
results : TimeResponseData
1670+
Time response represented as a :class:`TimeResponseData` object
1671+
containing the following properties:
1672+
1673+
* time (array): Time values of the output.
1674+
1675+
* outputs (array): Response of the system. If the system is SISO and
1676+
`squeeze` is not True, the array is 1D (indexed by time). If the
1677+
system is not SISO or `squeeze` is False, the array is 2D (indexed
1678+
by output and time).
1679+
1680+
* states (array): Time evolution of the state vector, represented as
1681+
a 2D array indexed by state and time.
1682+
1683+
* inputs (array): Input(s) to the system, indexed by input and time.
1684+
1685+
The return value of the system can also be accessed by assigning the
1686+
function to a tuple of length 2 (time, output) or of length 3 (time,
1687+
output, state) if ``return_x`` is ``True``. If the input/output
1688+
system signals are named, these names will be used as labels for the
1689+
time response.
16691690
16701691
Other parameters
16711692
----------------
@@ -1727,8 +1748,9 @@ def input_output_response(
17271748
for i in range(len(T)):
17281749
u = U[i] if len(U.shape) == 1 else U[:, i]
17291750
y[:, i] = sys._out(T[i], [], u)
1730-
return _process_time_response(
1731-
sys, T, y, np.array((0, 0, np.asarray(T).size)),
1751+
return TimeResponseData(
1752+
T, y, None, U, issiso=sys.issiso(),
1753+
output_labels=sys.output_index, input_labels=sys.input_index,
17321754
transpose=transpose, return_x=return_x, squeeze=squeeze)
17331755

17341756
# create X0 if not given, test if X0 has correct shape
@@ -1823,8 +1845,11 @@ def ivp_rhs(t, x):
18231845
else: # Neither ctime or dtime??
18241846
raise TypeError("Can't determine system type")
18251847

1826-
return _process_time_response(sys, soln.t, y, soln.y, transpose=transpose,
1827-
return_x=return_x, squeeze=squeeze)
1848+
return TimeResponseData(
1849+
soln.t, y, soln.y, U, issiso=sys.issiso(),
1850+
output_labels=sys.output_index, input_labels=sys.input_index,
1851+
state_labels=sys.state_index,
1852+
transpose=transpose, return_x=return_x, squeeze=squeeze)
18281853

18291854

18301855
def find_eqpt(sys, x0, u0=[], y0=None, t=0, params={},

control/optimal.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import logging
1717
import time
1818

19-
from .timeresp import _process_time_response
19+
from .timeresp import TimeResponseData
2020

2121
__all__ = ['find_optimal_input']
2222

@@ -826,13 +826,14 @@ def __init__(
826826
else:
827827
states = None
828828

829-
retval = _process_time_response(
830-
ocp.system, ocp.timepts, inputs, states,
829+
# Process data as a time response (with "outputs" = inputs)
830+
response = TimeResponseData(
831+
ocp.timepts, inputs, states, issiso=ocp.system.issiso(),
831832
transpose=transpose, return_x=return_states, squeeze=squeeze)
832833

833-
self.time = retval[0]
834-
self.inputs = retval[1]
835-
self.states = None if states is None else retval[2]
834+
self.time = response.time
835+
self.inputs = response.outputs
836+
self.states = response.states
836837

837838

838839
# Compute the input for a nonlinear, (constrained) optimal control problem

control/statesp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,10 +1946,10 @@ def rss(states=1, outputs=1, inputs=1, strictly_proper=False):
19461946
----------
19471947
states : int
19481948
Number of state variables
1949-
inputs : int
1950-
Number of system inputs
19511949
outputs : int
19521950
Number of system outputs
1951+
inputs : int
1952+
Number of system inputs
19531953
strictly_proper : bool, optional
19541954
If set to 'True', returns a proper system (no direct term).
19551955

control/tests/timeresp_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,7 @@ def test_squeeze(self, fcn, nstate, nout, ninp, squeeze, shape1, shape2):
11181118
@pytest.mark.parametrize("fcn", [ct.ss, ct.tf, ct.ss2io])
11191119
def test_squeeze_exception(self, fcn):
11201120
sys = fcn(ct.rss(2, 1, 1))
1121-
with pytest.raises(ValueError, match="unknown squeeze value"):
1121+
with pytest.raises(ValueError, match="Unknown squeeze value"):
11221122
step_response(sys, squeeze=1)
11231123

11241124
@pytest.mark.usefixtures("editsdefaults")

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy