@@ -277,8 +277,6 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
277
277
if not isinstance (sys , LTI ):
278
278
raise TypeError ('Parameter ``sys``: must be a ``LTI`` object. '
279
279
'(For example ``StateSpace`` or ``TransferFunction``)' )
280
- if squeeze is None :
281
- squeeze = config .defaults ['control.squeeze' ]
282
280
283
281
sys = _convert_to_statespace (sys )
284
282
A , B , C , D = np .asarray (sys .A ), np .asarray (sys .B ), np .asarray (sys .C ), \
@@ -433,7 +431,16 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
433
431
xout = np .transpose (xout )
434
432
yout = np .transpose (yout )
435
433
434
+ return _process_time_response (sys , tout , yout , xout , transpose = transpose ,
435
+ return_x = return_x , squeeze = squeeze )
436
+
437
+
438
+ # Process time responses in a uniform way
439
+ def _process_time_response (sys , tout , yout , xout , transpose = None ,
440
+ return_x = False , squeeze = None ):
436
441
# Get rid of unneeded dimensions
442
+ if squeeze is None :
443
+ squeeze = config .defaults ['control.squeeze' ]
437
444
if squeeze and yout .shape [0 ] == 1 :
438
445
yout = yout [0 ]
439
446
@@ -443,10 +450,8 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
443
450
yout = np .transpose (yout )
444
451
xout = np .transpose (xout )
445
452
446
- if return_x :
447
- return tout , yout , xout
448
-
449
- return tout , yout
453
+ # Return time, output, and (optionally) state
454
+ return (tout , yout , xout ) if return_x else (tout , yout )
450
455
451
456
452
457
def _get_ss_simo (sys , input = None , output = None ):
@@ -640,7 +645,7 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
640
645
'SettlingMin' : yout [tr_upper_index :].min (),
641
646
'SettlingMax' : yout .max (),
642
647
'Overshoot' : 100. * (yout .max () - InfValue ) / (InfValue - yout [0 ]),
643
- 'Undershoot' : yout .min (), # not very confident about this
648
+ 'Undershoot' : yout .min (), # not very confident about this
644
649
'Peak' : yout [PeakIndex ],
645
650
'PeakTime' : T [PeakIndex ],
646
651
'SteadyStateValue' : InfValue
@@ -728,13 +733,8 @@ def initial_response(sys, T=None, X0=0., input=0, output=None, T_num=None,
728
733
T = _default_time_vector (sys , N = T_num , tfinal = T , is_step = False )
729
734
U = np .zeros_like (T )
730
735
731
- T , yout , _xout = forced_response (sys , T , U , X0 , transpose = transpose ,
732
- return_x = True , squeeze = squeeze )
733
-
734
- if return_x :
735
- return T , yout , _xout
736
-
737
- return T , yout
736
+ return forced_response (sys , T , U , X0 , transpose = transpose ,
737
+ return_x = return_x , squeeze = squeeze )
738
738
739
739
740
740
def impulse_response (sys , T = None , X0 = 0. , input = None , output = None , T_num = None ,
@@ -841,15 +841,11 @@ def impulse_response(sys, T=None, X0=0., input=None, output=None, T_num=None,
841
841
new_X0 = B + X0
842
842
else :
843
843
new_X0 = X0
844
- U [0 ] = 1. / sys .dt # unit area impulse
844
+ U [0 ] = 1. / sys .dt # unit area impulse
845
845
846
- T , yout , _xout = forced_response (sys , T , U , new_X0 , transpose = transpose ,
847
- return_x = True , squeeze = squeeze )
846
+ return forced_response (sys , T , U , new_X0 , transpose = transpose ,
847
+ return_x = return_x , squeeze = squeeze )
848
848
849
- if return_x :
850
- return T , yout , _xout
851
-
852
- return T , yout
853
849
854
850
# utility function to find time period and time increment using pole locations
855
851
def _ideal_tfinal_and_dt (sys , is_step = True ):
@@ -949,7 +945,7 @@ def _ideal_tfinal_and_dt(sys, is_step=True):
949
945
950
946
if p_int .size > 0 :
951
947
tfinal = tfinal * 5
952
- else : # cont time
948
+ else : # cont time
953
949
sys_ss = _convert_to_statespace (sys )
954
950
# Improve conditioning via balancing and zeroing tiny entries
955
951
# See <w,v> for [[1, 2, 0], [9, 1, 0.01], [1, 2, 10*np.pi]]
@@ -977,7 +973,7 @@ def _ideal_tfinal_and_dt(sys, is_step=True):
977
973
dc = np .zeros_like (p , dtype = float )
978
974
# well-conditioned nonzero poles, np.abs just in case
979
975
ok = np .abs (eig_sens ) <= 1 / sqrt_eps
980
- # the averaged t->inf response of each simple eigval on each i/o channel
976
+ # averaged t->inf response of each simple eigval on each i/o channel
981
977
# See, A = [[-1, k], [0, -2]], response sizes are k-dependent (that is
982
978
# R/L eigenvector dependent)
983
979
dc [ok ] = norm (v [ok , :], axis = 1 )* norm (w [:, ok ], axis = 0 )* eig_sens [ok ]
@@ -1003,7 +999,7 @@ def _ideal_tfinal_and_dt(sys, is_step=True):
1003
999
texp_mode = log_decay_percent / np .abs (psub [~ iw & ~ ints ].real )
1004
1000
tfinal += texp_mode .tolist ()
1005
1001
dt += minimum (texp_mode / 50 ,
1006
- ( 2 * np .pi / pts_per_cycle / wnsub [~ iw & ~ ints ])).tolist ()
1002
+ ( 2 * np .pi / pts_per_cycle / wnsub [~ iw & ~ ints ])).tolist ()
1007
1003
1008
1004
# All integrators?
1009
1005
if len (tfinal ) == 0 :
@@ -1014,30 +1010,32 @@ def _ideal_tfinal_and_dt(sys, is_step=True):
1014
1010
1015
1011
return tfinal , dt
1016
1012
1013
+
1017
1014
def _default_time_vector (sys , N = None , tfinal = None , is_step = True ):
1018
1015
"""Returns a time vector that has a reasonable number of points.
1019
1016
if system is discrete-time, N is ignored """
1020
1017
1021
1018
N_max = 5000
1022
- N_min_ct = 100 # min points for cont time systems
1023
- N_min_dt = 20 # more common to see just a few samples in discrete-time
1019
+ N_min_ct = 100 # min points for cont time systems
1020
+ N_min_dt = 20 # more common to see fewer samples in discrete-time
1024
1021
1025
1022
ideal_tfinal , ideal_dt = _ideal_tfinal_and_dt (sys , is_step = is_step )
1026
1023
1027
1024
if isdtime (sys , strict = True ):
1028
1025
# only need to use default_tfinal if not given; N is ignored.
1029
1026
if tfinal is None :
1030
1027
# for discrete time, change from ideal_tfinal if N too large/small
1031
- N = int (np .clip (ideal_tfinal / sys .dt , N_min_dt , N_max ))# [N_min, N_max]
1028
+ N = int (np .clip (ideal_tfinal / sys .dt , N_min_dt , N_max ))
1032
1029
tfinal = sys .dt * N
1033
1030
else :
1034
1031
N = int (tfinal / sys .dt )
1035
- tfinal = N * sys .dt # make tfinal an integer multiple of sys.dt
1032
+ tfinal = N * sys .dt # make tfinal an integer multiple of sys.dt
1036
1033
else :
1037
1034
if tfinal is None :
1038
1035
# for continuous time, simulate to ideal_tfinal but limit N
1039
1036
tfinal = ideal_tfinal
1040
1037
if N is None :
1041
- N = int (np .clip (tfinal / ideal_dt , N_min_ct , N_max )) # N<-[N_min, N_max]
1038
+ # N <- [N_min, N_max]
1039
+ N = int (np .clip (tfinal / ideal_dt , N_min_ct , N_max ))
1042
1040
1043
1041
return np .linspace (0 , tfinal , N , endpoint = False )
0 commit comments