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.
5
3
6
- """ The :mod:`~control.timeresp` module contains a collection of
4
+ The :mod:`~control.timeresp` module contains a collection of
7
5
functions that are used to compute time-domain simulations of LTI
8
6
systems.
9
7
21
19
See :ref:`time-series-convention` for more information on how time
22
20
series data are represented.
23
21
24
- """
25
-
26
- """Copyright (c) 2011 by California Institute of Technology
22
+ Copyright (c) 2011 by California Institute of Technology
27
23
All rights reserved.
28
24
29
25
Copyright (c) 2011 by Eike Welk
75
71
76
72
import numpy as np
77
73
import scipy as sp
78
- from numpy import atleast_1d , einsum , maximum , minimum
74
+ from numpy import einsum , maximum , minimum
79
75
from scipy .linalg import eig , eigvals , matrix_balance , norm
80
76
81
77
from . 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
84
80
from .xferfcn import TransferFunction
85
81
86
82
__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,
209
205
210
206
Parameters
211
207
----------
212
- sys : LTI ( StateSpace or TransferFunction)
208
+ sys : StateSpace or TransferFunction
213
209
LTI system to simulate
214
210
215
211
T : array_like, optional for discrete LTI `sys`
@@ -284,9 +280,9 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
284
280
See :ref:`time-series-convention`.
285
281
286
282
"""
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``)' )
290
286
291
287
# If return_x was not specified, figure out the default
292
288
if return_x is None :
@@ -738,20 +734,24 @@ def step_response(sys, T=None, X0=0., input=None, output=None, T_num=None,
738
734
squeeze = squeeze , input = input , output = output )
739
735
740
736
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 ,
742
738
RiseTimeLimits = (0.1 , 0.9 )):
743
739
"""
744
740
Step response characteristics (Rise time, Settling Time, Peak and others).
745
741
746
742
Parameters
747
743
----------
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.
749
747
T : array_like or float, optional
750
748
Time vector, or simulation time duration if a number (time vector is
751
749
autocomputed if not given, see :func:`step_response` for more detail)
750
+ Required, if sysdata is a time series of response data.
752
751
T_num : int, optional
753
752
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.
755
755
SettlingTimeThreshold : float value, optional
756
756
Defines the error to compute settling time (default = 0.02)
757
757
RiseTimeLimits : tuple (lower_threshold, upper_theshold)
@@ -760,7 +760,8 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
760
760
Returns
761
761
-------
762
762
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:
764
765
765
766
RiseTime:
766
767
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,
781
782
SteadyStateValue:
782
783
Steady-state value
783
784
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]``
787
788
788
789
789
790
See Also
@@ -833,18 +834,46 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
833
834
PeakTime: 4.242
834
835
SteadyStateValue: -1.0
835
836
"""
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 ]
839
868
840
869
ret = []
841
- for i in range (sys . noutputs ):
870
+ for i in range (noutputs ):
842
871
retrow = []
843
- for j in range (sys . ninputs ):
872
+ for j in range (ninputs ):
844
873
yout = Yout [i , j , :]
845
874
846
875
# Steady state value
847
- InfValue = sys . dcgain () if sys . issiso () else sys . dcgain () [i , j ]
876
+ InfValue = InfValues [i , j ]
848
877
sgnInf = np .sign (InfValue .real )
849
878
850
879
rise_time : float = np .NaN
@@ -869,7 +898,7 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
869
898
870
899
# SettlingTime
871
900
settled = np .where (
872
- np .abs (yout / InfValue - 1 ) >= SettlingTimeThreshold )[0 ][- 1 ]+ 1
901
+ np .abs (yout / InfValue - 1 ) >= SettlingTimeThreshold )[0 ][- 1 ]+ 1
873
902
# MIMO systems can have unsettled channels without infinite
874
903
# InfValue
875
904
if settled < len (T ):
@@ -917,7 +946,7 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
917
946
918
947
ret .append (retrow )
919
948
920
- return ret [0 ][0 ] if sys . issiso () else ret
949
+ return ret [0 ][0 ] if retsiso else ret
921
950
922
951
def initial_response (sys , T = None , X0 = 0. , input = 0 , output = None , T_num = None ,
923
952
transpose = False , return_x = False , squeeze = None ):
0 commit comments