@@ -746,36 +746,43 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
746746
747747 Parameters
748748 ----------
749- sys : SISO dynamic system model. Dynamic systems that you can use include:
750- StateSpace or TransferFunction
751- LTI system to simulate
752-
749+ sys : LTI system
753750 T : array_like or float, optional
754751 Time vector, or simulation time duration if a number (time vector is
755752 autocomputed if not given, see :func:`step_response` for more detail)
756-
757753 T_num : int, optional
758754 Number of time steps to use in simulation if T is not provided as an
759755 array (autocomputed if not given); ignored if sys is discrete-time.
760-
761756 SettlingTimeThreshold : float value, optional
762757 Defines the error to compute settling time (default = 0.02)
763-
764758 RiseTimeLimits : tuple (lower_threshold, upper_theshold)
765759 Defines the lower and upper threshold for RiseTime computation
766760
767761 Returns
768762 -------
769- S: a dictionary containing:
770- RiseTime: Time from 10% to 90% of the steady-state value.
771- SettlingTime: Time to enter inside a default error of 2%
772- SettlingMin: Minimum value after RiseTime
773- SettlingMax: Maximum value after RiseTime
774- Overshoot: Percentage of the Peak relative to steady value
775- Undershoot: Percentage of undershoot
776- Peak: Absolute peak value
777- PeakTime: time of the Peak
778- SteadyStateValue: Steady-state value
763+ S : dict or list of list of dict
764+ If `sys` is a SISO system, S is a dictionary containing:
765+
766+ RiseTime:
767+ Time from 10% to 90% of the steady-state value.
768+ SettlingTime:
769+ Time to enter inside a default error of 2%
770+ SettlingMin:
771+ Minimum value after RiseTime
772+ SettlingMax:
773+ Maximum value after RiseTime
774+ Overshoot:
775+ Percentage of the Peak relative to steady value
776+ Undershoot:
777+ Percentage of undershoot
778+ Peak:
779+ Absolute peak value
780+ PeakTime:
781+ time of the Peak
782+ SteadyStateValue:
783+ Steady-state value
784+
785+ If `sys` is a MIMO system, S is a 2D-List of dicts.
779786
780787
781788 See Also
@@ -786,81 +793,86 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
786793 --------
787794 >>> info = step_info(sys, T)
788795 '''
789-
790- if not sys .issiso ():
791- sys = _mimo2siso (sys ,0 ,0 )
792- warnings .warn (" Internal conversion from a MIMO system to a SISO system,"
793- " the first input and the first output were used (u1 -> y1);"
794- " it may not be the result you are looking for" )
796+
795797
796798 if T is None or np .asarray (T ).size == 1 :
797799 T = _default_time_vector (sys , N = T_num , tfinal = T , is_step = True )
798800
799- T , yout = step_response (sys , T )
800-
801- # Steady state value
802- InfValue = sys .dcgain ().real
803-
804- # TODO: this could be a function step_info4data(t,y,yfinal)
805- rise_time : float = np .NaN
806- settling_time : float = np .NaN
807- settling_min : float = np .NaN
808- settling_max : float = np .NaN
809- peak_value : float = np .Inf
810- peak_time : float = np .Inf
811- undershoot : float = np .NaN
812- overshoot : float = np .NaN
813- steady_state_value : float = np .NaN
814-
815- if not np .isnan (InfValue ) and not np .isinf (InfValue ):
816- # SteadyStateValue
817- steady_state_value = InfValue
818- # Peak
819- peak_index = np .abs (yout ).argmax ()
820- peak_value = np .abs (yout [peak_index ])
821- peak_time = T [peak_index ]
822-
823- sup_margin = (1. + SettlingTimeThreshold ) * InfValue
824- inf_margin = (1. - SettlingTimeThreshold ) * InfValue
825-
826- # RiseTime
827- tr_lower_index = (np .where (np .sign (InfValue .real ) * (yout - RiseTimeLimits [0 ] * InfValue ) >= 0 )[0 ])[0 ]
828- tr_upper_index = (np .where (np .sign (InfValue .real ) * yout >= np .sign (InfValue .real ) * RiseTimeLimits [1 ] * InfValue )[0 ])[0 ]
829-
830- # SettlingTime
831- settling_time = T [np .where (np .abs (yout - InfValue ) >= np .abs (SettlingTimeThreshold * InfValue ))[0 ][- 1 ]+ 1 ]
832- # Overshoot and Undershoot
833- y_os = (np .sign (InfValue .real )* yout ).max ()
834- dy_os = np .abs (y_os ) - np .abs (InfValue )
835- if dy_os > 0 :
836- overshoot = np .abs (100. * dy_os / InfValue )
837- else :
838- overshoot = 0
839-
840- y_us = (np .sign (InfValue .real )* yout ).min ()
841- dy_us = np .abs (y_us )
842- if dy_us > 0 :
843- undershoot = np .abs (100. * dy_us / InfValue )
844- else :
845- undershoot = 0
846-
847- # RiseTime
848- rise_time = T [tr_upper_index ] - T [tr_lower_index ]
849-
850- settling_max = (yout [tr_upper_index :]).max ()
851- settling_min = (yout [tr_upper_index :]).min ()
852-
853- return {
854- 'RiseTime' : rise_time ,
855- 'SettlingTime' : settling_time ,
856- 'SettlingMin' : settling_min ,
857- 'SettlingMax' : settling_max ,
858- 'Overshoot' : overshoot ,
859- 'Undershoot' : undershoot ,
860- 'Peak' : peak_value ,
861- 'PeakTime' : peak_time ,
862- 'SteadyStateValue' : steady_state_value
863- }
801+ ret = [[None ] * sys .ninputs ] * sys .noutputs
802+ for i in range (sys .noutputs ):
803+ for j in range (sys .ninputs ):
804+ sys_siso = sys [i , j ]
805+ T , yout = step_response (sys_siso , T )
806+
807+ # Steady state value
808+ InfValue = sys_siso .dcgain ()
809+ sgnInf = np .sign (InfValue .real )
810+
811+ rise_time : float = np .NaN
812+ settling_time : float = np .NaN
813+ settling_min : float = np .NaN
814+ settling_max : float = np .NaN
815+ peak_value : float = np .Inf
816+ peak_time : float = np .Inf
817+ undershoot : float = np .NaN
818+ overshoot : float = np .NaN
819+ steady_state_value : complex = np .NaN
820+
821+ if not np .isnan (InfValue ) and not np .isinf (InfValue ):
822+ # RiseTime
823+ tr_lower_index = np .where (
824+ sgnInf * (yout - RiseTimeLimits [0 ] * InfValue ) >= 0
825+ )[0 ][0 ]
826+ tr_upper_index = np .where (
827+ sgnInf * (yout - RiseTimeLimits [1 ] * InfValue ) >= 0
828+ )[0 ][0 ]
829+ rise_time = T [tr_upper_index ] - T [tr_lower_index ]
830+
831+ # SettlingTime
832+ settling_th = np .abs (SettlingTimeThreshold * InfValue )
833+ not_settled = np .where (np .abs (yout - InfValue ) >= settling_th )
834+ settling_time = T [not_settled [0 ][- 1 ] + 1 ]
835+
836+ settling_min = (yout [tr_upper_index :]).min ()
837+ settling_max = (yout [tr_upper_index :]).max ()
838+
839+ # Overshoot
840+ y_os = (sgnInf * yout ).max ()
841+ dy_os = np .abs (y_os ) - np .abs (InfValue )
842+ if dy_os > 0 :
843+ overshoot = np .abs (100. * dy_os / InfValue )
844+ else :
845+ overshoot = 0
846+
847+ # Undershoot
848+ y_us = (sgnInf * yout ).min ()
849+ dy_us = np .abs (y_us )
850+ if dy_us > 0 :
851+ undershoot = np .abs (100. * dy_us / InfValue )
852+ else :
853+ undershoot = 0
854+
855+ # Peak
856+ peak_index = np .abs (yout ).argmax ()
857+ peak_value = np .abs (yout [peak_index ])
858+ peak_time = T [peak_index ]
859+
860+ # SteadyStateValue
861+ steady_state_value = InfValue
862+
863+ ret [i ][j ] = {
864+ 'RiseTime' : rise_time ,
865+ 'SettlingTime' : settling_time ,
866+ 'SettlingMin' : settling_min ,
867+ 'SettlingMax' : settling_max ,
868+ 'Overshoot' : overshoot ,
869+ 'Undershoot' : undershoot ,
870+ 'Peak' : peak_value ,
871+ 'PeakTime' : peak_time ,
872+ 'SteadyStateValue' : steady_state_value
873+ }
874+
875+ return ret [0 ][0 ] if sys .issiso () else ret
864876
865877def initial_response (sys , T = None , X0 = 0. , input = 0 , output = None , T_num = None ,
866878 transpose = False , return_x = False , squeeze = None ):
0 commit comments