@@ -537,8 +537,8 @@ def linearize(self, x0, u0, t=0, params=None, eps=1e-6,
537537 u0 = _concatenate_list_elements (u0 , 'u0' )
538538
539539 # Figure out dimensions if they were not specified.
540- nstates = _find_size (self .nstates , x0 , "states " )
541- ninputs = _find_size (self .ninputs , u0 , "inputs " )
540+ nstates = _find_size (self .nstates , x0 , "x0 " )
541+ ninputs = _find_size (self .ninputs , u0 , "u0 " )
542542
543543 # Convert x0, u0 to arrays, if needed
544544 if np .isscalar (x0 ):
@@ -1468,7 +1468,8 @@ def input_output_response(
14681468 # Use the input time points as the output time points
14691469 t_eval = T
14701470
1471- # If we were passed a list of input, concatenate them (w/ broadcast)
1471+ # If we were passed a list of inputs, concatenate them (w/ broadcast)
1472+ # TODO: call _concatenate_list_elements
14721473 if isinstance (U , (tuple , list )) and len (U ) != ntimepts :
14731474 U_elements = []
14741475 for i , u in enumerate (U ):
@@ -1492,11 +1493,21 @@ def input_output_response(
14921493 # Save the newly created input vector
14931494 U = np .vstack (U_elements )
14941495
1496+ # Figure out the number of inputs
1497+ # TODO: call _concatenate_list_elements?
1498+ if sys .ninputs is None :
1499+ if isinstance (U , np .ndarray ):
1500+ ninputs = U .shape [0 ] if U .size > 1 else U .size
1501+ else :
1502+ ninputs = 1
1503+ else :
1504+ ninputs = sys .ninputs
1505+
14951506 # Make sure the input has the right shape
1496- if sys . ninputs is None or sys . ninputs == 1 :
1507+ if ninputs is None or ninputs == 1 :
14971508 legal_shapes = [(ntimepts ,), (1 , ntimepts )]
14981509 else :
1499- legal_shapes = [(sys . ninputs , ntimepts )]
1510+ legal_shapes = [(ninputs , ntimepts )]
15001511
15011512 U = _check_convert_array (
15021513 U , legal_shapes , 'Parameter ``U``: ' , squeeze = False )
@@ -1522,15 +1533,19 @@ def input_output_response(
15221533 X0 = _check_convert_array (
15231534 X0 , [(nstates ,), (nstates , 1 )], 'Parameter ``X0``: ' , squeeze = True )
15241535
1536+ # Update the parameter values (prior to evaluating outfcn)
1537+ sys ._update_params (params )
1538+
15251539 # Figure out the number of outputs
1526- if sys .noutputs is None :
1527- # Evaluate the output function to find number of outputs
1528- noutputs = np .shape (sys ._out (T [0 ], X0 , U [:, 0 ]))[0 ]
1540+ if sys .outfcn is None :
1541+ noutputs = nstates if sys .noutputs is None else sys .noutputs
15291542 else :
1530- noutputs = sys .noutputs
1543+ noutputs = np . shape ( sys ._out ( T [ 0 ], X0 , U [:, 0 ]))[ 0 ]
15311544
1532- # Update the parameter values
1533- sys ._update_params (params )
1545+ if sys .noutputs is not None and sys .noutputs != noutputs :
1546+ raise RuntimeError (
1547+ f"inconsistent size of outputs; system specified { sys .noutputs } , "
1548+ f"output function returned { noutputs } " )
15341549
15351550 #
15361551 # Define a function to evaluate the input at an arbitrary time
@@ -1737,9 +1752,9 @@ def find_eqpt(sys, x0, u0=None, y0=None, t=0, params=None,
17371752 from scipy .optimize import root
17381753
17391754 # Figure out the number of states, inputs, and outputs
1740- nstates = _find_size (sys .nstates , x0 , "states " )
1741- ninputs = _find_size (sys .ninputs , u0 , "inputs " )
1742- noutputs = _find_size (sys .noutputs , y0 , "outputs " )
1755+ nstates = _find_size (sys .nstates , x0 , "x0 " )
1756+ ninputs = _find_size (sys .ninputs , u0 , "u0 " )
1757+ noutputs = _find_size (sys .noutputs , y0 , "y0 " )
17431758
17441759 # Convert x0, u0, y0 to arrays, if needed
17451760 if np .isscalar (x0 ):
@@ -1982,23 +1997,24 @@ def linearize(sys, xeq, ueq=None, t=0, params=None, **kw):
19821997 return sys .linearize (xeq , ueq , t = t , params = params , ** kw )
19831998
19841999
1985- def _find_size (sysval , vecval , label ):
2000+ def _find_size (sysval , vecval , name = "system component" ):
19862001 """Utility function to find the size of a system parameter
19872002
19882003 If both parameters are not None, they must be consistent.
19892004 """
19902005 if hasattr (vecval , '__len__' ):
19912006 if sysval is not None and sysval != len (vecval ):
19922007 raise ValueError (
1993- f"inconsistent information for number of { label } " )
2008+ f"inconsistent information to determine size of { name } ; "
2009+ f"expected { sysval } values, received { len (vecval )} " )
19942010 return len (vecval )
19952011 # None or 0, which is a valid value for "a (sysval, ) vector of zeros".
19962012 if not vecval :
19972013 return 0 if sysval is None else sysval
19982014 elif sysval == 1 :
19992015 # (1, scalar) is also a valid combination from legacy code
20002016 return 1
2001- raise ValueError (f"can't determine number of { label } " )
2017+ raise ValueError (f"can't determine size of { name } " )
20022018
20032019
20042020# Function to create an interconnected system
0 commit comments