1313:class:`~control.NonlinearIOSystem` class that represents (possibly nonlinear)
1414input/output systems. The :class:`~control.NonlinearIOSystem` class is a
1515general class that defines any continuous or discrete time dynamical system.
16- Input/output systems can be simulated and also used to compute equilibrium
16+ Input/output systems can be simulated and also used to compute operating
1717points and linearizations.
1818
1919"""
@@ -1663,69 +1663,98 @@ def ivp_rhs(t, x):
16631663 success = soln .success , message = message )
16641664
16651665
1666- def find_eqpt (sys , x0 , u0 = None , y0 = None , t = 0 , params = None ,
1667- iu = None , iy = None , ix = None , idx = None , dx0 = None ,
1668- return_y = False , return_result = False ):
1669- """Find the equilibrium point for an input/output system.
1666+ def find_operating_point (
1667+ sys , x0 , u0 = None , y0 = None , t = 0 , params = None ,
1668+ iu = None , iy = None , ix = None , idx = None , dx0 = None , root_method = None ,
1669+ root_kwargs = None , return_y = False , return_result = False ):
1670+ """Find an operating point for an input/output system.
16701671
1671- Returns the value of an equilibrium point given the initial state and
1672- either input value or desired output value for the equilibrium point.
1672+ An operating point for a nonlinear system is a state `xop` and input
1673+ `uop` around which a nonlinear system operates. This point is most
1674+ commonly an equilibrium point for the system, but in some cases a
1675+ non-equilibrium operating point can be used.
1676+
1677+ This function attempts to find an operating point given a specification
1678+ for the desired inputs, outputs, states, or state updates of the system.
1679+
1680+ In its simplest form, `find_operating_point` finds an equilibrium point
1681+ given either the desired input or desired output:
1682+
1683+ xeq, ueq = find_operating_point(sys, x0, u0)
1684+ xeq, ueq = find_operating_point(sys, x0, u0, y0)
1685+
1686+ The first form finds an equilibrium point for a given input u0 based on
1687+ an initial guess x0. The second form fixes the desired output values
1688+ and uses x0 and u0 as an initial guess to find the equilibrium point.
1689+ If no equilibrium point can be found, the function returns the
1690+ operating point that minimizes the state update (state derivative for
1691+ continuous time systems, state difference for discrete time systems).
1692+
1693+ More complex operating points can be found by specifying which states,
1694+ inputs, or outputs should be used in computing the operating point, as
1695+ well as desired values of the states, inputs, outputs, or state
1696+ updates.
16731697
16741698 Parameters
16751699 ----------
16761700 sys : NonlinearIOSystem
1677- I/O system for which the equilibrium point is sought.
1701+ I/O system for which the operating point is sought.
16781702 x0 : list of initial state values
1679- Initial guess for the value of the state near the equilibrium point.
1703+ Initial guess for the value of the state near the operating point.
16801704 u0 : list of input values, optional
1681- If `y0` is not specified, sets the equilibrium value of the input. If
1682- `y0` is given, provides an initial guess for the value of the input.
1683- Can be omitted if the system does not have any inputs.
1705+ If `y0` is not specified, sets the value of the input. If `y0` is
1706+ given, provides an initial guess for the value of the input. Can
1707+ be omitted if the system does not have any inputs.
16841708 y0 : list of output values, optional
16851709 If specified, sets the desired values of the outputs at the
1686- equilibrium point.
1710+ operating point.
16871711 t : float, optional
1688- Evaluation time, for time-varying systems
1712+ Evaluation time, for time-varying systems.
16891713 params : dict, optional
16901714 Parameter values for the system. Passed to the evaluation functions
16911715 for the system as default values, overriding internal defaults.
16921716 iu : list of input indices, optional
16931717 If specified, only the inputs with the given indices will be fixed at
1694- the specified values in solving for an equilibrium point. All other
1718+ the specified values in solving for an operating point. All other
16951719 inputs will be varied. Input indices can be listed in any order.
16961720 iy : list of output indices, optional
16971721 If specified, only the outputs with the given indices will be fixed at
1698- the specified values in solving for an equilibrium point. All other
1722+ the specified values in solving for an operating point. All other
16991723 outputs will be varied. Output indices can be listed in any order.
17001724 ix : list of state indices, optional
17011725 If specified, states with the given indices will be fixed at the
1702- specified values in solving for an equilibrium point. All other
1726+ specified values in solving for an operating point. All other
17031727 states will be varied. State indices can be listed in any order.
17041728 dx0 : list of update values, optional
17051729 If specified, the value of update map must match the listed value
1706- instead of the default value of 0 .
1730+ instead of the default value for an equilibrium point .
17071731 idx : list of state indices, optional
17081732 If specified, state updates with the given indices will have their
17091733 update maps fixed at the values given in `dx0`. All other update
1710- values will be ignored in solving for an equilibrium point. State
1734+ values will be ignored in solving for an operating point. State
17111735 indices can be listed in any order. By default, all updates will be
1712- fixed at `dx0` in searching for an equilibrium point.
1736+ fixed at `dx0` in searching for an operating point.
1737+ root_method : str, optonal
1738+ Method to find the operating point. If specified, this parameter
1739+ is passed to the :func:`scipy.optimize.root` function.
1740+ root_kwargs : dict, optional
1741+ Additional keyword arguments to pass :func:`scipy.optimize.root`.
17131742 return_y : bool, optional
1714- If True, return the value of output at the equilibrium point.
1743+ If True, return the value of output at the operating point.
17151744 return_result : bool, optional
17161745 If True, return the `result` option from the
1717- :func:`scipy.optimize.root` function used to compute the equilibrium
1718- point.
1746+ :func:`scipy.optimize.root` function used to compute the
1747+ operating point.
17191748
17201749 Returns
17211750 -------
1722- xeq : array of states
1751+ xop : array of states
17231752 Value of the states at the equilibrium point, or `None` if no
17241753 equilibrium point was found and `return_result` was False.
1725- ueq : array of input values
1754+ uop : array of input values
17261755 Value of the inputs at the equilibrium point, or `None` if no
17271756 equilibrium point was found and `return_result` was False.
1728- yeq : array of output values, optional
1757+ yop : array of output values, optional
17291758 If `return_y` is True, returns the value of the outputs at the
17301759 equilibrium point, or `None` if no equilibrium point was found and
17311760 `return_result` was False.
@@ -1744,6 +1773,11 @@ def find_eqpt(sys, x0, u0=None, y0=None, t=0, params=None,
17441773 """
17451774 from scipy .optimize import root
17461775
1776+ # Process arguments for the root function
1777+ root_kwargs = dict () if root_kwargs is None else root_kwargs
1778+ if root_method :
1779+ root_kwargs ['method' ] = root_method
1780+
17471781 # Figure out the number of states, inputs, and outputs
17481782 x0 , nstates = _process_vector_argument (x0 , "x0" , sys .nstates )
17491783 u0 , ninputs = _process_vector_argument (u0 , "u0" , sys .ninputs )
@@ -1769,7 +1803,7 @@ def state_rhs(z): return sys._rhs(t, z, u0) - z
17691803 else :
17701804 def state_rhs (z ): return sys ._rhs (t , z , u0 )
17711805
1772- result = root (state_rhs , x0 )
1806+ result = root (state_rhs , x0 , ** root_kwargs )
17731807 z = (result .x , u0 , sys ._out (t , result .x , u0 ))
17741808
17751809 else :
@@ -1786,9 +1820,10 @@ def rootfun(z):
17861820 return np .concatenate (
17871821 (sys ._rhs (t , x , u ), sys ._out (t , x , u ) - y0 ), axis = 0 )
17881822
1789- z0 = np .concatenate ((x0 , u0 ), axis = 0 ) # Put variables together
1790- result = root (rootfun , z0 ) # Find the eq point
1791- x , u = np .split (result .x , [nstates ]) # Split result back in two
1823+ # Find roots with (x, u) as free variables
1824+ z0 = np .concatenate ((x0 , u0 ), axis = 0 )
1825+ result = root (rootfun , z0 , ** root_kwargs )
1826+ x , u = np .split (result .x , [nstates ])
17921827 z = (x , u , sys ._out (t , x , u ))
17931828
17941829 else :
@@ -1903,7 +1938,7 @@ def rootfun(z):
19031938 z0 = np .concatenate ((x [state_vars ], u [input_vars ]), axis = 0 )
19041939
19051940 # Finally, call the root finding function
1906- result = root (rootfun , z0 )
1941+ result = root (rootfun , z0 , ** root_kwargs )
19071942
19081943 # Extract out the results and insert into x and u
19091944 x [state_vars ] = result .x [:nstate_vars ]
@@ -2509,7 +2544,7 @@ def _find_output_or_input_signal(spec):
25092544 (syslist [isys ].name ,
25102545 syslist [isys ].input_labels [isig ], gain ))
25112546 return signal_list
2512-
2547+
25132548 if isinstance (connection , list ):
25142549 # Passed a list => create input map
25152550 dprint (f" detected output list" )
@@ -2519,7 +2554,7 @@ def _find_output_or_input_signal(spec):
25192554 new_outlist .append (signal_list )
25202555 else :
25212556 new_outlist += _find_output_or_input_signal (connection )
2522-
2557+
25232558 outlist , outputs = new_outlist , new_outputs
25242559 dprint (f" { outlist = } \n { outputs = } " )
25252560
@@ -2679,3 +2714,7 @@ def connection_table(sys, show_names=False, column_width=32):
26792714 "an InterconnectedSystem."
26802715
26812716 sys .connection_table (show_names = show_names , column_width = column_width )
2717+
2718+
2719+ # Short versions of function call
2720+ find_eqpt = find_operating_point
0 commit comments