@@ -277,8 +277,6 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
277277 if not isinstance (sys , LTI ):
278278 raise TypeError ('Parameter ``sys``: must be a ``LTI`` object. '
279279 '(For example ``StateSpace`` or ``TransferFunction``)' )
280- if squeeze is None :
281- squeeze = config .defaults ['control.squeeze' ]
282280
283281 sys = _convert_to_statespace (sys )
284282 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,
433431 xout = np .transpose (xout )
434432 yout = np .transpose (yout )
435433
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 ):
436441 # Get rid of unneeded dimensions
442+ if squeeze is None :
443+ squeeze = config .defaults ['control.squeeze' ]
437444 if squeeze and yout .shape [0 ] == 1 :
438445 yout = yout [0 ]
439446
@@ -443,10 +450,8 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
443450 yout = np .transpose (yout )
444451 xout = np .transpose (xout )
445452
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 )
450455
451456
452457def _get_ss_simo (sys , input = None , output = None ):
@@ -640,7 +645,7 @@ def step_info(sys, T=None, T_num=None, SettlingTimeThreshold=0.02,
640645 'SettlingMin' : yout [tr_upper_index :].min (),
641646 'SettlingMax' : yout .max (),
642647 '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
644649 'Peak' : yout [PeakIndex ],
645650 'PeakTime' : T [PeakIndex ],
646651 'SteadyStateValue' : InfValue
@@ -728,13 +733,8 @@ def initial_response(sys, T=None, X0=0., input=0, output=None, T_num=None,
728733 T = _default_time_vector (sys , N = T_num , tfinal = T , is_step = False )
729734 U = np .zeros_like (T )
730735
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 )
738738
739739
740740def 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,
841841 new_X0 = B + X0
842842 else :
843843 new_X0 = X0
844- U [0 ] = 1. / sys .dt # unit area impulse
844+ U [0 ] = 1. / sys .dt # unit area impulse
845845
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 )
848848
849- if return_x :
850- return T , yout , _xout
851-
852- return T , yout
853849
854850# utility function to find time period and time increment using pole locations
855851def _ideal_tfinal_and_dt (sys , is_step = True ):
@@ -949,7 +945,7 @@ def _ideal_tfinal_and_dt(sys, is_step=True):
949945
950946 if p_int .size > 0 :
951947 tfinal = tfinal * 5
952- else : # cont time
948+ else : # cont time
953949 sys_ss = _convert_to_statespace (sys )
954950 # Improve conditioning via balancing and zeroing tiny entries
955951 # 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):
977973 dc = np .zeros_like (p , dtype = float )
978974 # well-conditioned nonzero poles, np.abs just in case
979975 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
981977 # See, A = [[-1, k], [0, -2]], response sizes are k-dependent (that is
982978 # R/L eigenvector dependent)
983979 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):
1003999 texp_mode = log_decay_percent / np .abs (psub [~ iw & ~ ints ].real )
10041000 tfinal += texp_mode .tolist ()
10051001 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 ()
10071003
10081004 # All integrators?
10091005 if len (tfinal ) == 0 :
@@ -1014,30 +1010,32 @@ def _ideal_tfinal_and_dt(sys, is_step=True):
10141010
10151011 return tfinal , dt
10161012
1013+
10171014def _default_time_vector (sys , N = None , tfinal = None , is_step = True ):
10181015 """Returns a time vector that has a reasonable number of points.
10191016 if system is discrete-time, N is ignored """
10201017
10211018 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
10241021
10251022 ideal_tfinal , ideal_dt = _ideal_tfinal_and_dt (sys , is_step = is_step )
10261023
10271024 if isdtime (sys , strict = True ):
10281025 # only need to use default_tfinal if not given; N is ignored.
10291026 if tfinal is None :
10301027 # 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 ))
10321029 tfinal = sys .dt * N
10331030 else :
10341031 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
10361033 else :
10371034 if tfinal is None :
10381035 # for continuous time, simulate to ideal_tfinal but limit N
10391036 tfinal = ideal_tfinal
10401037 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 ))
10421040
10431041 return np .linspace (0 , tfinal , N , endpoint = False )
0 commit comments