Skip to content

Commit df4508c

Browse files
committed
updated docstrings and docs, trim slow unit tests
1 parent ebedf19 commit df4508c

6 files changed

Lines changed: 159 additions & 157 deletions

File tree

control/optimal.py

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ def solve_ocp(
10381038
10391039
Notes
10401040
-----
1041-
Additional keyword parameters can be used to fine tune the behavior of
1041+
Additional keyword parameters can be used to fine-tune the behavior of
10421042
the underlying optimization and integration functions. See
10431043
:func:`OptimalControlProblem` for more information.
10441044
@@ -1138,7 +1138,7 @@ def create_mpc_iosystem(
11381138
11391139
Notes
11401140
-----
1141-
Additional keyword parameters can be used to fine tune the behavior of
1141+
Additional keyword parameters can be used to fine-tune the behavior of
11421142
the underlying optimization and integrations functions. See
11431143
:func:`OptimalControlProblem` for more information.
11441144
@@ -1189,15 +1189,15 @@ class OptimalEstimationProblem():
11891189
control_indices : int, slice, or list of int or string, optional
11901190
Specify the indices in the system input vector that correspond to
11911191
the control inputs. These inputs will be used as known control
1192-
inputs for the estimate. If value is an integer `m`, the first `m`
1193-
system inputs are used. Otherwise, the value should be a slice or
1194-
a list of indices. The list of indices can be specified as either
1195-
integer offsets or as system input signal names. If not specified,
1196-
defaults to the complement of the disturbance indices (see also
1197-
notes below).
1192+
inputs for the estimator. If value is an integer `m`, the first
1193+
`m` system inputs are used. Otherwise, the value should be a slice
1194+
or a list of indices. The list of indices can be specified as
1195+
either integer offsets or as system input signal names. If not
1196+
specified, defaults to the complement of the disturbance indices
1197+
(see also notes below).
11981198
disturbance_indices : int, list of int, or slice, optional
11991199
Specify the indices in the system input vector that correspond to
1200-
the input disturbances. If value is an integer `m`, the last `m`
1200+
the process disturbances. If value is an integer `m`, the last `m`
12011201
system inputs are used. Otherwise, the value should be a slice or
12021202
a list of indices, as describedf for `control_indices`. If not
12031203
specified, defaults to the complement of the control indicies (see
@@ -1227,14 +1227,13 @@ class OptimalEstimationProblem():
12271227
12281228
Notes
12291229
-----
1230-
To describe an optimal estimation problem we need an input/output
1231-
system, a set of time points, measured inputs and outputs, a cost
1232-
function, and (optionally) a set of constraints on the state
1233-
and/or inputs along the trajectory (and at the terminal time).
1234-
This class sets up an optimization over the state and disturbances
1235-
at each point in time, using the integral and terminal costs as
1236-
well as the trajectory constraints. The
1237-
:func:`~control.optimal.OptimalEstimationProblem.compute_estimate`
1230+
To describe an optimal estimation problem we need an input/output system,
1231+
a set of time points, applied inputs and measured outputs, a cost
1232+
function, and (optionally) a set of constraints on the state and/or inputs
1233+
along the trajectory (and at the terminal time). This class sets up an
1234+
optimization over the state and disturbances at each point in time, using
1235+
the integral and terminal costs as well as the trajectory constraints.
1236+
The :func:`~control.optimal.OptimalEstimationProblem.compute_estimate`
12381237
method solves the underling optimization problem using
12391238
:func:`scipy.optimize.minimize`.
12401239
@@ -1245,12 +1244,11 @@ class OptimalEstimationProblem():
12451244
the same as the control inputs.
12461245
12471246
The "cost" (e.g. negative of the log likelihood) of the estimated
1248-
trajectory generated by the estimated state, the disturbances and
1249-
noise, and the measured output. It does this by calling a user-defined
1250-
function for the integral_cost given the current estimated states,
1251-
inputs, and measured outputs at each point along the trajectory and
1252-
then adding the value of a user-defined terminal cost at the initial
1253-
point in the trajectory.
1247+
trajectory is computed using the estimated state, the disturbances and
1248+
noise, and the measured output. This is done by calling a user-defined
1249+
function for the integral_cost along the trajectory and then adding the
1250+
value of a user-defined terminal cost at the initial point in the
1251+
trajectory.
12541252
12551253
The constraint functions are evaluated at each point on the trajectory
12561254
generated by the proposed estimate and disturbances. As in the case of
@@ -1261,8 +1259,8 @@ class OptimalEstimationProblem():
12611259
so that it only needs to be computed once.
12621260
12631261
The default values for ``minimize_method``, ``minimize_options``,
1264-
``minimize_kwargs``, ``solve_ivp_method``, and ``solve_ivp_options`` can
1265-
be set using config.defaults['optimal.<keyword>'].
1262+
``minimize_kwargs``, ``solve_ivp_method``, and ``solve_ivp_options``
1263+
can be set using config.defaults['optimal.<keyword>'].
12661264
12671265
"""
12681266
def __init__(
@@ -1628,7 +1626,7 @@ def compute_estimate(
16281626
-------
16291627
res : OptimalEstimationResult
16301628
Bundle object with the results of the optimal estimation problem.
1631-
res.success: bool
1629+
res.success : bool
16321630
Boolean flag indicating whether the optimization was successful.
16331631
res.time : array
16341632
Time values of the input (same as self.timepts).
@@ -1929,27 +1927,26 @@ def solve_oep(
19291927
-------
19301928
res : TimeResponseData
19311929
Bundle object with the estimated state and noise values.
1932-
1933-
res.success : bool
1934-
Boolean flag indicating whether the optimization was successful.
1935-
res.time : array
1936-
Time values of the input.
1937-
res.inputs : array
1938-
Disturbance values corresponding to the estimated state. If
1939-
the system is SISO and squeeze is not True, the array is 1D
1940-
(indexed by time). If the system is not SISO or squeeze is
1941-
False, the array is 2D (indexed by the output number and time).
1942-
res.states : array
1943-
Estimated state vector over the given time points.
1944-
res.outputs : array
1945-
Noise values corresponding to the estimated state. If the
1946-
system is SISO and squeeze is not True, the array is 1D
1947-
(indexed by time). If the system is not SISO or squeeze is
1948-
False, the array is 2D (indexed by the output number and time).
1930+
res.success : bool
1931+
Boolean flag indicating whether the optimization was successful.
1932+
res.time : array
1933+
Time values of the input.
1934+
res.inputs : array
1935+
Disturbance values corresponding to the estimated state. If the
1936+
system is SISO and squeeze is not True, the array is 1D (indexed by
1937+
time). If the system is not SISO or squeeze is False, the array is
1938+
2D (indexed by the output number and time).
1939+
res.states : array
1940+
Estimated state vector over the given time points.
1941+
res.outputs : array
1942+
Noise values corresponding to the estimated state. If the system
1943+
is SISO and squeeze is not True, the array is 1D (indexed by time).
1944+
If the system is not SISO or squeeze is False, the array is 2D
1945+
(indexed by the output number and time).
19491946
19501947
Notes
19511948
-----
1952-
Additional keyword parameters can be used to fine tune the behavior of
1949+
Additional keyword parameters can be used to fine-tune the behavior of
19531950
the underlying optimization and integration functions. See
19541951
:func:`~control.optimal.OptimalControlProblem` for more information.
19551952

control/statefbk.py

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,11 @@ def lqr(*args, **kwargs):
341341
integral_action : ndarray, optional
342342
If this keyword is specified, the controller includes integral
343343
action in addition to state feedback. The value of the
344-
`integral_action`` keyword should be an ndarray that will be
344+
`integral_action` keyword should be an ndarray that will be
345345
multiplied by the current state to generate the error for the
346346
internal integrator states of the control law. The number of
347347
outputs that are to be integrated must match the number of
348-
additional rows and columns in the ``Q`` matrix.
348+
additional rows and columns in the `Q` matrix.
349349
method : str, optional
350350
Set the method used for computing the result. Current methods are
351351
'slycot' and 'scipy'. If set to None (default), try 'slycot' first
@@ -491,11 +491,11 @@ def dlqr(*args, **kwargs):
491491
integral_action : ndarray, optional
492492
If this keyword is specified, the controller includes integral
493493
action in addition to state feedback. The value of the
494-
`integral_action`` keyword should be an ndarray that will be
494+
`integral_action` keyword should be an ndarray that will be
495495
multiplied by the current state to generate the error for the
496496
internal integrator states of the control law. The number of
497497
outputs that are to be integrated must match the number of
498-
additional rows and columns in the ``Q`` matrix.
498+
additional rows and columns in the `Q` matrix.
499499
method : str, optional
500500
Set the method used for computing the result. Current methods are
501501
'slycot' and 'scipy'. If set to None (default), try 'slycot' first
@@ -617,9 +617,9 @@ def create_statefbk_iosystem(
617617
618618
ctrl, clsys = ct.create_statefbk_iosystem(sys, K)
619619
620-
where ``sys`` is the process dynamics and ``K`` is the state (+ integral)
620+
where `sys` is the process dynamics and `K` is the state (+ integral)
621621
feedback gain (eg, from LQR). The function returns the controller
622-
``ctrl`` and the closed loop systems ``clsys``, both as I/O systems.
622+
`ctrl` and the closed loop systems `clsys`, both as I/O systems.
623623
624624
A gain scheduled controller can also be created, by passing a list of
625625
gains and a corresponding list of values of a set of scheduling
@@ -636,32 +636,32 @@ def create_statefbk_iosystem(
636636
is given, the output of this system should represent the full state.
637637
638638
gain : ndarray or tuple
639-
If a array is give, it represents the state feedback gain (K).
639+
If an array is given, it represents the state feedback gain (K).
640640
This matrix defines the gains to be applied to the system. If
641-
``integral_action`` is None, then the dimensions of this array
641+
`integral_action` is None, then the dimensions of this array
642642
should be (sys.ninputs, sys.nstates). If `integral action` is
643643
set to a matrix or a function, then additional columns
644644
represent the gains of the integral states of the controller.
645645
646646
If a tuple is given, then it specifies a gain schedule. The tuple
647-
should be of the form ``(gains, points)`` where gains is a list of
647+
should be of the form `(gains, points)` where gains is a list of
648648
gains :math:`K_j` and points is a list of values :math:`\\mu_j` at
649649
which the gains are computed. The `gainsched_indices` parameter
650650
should be used to specify the scheduling variables.
651651
652652
xd_labels, ud_labels : str or list of str, optional
653-
Set the name of the signals to use for the desired state and inputs.
654-
If a single string is specified, it should be a format string using
655-
the variable ``i`` as an index. Otherwise, a list of strings
656-
matching the size of xd and ud, respectively, should be used.
657-
Default is ``'xd[{i}]'`` for xd_labels and ``'ud[{i}]'`` for
658-
ud_labels. These settings can also be overriden using the `inputs`
659-
keyword.
653+
Set the name of the signals to use for the desired state and
654+
inputs. If a single string is specified, it should be a
655+
format string using the variable `i` as an index. Otherwise,
656+
a list of strings matching the size of xd and ud,
657+
respectively, should be used. Default is "xd[{i}]" for
658+
xd_labels and "ud[{i}]" for ud_labels. These settings can
659+
also be overriden using the `inputs` keyword.
660660
661661
integral_action : ndarray, optional
662662
If this keyword is specified, the controller can include integral
663663
action in addition to state feedback. The value of the
664-
`integral_action`` keyword should be an ndarray that will be
664+
`integral_action` keyword should be an ndarray that will be
665665
multiplied by the current and desired state to generate the error
666666
for the internal integrator states of the control law.
667667
@@ -678,7 +678,7 @@ def create_statefbk_iosystem(
678678
[xd, ud, x] vector are used. Otherwise, the value should be a
679679
slice or a list of indices. The list of indices can be specified
680680
as either integer offsets or as signal names. The default is to
681-
use the desire state xd.
681+
use the desired state xd.
682682
683683
gainsched_method : str, optional
684684
The method to use for gain scheduling. Possible values are 'linear'
@@ -691,28 +691,29 @@ def create_statefbk_iosystem(
691691
Set the type of controller to create. The default for a linear gain
692692
is a linear controller implementing the LQR regulator. If the type
693693
is 'nonlinear', a :class:NonlinearIOSystem is created instead, with
694-
the gain ``K`` as a parameter (allowing modifications of the gain at
694+
the gain `K` as a parameter (allowing modifications of the gain at
695695
runtime). If the gain parameter is a tuple, then a nonlinear,
696696
gain-scheduled controller is created.
697697
698698
Returns
699699
-------
700700
ctrl : InputOutputSystem
701-
Input/output system representing the controller. This system takes
702-
as inputs the desired state ``xd``, the desired input ``ud``, and
703-
either the system state ``x`` or the estimated state ``xhat``. It
704-
outputs the controller action u according to the formula :math:`u =
705-
u_d - K(x - x_d)`. If the keyword ``integral_action`` is specified,
706-
then an additional set of integrators is included in the control
707-
system (with the gain matrix ``K`` having the integral gains
708-
appended after the state gains). If a gain scheduled controller is
709-
specified, the gain (proportional and integral) are evaluated using
710-
the scheduling variables specified by ``gainsched_indices``.
701+
Input/output system representing the controller. This system
702+
takes as inputs the desired state `xd`, the desired input
703+
`ud`, and either the system state `x` or the estimated state
704+
`xhat`. It outputs the controller action `u` according to the
705+
formula :math:`u = u_d - K(x - x_d)`. If the keyword
706+
`integral_action` is specified, then an additional set of
707+
integrators is included in the control system (with the gain
708+
matrix `K` having the integral gains appended after the state
709+
gains). If a gain scheduled controller is specified, the gain
710+
(proportional and integral) are evaluated using the scheduling
711+
variables specified by `gainsched_indices`.
711712
712713
clsys : InputOutputSystem
713714
Input/output system representing the closed loop system. This
714-
systems takes as inputs the desired trajectory ``(xd, ud)`` and
715-
outputs the system state ``x`` and the applied input ``u``
715+
systems takes as inputs the desired trajectory `(xd, ud)` and
716+
outputs the system state `x` and the applied input `u`
716717
(vertically stacked).
717718
718719
Other Parameters

control/stochsys.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,6 @@ def dlqe(*args, **kwargs):
312312
# Function to create an estimator
313313
#
314314
# TODO: create predictor/corrector, UKF, and other variants (?)
315-
# TODO: change *_labels to *_fmtstr and use signal keywords instead
316315
#
317316
def create_estimator_iosystem(
318317
sys, QN, RN, P0=None, G=None, C=None,
@@ -344,19 +343,17 @@ def create_estimator_iosystem(
344343
estim = ct.create_estimator_iosystem(sys, QN, RN)
345344
346345
where `sys` is the process dynamics and `QN` and `RN` are the covariance
347-
of the disturbance noise and sensor noise. The function returns the
348-
estimator `estim` as I/O system with a parameter `correct` that can
346+
of the disturbance noise and measurement noise. The function returns
347+
the estimator `estim` as I/O system with a parameter `correct` that can
349348
be used to turn off the correction term in the estimation (for forward
350349
predictions).
351350
352351
Parameters
353352
----------
354353
sys : LinearIOSystem
355-
The linear I/O system that represents the process dynamics. If no
356-
estimator is given, the output of this system should represent the
357-
full state.
354+
The linear I/O system that represents the process dynamics.
358355
QN, RN : ndarray
359-
Process and sensor noise covariance matrices.
356+
Disturbance and measurement noise covariance matrices.
360357
P0 : ndarray, optional
361358
Initial covariance matrix. If not specified, defaults to the steady
362359
state covariance.
@@ -409,13 +406,13 @@ def create_estimator_iosystem(
409406
Set the name of the measurement and control signal names (estimator
410407
inputs). If a single string is specified, it should be a format
411408
string using the variable ``i`` as an index. Otherwise, a list of
412-
strings matching the size of the system inputs and outputs should
413-
be used. Default is the signal names for the system outputs and
414-
control inputs. These settings can also be overriden using the
409+
strings matching the size of the system inputs and outputs should be
410+
used. Default is the signal names for the system measurements and
411+
known control inputs. These settings can also be overriden using the
415412
`inputs` keyword.
416413
inputs, outputs, states : int or list of str, optional
417414
Set the names of the inputs, outputs, and states, as described in
418-
:func:`~control.InputOutputSystem`.
415+
:func:`~control.InputOutputSystem`. Overrides signal labels.
419416
name : string, optional
420417
System name (used for specifying signals). If unspecified, a generic
421418
name <sys[id]> is generated with a unique integer id.
@@ -434,7 +431,7 @@ def create_estimator_iosystem(
434431
resp = ct.input_output_response(est, T, [Y, U], [X0, P0])
435432
436433
If desired, the ``correct`` parameter can be set to ``False`` to allow
437-
prediction with no additional sensor information::
434+
prediction with no additional measurement information::
438435
439436
resp = ct.input_output_response(
440437
est, T, 0, [X0, P0], param={'correct': False)
@@ -458,7 +455,8 @@ def create_estimator_iosystem(
458455
kwargs, 'state_labels', estimate_labels)
459456
else:
460457
warnings.warn(
461-
"deprecated 'state_labels' ignored; use 'state' instead")
458+
"deprecated 'state_labels' ignored; use 'states' instead")
459+
kwargs.pop('state_labels')
462460

463461
# Set the state matrix for later use
464462
A = sys.A
@@ -482,7 +480,7 @@ def create_estimator_iosystem(
482480
if C.shape[0] != RN.shape[0]:
483481
raise ValueError("System output is the wrong size for C")
484482
else:
485-
# Use the system outputs as the sensor outputs
483+
# Use the system outputs as the measurements
486484
C = sys.C
487485

488486
# Generate the disturbance matrix (G)

control/tests/optimal_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ def test_ocp_argument_errors():
551551
sys, time, x0, cost, solve_ivp_kwargs={'eps': 0.1})
552552

553553

554+
@pytest.mark.slow
554555
@pytest.mark.parametrize("basis", [
555556
flat.PolyFamily(4), flat.PolyFamily(6),
556557
flat.BezierFamily(4), flat.BSplineFamily([0, 4, 8], 6)

0 commit comments

Comments
 (0)