Skip to content

Commit 1d9b689

Browse files
committed
update nonlinear.rst and associated doc files
1 parent cf3ea81 commit 1d9b689

File tree

8 files changed

+296
-178
lines changed

8 files changed

+296
-178
lines changed

doc/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
# -- Project information -----------------------------------------------------
3030

3131
project = u'Python Control Systems Library'
32-
copyright = u'2023, python-control.org'
32+
copyright = u'2024, python-control.org'
3333
author = u'Python Control Developers'
3434

3535
# Version information - read from the source code
@@ -285,7 +285,7 @@ def linkcode_resolve(domain, info):
285285
doctest_global_setup = """
286286
import numpy as np
287287
import control as ct
288-
import control.optimal as obc
288+
import control.optimal as opt
289289
import control.flatsys as fs
290290
import control.phaseplot as pp
291291
ct.reset_defaults()

doc/figures/servomech-diagram.png

51.9 KB
Loading

doc/flatsys.rst

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,40 @@
1+
.. currentmodule:: control
2+
13
.. _flatsys-module:
24

3-
***************************
45
Differentially flat systems
5-
***************************
6+
===========================
67

78
.. automodule:: control.flatsys
9+
:noindex:
810
:no-members:
911
:no-inherited-members:
1012
:no-special-members:
1113

14+
1215
Overview of differential flatness
13-
=================================
16+
---------------------------------
1417

1518
A nonlinear differential equation of the form
1619

1720
.. math::
21+
1822
\dot x = f(x, u), \qquad x \in R^n, u \in R^m
1923
2024
is *differentially flat* if there exists a function :math:`\alpha` such that
2125

2226
.. math::
27+
2328
z = \alpha(x, u, \dot u\, \dots, u^{(p)})
2429
2530
and we can write the solutions of the nonlinear system as functions of
2631
:math:`z` and a finite number of derivatives
2732

2833
.. math::
34+
:label: flat2state
35+
2936
x &= \beta(z, \dot z, \dots, z^{(q)}) \\
3037
u &= \gamma(z, \dot z, \dots, z^{(q)}).
31-
:label: flat2state
3238
3339
For a differentially flat system, all of the feasible trajectories for
3440
the system can be written as functions of a flat output :math:`z(\cdot)` and
@@ -42,11 +48,13 @@ space, and then map these to appropriate inputs. Suppose we wish to
4248
generate a feasible trajectory for the nonlinear system
4349

4450
.. math::
51+
4552
\dot x = f(x, u), \qquad x(0) = x_0,\, x(T) = x_f.
4653
4754
If the system is differentially flat then
4855

4956
.. math::
57+
5058
x(0) &= \beta\bigl(z(0), \dot z(0), \dots, z^{(q)}(0) \bigr) = x_0, \\
5159
x(T) &= \gamma\bigl(z(T), \dot z(T), \dots, z^{(q)}(T) \bigr) = x_f,
5260
@@ -64,6 +72,7 @@ trajectory of the system. We can parameterize the flat output trajectory
6472
using a set of smooth basis functions :math:`\psi_i(t)`:
6573

6674
.. math::
75+
6776
z(t) = \sum_{i=1}^N c_i \psi_i(t), \qquad c_i \in R
6877
6978
We seek a set of coefficients :math:`c_i`, :math:`i = 1, \dots, N` such
@@ -72,6 +81,7 @@ that :math:`z(t)` satisfies the boundary conditions for :math:`x(0)` and
7281
the derivatives of the basis functions:
7382

7483
.. math::
84+
7585
\dot z(t) &= \sum_{i=1}^N c_i \dot \psi_i(t) \\
7686
&\,\vdots \\
7787
\dot z^{(q)}(t) &= \sum_{i=1}^N c_i \psi^{(q)}_i(t).
@@ -80,6 +90,7 @@ We can thus write the conditions on the flat outputs and their
8090
derivatives as
8191

8292
.. math::
93+
8394
\begin{bmatrix}
8495
\psi_1(0) & \psi_2(0) & \dots & \psi_N(0) \\
8596
\dot \psi_1(0) & \dot \psi_2(0) & \dots & \dot \psi_N(0) \\
@@ -99,6 +110,7 @@ derivatives as
99110
This equation is a *linear* equation of the form
100111

101112
.. math::
113+
102114
M c = \begin{bmatrix} \bar z(0) \\ \bar z(T) \end{bmatrix}
103115
104116
where :math:`\bar z` is called the *flat flag* for the system.
@@ -107,7 +119,7 @@ column rank, we can solve for a (possibly non-unique) :math:`\alpha` that
107119
solves the trajectory generation problem.
108120

109121
Module usage
110-
============
122+
------------
111123

112124
To create a trajectory for a differentially flat system, a
113125
:class:`~flatsys.FlatSystem` object must be created. This is done
@@ -138,7 +150,7 @@ and their derivatives up to order :math:`q_i`:
138150
The number of flat outputs must match the number of system inputs.
139151

140152
For a linear system, a flat system representation can be generated by
141-
passing a :class:`~control.StateSpace` system to the
153+
passing a :class:`StateSpace` system to the
142154
:func:`~flatsys.flatsys` factory function::
143155

144156
sys = fs.flatsys(linsys)
@@ -180,7 +192,7 @@ where `T` is a list of times on which the trajectory should be evaluated
180192

181193
The :func:`~flatsys.point_to_point` function also allows the
182194
specification of a cost function and/or constraints, in the same
183-
format as :func:`~control.optimal.solve_ocp`.
195+
format as :func:`optimal.solve_ocp`.
184196

185197
The :func:`~flatsys.solve_flat_ocp` function can be used to
186198
solve an optimal control problem without a final state::
@@ -195,7 +207,7 @@ vector. The `terminal_cost` parameter can be used to specify a cost
195207
function for the final point in the trajectory.
196208

197209
Example
198-
=======
210+
-------
199211

200212
To illustrate how we can use a two degree-of-freedom design to improve the
201213
performance of the system, consider the problem of steering a car to change
@@ -309,9 +321,7 @@ cost:`
309321
x, u = traj.eval(t)
310322

311323
Module classes and functions
312-
============================
313-
314-
.. currentmodule:: control
324+
----------------------------
315325

316326
.. autosummary::
317327
:template: custom-class-template.rst

doc/iosys.rst

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,19 @@
11
.. _iosys-module:
22

3-
********************
4-
Input/output systems
5-
********************
3+
**************************
4+
Interconnected I/O Systems
5+
**************************
66

7-
Module usage
8-
============
7+
Operator overloading
8+
====================
99

10-
An input/output system is defined as a dynamical system that has a system
11-
state as well as inputs and outputs (either inputs or states can be empty).
12-
The dynamics of the system can be in continuous or discrete time. To simulate
13-
an input/output system, use the :func:`~control.input_output_response`
14-
function::
1510

16-
resp = ct.input_output_response(io_sys, T, U, X0, params)
17-
t, y, x = resp.time, resp.outputs, resp.states
11+
Block diagram algebra
12+
=====================
1813

19-
An input/output system can be linearized around an equilibrium point
20-
to obtain a :class:`~control.StateSpace` linear system. Use the
21-
:func:`~control.find_operating_point` function to obtain an
22-
equilibrium point and the :func:`~control.linearize` function to
23-
linearize about that equilibrium point::
2414

25-
xeq, ueq = ct.find_operating_point(io_sys, X0, U0)
26-
ss_sys = ct.linearize(io_sys, xeq, ueq)
27-
28-
Input/output systems are automatically created for state space LTI systems
29-
when using the :func:`~control.ss` function. Nonlinear input/output
30-
systems can be created using the :func:`~control.nlsys` function, which
31-
requires the definition of an update function (for the right hand side of
32-
the differential or different equation) and an output function (computes
33-
the outputs from the state)::
34-
35-
io_sys = ct.nlsys(updfcn, outfcn, inputs=M, outputs=P, states=N)
15+
Signal-based interconnection
16+
============================
3617

3718
More complex input/output systems can be constructed by using the
3819
:func:`~control.interconnect` function, which allows a collection of
@@ -556,25 +537,3 @@ bottom of the file).
556537

557538
Integral action and state estimation can also be used with gain
558539
scheduled controllers.
559-
560-
561-
Module classes and functions
562-
============================
563-
564-
.. autosummary::
565-
:template: custom-class-template.rst
566-
567-
~control.InputOutputSystem
568-
~control.InterconnectedSystem
569-
~control.LinearICSystem
570-
~control.NonlinearIOSystem
571-
~control.OperatingPoint
572-
573-
.. autosummary::
574-
575-
~control.find_operating_point
576-
~control.interconnect
577-
~control.input_output_response
578-
~control.linearize
579-
~control.nlsys
580-
~control.summing_junction

doc/nlsys.rst

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,160 @@
1+
..currentmodule control
2+
13
Nonlinear system models
24
=======================
35

6+
Nonlinear input/output systems are represented as state space systems
7+
of the form
8+
9+
.. math::
10+
11+
\frac{dx}{dt} &= f(t, x, u, \theta) \\
12+
y &= h(t, x, u, \theta)
13+
14+
where :math:`t` represents the current time, :math:`x` is the system
15+
state, math:`u` is the system input, :math:`y` is the system output,
16+
and :math:`\theta` represents a set of parameters.
17+
18+
Discrete time systems are also supported and have dynamics of the form
19+
420
Creating nonlinear models
521
-------------------------
622

23+
A nonlinear system is created using the :func:`nlsys` factory function::
24+
25+
sys = ct.nlsys(
26+
updfcn[, outfcn], inputs=m, states=n, outputs=p, [, params=params])
27+
28+
The `updfcn` argument is a function returning the state update function::
29+
30+
updfcn(t, x, u, params) -> array
31+
32+
where `x` is a 1-D array with shape (n,), `u` is a 1-D array
33+
with shape (m,), `t` is a float representing the currrent time,
34+
and `params` is a dict containing the values of parameters used by the
35+
function. The dynamics of the system can be in continuous or discrete
36+
time (use the `dt` keyword to create a discrte time system).
37+
38+
The output function `outfcn` is used to specify the outputs of the
39+
system and has the same calling signature as `updfcn`. If it is not
40+
specified, then the output of the system is set equal to the system
41+
state. Otherwise, it should return an output of shape (p,).
42+
43+
Note that the number of states, inputs, and outputs should generally
44+
be explicitly specified, although some operations can infer the
45+
dimensions if they are not given when the system is created. The
46+
`inputs`, `outputs`, and `states` keywords can also be given as lists
47+
of strings, in which case the various signals will be given the
48+
appropriate names.
49+
50+
To illustrate the creation of a nonlinear I/O system model, consider a
51+
simple model of a spring loaded arm driven by a motor:
52+
53+
.. image:: figures/servomech-diagram.png
54+
:width: 240
55+
56+
The dynamics of this system can be modeling using the following code::
57+
58+
# Parameter values
59+
servomech_params = {
60+
'J': 100, # Moment of inertia of the motor
61+
'b': 10, # Angular damping of the arm
62+
'k': 1, # Spring constant
63+
'r': 1, # Location of spring contact on arm
64+
'l': 2, # Distance to the read head
65+
'eps': 0.01, # Magnitude of velocity-dependent perturbation
66+
}
67+
68+
# State derivative
69+
def servomech_update(t, x, u, params):
70+
# Extract the configuration and velocity variables from the state vector
71+
theta = x[0] # Angular position of the disk drive arm
72+
thetadot = x[1] # Angular velocity of the disk drive arm
73+
tau = u[0] # Torque applied at the base of the arm
74+
75+
# Get the parameter values
76+
J, b, k, r = map(params.get, ['J', 'b', 'k', 'r'])
77+
78+
# Compute the angular acceleration
79+
dthetadot = 1/J * (
80+
-b * thetadot - k * r * np.sin(theta) + tau)
81+
82+
# Return the state update law
83+
return np.array([thetadot, dthetadot])
84+
85+
# System output (tip radial position + angular velocity)
86+
def servomech_output(t, x, u, params):
87+
l = params['l']
88+
return np.array([l * x[0], x[1]])
89+
90+
# System dynamics
91+
servomech = ct.nlsys(
92+
servomech_update, servomech_output, name='servomech',
93+
params=servomech_params, states=['theta', 'thdot'],
94+
outputs=['y', 'thdot'], inputs=['tau'])
95+
96+
A summary of the model can be obtained using the string representation
97+
of the model (via the Python `print()` function)::
98+
99+
>>> print(servomech)
100+
<NonlinearIOSystem>: servomech
101+
Inputs (1): ['tau']
102+
Outputs (2): ['y', 'thdot']
103+
States (2): ['theta', 'thdot']
104+
Parameters: ['J', 'b', 'k', 'r', 'l', 'eps']
105+
106+
Update: <function servomech_update at 0x117a17f60>
107+
Output: <function servomech_output at 0x1354e3d80>
108+
109+
7110
Operating points and linearization
8111
----------------------------------
9112

113+
A nonlinear input/output system can be linearized around an equilibrium point
114+
to obtain a :class:`~control.StateSpace` linear system::
115+
116+
sys_ss = ct.linearize(sys_nl, xeq, ueq)
117+
118+
If the equilibrium point is not known, the
119+
:func:`find_operating_point` function can be used to obtain an
120+
equilibrium point. In its simplest form, `find_operating_point` finds
121+
an equilibrium point given either the desired input or desired
122+
output::
123+
124+
xeq, ueq = find_operating_point(sys, x0, u0)
125+
xeq, ueq = find_operating_point(sys, x0, u0, y0)
126+
127+
The first form finds an equilibrium point for a given input `u0` based
128+
on an initial guess `x0`. The second form fixes the desired output
129+
values `y0` and uses x0 and u0 as an initial guess to find the
130+
equilibrium point. If no equilibrium point can be found, the function
131+
returns the operating point that minimizes the state update (state
132+
derivative for continuous time systems, state difference for discrete
133+
time systems).
134+
135+
More complex operating points can be found by specifying which states,
136+
inputs, or outputs should be used in computing the operating point, as
137+
well as desired values of the states, inputs, outputs, or state
138+
updates. See the :func:`find_operating_point` documentation for more deatils.
139+
140+
10141
Simulations and plotting
11142
------------------------
143+
144+
To simulate an input/output system, use the
145+
:func:`~control.input_output_response` function::
146+
147+
resp = ct.input_output_response(io_sys, T, U, x0, params)
148+
t, y, x = resp.time, resp.outputs, resp.states
149+
150+
Time responses can be plotted using the :func:`time_response_plot`
151+
function or (equivalently) the :func:`TimeResponseData.plot`
152+
method::
153+
154+
cplt = ct.time_response_plot(resp)
155+
156+
The resulting :class:`ControlPlot` object can be used to access
157+
different plot elements. The :func:`combine_time_responses` function
158+
an be used to combine multiple time responses into a single
159+
`TimeResponseData` object. See the :ref:`response-chapter` chapter
160+
for more information on this functionality.

0 commit comments

Comments
 (0)