1- # timeresp.py - time-domain simulation routines
2- #
3- # This file contains a collection of functions that calculate time
4- # responses for linear systems.
1+ """
2+ timeresp.py - time-domain simulation routines.
53
6- """ The :mod:`~control.timeresp` module contains a collection of
4+ The :mod:`~control.timeresp` module contains a collection of
75functions that are used to compute time-domain simulations of LTI
86systems.
97
2119See :ref:`time-series-convention` for more information on how time
2220series data are represented.
2321
24- """
25-
26- """Copyright (c) 2011 by California Institute of Technology
22+ Copyright (c) 2011 by California Institute of Technology
2723All rights reserved.
2824
2925Copyright (c) 2011 by Eike Welk
7571
7672import numpy as np
7773import scipy as sp
78- from numpy import atleast_1d , einsum , maximum , minimum
74+ from numpy import einsum , maximum , minimum
7975from scipy .linalg import eig , eigvals , matrix_balance , norm
8076
8177from . import config
82- from .lti import ( LTI , isctime , isdtime )
83- from .statesp import _convert_to_statespace , _mimo2simo , _mimo2siso , ssdata
78+ from .lti import isctime , isdtime
79+ from .statesp import StateSpace , _convert_to_statespace , _mimo2simo , _mimo2siso
8480from .xferfcn import TransferFunction
8581
8682__all__ = ['forced_response' , 'step_response' , 'step_info' , 'initial_response' ,
@@ -209,7 +205,7 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
209205
210206 Parameters
211207 ----------
212- sys : LTI ( StateSpace or TransferFunction)
208+ sys : StateSpace or TransferFunction
213209 LTI system to simulate
214210
215211 T : array_like, optional for discrete LTI `sys`
@@ -284,9 +280,9 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
284280 See :ref:`time-series-convention`.
285281
286282 """
287- if not isinstance (sys , LTI ):
288- raise TypeError ('Parameter ``sys``: must be a ``LTI `` object. '
289- '(For example ``StateSpace`` or ``TransferFunction``)' )
283+ if not isinstance (sys , ( StateSpace , TransferFunction ) ):
284+ raise TypeError ('Parameter ``sys``: must be a ``StateSpace `` or '
285+ ' ``TransferFunction``)' )
290286
291287 # If return_x was not specified, figure out the default
292288 if return_x is None :
@@ -738,20 +734,24 @@ def step_response(sys, T=None, X0=0., input=None, output=None, T_num=None,
738734 squeeze = squeeze , input = input , output = output )
739735
740736
741- def step_info (sys , T = None , T_num = None , SettlingTimeThreshold = 0.02 ,
737+ def step_info (sysdata , T = None , T_num = None , SettlingTimeThreshold = 0.02 ,
742738 RiseTimeLimits = (0.1 , 0.9 )):
743739 """
744740 Step response characteristics (Rise time, Settling Time, Peak and others).
745741
746742 Parameters
747743 ----------
748- sys : LTI system
744+ sysdata : StateSpace or TransferFunction or array_like
745+ The system data. Either LTI system to similate (StateSpace,
746+ TransferFunction), or a time series of step response data.
749747 T : array_like or float, optional
750748 Time vector, or simulation time duration if a number (time vector is
751749 autocomputed if not given, see :func:`step_response` for more detail)
750+ Required, if sysdata is a time series of response data.
752751 T_num : int, optional
753752 Number of time steps to use in simulation if T is not provided as an
754- array (autocomputed if not given); ignored if sys is discrete-time.
753+ array; autocomputed if not given; ignored if sysdata is a
754+ discrete-time system or a time series or response data.
755755 SettlingTimeThreshold : float value, optional
756756 Defines the error to compute settling time (default = 0.02)
757757 RiseTimeLimits : tuple (lower_threshold, upper_theshold)
@@ -760,7 +760,8 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
760760 Returns
761761 -------
762762 S : dict or list of list of dict
763- If `sys` is a SISO system, S is a dictionary containing:
763+ If `sysdata` corresponds to a SISO system, S is a dictionary
764+ containing:
764765
765766 RiseTime:
766767 Time from 10% to 90% of the steady-state value.
@@ -781,9 +782,9 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
781782 SteadyStateValue:
782783 Steady-state value
783784
784- If `sys` is a MIMO system, `S` is a 2D list of dicts. To get the
785- step response characteristics from the j-th input to the i-th output,
786- access ``S[i][j]``
785+ If `sysdata` corresponds to a MIMO system, `S` is a 2D list of dicts.
786+ To get the step response characteristics from the j-th input to the
787+ i-th output, access ``S[i][j]``
787788
788789
789790 See Also
@@ -833,18 +834,46 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
833834 PeakTime: 4.242
834835 SteadyStateValue: -1.0
835836 """
836- if T is None or np .asarray (T ).size == 1 :
837- T = _default_time_vector (sys , N = T_num , tfinal = T , is_step = True )
838- T , Yout = step_response (sys , T , squeeze = False )
837+ if isinstance (sysdata , (StateSpace , TransferFunction )):
838+ if T is None or np .asarray (T ).size == 1 :
839+ T = _default_time_vector (sysdata , N = T_num , tfinal = T , is_step = True )
840+ T , Yout = step_response (sysdata , T , squeeze = False )
841+ InfValues = np .atleast_2d (sysdata .dcgain ())
842+ retsiso = sysdata .issiso ()
843+ noutputs = sysdata .noutputs
844+ ninputs = sysdata .ninputs
845+ else :
846+ # Time series of response data
847+ errmsg = ("`sys` must be a LTI system, or time response data"
848+ " with a shape following the python-control"
849+ " time series data convention." )
850+ try :
851+ Yout = np .array (sysdata , dtype = float )
852+ except ValueError :
853+ raise ValueError (errmsg )
854+ if Yout .ndim == 1 or (Yout .ndim == 2 and Yout .shape [0 ] == 1 ):
855+ Yout = Yout [np .newaxis , np .newaxis , :]
856+ retsiso = True
857+ elif Yout .ndim == 3 :
858+ retsiso = False
859+ else :
860+ raise ValueError (errmsg )
861+ if T is None or Yout .shape [2 ] != len (np .squeeze (T )):
862+ raise ValueError ("For time response data, a matching time vector"
863+ " must be given" )
864+ T = np .squeeze (T )
865+ noutputs = Yout .shape [0 ]
866+ ninputs = Yout .shape [1 ]
867+ InfValues = Yout [:, :, - 1 ]
839868
840869 ret = []
841- for i in range (sys . noutputs ):
870+ for i in range (noutputs ):
842871 retrow = []
843- for j in range (sys . ninputs ):
872+ for j in range (ninputs ):
844873 yout = Yout [i , j , :]
845874
846875 # Steady state value
847- InfValue = sys . dcgain () if sys . issiso () else sys . dcgain () [i , j ]
876+ InfValue = InfValues [i , j ]
848877 sgnInf = np .sign (InfValue .real )
849878
850879 rise_time : float = np .NaN
@@ -869,7 +898,7 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
869898
870899 # SettlingTime
871900 settled = np .where (
872- np .abs (yout / InfValue - 1 ) >= SettlingTimeThreshold )[0 ][- 1 ]+ 1
901+ np .abs (yout / InfValue - 1 ) >= SettlingTimeThreshold )[0 ][- 1 ]+ 1
873902 # MIMO systems can have unsettled channels without infinite
874903 # InfValue
875904 if settled < len (T ):
@@ -917,7 +946,7 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
917946
918947 ret .append (retrow )
919948
920- return ret [0 ][0 ] if sys . issiso () else ret
949+ return ret [0 ][0 ] if retsiso else ret
921950
922951def initial_response (sys , T = None , X0 = 0. , input = 0 , output = None , T_num = None ,
923952 transpose = False , return_x = False , squeeze = None ):
0 commit comments