Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ff960c3

Browse files
committed
enhance step_info to MIMO
1 parent b41574f commit ff960c3

File tree

1 file changed

+100
-88
lines changed

1 file changed

+100
-88
lines changed

control/timeresp.py

Lines changed: 100 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -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

865877
def 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

Comments
 (0)