@@ -157,8 +157,10 @@ class TimeResponseData:
157157 compatibility with MATLAB and :func:`scipy.signal.lsim`). Default
158158 value is False.
159159
160- sys : InputOutputSystem or LTI, optional
161- If present, stores the system used to generate the response.
160+ issiso : bool, optional
161+ Set to ``True`` if the system generating the data is single-input,
162+ single-output. If passed as ``None`` (default), the input data
163+ will be used to set the value.
162164
163165 ninputs, noutputs, nstates : int
164166 Number of inputs, outputs, and states of the underlying system.
@@ -198,7 +200,7 @@ class TimeResponseData:
198200 """
199201
200202 def __init__ (
201- self , time , outputs , states = None , inputs = None , sys = None , dt = None ,
203+ self , time , outputs , states = None , inputs = None , issiso = None ,
202204 transpose = False , return_x = False , squeeze = None ,
203205 multi_trace = False , input_index = None , output_index = None
204206 ):
@@ -369,15 +371,22 @@ def __init__(
369371 if self .t .shape [- 1 ] != self .u .shape [- 1 ]:
370372 raise ValueError ("Input vector does not match time vector" )
371373
372- # If the system was specified, make sure it is compatible
373- if sys is not None :
374- if sys .noutputs != self .noutputs :
375- ValueError ("System outputs do not match response data" )
376- if self .x is not None and sys .nstates != self .nstates :
377- ValueError ("System states do not match response data" )
378- if self .u is not None and sys .ninputs != self .ninputs :
379- ValueError ("System inputs do not match response data" )
380- self .sys = sys
374+ # Figure out if the system is SISO
375+ if issiso is None :
376+ # Figure out based on the data
377+ if self .ninputs == 1 :
378+ issiso = self .noutputs == 1
379+ elif self .niinputs > 1 :
380+ issiso = False
381+ else :
382+ # Missing input data => can't resolve
383+ raise ValueError ("Can't determine if system is SISO" )
384+ elif issiso is True and (self .ninputs > 1 or self .noutputs > 1 ):
385+ raise ValueError ("Keyword `issiso` does not match data" )
386+
387+ # Set the value to be used for future processing
388+ self .issiso = issiso or \
389+ (input_index is not None and output_index is not None )
381390
382391 # Keep track of whether to squeeze inputs, outputs, and states
383392 if not (squeeze is True or squeeze is None or squeeze is False ):
@@ -397,9 +406,8 @@ def time(self):
397406 @property
398407 def outputs (self ):
399408 t , y = _process_time_response (
400- self .sys , self .t , self .y ,
401- transpose = self .transpose , squeeze = self .squeeze ,
402- input = self .input_index , output = self .output_index )
409+ self .t , self .y , issiso = self .issiso ,
410+ transpose = self .transpose , squeeze = self .squeeze )
403411 return y
404412
405413 # Getter for state (implements non-standard squeeze processing)
@@ -430,9 +438,8 @@ def inputs(self):
430438 return None
431439
432440 t , u = _process_time_response (
433- self .sys , self .t , self .u ,
434- transpose = self .transpose , squeeze = self .squeeze ,
435- input = self .input_index , output = self .output_index )
441+ self .t , self .u , issiso = self .issiso ,
442+ transpose = self .transpose , squeeze = self .squeeze )
436443 return u
437444
438445 # Implement iter to allow assigning to a tuple
@@ -571,7 +578,7 @@ def shape_matches(s_legal, s_actual):
571578
572579
573580# Forced response of a linear system
574- def forced_response (sys , T = None , U = 0. , X0 = 0. , transpose = False ,
581+ def forced_response (sys , T = None , U = 0. , X0 = 0. , issiso = False , transpose = False ,
575582 interpolate = False , return_x = None , squeeze = None ):
576583 """Simulate the output of a linear system.
577584
@@ -860,24 +867,20 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
860867 yout = np .transpose (yout )
861868
862869 return TimeResponseData (
863- tout , yout , xout , U , sys = sys ,
870+ tout , yout , xout , U , issiso = sys . issiso () ,
864871 transpose = transpose , return_x = return_x , squeeze = squeeze )
865872
866873
867874# Process time responses in a uniform way
868875def _process_time_response (
869- sys , tout , yout , transpose = None ,
870- squeeze = None , input = None , output = None ):
876+ tout , yout , issiso = False , transpose = None , squeeze = None ):
871877 """Process time response signals.
872878
873- This function processes the outputs of the time response functions and
874- processes the transpose and squeeze keywords.
879+ This function processes the outputs (or inputs) of time response
880+ functions and processes the transpose and squeeze keywords.
875881
876882 Parameters
877883 ----------
878- sys : LTI or InputOutputSystem
879- System that generated the data (used to check if SISO/MIMO).
880-
881884 T : 1D array
882885 Time values of the output. Ignored if None.
883886
@@ -887,6 +890,10 @@ def _process_time_response(
887890 systems with no input indexing, such as initial_response or forced
888891 response) or a 3D array indexed by output, input, and time.
889892
893+ issiso : bool, optional
894+ If ``True``, process data as single-input, single-output data.
895+ Default is ``False``.
896+
890897 transpose : bool, optional
891898 If True, transpose all input and output arrays (for backward
892899 compatibility with MATLAB and :func:`scipy.signal.lsim`). Default
@@ -901,12 +908,6 @@ def _process_time_response(
901908 the system is SISO. The default value can be set using
902909 config.defaults['control.squeeze_time_response'].
903910
904- input : int, optional
905- If present, the response represents only the listed input.
906-
907- output : int, optional
908- If present, the response represents only the listed output.
909-
910911 Returns
911912 -------
912913 T : 1D array
@@ -923,9 +924,6 @@ def _process_time_response(
923924 if squeeze is None :
924925 squeeze = config .defaults ['control.squeeze_time_response' ]
925926
926- # Determine if the system is SISO
927- issiso = sys .issiso () or (input is not None and output is not None )
928-
929927 # Figure out whether and how to squeeze output data
930928 if squeeze is True : # squeeze all dimensions
931929 yout = np .squeeze (yout )
@@ -1116,16 +1114,15 @@ def step_response(sys, T=None, X0=0., input=None, output=None, T_num=None,
11161114 # Create a set of single inputs system for simulation
11171115 squeeze , simo = _get_ss_simo (sys , i , output , squeeze = squeeze )
11181116
1119- out = forced_response (simo , T , U , X0 , transpose = False ,
1120- return_x = return_x , squeeze = True )
1117+ response = forced_response (simo , T , U , X0 , squeeze = True )
11211118 inpidx = i if input is None else 0
1122- yout [:, inpidx , :] = out [ 1 ]
1123- xout [:, inpidx , :] = out [ 2 ]
1119+ yout [:, inpidx , :] = response . y
1120+ xout [:, inpidx , :] = response . x
11241121 uout [:, inpidx , :] = U
11251122
11261123 return TimeResponseData (
1127- out [ 0 ] , yout , xout , uout , sys = sys , transpose = transpose ,
1128- return_x = return_x , squeeze = squeeze ,
1124+ response . time , yout , xout , uout , issiso = sys . issiso () ,
1125+ transpose = transpose , return_x = return_x , squeeze = squeeze ,
11291126 input_index = input , output_index = output )
11301127
11311128
@@ -1441,12 +1438,11 @@ def initial_response(sys, T=None, X0=0., input=0, output=None, T_num=None,
14411438 T = _default_time_vector (sys , N = T_num , tfinal = T , is_step = False )
14421439
14431440 # Compute the forced response
1444- res = forced_response (sys , T , 0 , X0 , transpose = transpose ,
1445- return_x = return_x , squeeze = squeeze )
1441+ response = forced_response (sys , T , 0 , X0 )
14461442
14471443 # Store the response without an input
14481444 return TimeResponseData (
1449- res .t , res .y , res .x , None , sys = sys ,
1445+ response .t , response .y , response .x , None , issiso = sys . issiso () ,
14501446 transpose = transpose , return_x = return_x , squeeze = squeeze )
14511447
14521448
@@ -1593,17 +1589,16 @@ def impulse_response(sys, T=None, X0=0., input=None, output=None, T_num=None,
15931589 U [0 ] = 1. / simo .dt # unit area impulse
15941590
15951591 # Simulate the impulse response fo this input
1596- out = forced_response (simo , T , U , new_X0 , transpose = False ,
1597- return_x = True , squeeze = squeeze )
1592+ response = forced_response (simo , T , U , new_X0 )
15981593
15991594 # Store the output (and states)
16001595 inpidx = i if input is None else 0
1601- yout [:, inpidx , :] = out [ 1 ]
1602- xout [:, inpidx , :] = out [ 2 ]
1596+ yout [:, inpidx , :] = response . y
1597+ xout [:, inpidx , :] = response . x
16031598
16041599 return TimeResponseData (
1605- out [ 0 ] , yout , xout , uout , sys = sys , transpose = transpose ,
1606- return_x = return_x , squeeze = squeeze ,
1600+ response . time , yout , xout , uout , issiso = sys . issiso () ,
1601+ transpose = transpose , return_x = return_x , squeeze = squeeze ,
16071602 input_index = input , output_index = output )
16081603
16091604
0 commit comments