Skip to content

Commit 7479353

Browse files
committed
create find_operating_point with updated documentation
1 parent cc0020a commit 7479353

File tree

1 file changed

+72
-33
lines changed

1 file changed

+72
-33
lines changed

control/nlsys.py

Lines changed: 72 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
:class:`~control.NonlinearIOSystem` class that represents (possibly nonlinear)
1414
input/output systems. The :class:`~control.NonlinearIOSystem` class is a
1515
general 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
1717
points 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

Comments
 (0)