@@ -746,36 +746,43 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
746
746
747
747
Parameters
748
748
----------
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
753
750
T : array_like or float, optional
754
751
Time vector, or simulation time duration if a number (time vector is
755
752
autocomputed if not given, see :func:`step_response` for more detail)
756
-
757
753
T_num : int, optional
758
754
Number of time steps to use in simulation if T is not provided as an
759
755
array (autocomputed if not given); ignored if sys is discrete-time.
760
-
761
756
SettlingTimeThreshold : float value, optional
762
757
Defines the error to compute settling time (default = 0.02)
763
-
764
758
RiseTimeLimits : tuple (lower_threshold, upper_theshold)
765
759
Defines the lower and upper threshold for RiseTime computation
766
760
767
761
Returns
768
762
-------
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.
779
786
780
787
781
788
See Also
@@ -786,81 +793,86 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
786
793
--------
787
794
>>> info = step_info(sys, T)
788
795
'''
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
+
795
797
796
798
if T is None or np .asarray (T ).size == 1 :
797
799
T = _default_time_vector (sys ,N = T_num ,tfinal = T ,is_step = True )
798
800
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
864
876
865
877
def initial_response (sys ,T = None ,X0 = 0. ,input = 0 ,output = None ,T_num = None ,
866
878
transpose = False ,return_x = False ,squeeze = None ):