Python Control Readthedocs Io en Latest
Python Control Readthedocs Io en Latest
Release dev
RMM
1 Introduction 3
1.1 Overview of the toolbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Some differences from MATLAB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 Library conventions 5
2.1 LTI system representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Time series data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 Package configuration parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3 Function reference 11
3.1 System creation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2 System interconnections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.3 Frequency domain plotting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.4 Time domain simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.5 Block diagram algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.6 Control system analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.7 Matrix computations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.8 Control system synthesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.9 Model simplification tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.10 Nonlinear system support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.11 Utility functions and conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
i
5.6 Frequency-domain analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.7 Compensator design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.8 State-space (SS) models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
5.9 Model simplification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
5.10 Time delays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
5.11 Matrix equation solvers and linear algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
5.12 Additional functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
5.13 Functions imported from other modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
8 Examples 133
8.1 Python scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
8.2 Jupyter notebooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Index 213
ii
Python Control Library Documentation, Release dev
The Python Control Systems Library (python-control) is a Python package that implements basic operations for anal-
ysis and design of feedback control systems.
Features
Documentation
Contents 1
Python Control Library Documentation, Release dev
2 Contents
CHAPTER 1
Introduction
Welcome to the Python Control Systems Toolbox (python-control) User’s Manual. This manual contains informa-
tion on using the python-control package, including documentation for all functions in the package and examples
illustrating their use.
The python-control package is a set of python classes and functions that implement common operations for the analysis
and design of feedback control systems. The initial goal is to implement all of the functionality required to work
through the examples in the textbook Feedback Systems by Astrom and Murray. A MATLAB compatibility module is
available that provides many of the common functions corresponding to commands available in the MATLAB Control
Systems Toolbox.
The python-control package makes use of NumPy and SciPy. A list of general differences between NumPy and
MATLAB can be found here.
In terms of the python-control package more specifically, here are some thing to keep in mind:
• You must include commas in vectors. So [1 2 3] must be [1, 2, 3].
• Functions that return multiple arguments use tuples.
• You cannot use braces for collections; use tuples instead.
1.3 Installation
The python-control package can be installed using pip, conda or the standard distutils/setuptools mechanisms. The
package requires numpy and scipy, and the plotting routines require matplotlib. In addition, some routines require the
3
Python Control Library Documentation, Release dev
slycot library in order to implement more advanced features (including some MIMO functionality).
To install using pip:
Many parts of python-control will work without slycot, but some functionality is limited or absent, and installation of
slycot is recommended.
Note: the slycot library only works on some platforms, mostly linux-based. Users should check to insure that slycot is
installed correctly by running the command:
and verifying that no error message appears. It may be necessary to install slycot from source, which requires a
working FORTRAN compiler and either the lapack or openplas library. More information on the slycot package can
be obtained from the slycot project page.
For users with the Anaconda distribution of Python, the following commands can be used:
This installs slycot and python-control from conda-forge, including the openblas package.
Alternatively, to use setuptools, first download the source and unpack it. To install in your home directory, use:
There are two different ways to use the package. For the default interface described in Function reference, simply
import the control package as follows:
If you want to have a MATLAB-like environment, use the MATLAB compatibility module:
4 Chapter 1. Introduction
CHAPTER 2
Library conventions
The python-control library uses a set of standard conventions for the way that different types of standard information
used by the library.
Linear time invariant (LTI) systems are represented in python-control in state space, transfer function, or frequency
response data (FRD) form. Most functions in the toolbox will operate on any of these data types and functions for
converting between compatible types is provided.
The StateSpace class is used to represent state-space realizations of linear time-invariant (LTI) systems:
𝑑𝑥
= 𝐴𝑥 + 𝐵𝑢
𝑑𝑡
𝑦 = 𝐶𝑥 + 𝐷𝑢
where u is the input, y is the output, and x is the state.
To create a state space system, use the StateSpace constructor:
sys = StateSpace(A, B, C, D)
State space systems can be manipulated using standard arithmetic operations as well as the feedback(),
parallel(), and series() function. A full list of functions can be found in Function reference.
5
Python Control Library Documentation, Release dev
The FrequencyResponseData (FRD) class is used to represent systems in frequency response data form.
The main data members are omega and fresp, where omega is a 1D array with the frequency points of the response,
and fresp is a 3D array, with the first dimension corresponding to the output index of the FRD, the second dimension
corresponding to the input index, and the 3rd dimension corresponding to the frequency points in omega.
FRD systems have a somewhat more limited set of functions that are available, although all of the standard algebraic
manipulations can be performed.
A discrete time system is created by specifying a nonzero ‘timebase’, dt. The timebase argument can be given when a
system is constructed:
• dt = None: no timebase specified (default)
• dt = 0: continuous time system
• dt > 0: discrete time system with sampling period ‘dt’
• dt = True: discrete time with unspecified sampling period
Only the StateSpace, TransferFunction, and InputOutputSystem classes allow explicit representation
of discrete time systems.
Systems must have compatible timebases in order to be combined. A system with timebase None can be combined with
a system having a specified timebase; the result will have the timebase of the latter system. Similarly, a discrete time
system with unspecified sampling time (dt = True) can be combined with a system having a specified sampling time;
the result will be a discrete time system with the sample time of the latter system. For continuous time systems, the
sample_system() function or the StateSpace.sample() and TransferFunction.sample() methods
can be used to create a discrete time system from a continuous time system. See Utility functions and conversions.
LTI systems can be converted between representations either by calling the constructor for the desired data type using
the original system as the sole argument or using the explicit conversion functions ss2tf() and tf2ss().
A variety of functions in the library return time series data: sequences of values that change over time. A common set of
conventions is used for returning such data: columns represent different points in time, rows are different components
(e.g., inputs, outputs or states). For return arguments, an array of times is given as the first returned argument, followed
by one or more arrays of variable values. This convention is used throughout the library, for example in the functions
forced_response(), step_response(), impulse_response(), and initial_response().
Note: The convention used by python-control is different from the convention used in the scipy.signal library. In
Scipy’s convention the meaning of rows and columns is interchanged. Thus, all 2D values must be transposed when
they are used with functions from scipy.signal.
Types:
• Arguments can be arrays, matrices, or nested lists.
• Return values are arrays (not matrices).
The time vector is either 1D, or 2D with shape (1, n):
Input, state, and output all follow the same convention. Columns are different points in time, rows are different
components. When there is only one row, a 1D object is accepted or returned, which adds convenience for SISO
systems:
Same for X, Y
So, U[:,2] is the system’s input at the third point in time; and U[1] or U[1,:] is the sequence of values for the system’s
second input.
The initial conditions are either 1D, or 2D with shape (j, 1):
X0 = [[x1]
[x2]
...
...
[xj]]
t, y = step_response(sys)
plot(t, y)
t, y, x = forced_response(sys, u, t)
plot(t, y[0], label='y_0')
plot(t, y[1], label='y_1')
The convention also works well with the state space form of linear systems. If D is the feedthrough matrix of a linear
system, and U is its input (matrix or array), then the feedthrough part of the system’s response, can be computed like
this:
ft = D * U
The python-control library can be customized to allow for different default values for selected parameters. This
includes the ability to set the style for various types of plots and establishing the underlying representation for state
space matrices.
To set the default value of a configuration variable, set the appropriate element of the control.config.defaults dictionary:
control.config.defaults['module.parameter'] = value
The ~control.config.set_defaults function can also be used to set multiple configuration parameters at the same time:
Finally, there are also functions available set collections of variables based on standard configurations.
Selected variables that can be configured, along with their default values:
• bode.dB (False): Bode plot magnitude plotted in dB (otherwise powers of 10)
• bode.deg (True): Bode plot phase plotted in degrees (otherwise radians)
• bode.Hz (False): Bode plot frequency plotted in Hertz (otherwise rad/sec)
• bode.grid (True): Include grids for magnitude and phase plots
• freqplot.number_of_samples (None): Number of frequency points in Bode plots
• freqplot.feature_periphery_decade (1.0): How many decades to include in the frequency range on both sides of
features (poles, zeros).
• statesp.use_numpy_matrix: set the return type for state space matrices to numpy.matrix (verus numpy.ndarray)
Additional parameter variables are documented in individual functions
Functions that can be used to set standard configurations:
2.3.1 control.reset_defaults
control.reset_defaults()
Reset configuration values to their default (initial) values.
2.3.2 control.use_fbs_defaults
control.use_fbs_defaults()
Use Feedback Systems (FBS) compatible settings.
The following conventions are used:
• Bode plots plot gain in powers of ten, phase in degrees, frequency in rad/sec, no grid
2.3.3 control.use_matlab_defaults
control.use_matlab_defaults()
Use MATLAB compatible configuration settings.
The following conventions are used:
• Bode plots plot gain in dB, phase in degrees, frequency in rad/sec, with grids
• State space class and functions use Numpy matrix objects
2.3.4 control.use_numpy_matrix
control.use_numpy_matrix(flag=True, warn=True)
Turn on/off use of Numpy matrix class for state space operations.
Parameters
• flag (bool) – If flag is True (default), use the Numpy (soon to be deprecated) matrix
class to represent matrices in the ~control.StateSpace class and functions. If flat is False,
then matrices are represented by a 2D ndarray object.
• warn (bool) – If flag is True (default), issue a warning when turning on the use of the
Numpy matrix class. Set warn to false to omit display of the warning message.
Function reference
The Python Control Systems Library control provides common functions for analyzing and designing feedback
control systems.
3.1.1 control.ss
control.ss(A, B, C, D[, dt ])
Create a state space system.
The function accepts either 1, 4 or 5 parameters:
ss(sys) Convert a linear system into space system form. Always creates a new system, even if sys is already
a StateSpace object.
ss(A, B, C, D) Create a state space system from the matrices of its state and output equations:
𝑥˙ = 𝐴 · 𝑥 + 𝐵 · 𝑢
𝑦 =𝐶 ·𝑥+𝐷·𝑢
ss(A, B, C, D, dt) Create a discrete-time state space system from the matrices of its state and output
equations:
𝑥[𝑘 + 1] = 𝐴 · 𝑥[𝑘] + 𝐵 · 𝑢[𝑘]
𝑦[𝑘] = 𝐶 · 𝑥[𝑘] + 𝐷 · 𝑢[𝑘𝑖]
11
Python Control Library Documentation, Release dev
The matrices can be given as array like data types or strings. Everything that the constructor of numpy.
matrix accepts is permissible here too.
Parameters
• sys (StateSpace or TransferFunction) – A linear system
• A (array_like or string) – System matrix
• B (array_like or string) – Control matrix
• C (array_like or string) – Output matrix
• D (array_like or string) – Feed forward matrix
• dt (If present, specifies the sampling period and a discrete
time) – system is created
Returns out – The new linear system
Return type StateSpace
Raises ValueError – if matrix sizes are not self-consistent
See also:
StateSpace(), tf(), ss2tf(), tf2ss()
Examples
3.1.2 control.tf
control.tf(num, den[, dt ])
Create a transfer function system. Can create MIMO systems.
The function accepts either 1, 2, or 3 parameters:
tf(sys) Convert a linear system into transfer function form. Always creates a new system, even if sys is
already a TransferFunction object.
tf(num, den) Create a transfer function system from its numerator and denominator polynomial coeffi-
cients.
If num and den are 1D array_like objects, the function creates a SISO system.
To create a MIMO system, num and den need to be 2D nested lists of array_like objects. (A 3 dimensional
data structure in total.) (For details see note below.)
tf(num, den, dt) Create a discrete time transfer function system; dt can either be a positive number
indicating the sampling time or ‘True’ if no specific timebase is given.
tf('s') or tf('z') Create a transfer function representing the differential operator (‘s’) or delay operator
(‘z’).
Parameters
• sys (LTI (StateSpace or TransferFunction)) – A linear system
• num (array_like, or list of list of array_like) – Polynomial coeffi-
cients of the numerator
• den (array_like, or list of list of array_like) – Polynomial coeffi-
cients of the denominator
Returns out – The new linear system
Return type TransferFunction
Raises
• ValueError – if num and den have invalid or unequal dimensions
• TypeError – if num or den are of incorrect type
See also:
TransferFunction(), ss(), ss2tf(), tf2ss()
Notes
num[i][j] contains the polynomial coefficients of the numerator for the transfer function from the (j+1)st
input to the (i+1)st output. den[i][j] works the same way.
The list [2, 3, 4] denotes the polynomial 2𝑠2 + 3𝑠 + 4.
The special forms tf('s') and tf('z') can be used to create transfer functions for differentiation and unit
delays.
Examples
>>> # Create a variable 's' to allow algebra operations for SISO systems
>>> s = tf('s')
>>> G = (s + 1)/(s**2 + 2*s + 1)
3.1.3 control.frd
control.frd(d, w)
Construct a frequency response data model
frd models store the (measured) frequency response of a system.
Parameters
• response (array_like, or list) – complex vector with the system response
• freq (array_lik or lis) – vector with frequencies
• sys (LTI (StateSpace or TransferFunction)) – A linear system
Returns sys – New frequency response system
Return type FRD
See also:
FRD(), ss(), tf()
3.1.4 control.rss
Notes
If the number of states, inputs, or outputs is not specified, then the missing numbers are assumed to be 1. The
poles of the returned system will always have a negative real part.
3.1.5 control.drss
Notes
If the number of states, inputs, or outputs is not specified, then the missing numbers are assumed to be 1. The
poles of the returned system will always have a magnitude less than 1.
append(sys1, sys2, . . . , sysn) Group models by appending their inputs and outputs
connect(sys, Q, inputv, outputv) Index-based interconnection of an LTI system.
feedback(sys1[, sys2, sign]) Feedback interconnection between two I/O systems.
negate(sys) Return the negative of a system.
parallel(sys1, *sysn) Return the parallel connection sys1 + sys2 (+ . . .
series(sys1, *sysn) Return the series connection (sysn * . . .
3.2.1 control.append
Examples
>>> sys1 = ss([[1., -2], [3., -4]], [[5.], [7]]", [[6., 8]], [[9.]])
>>> sys2 = ss([[-1.]], [[1.]], [[1.]], [[0.]])
>>> sys = append(sys1, sys2)
3.2.2 control.connect
The system sys is a system typically constructed with append, with multiple inputs and outputs. The inputs
and outputs are connected according to the interconnection matrix Q, and then the final inputs and outputs are
trimmed according to the inputs and outputs listed in inputv and outputv.
NOTE: Inputs and outputs are indexed starting at 1 and negative values correspond to a negative feedback
interconnection.
Parameters
• sys (StateSpace Transferfunction) – System to be connected
• Q (2D array) – Interconnection matrix. First column gives the input to be connected
second column gives the output to be fed into this input. Negative values for the second
column mean the feedback is negative, 0 means no connection is made. Inputs and outputs
are indexed starting at 1.
• inputv (1D array) – list of final external inputs
• outputv (1D array) – list of final external outputs
Returns sys – Connected and trimmed LTI system
Return type LTI system
Examples
>>> sys1 = ss([[1., -2], [3., -4]], [[5.], [7]], [[6, 8]], [[9.]])
>>> sys2 = ss([[-1.]], [[1.]], [[1.]], [[0.]])
>>> sys = append(sys1, sys2)
>>> Q = [[1, 2], [2, -1]] # negative feedback interconnection
>>> sysc = connect(sys, Q, [2], [1, 2])
3.2.3 control.feedback
See also:
series(), parallel()
Notes
This function is a wrapper for the feedback function in the StateSpace and TransferFunction classes. It calls
TransferFunction.feedback if sys1 is a TransferFunction object, and StateSpace.feedback if sys1 is a StateSpace
object. If sys1 is a scalar, then it is converted to sys2’s type, and the corresponding feedback function is used. If
sys1 and sys2 are both scalars, then TransferFunction.feedback is used.
3.2.4 control.negate
control.negate(sys)
Return the negative of a system.
Parameters sys (StateSpace, TransferFunction or FRD) –
Returns out
Return type StateSpace or TransferFunction
Notes
This function is a wrapper for the __neg__ function in the StateSpace and TransferFunction classes. The output
type is the same as the input type.
Examples
3.2.5 control.parallel
control.parallel(sys1, *sysn)
Return the parallel connection sys1 + sys2 (+ . . . + sysn)
Parameters
• sys1 (scalar, StateSpace, TransferFunction, or FRD) –
• *sysn (other scalars, StateSpaces, TransferFunctions, or FRDs)
–
Returns out
Return type scalar, StateSpace, or TransferFunction
Raises ValueError – if sys1 and sys2 do not have the same numbers of inputs and outputs
See also:
series(), feedback()
Notes
This function is a wrapper for the __add__ function in the StateSpace and TransferFunction classes. The output
type is usually the type of sys1. If sys1 is a scalar, then the output type is the type of sys2.
If both systems have a defined timebase (dt = 0 for continuous time, dt > 0 for discrete time), then the timebase
for both systems must match. If only one of the system has a timebase, the return timebase will be set to match
it.
Examples
3.2.6 control.series
control.series(sys1, *sysn)
Return the series connection (sysn * . . . *) sys2 * sys1
Parameters
• sys1 (scalar, StateSpace, TransferFunction, or FRD) –
• *sysn (other scalars, StateSpaces, TransferFunctions, or FRDs)
–
Returns out
Return type scalar, StateSpace, or TransferFunction
Raises ValueError – if sys2.inputs does not equal sys1.outputs if sys1.dt is not compatible with
sys2.dt
See also:
parallel(), feedback()
Notes
This function is a wrapper for the __mul__ function in the StateSpace and TransferFunction classes. The output
type is usually the type of sys2. If sys2 is a scalar, then the output type is the type of sys1.
If both systems have a defined timebase (dt = 0 for continuous time, dt > 0 for discrete time), then the timebase
for both systems must match. If only one of the system has a timebase, the return timebase will be set to match
it.
Examples
See also the Input/output systems module, which can be used to create and interconnect nonlinear input/output systems.
3.3.1 control.bode_plot
Notes
1. Alternatively, you may use the lower-level method (mag, phase, freq) = sys.freqresp(freq) to generate the
frequency response for a system, but it returns a MIMO response.
2. If a discrete time model is given, the frequency response is plotted along the upper branch of the unit circle,
using the mapping z = exp(j omega dt) where omega ranges from 0 to pi/dt and dt is the discrete timebase. If
not timebase is specified (dt = True), dt is set to 1.
Examples
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> mag, phase, omega = bode(sys)
3.3.2 control.nyquist_plot
Examples
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> real, imag, freq = nyquist_plot(sys)
3.3.3 control.gangof4_plot
3.3.4 control.nichols_plot
3.4.1 control.forced_response
Notes
For discrete time systems, the input/output response is computed using the scipy.signal.dlsim function.
For continuous time systems, the output is computed using the matrix exponential exp(A t) and assuming linear
interpolation of the inputs between time points.
Examples
3.4.2 control.impulse_response
Notes
This function uses the forced_response function to compute the time response. For continuous time systems,
the initial condition is altered to account for the initial impulse.
Examples
3.4.3 control.initial_response
Notes
This function uses the forced_response function with the input set to zero.
Examples
3.4.4 control.input_output_response
3.4.5 control.step_response
• output (int) – Index of the output that will be used in this simulation. Set to None to not
trim outputs
• transpose (bool) – If True, transpose all input and output arrays (for backward com-
patibility with MATLAB and scipy.signal.lsim)
• return_x (bool) – If True, return the state vector (default = False).
• squeeze (bool, optional (default=True)) – If True, remove single-
dimensional entries from the shape of the output. For single output systems, this converts
the output response to a 1D array.
Returns
• T (array) – Time values of the output
• yout (array) – Response of the system
• xout (array) – Individual response of each x variable
See also:
forced_response(), initial_response(), impulse_response()
Notes
This function uses the forced_response function with the input set to a unit step.
Examples
3.4.6 control.phase_plot
Parameters
• func (callable(x, t, ..)) – Computes the time derivative of y (compatible with
odeint). The function should be the same for as used for scipy.integrate. Namely, it should
be a function of the form dxdt = F(x, t) that accepts a state x of dimension 2 and returns a
derivative dx/dt of dimension 2.
• Y (X,) – Two 3-element sequences specifying x and y coordinates of a grid. These argu-
ments are passed to linspace and meshgrid to generate the points at which the vector field is
plotted. If absent (or None), the vector field is not plotted.
• scale (float, optional) – Scale size of arrows; default = 1
See also:
Examples
dcgain(sys) Return the zero-frequency (or DC) gain of the given sys-
tem
evalfr(sys, x) Evaluate the transfer function of an LTI system for a
single complex number x.
freqresp(sys, omega) Frequency response of an LTI system at multiple angu-
lar frequencies.
margin(sysdata) Calculate gain and phase margins and associated
crossover frequencies
stability_margins(sysdata[, returnall, epsw]) Calculate stability margins and associated crossover fre-
quencies.
phase_crossover_frequencies(sys) Compute frequencies and gains at intersections with real
axis in Nyquist plot.
pole(sys) Compute system poles.
zero(sys) Compute system zeros.
Continued on next page
3.6.1 control.dcgain
control.dcgain(sys)
Return the zero-frequency (or DC) gain of the given system
Returns gain – The zero-frequency gain, or np.nan if the system has a pole at the origin
Return type ndarray
3.6.2 control.evalfr
control.evalfr(sys, x)
Evaluate the transfer function of an LTI system for a single complex number x.
To evaluate at a frequency, enter x = omega*j, where omega is the frequency in radians
Parameters
• sys (StateSpace or TransferFunction) – Linear system
• x (scalar) – Complex number
Returns fresp
Return type ndarray
See also:
freqresp(), bode()
Notes
Examples
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> evalfr(sys, 1j)
array([[ 44.8-21.4j]])
>>> # This is the transfer function matrix evaluated at s = i.
3.6.3 control.freqresp
control.freqresp(sys, omega)
Frequency response of an LTI system at multiple angular frequencies.
Parameters
• sys (StateSpace or TransferFunction) – Linear system
• omega (array_like) – List of frequencies
Returns
• mag (ndarray)
• phase (ndarray)
• omega (list, tuple, or ndarray)
See also:
evalfr(), bode()
Notes
This function is a wrapper for StateSpace.freqresp and TransferFunction.freqresp. The output omega is a sorted
version of the input omega.
Examples
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> mag, phase, omega = freqresp(sys, [0.1, 1., 10.])
>>> mag
array([[[ 58.8576682 , 49.64876635, 13.40825927]]])
>>> phase
array([[[-0.05408304, -0.44563154, -0.66837155]]])
3.6.4 control.margin
control.margin(sysdata)
Calculate gain and phase margins and associated crossover frequencies
Parameters sysdata (LTI system or (mag, phase, omega) sequence) –
sys [StateSpace or TransferFunction] Linear SISO system
mag, phase, omega [sequence of array_like] Input magnitude, phase (in deg.), and frequencies
(rad/sec) from bode frequency response data
Returns
• gm (float) – Gain margin
• pm (float) – Phase margin (in degrees)
• wg (float) – Frequency for gain margin (at phase crossover, phase = -180 degrees)
• wp (float) – Frequency for phase margin (at gain crossover, gain = 1)
• Margins are calculated for a SISO open-loop system.
• If there is more than one gain crossover, the one at the smallest
• margin (deviation from gain = 1), in absolute sense, is
• returned. Likewise the smallest phase margin (in absolute sense)
• is returned.
Examples
3.6.5 control.stability_margins
3.6.6 control.phase_crossover_frequencies
control.phase_crossover_frequencies(sys)
Compute frequencies and gains at intersections with real axis in Nyquist plot.
Call as: omega, gain = phase_crossover_frequencies()
Returns
• omega (1d array of (non-negative) frequencies where Nyquist plot)
• intersects the real axis
• gain (1d array of corresponding gains)
Examples
3.6.7 control.pole
control.pole(sys)
Compute system poles.
Parameters sys (StateSpace or TransferFunction) – Linear system
Returns poles – Array that contains the system’s poles.
Return type ndarray
Raises NotImplementedError – when called on a TransferFunction object
See also:
zero(), TransferFunction.pole(), StateSpace.pole()
3.6.8 control.zero
control.zero(sys)
Compute system zeros.
Parameters sys (StateSpace or TransferFunction) – Linear system
Returns zeros – Array that contains the system’s zeros.
Return type ndarray
Raises NotImplementedError – when called on a MIMO system
See also:
pole(), StateSpace.zero(), TransferFunction.zero()
3.6.9 control.pzmap
3.6.10 control.root_locus
3.6.11 control.sisotool
and phase diagrams. The top right plot is a clickable root locus plot, clicking on the root locus will change the
gain of the system. The bottom left plot shows a closed loop time response.
Parameters
• sys (LTI object) – Linear input/output systems (SISO only)
• kvect (list or ndarray, optional) – List of gains to use for plotting root locus
• xlim_rlocus (tuple or list, optional) – control of x-axis range, normally
with tuple (see matplotlib.axes)
• ylim_rlocus (tuple or list, optional) – control of y-axis range
• plotstr_rlocus (Additional options to matplotlib) – plotting style for
the root locus plot(color, linestyle, etc)
• rlocus_grid (boolean (default = False)) – If True plot s-plane grid.
• omega (freq_range) – Range of frequencies in rad/sec for the bode plot
• dB (boolean) – If True, plot result in dB for the bode plot
• Hz (boolean) – If True, plot frequency in Hz for the bode plot (omega must be provided
in rad/sec)
• deg (boolean) – If True, plot phase in degrees for the bode plot (else radians)
• omega_limits (tuple, list, .. of two values) – Limits of the to generate
frequency vector. If Hz=True the limits are in Hz otherwise in rad/s.
• omega_num (int) – number of samples
• margins_bode (boolean) – If True, plot gain and phase margin in the bode plot
• tvect (list or ndarray, optional) – List of timesteps to use for closed loop
step response
Examples
3.7.1 control.care
3.7.2 control.dare
3.7.3 control.lyap
3.7.4 control.dlyap
3.7.5 control.ctrb
control.ctrb(A, B)
Controllabilty matrix
Parameters B (A,) – Dynamics and input matrix of the system
Returns C – Controllability matrix
Return type matrix
Examples
>>> C = ctrb(A, B)
3.7.6 control.obsv
control.obsv(A, C)
Observability matrix
Parameters C (A,) – Dynamics and output matrix of the system
Returns O – Observability matrix
Return type matrix
Examples
>>> O = obsv(A, C)
3.7.7 control.gram
control.gram(sys, type)
Gramian (controllability or observability)
Parameters
• sys (StateSpace) – State-space system to compute Gramian for
• type (String) – Type of desired computation. type is either ‘c’ (controllability) or ‘o’
(observability). To compute the Cholesky factors of gramians use ‘cf’ (controllability) or
‘of’ (observability)
Returns gram – Gramian of system
Return type array
Raises
• ValueError – * if system is not instance of StateSpace class * if type is not ‘c’, ‘o’, ‘cf’
or ‘of’ * if system is unstable (sys.A has eigenvalues not in left half plane)
• ImportError – if slycot routine sb03md cannot be found if slycot routine sb03od cannot
be found
Examples
>>> Wc = gram(sys,'c')
>>> Wo = gram(sys,'o')
>>> Rc = gram(sys,'cf'), where Wc=Rc'*Rc
>>> Ro = gram(sys,'of'), where Wo=Ro'*Ro
3.8.1 control.acker
control.acker(A, B, poles)
Pole placement using Ackermann method
Call: K = acker(A, B, poles)
Parameters
• B (A,) – State and input matrix of the system
• poles (1-d list) – Desired eigenvalue locations
Returns K – Gains such that A - B K has given eigenvalues
Return type matrix
3.8.2 control.h2syn
Examples
>>> K = h2syn(P,nmeas,ncon)
3.8.3 control.hinfsyn
Examples
3.8.4 control.lqr
control.lqr(A, B, Q, R[, N ])
Linear quadratic regulator design
The lqr() function computes the optimal state feedback controller that minimizes the quadratic cost
∫︁ ∞
𝐽= (𝑥′ 𝑄𝑥 + 𝑢′ 𝑅𝑢 + 2𝑥′ 𝑁 𝑢)𝑑𝑡
0
Examples
See also:
lqe()
3.8.5 control.mixsyn
Parameters
• g (LTI; the plant for which controller must be synthesized) –
• w1 (weighting on s = (1+g*k)**-1; None, or scalar or k1-by-ny
LTI) –
• w2 (weighting on k*s; None, or scalar or k2-by-nu LTI) –
• w3 (weighting on t = g*k*(1+g*k)**-1; None, or scalar or
k3-by-ny LTI) –
• least one of w1, w2, and w3 must not be None. (At) –
Returns
• k (synthesized controller; StateSpace object)
• cl (closed system mapping evaluation inputs to evaluation outputs; if )
• p is the augmented plant, with – [z] = [p11 p12] [w], [y] [p21 g] [u]
• then cl is the system from w->z with u=-k*y. StateSpace object.
• info (tuple with entries, in order,) –
– gamma: scalar; H-infinity norm of cl
– rcond: array; estimates of reciprocal condition numbers computed during synthesis. See
hinfsyn for details
• If a weighting w is scalar, it will be replaced by I*w, where I is
• ny-by-ny for w1 and w3, and nu-by-nu for w2.
See also:
hinfsyn(), augw()
3.8.6 control.place
control.place(A, B, p)
Place closed loop eigenvalues K = place(A, B, p)
Parameters
• A (2-d array) – Dynamics matrix
• B (2-d array) – Input matrix
• p (1-d list) – Desired eigenvalue locations
Returns
• K (2-d array) – Gain such that A - B K has eigenvalues given in p
• Algorithm
• ———
• This is a wrapper function for scipy.signal.place_poles, which
• implements the Tits and Yang algorithm [1]. It will handle SISO,
• MISO, and MIMO systems. If you want more control over the algorithm,
• use scipy.signal.place_poles directly.
• [1] A.L. Tits and Y. Yang, “Globally convergent algorithms for robust
• pole assignment by state feedback, IEEE Transactions on Automatic
• Control, Vol. 41, pp. 1432-1452, 1996.
• Limitations
• ———–
• The algorithm will not place poles at the same location more
• than rank(B) times.
Examples
See also:
place_varga(), acker()
3.9.1 control.minreal
3.9.2 control.balred
Examples
3.9.3 control.hsvd
control.hsvd(sys)
Calculate the Hankel singular values.
Parameters sys (StateSpace) – A state space system
Returns H – A list of Hankel singular values
Return type array
See also:
gram()
Notes
The Hankel singular values are the singular values of the Hankel operator. In practice, we compute the square
root of the eigenvalues of the matrix formed by taking the product of the observability and controllability grami-
ans. There are other (more efficient) methods based on solving the Lyapunov equation in a particular way (more
details soon).
Examples
>>> H = hsvd(sys)
3.9.4 control.modred
Examples
3.9.5 control.era
Parameters
• YY (array) – nout x nin dimensional impulse-response data
• m (integer) – Number of rows in Hankel matrix
• n (integer) – Number of columns in Hankel matrix
Examples
3.9.6 control.markov
control.markov(Y, U, m)
Calculate the first M Markov parameters [D CB CAB . . . ] from input U, output Y.
Parameters
• Y (array_like) – Output data
• U (array_like) – Input data
• m (int) – Number of Markov parameters to output
Returns H – First m Markov parameters
Return type ndarray
Notes
Examples
>>> H = markov(Y, U, m)
find_eqpt(sys, x0[, u0, y0, t, params, iu, . . . ]) Find the equilibrium point for an input/output system.
linearize(sys, xeq[, ueq, t, params]) Linearize an input/output system at a given state and in-
put.
input_output_response(sys, T[, U, X0, . . . ]) Compute the output response of a system to a given in-
put.
ss2io(*args, **kw) Create an I/O system from a state space linear system.
tf2io(*args, **kw) Convert a transfer function into an I/O system
flatsys.point_to_point(sys, x0, u0, xf, uf, Tf) Compute trajectory between an initial and final condi-
tions.
3.10.1 control.iosys.find_eqpt
• result (scipy root() result object, optional) – If return_result is True, returns the result from
the scipy root function.
3.10.2 control.iosys.linearize
3.10.3 control.iosys.input_output_response
3.10.4 control.iosys.ss2io
control.iosys.ss2io(*args, **kw)
Create an I/O system from a state space linear system.
Converts a StateSpace system into an InputOutputSystem with the same inputs, outputs, and states.
The new system can be a continuous or discrete time system
Parameters
• linsys (StateSpace) – LTI StateSpace system to be converted
• inputs (int, list of str or None, optional) – Description of the system
inputs. This can be given as an integer count or as a list of strings that name the individual
signals. If an integer count is specified, the names of the signal will be of the form s[i]
(where s is one of u, y, or x). If this parameter is not given or given as None, the relevant
quantity will be determined when possible based on other information provided to functions
using the system.
• outputs (int, list of str or None, optional) – Description of the system
outputs. Same format as inputs.
• states (int, list of str, or None, optional) – Description of the system
states. Same format as inputs.
• dt (None, True or float, optional) – System timebase. None (default) indi-
cates continuous time, True indicates discrete time with undefined sampling time, positive
number is discrete time with specified sampling time.
• params (dict, optional) – Parameter values for the systems. Passed to the evalua-
tion functions for the system as default values, overriding internal defaults.
• name (string, optional) – System name (used for specifying signals)
Returns iosys – Linear system represented as an input/output system
Return type LinearIOSystem
3.10.5 control.iosys.tf2io
control.iosys.tf2io(*args, **kw)
Convert a transfer function into an I/O system
3.10.6 control.flatsys.point_to_point
Parameters
• flatsys (FlatSystem object) – Description of the differentially flat system. This
object must define a function flatsys.forward() that takes the system state and produceds the
flag of flat outputs and a system flatsys.reverse() that takes the flag of the flat output and
prodes the state and input.
• u0, xf, uf (x0,) – Define the desired initial and final conditions for the system. If any
of the values are given as None, they are replaced by a vector of zeros of the appropriate
dimension.
• Tf (float) – The final time for the trajectory (corresponding to xf)
• T0 (float (optional)) – The initial time for the trajectory (corresponding to x0). If
not specified, its value is taken to be zero.
• basis (BasisFamily object (optional)) – The basis functions to use for gen-
erating the trajectory. If not specified, the PolyFamily basis family will be used, with the
minimal number of elements required to find a feasible trajectory (twice the number of sys-
tem states)
Returns traj – The system trajectory is returned as an object that implements the eval() function,
we can be used to compute the value of the state and input and a given time t.
Return type SystemTrajectory object
augw(g[, w1, w2, w3]) Augment plant for mixed sensitivity problem.
canonical_form(xsys[, form]) Convert a system into canonical form
damp(sys[, doprint]) Compute natural frequency, damping ratio, and poles of
a system
db2mag(db) Convert a gain in decibels (dB) to a magnitude
isctime(sys[, strict]) Check to see if a system is a continuous-time system
isdtime(sys[, strict]) Check to see if a system is a discrete time system
issiso(sys[, strict]) Check to see if a system is single input, single output
issys(obj) Return True if an object is a system, otherwise False
mag2db(mag) Convert a magnitude to decibels (dB)
observable_form(xsys) Convert a system into observable canonical form
pade(T[, n, numdeg]) Create a linear system that approximates a delay.
reachable_form(xsys) Convert a system into reachable canonical form
reset_defaults() Reset configuration values to their default (initial) val-
ues.
sample_system(sysc, Ts[, method, alpha]) Convert a continuous time system to discrete time
ss2tf(sys) Transform a state space system to a transfer function.
ssdata(sys) Return state space data objects for a system
tf2ss(sys) Transform a transfer function to a state space system.
tfdata(sys) Return transfer function data objects for a system
timebase(sys[, strict]) Return the timebase for an LTI system
timebaseEqual(sys1, sys2) Check to see if two systems have the same timebase
unwrap(angle[, period]) Unwrap a phase angle to give a continuous curve
use_fbs_defaults() Use Feedback Systems (FBS) compatible settings.
use_matlab_defaults() Use MATLAB compatible configuration settings.
Continued on next page
3.11.1 control.augw
3.11.2 control.canonical_form
control.canonical_form(xsys, form=’reachable’)
Convert a system into canonical form
Parameters
• xsys (StateSpace object) – System to be transformed, with state ‘x’
• form (String) –
Canonical form for transformation. Chosen from:
– ’reachable’ - reachable canonical form
– ’observable’ - observable canonical form
– ’modal’ - modal canonical form
Returns
• zsys (StateSpace object) – System in desired canonical form, with state ‘z’
• T (matrix) – Coordinate transformation matrix, z = T * x
3.11.3 control.damp
control.damp(sys, doprint=True)
Compute natural frequency, damping ratio, and poles of a system
The function takes 1 or 2 parameters
Parameters
• sys (LTI (StateSpace or TransferFunction)) – A linear system object
• doprint – if true, print table with values
Returns
• wn (array) – Natural frequencies of the poles
• damping (array) – Damping values
• poles (array) – Pole locations
• Algorithm
• ———
• If the system is continuous, – wn = abs(poles) Z = -real(poles)/poles.
• If the system is discrete, the discrete poles are mapped to their
• equivalent location in the s-plane via – s = log10(poles)/dt
• and – wn = abs(s) Z = -real(s)/wn.
See also:
pole()
3.11.4 control.db2mag
control.db2mag(db)
Convert a gain in decibels (dB) to a magnitude
If A is magnitude,
db = 20 * log10(A)
3.11.5 control.isctime
control.isctime(sys, strict=False)
Check to see if a system is a continuous-time system
Parameters
• sys (LTI system) – System to be checked
• strict (bool (default = False)) – If strict is True, make sure that timebase is
not None
3.11.6 control.isdtime
control.isdtime(sys, strict=False)
Check to see if a system is a discrete time system
Parameters
• sys (LTI system) – System to be checked
• strict (bool (default = False)) – If strict is True, make sure that timebase is
not None
3.11.7 control.issiso
control.issiso(sys, strict=False)
Check to see if a system is single input, single output
Parameters
• sys (LTI system) – System to be checked
• strict (bool (default = False)) – If strict is True, do not treat scalars as SISO
3.11.8 control.issys
control.issys(obj)
Return True if an object is a system, otherwise False
3.11.9 control.mag2db
control.mag2db(mag)
Convert a magnitude to decibels (dB)
If A is magnitude,
db = 20 * log10(A)
3.11.10 control.observable_form
control.observable_form(xsys)
Convert a system into observable canonical form
Parameters xsys (StateSpace object) – System to be transformed, with state x
Returns
• zsys (StateSpace object) – System in observable canonical form, with state z
• T (matrix) – Coordinate transformation: z = T * x
3.11.11 control.pade
Notes
Based on:
1. Algorithm 11.3.1 in Golub and van Loan, “Matrix Computation” 3rd. Ed. pp. 572-574
2. M. Vajta, “Some remarks on Padé-approximations”, 3rd TEMPUS-INTCOM Symposium
3.11.12 control.reachable_form
control.reachable_form(xsys)
Convert a system into reachable canonical form
Parameters xsys (StateSpace object) – System to be transformed, with state x
Returns
• zsys (StateSpace object) – System in reachable canonical form, with state z
• T (matrix) – Coordinate transformation: z = T * x
3.11.13 control.sample_system
Notes
Examples
3.11.14 control.ss2tf
control.ss2tf(sys)
Transform a state space system to a transfer function.
The function accepts either 1 or 4 parameters:
ss2tf(sys) Convert a linear system into space system form. Always creates a new system, even if sys is
already a StateSpace object.
ss2tf(A, B, C, D) Create a state space system from the matrices of its state and output equations.
For details see: ss()
Parameters
• sys (StateSpace) – A linear system
• A (array_like or string) – System matrix
• B (array_like or string) – Control matrix
• C (array_like or string) – Output matrix
• D (array_like or string) – Feedthrough matrix
Returns out – New linear system in transfer function form
Return type TransferFunction
Raises
• ValueError – if matrix sizes are not self-consistent, or if an invalid number of arguments
is passed in
• TypeError – if sys is not a StateSpace object
See also:
tf(), ss(), tf2ss()
Examples
3.11.15 control.ssdata
control.ssdata(sys)
Return state space data objects for a system
Parameters sys (LTI (StateSpace, or TransferFunction)) – LTI system whose
data will be returned
Returns (A, B, C, D) – State space data for the system
Return type list of matrices
3.11.16 control.tf2ss
control.tf2ss(sys)
Transform a transfer function to a state space system.
The function accepts either 1 or 2 parameters:
tf2ss(sys) Convert a linear system into transfer function form. Always creates a new system, even if sys is
already a TransferFunction object.
tf2ss(num, den) Create a transfer function system from its numerator and denominator polynomial coef-
ficients.
For details see: tf()
Parameters
• sys (LTI (StateSpace or TransferFunction)) – A linear system
• num (array_like, or list of list of array_like) – Polynomial coeffi-
cients of the numerator
• den (array_like, or list of list of array_like) – Polynomial coeffi-
cients of the denominator
Returns out – New linear system in state space form
Return type StateSpace
Raises
• ValueError – if num and den have invalid or unequal dimensions, or if an invalid number
of arguments is passed in
• TypeError – if num or den are of incorrect type, or if sys is not a TransferFunction object
See also:
ss(), tf(), ss2tf()
Examples
>>> num = [[[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]]]
>>> den = [[[9., 8., 7.], [6., 5., 4.]], [[3., 2., 1.], [-1., -2., -3.]]]
>>> sys1 = tf2ss(num, den)
3.11.17 control.tfdata
control.tfdata(sys)
Return transfer function data objects for a system
Parameters sys (LTI (StateSpace, or TransferFunction)) – LTI system whose
data will be returned
Returns (num, den) – Transfer function coefficients (SISO only)
Return type numerator and denominator arrays
3.11.18 control.timebase
control.timebase(sys, strict=True)
Return the timebase for an LTI system
dt = timebase(sys)
returns the timebase for a system ‘sys’. If the strict option is set to False, dt = True will be returned as 1.
3.11.19 control.timebaseEqual
control.timebaseEqual(sys1, sys2)
Check to see if two systems have the same timebase
timebaseEqual(sys1, sys2)
returns True if the timebases for the two systems are compatible. By default, systems with timebase ‘None’ are
compatible with either discrete or continuous timebase systems. If two systems have a discrete timebase (dt >
0) then their timebases must be equal.
3.11.20 control.unwrap
control.unwrap(angle, period=6.283185307179586)
Unwrap a phase angle to give a continuous curve
Parameters
• angle (array_like) – Array of angles to be unwrapped
• period (float, optional) – Period (defaults to 2*pi)
Returns angle_out – Output array, with jumps of period/2 eliminated
Return type array_like
Examples
The classes listed below are used to represent models of linear time-invariant (LTI) systems. They are usually created
from factory functions such as tf() and ss(), so the user should normally not need to instantiate these directly.
4.1 control.TransferFunction
means that the numerator of the transfer function from the 6th input to the 3rd output is set to s^2 + 4s + 8.
Discrete-time transfer functions are implemented by using the ‘dt’ instance variable and setting it to something
other than ‘None’. If ‘dt’ has a non-zero value, then it must match whenever two transfer functions are combined.
If ‘dt’ is set to True, the system will be treated as a discrete time system with unspecified sampling time.
The TransferFunction class defines two constants s and z that represent the differentiation and delay operators
in continuous and discrete time. These can be used to create variables that allow algebraic creation of transfer
functions. For example,
57
Python Control Library Documentation, Release dev
>>> s = TransferFunction.s
>>> G = (s + 1)/(s**2 + 2*s + 1)
__init__(*args)
TransferFunction(num, den[, dt])
Construct a transfer function.
The default constructor is TransferFunction(num, den), where num and den are lists of lists of arrays con-
taining polynomial coefficients. To create a discrete time transfer funtion, use TransferFunction(num, den,
dt) where ‘dt’ is the sampling time (or True for unspecified sampling time). To call the copy constructor,
call TransferFunction(sys), where sys is a TransferFunction object (continuous or discrete).
Methods
Attributes
s
z
damp()
Natural frequency, damping ratio of system poles
Returns
• wn (array) – Natural frequencies for each system pole
• zeta (array) – Damping ratio for each system pole
• poles (array) – Array of system poles
dcgain()
Return the zero-frequency (or DC) gain
For a continous-time transfer function G(s), the DC gain is G(0) For a discrete-time transfer function G(z),
the DC gain is G(1)
Returns gain – The zero-frequency gain
Return type ndarray
evalfr(omega)
Evaluate a transfer function at a single angular frequency.
self._evalfr(omega) returns the value of the transfer function matrix with input value s = i * omega.
feedback(other=1, sign=-1)
Feedback interconnection between two LTI objects.
freqresp(omega)
Evaluate a transfer function at a list of angular frequencies.
mag, phase, omega = self.freqresp(omega)
reports the value of the magnitude, phase, and angular frequency of the transfer function matrix evaluated
at s = i * omega, where omega is a list of angular frequencies, and is a sorted version of the input omega.
horner(s)
Evaluate the systems’s transfer function for a complex variable
Returns a matrix of values evaluated at complex variable s.
isctime(strict=False)
Check to see if a system is a continuous-time system
Parameters
• sys (LTI system) – System to be checked
• strict (bool, optional) – If strict is True, make sure that timebase is not None.
Default is False.
isdtime(strict=False)
Check to see if a system is a discrete-time system
Parameters strict (bool, optional) – If strict is True, make sure that timebase is not
None. Default is False.
issiso()
Check to see if a system is single input, single output
minreal(tol=None)
Remove cancelling pole/zero pairs from a transfer function
pole()
Compute the poles of a transfer function.
returnScipySignalLTI()
Return a list of a list of scipy.signal.lti objects.
For instance,
is a signal.scipy.lti object corresponding to the transfer function from the 6th input to the 4th output.
sample(Ts, method=’zoh’, alpha=None)
Convert a continuous-time system to discrete time
4.1. control.TransferFunction 59
Python Control Library Documentation, Release dev
Creates a discrete-time system from a continuous-time system by sampling. Multiple methods of conver-
sion are supported.
Parameters
• Ts (float) – Sampling period
• method ({"gbt", "bilinear", "euler", "backward_diff",) – “zoh”,
“matched”} Method to use for sampling:
– gbt: generalized bilinear transformation
– bilinear: Tustin’s approximation (“gbt” with alpha=0.5)
– euler: Euler (or forward difference) method (“gbt” with alpha=0)
– backward_diff: Backwards difference (“gbt” with alpha=1.0)
– zoh: zero-order hold (default)
• alpha (float within [0, 1]) – The generalized bilinear transformation weight-
ing parameter, which should only be specified with method=”gbt”, and is ignored other-
wise.
Returns sysd – Discrete time system, with sampling rate Ts
Return type StateSpace system
Notes
Examples
zero()
Compute the zeros of a transfer function.
4.2 control.StateSpace
Discrete-time state space system are implemented by using the ‘dt’ instance variable and setting it to the sam-
pling period. If ‘dt’ is not None, then it must match whenever two state space systems are combined. Setting dt
= 0 specifies a continuous system, while leaving dt = None means the system timebase is not specified. If ‘dt’ is
set to True, the system will be treated as a discrete time system with unspecified sampling time.
__init__(*args, **kw)
StateSpace(A, B, C, D[, dt])
Construct a state space object.
The default constructor is StateSpace(A, B, C, D), where A, B, C, D are matrices or equivalent objects. To
create a discrete time system, use StateSpace(A, B, C, D, dt) where ‘dt’ is the sampling time (or True for
unspecified sampling time). To call the copy constructor, call StateSpace(sys), where sys is a StateSpace
object.
Methods
append(other)
Append a second model to the present model. The second model is converted to state-space if necessary,
inputs and outputs are appended and their order is preserved
damp()
Natural frequency, damping ratio of system poles
Returns
• wn (array) – Natural frequencies for each system pole
• zeta (array) – Damping ratio for each system pole
• poles (array) – Array of system poles
dcgain()
Return the zero-frequency gain
The zero-frequency gain of a continuous-time state-space system is given by:
4.2. control.StateSpace 61
Python Control Library Documentation, Release dev
Parameters omega (array) – A list of frequencies in radians/sec at which the system should
be evaluated. The list can be either a python list or a numpy array and will be sorted before
evaluation.
Returns
• mag (float) – The magnitude (absolute value, not dB or log10) of the system frequency
response.
• phase (float) – The wrapped phase in radians of the system frequency response.
• omega (array) – The list of sorted frequencies at which the response was evaluated.
horner(s)
Evaluate the systems’s transfer function for a complex variable
Returns a matrix of values evaluated at complex variable s.
isctime(strict=False)
Check to see if a system is a continuous-time system
Parameters
• sys (LTI system) – System to be checked
• strict (bool, optional) – If strict is True, make sure that timebase is not None.
Default is False.
isdtime(strict=False)
Check to see if a system is a discrete-time system
Parameters strict (bool, optional) – If strict is True, make sure that timebase is not
None. Default is False.
issiso()
Check to see if a system is single input, single output
is a signal.scipy.lti object corresponding to the transfer function from the 6th input to the 4th output.
sample(Ts, method=’zoh’, alpha=None)
Convert a continuous time system to discrete time
Creates a discrete-time system from a continuous-time system by sampling. Multiple methods of conver-
sion are supported.
Parameters
• Ts (float) – Sampling period
• method ({"gbt", "bilinear", "euler", "backward_diff", "zoh"})
– Which method to use:
– gbt: generalized bilinear transformation
– bilinear: Tustin’s approximation (“gbt” with alpha=0.5)
– euler: Euler (or forward differencing) method (“gbt” with alpha=0)
– backward_diff: Backwards differencing (“gbt” with alpha=1.0)
– zoh: zero-order hold (default)
• alpha (float within [0, 1]) – The generalized bilinear transformation weight-
ing parameter, which should only be specified with method=”gbt”, and is ignored other-
wise
Returns sysd – Discrete time system, with sampling rate Ts
Return type StateSpace
4.2. control.StateSpace 63
Python Control Library Documentation, Release dev
Notes
Examples
zero()
Compute the zeros of a state space system.
4.3 control.FrequencyResponseData
class control.FrequencyResponseData(d, w)
A class for models defined by frequency response data (FRD)
The FrequencyResponseData (FRD) class is used to represent systems in frequency response data form.
The main data members are ‘omega’ and ‘fresp’, where omega is a 1D array with the frequency points of the
response, and fresp is a 3D array, with the first dimension corresponding to the output index of the FRD, the
second dimension corresponding to the input index, and the 3rd dimension corresponding to the frequency points
in omega. For example,
means that the frequency response from the 6th input to the 3rd output at the frequencies defined in omega is set
to the array above, i.e. the rows represent the outputs and the columns represent the inputs.
__init__(*args, **kwargs)
Construct an FRD object.
The default constructor is FRD(d, w), where w is an iterable of frequency points, and d is the matching
frequency data.
If d is a single list, 1d array, or tuple, a SISO system description is assumed. d can also be
To call the copy constructor, call FRD(sys), where sys is a FRD object.
To construct frequency response data for an existing LTI object, other than an FRD, call FRD(sys, omega)
Methods
Attributes
epsw
damp()
Natural frequency, damping ratio of system poles
Returns
• wn (array) – Natural frequencies for each system pole
• zeta (array) – Damping ratio for each system pole
• poles (array) – Array of system poles
dcgain()
Return the zero-frequency gain
eval(omega)
Evaluate a transfer function at a single angular frequency.
self.evalfr(omega) returns the value of the frequency response at frequency omega.
Note that a “normal” FRD only returns values for which there is an entry in the omega vector. An interpo-
lating FRD can return intermediate values.
evalfr(omega)
Evaluate a transfer function at a single angular frequency.
self._evalfr(omega) returns the value of the frequency response at frequency omega.
Note that a “normal” FRD only returns values for which there is an entry in the omega vector. An interpo-
lating FRD can return intermediate values.
feedback(other=1, sign=-1)
Feedback interconnection between two FRD objects.
freqresp(omega)
Evaluate a transfer function at a list of angular frequencies.
mag, phase, omega = self.freqresp(omega)
reports the value of the magnitude, phase, and angular frequency of the transfer function matrix evaluated
at s = i * omega, where omega is a list of angular frequencies, and is a sorted version of the input omega.
isctime(strict=False)
Check to see if a system is a continuous-time system
Parameters
• sys (LTI system) – System to be checked
• strict (bool, optional) – If strict is True, make sure that timebase is not None.
Default is False.
isdtime(strict=False)
Check to see if a system is a discrete-time system
4.3. control.FrequencyResponseData 65
Python Control Library Documentation, Release dev
Parameters strict (bool, optional) – If strict is True, make sure that timebase is not
None. Default is False.
issiso()
Check to see if a system is single input, single output
4.4 control.iosys.InputOutputSystem
class control.iosys.InputOutputSystem(inputs=None, outputs=None, states=None,
params={}, dt=None, name=None)
A class for representing input/output systems.
The InputOutputSystem class allows (possibly nonlinear) input/output systems to be represented in Python. It
is intended as a parent class for a set of subclasses that are used to implement specific structures and operations
for different types of input/output dynamical systems.
Parameters
• inputs (int, list of str, or None) – Description of the system inputs. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form s[i] (where s is
one of u, y, or x). If this parameter is not given or given as None, the relevant quantity will
be determined when possible based on other information provided to functions using the
system.
• outputs (int, list of str, or None) – Description of the system outputs.
Same format as inputs.
• states (int, list of str, or None) – Description of the system states. Same
format as inputs.
• dt (None, True or float, optional) – System timebase. None (default) indi-
cates continuous time, True indicates discrete time with undefined sampling time, positive
number is discrete time with specified sampling time.
• params (dict, optional) – Parameter values for the systems. Passed to the evalua-
tion functions for the system as default values, overriding internal defaults.
• name (string, optional) – System name (used for specifying signals)
ninputs, noutputs, nstates
Number of input, output and state variables
Type int
input_index, output_index, state_index
Dictionary of signal names for the inputs, outputs and states and the index of the corresponding array
Type dict
dt
System timebase. None (default) indicates continuous time, True indicates discrete time with undefined
sampling time, positive number is discrete time with specified sampling time.
Type None, True or float
params
Parameter values for the systems. Passed to the evaluation functions for the system as default values,
overriding internal defaults.
Type dict, optional
name
System name (used for specifying signals)
Type string, optional
Notes
The InputOuputSystem class (and its subclasses) makes use of two special methods for implementing much of
the work of the class:
• _rhs(t, x, u): compute the right hand side of the differential or difference equation for the system. This
must be specified by the subclass for the system.
• _out(t, x, u): compute the output for the current state of the system. The default is to return the entire
system state.
__init__(inputs=None, outputs=None, states=None, params={}, dt=None, name=None)
Create an input/output system.
The InputOutputSystem contructor is used to create an input/output object with the core information re-
quired for all input/output systems. Instances of this class are normally created by one of the input/output
subclasses: LinearIOSystem, NonlinearIOSystem, InterconnectedSystem.
Parameters
• inputs (int, list of str, or None) – Description of the system inputs. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form s[i] (where s is
one of u, y, or x). If this parameter is not given or given as None, the relevant quantity will
be determined when possible based on other information provided to functions using the
system.
• outputs (int, list of str, or None) – Description of the system outputs.
Same format as inputs.
• states (int, list of str, or None) – Description of the system states. Same
format as inputs.
• dt (None, True or float, optional) – System timebase. None (default) indi-
cates continuous time, True indicates discrete time with undefined sampling time, positive
number is discrete time with specified sampling time.
• params (dict, optional) – Parameter values for the systems. Passed to the evalu-
ation functions for the system as default values, overriding internal defaults.
• name (string, optional) – System name (used for specifying signals)
Returns Input/output system object
Return type InputOutputSystem
Methods
4.4. control.iosys.InputOutputSystem 67
Python Control Library Documentation, Release dev
copy()
Make a copy of an input/output system.
feedback(other=1, sign=-1, params={})
Feedback interconnection between two input/output systems
Parameters
• sys1 (InputOutputSystem) – The primary process.
• sys2 (InputOutputSystem) – The feedback process (often a feedback controller).
• sign (scalar, optional) – The sign of feedback. sign = -1 indicates negative feed-
back, and sign = 1 indicates positive feedback. sign is an optional argument; it assumes a
value of -1 if not specified.
Returns out
Return type InputOutputSystem
Raises ValueError – if the inputs, outputs, or timebases of the systems are incompatible.
find_input(name)
Find the index for an input given its name (None if not found)
find_output(name)
Find the index for an output given its name (None if not found)
find_state(name)
Find the index for a state given its name (None if not found)
linearize(x0, u0, t=0, params={}, eps=1e-06)
Linearize an input/output system at a given state and input.
Return the linearization of an input/output system at a given state and input value as a StateSpace system.
See linearize() for complete documentation.
set_inputs(inputs, prefix=’u’)
Set the number/names of the system inputs.
Parameters
• inputs (int, list of str, or None) – Description of the system inputs. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If inputs is an integer, create the names of the states
using the given prefix (default = ‘u’). The names of the input will be of the form prefix[i].
set_outputs(outputs, prefix=’y’)
Set the number/names of the system outputs.
Parameters
• outputs (int, list of str, or None) – Description of the system outputs.
This can be given as an integer count or as a list of strings that name the individual signals.
If an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If outputs is an integer, create the names of the states
using the given prefix (default = ‘y’). The names of the input will be of the form prefix[i].
set_states(states, prefix=’x’)
Set the number/names of the system states.
Parameters
• states (int, list of str, or None) – Description of the system states. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If states is an integer, create the names of the states
using the given prefix (default = ‘x’). The names of the input will be of the form prefix[i].
Input/output systems are accessed primarily via a set of subclasses that allow for linear, nonlinear, and interconnected
elements:
4.5.1 control.iosys.LinearIOSystem
Methods
__init__(linsys[, inputs, outputs, states, name]) Create an I/O system from a state space linear sys-
tem.
append(other) Append a second model to the present model.
copy() Make a copy of an input/output system.
damp() Natural frequency, damping ratio of system poles
dcgain() Return the zero-frequency gain
evalfr(omega) Evaluate a SS system’s transfer function at a single
frequency.
feedback([other, sign, params]) Feedback interconnection between two input/output
systems
find_input(name) Find the index for an input given its name (None if
not found)
find_output(name) Find the index for an output given its name (None if
not found)
find_state(name) Find the index for a state given its name (None if not
found)
freqresp(omega) Evaluate the system’s transfer func.
horner(s) Evaluate the systems’s transfer function for a com-
plex variable
isctime([strict]) Check to see if a system is a continuous-time system
isdtime([strict]) Check to see if a system is a discrete-time system
issiso() Check to see if a system is single input, single output
lft(other[, nu, ny]) Return the Linear Fractional Transformation.
linearize(x0, u0[, t, params, eps]) Linearize an input/output system at a given state and
input.
Continued on next page
append(other)
Append a second model to the present model. The second model is converted to state-space if necessary,
inputs and outputs are appended and their order is preserved
copy()
Make a copy of an input/output system.
damp()
Natural frequency, damping ratio of system poles
Returns
• wn (array) – Natural frequencies for each system pole
• zeta (array) – Damping ratio for each system pole
• poles (array) – Array of system poles
dcgain()
Return the zero-frequency gain
The zero-frequency gain of a continuous-time state-space system is given by:
and of a discrete-time state-space system by:
Returns gain – An array of shape (outputs,inputs); the array will either be the zero-frequency
(or DC) gain, or, if the frequency response is singular, the array will be filled with np.nan.
Return type ndarray
evalfr(omega)
Evaluate a SS system’s transfer function at a single frequency.
self._evalfr(omega) returns the value of the transfer function matrix with input value s = i * omega.
feedback(other=1, sign=-1, params={})
Feedback interconnection between two input/output systems
Parameters
• sys1 (InputOutputSystem) – The primary process.
• sys2 (InputOutputSystem) – The feedback process (often a feedback controller).
• sign (scalar, optional) – The sign of feedback. sign = -1 indicates negative feed-
back, and sign = 1 indicates positive feedback. sign is an optional argument; it assumes a
value of -1 if not specified.
Returns out
Return type InputOutputSystem
Raises ValueError – if the inputs, outputs, or timebases of the systems are incompatible.
find_input(name)
Find the index for an input given its name (None if not found)
find_output(name)
Find the index for an output given its name (None if not found)
find_state(name)
Find the index for a state given its name (None if not found)
freqresp(omega)
Evaluate the system’s transfer func. at a list of freqs, omega.
mag, phase, omega = self.freqresp(omega)
Reports the frequency response of the system,
G(j*omega) = mag*exp(j*phase)
for continuous time. For discrete time systems, the response is evaluated around the unit circle such that
G(exp(j*omega*dt)) = mag*exp(j*phase).
Parameters omega (array) – A list of frequencies in radians/sec at which the system should
be evaluated. The list can be either a python list or a numpy array and will be sorted before
evaluation.
Returns
• mag (float) – The magnitude (absolute value, not dB or log10) of the system frequency
response.
• phase (float) – The wrapped phase in radians of the system frequency response.
• omega (array) – The list of sorted frequencies at which the response was evaluated.
horner(s)
Evaluate the systems’s transfer function for a complex variable
Returns a matrix of values evaluated at complex variable s.
isctime(strict=False)
Check to see if a system is a continuous-time system
Parameters
• sys (LTI system) – System to be checked
• strict (bool, optional) – If strict is True, make sure that timebase is not None.
Default is False.
isdtime(strict=False)
Check to see if a system is a discrete-time system
Parameters strict (bool, optional) – If strict is True, make sure that timebase is not
None. Default is False.
issiso()
Check to see if a system is single input, single output
lft(other, nu=-1, ny=-1)
Return the Linear Fractional Transformation.
A definition of the LFT operator can be found in Appendix A.7, page 512 in the 2nd Edition, Multivariable
Feedback Control by Sigurd Skogestad.
is a signal.scipy.lti object corresponding to the transfer function from the 6th input to the 4th output.
sample(Ts, method=’zoh’, alpha=None)
Convert a continuous time system to discrete time
Creates a discrete-time system from a continuous-time system by sampling. Multiple methods of conver-
sion are supported.
Parameters
• Ts (float) – Sampling period
• method ({"gbt", "bilinear", "euler", "backward_diff", "zoh"})
– Which method to use:
– gbt: generalized bilinear transformation
– bilinear: Tustin’s approximation (“gbt” with alpha=0.5)
– euler: Euler (or forward differencing) method (“gbt” with alpha=0)
– backward_diff: Backwards differencing (“gbt” with alpha=1.0)
– zoh: zero-order hold (default)
• alpha (float within [0, 1]) – The generalized bilinear transformation weight-
ing parameter, which should only be specified with method=”gbt”, and is ignored other-
wise
Returns sysd – Discrete time system, with sampling rate Ts
Return type StateSpace
Notes
Examples
set_inputs(inputs, prefix=’u’)
Set the number/names of the system inputs.
Parameters
• inputs (int, list of str, or None) – Description of the system inputs. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If inputs is an integer, create the names of the states
using the given prefix (default = ‘u’). The names of the input will be of the form prefix[i].
set_outputs(outputs, prefix=’y’)
Set the number/names of the system outputs.
Parameters
• outputs (int, list of str, or None) – Description of the system outputs.
This can be given as an integer count or as a list of strings that name the individual signals.
If an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If outputs is an integer, create the names of the states
using the given prefix (default = ‘y’). The names of the input will be of the form prefix[i].
set_states(states, prefix=’x’)
Set the number/names of the system states.
Parameters
• states (int, list of str, or None) – Description of the system states. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If states is an integer, create the names of the states
using the given prefix (default = ‘x’). The names of the input will be of the form prefix[i].
zero()
Compute the zeros of a state space system.
4.5.2 control.iosys.NonlinearIOSystem
Methods
__init__(updfcn[, outfcn, inputs, outputs, . . . ]) Create a nonlinear I/O system given update and out-
put functions.
copy() Make a copy of an input/output system.
Continued on next page
copy()
Make a copy of an input/output system.
feedback(other=1, sign=-1, params={})
Feedback interconnection between two input/output systems
Parameters
• sys1 (InputOutputSystem) – The primary process.
• sys2 (InputOutputSystem) – The feedback process (often a feedback controller).
• sign (scalar, optional) – The sign of feedback. sign = -1 indicates negative feed-
back, and sign = 1 indicates positive feedback. sign is an optional argument; it assumes a
value of -1 if not specified.
Returns out
Return type InputOutputSystem
Raises ValueError – if the inputs, outputs, or timebases of the systems are incompatible.
find_input(name)
Find the index for an input given its name (None if not found)
find_output(name)
Find the index for an output given its name (None if not found)
find_state(name)
Find the index for a state given its name (None if not found)
linearize(x0, u0, t=0, params={}, eps=1e-06)
Linearize an input/output system at a given state and input.
Return the linearization of an input/output system at a given state and input value as a StateSpace system.
See linearize() for complete documentation.
set_inputs(inputs, prefix=’u’)
Set the number/names of the system inputs.
Parameters
• inputs (int, list of str, or None) – Description of the system inputs. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If inputs is an integer, create the names of the states
using the given prefix (default = ‘u’). The names of the input will be of the form prefix[i].
set_outputs(outputs, prefix=’y’)
Set the number/names of the system outputs.
Parameters
• outputs (int, list of str, or None) – Description of the system outputs.
This can be given as an integer count or as a list of strings that name the individual signals.
If an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If outputs is an integer, create the names of the states
using the given prefix (default = ‘y’). The names of the input will be of the form prefix[i].
set_states(states, prefix=’x’)
Set the number/names of the system states.
Parameters
• states (int, list of str, or None) – Description of the system states. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If states is an integer, create the names of the states
using the given prefix (default = ‘x’). The names of the input will be of the form prefix[i].
4.5.3 control.iosys.InterconnectedSystem
The input-spec should be a tuple of the form (subsys_i, inp_j) where subsys_i is the index
into syslist and inp_j is the index into the input vector for the subsystem. If subsys_i has a
single input, then the subsystem index subsys_i can be listed as the input-spec. If systems
and signals are given names, then the form ‘sys.sig’ or (‘sys’, ‘sig’) are also recognized.
Each output-spec should be a tuple of the form (subsys_i, out_j, gain). The input will be
constructed by summing the listed outputs after multiplying by the gain term. If the gain
term is omitted, it is assumed to be 1. If the system has a single output, then the subsystem
index subsys_i can be listed as the input-spec. If systems and signals are given names, then
the form ‘sys.sig’, (‘sys’, ‘sig’) or (‘sys’, ‘sig’, gain) are also recognized, and the special
form ‘-sys.sig’ can be used to specify a signal with gain -1.
If omitted, the connection map (matrix) can be specified using the
set_connect_map() method.
• inplist (tuple of input specifications, optional) – List of specifi-
cations for how the inputs for the overall system are mapped to the subsystem inputs. The
input specification is the same as the form defined in the connection specification. Each
system input is added to the input for the listed subsystem.
If omitted, the input map can be specified using the set_input_map method.
• outlist (tuple of output specifications, optional) – List of specifi-
cations for how the outputs for the subsystems are mapped to overall system outputs. The
output specification is the same as the form defined in the connection specification (includ-
ing the optional gain term). Numbered outputs must be chosen from the list of subsystem
outputs, but named outputs can also be contained in the list of subsystem inputs.
If omitted, the output map can be specified using the set_output_map method.
• params (dict, optional) – Parameter values for the systems. Passed to the evalu-
ation functions for the system as default values, overriding internal defaults.
• dt (timebase, optional) – The timebase for the system, used to specify whether
the system is operating in continuous or discrete time. It can have the following values:
– dt = None No timebase specified
– dt = 0 Continuous time system
– dt > 0 Discrete time system with sampling time dt
– dt = True Discrete time with unspecified sampling time
• name (string, optional) – System name (used for specifying signals).
Methods
__init__(syslist[, connections, inplist, . . . ]) Create an I/O system from a list of systems + con-
nection info.
copy() Make a copy of an input/output system.
feedback([other, sign, params]) Feedback interconnection between two input/output
systems
find_input(name) Find the index for an input given its name (None if
not found)
find_output(name) Find the index for an output given its name (None if
not found)
Continued on next page
copy()
Make a copy of an input/output system.
feedback(other=1, sign=-1, params={})
Feedback interconnection between two input/output systems
Parameters
• sys1 (InputOutputSystem) – The primary process.
• sys2 (InputOutputSystem) – The feedback process (often a feedback controller).
• sign (scalar, optional) – The sign of feedback. sign = -1 indicates negative feed-
back, and sign = 1 indicates positive feedback. sign is an optional argument; it assumes a
value of -1 if not specified.
Returns out
Return type InputOutputSystem
Raises ValueError – if the inputs, outputs, or timebases of the systems are incompatible.
find_input(name)
Find the index for an input given its name (None if not found)
find_output(name)
Find the index for an output given its name (None if not found)
find_state(name)
Find the index for a state given its name (None if not found)
linearize(x0, u0, t=0, params={}, eps=1e-06)
Linearize an input/output system at a given state and input.
Return the linearization of an input/output system at a given state and input value as a StateSpace system.
See linearize() for complete documentation.
set_connect_map(connect_map)
Set the connection map for an interconnected I/O system.
Parameters connect_map (2D array) – Specify the matrix that will be used to multiply
the vector of subsystem outputs to obtain the vector of subsystem inputs.
set_input_map(input_map)
Set the input map for an interconnected I/O system.
Parameters input_map (2D array) – Specify the matrix that will be used to multiply the
vector of system inputs to obtain the vector of subsystem inputs. These values are added to
the inputs specified in the connection map.
set_inputs(inputs, prefix=’u’)
Set the number/names of the system inputs.
Parameters
• inputs (int, list of str, or None) – Description of the system inputs. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If inputs is an integer, create the names of the states
using the given prefix (default = ‘u’). The names of the input will be of the form prefix[i].
set_output_map(output_map)
Set the output map for an interconnected I/O system.
Parameters output_map (2D array) – Specify the matrix that will be used to multiply the
vector of subsystem outputs to obtain the vector of system outputs.
set_outputs(outputs, prefix=’y’)
Set the number/names of the system outputs.
Parameters
• outputs (int, list of str, or None) – Description of the system outputs.
This can be given as an integer count or as a list of strings that name the individual signals.
If an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If outputs is an integer, create the names of the states
using the given prefix (default = ‘y’). The names of the input will be of the form prefix[i].
set_states(states, prefix=’x’)
Set the number/names of the system states.
Parameters
• states (int, list of str, or None) – Description of the system states. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If states is an integer, create the names of the states
using the given prefix (default = ‘x’). The names of the input will be of the form prefix[i].
The control.matlab module contains a number of functions that emulate some of the functionality of MATLAB.
The intent of these functions is to provide a simple interface to the python control systems library (python-control) for
people who are familiar with the MATLAB Control Systems Toolbox (tm).
5.1.1 control.matlab.tf
control.matlab.tf(num, den[, dt ])
Create a transfer function system. Can create MIMO systems.
The function accepts either 1, 2, or 3 parameters:
tf(sys) Convert a linear system into transfer function form. Always creates a new system, even if sys is
already a TransferFunction object.
tf(num, den) Create a transfer function system from its numerator and denominator polynomial coeffi-
cients.
If num and den are 1D array_like objects, the function creates a SISO system.
To create a MIMO system, num and den need to be 2D nested lists of array_like objects. (A 3 dimensional
data structure in total.) (For details see note below.)
tf(num, den, dt) Create a discrete time transfer function system; dt can either be a positive number
indicating the sampling time or ‘True’ if no specific timebase is given.
81
Python Control Library Documentation, Release dev
tf('s') or tf('z') Create a transfer function representing the differential operator (‘s’) or delay operator
(‘z’).
Parameters
• sys (LTI (StateSpace or TransferFunction)) – A linear system
• num (array_like, or list of list of array_like) – Polynomial coeffi-
cients of the numerator
• den (array_like, or list of list of array_like) – Polynomial coeffi-
cients of the denominator
Returns out – The new linear system
Return type TransferFunction
Raises
• ValueError – if num and den have invalid or unequal dimensions
• TypeError – if num or den are of incorrect type
See also:
TransferFunction(), ss(), ss2tf(), tf2ss()
Notes
num[i][j] contains the polynomial coefficients of the numerator for the transfer function from the (j+1)st
input to the (i+1)st output. den[i][j] works the same way.
The list [2, 3, 4] denotes the polynomial 2𝑠2 + 3𝑠 + 4.
The special forms tf('s') and tf('z') can be used to create transfer functions for differentiation and unit
delays.
Examples
>>> # Create a variable 's' to allow algebra operations for SISO systems
>>> s = tf('s')
>>> G = (s + 1)/(s**2 + 2*s + 1)
5.1.2 control.matlab.ss
control.matlab.ss(A, B, C, D[, dt ])
Create a state space system.
The function accepts either 1, 4 or 5 parameters:
ss(sys) Convert a linear system into space system form. Always creates a new system, even if sys is already
a StateSpace object.
ss(A, B, C, D) Create a state space system from the matrices of its state and output equations:
𝑥˙ = 𝐴 · 𝑥 + 𝐵 · 𝑢
𝑦 =𝐶 ·𝑥+𝐷·𝑢
ss(A, B, C, D, dt) Create a discrete-time state space system from the matrices of its state and output
equations:
The matrices can be given as array like data types or strings. Everything that the constructor of numpy.
matrix accepts is permissible here too.
Parameters
• sys (StateSpace or TransferFunction) – A linear system
• A (array_like or string) – System matrix
• B (array_like or string) – Control matrix
• C (array_like or string) – Output matrix
• D (array_like or string) – Feed forward matrix
• dt (If present, specifies the sampling period and a discrete
time) – system is created
Returns out – The new linear system
Return type StateSpace
Raises ValueError – if matrix sizes are not self-consistent
See also:
StateSpace(), tf(), ss2tf(), tf2ss()
Examples
5.1.3 control.matlab.frd
control.matlab.frd(d, w)
Construct a frequency response data model
frd models store the (measured) frequency response of a system.
This function can be called in different ways:
frd(response, freqs) Create an frd model with the given response data, in the form of complex re-
sponse vector, at matching frequency freqs [in rad/s]
frd(sys, freqs) Convert an LTI system into an frd model with data at frequencies freqs.
Parameters
• response (array_like, or list) – complex vector with the system response
• freq (array_lik or lis) – vector with frequencies
• sys (LTI (StateSpace or TransferFunction)) – A linear system
Returns sys – New frequency response system
Return type FRD
See also:
FRD(), ss(), tf()
5.1.4 control.matlab.rss
Notes
If the number of states, inputs, or outputs is not specified, then the missing numbers are assumed to be 1. The
poles of the returned system will always have a negative real part.
5.1.5 control.matlab.drss
Notes
If the number of states, inputs, or outputs is not specified, then the missing numbers are assumed to be 1. The
poles of the returned system will always have a magnitude less than 1.
5.2.1 control.matlab.mag2db
control.matlab.mag2db(mag)
Convert a magnitude to decibels (dB)
If A is magnitude,
db = 20 * log10(A)
5.2.2 control.matlab.db2mag
control.matlab.db2mag(db)
Convert a gain in decibels (dB) to a magnitude
If A is magnitude,
db = 20 * log10(A)
5.2.3 control.matlab.c2d
5.2.4 control.matlab.ss2tf
control.matlab.ss2tf(sys)
Transform a state space system to a transfer function.
The function accepts either 1 or 4 parameters:
ss2tf(sys) Convert a linear system into space system form. Always creates a new system, even if sys is
already a StateSpace object.
ss2tf(A, B, C, D) Create a state space system from the matrices of its state and output equations.
For details see: ss()
Parameters
• sys (StateSpace) – A linear system
• A (array_like or string) – System matrix
• B (array_like or string) – Control matrix
• C (array_like or string) – Output matrix
• D (array_like or string) – Feedthrough matrix
Returns out – New linear system in transfer function form
Return type TransferFunction
Raises
• ValueError – if matrix sizes are not self-consistent, or if an invalid number of arguments
is passed in
• TypeError – if sys is not a StateSpace object
See also:
tf(), ss(), tf2ss()
Examples
5.2.5 control.matlab.tf2ss
control.matlab.tf2ss(sys)
Transform a transfer function to a state space system.
The function accepts either 1 or 2 parameters:
tf2ss(sys) Convert a linear system into transfer function form. Always creates a new system, even if sys is
already a TransferFunction object.
tf2ss(num, den) Create a transfer function system from its numerator and denominator polynomial coef-
ficients.
For details see: tf()
Parameters
• sys (LTI (StateSpace or TransferFunction)) – A linear system
• num (array_like, or list of list of array_like) – Polynomial coeffi-
cients of the numerator
• den (array_like, or list of list of array_like) – Polynomial coeffi-
cients of the denominator
Returns out – New linear system in state space form
Return type StateSpace
Raises
• ValueError – if num and den have invalid or unequal dimensions, or if an invalid number
of arguments is passed in
• TypeError – if num or den are of incorrect type, or if sys is not a TransferFunction object
See also:
ss(), tf(), ss2tf()
Examples
>>> num = [[[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]]]
>>> den = [[[9., 8., 7.], [6., 5., 4.]], [[3., 2., 1.], [-1., -2., -3.]]]
>>> sys1 = tf2ss(num, den)
5.2.6 control.matlab.tfdata
control.matlab.tfdata(sys)
Return transfer function data objects for a system
Parameters sys (LTI (StateSpace, or TransferFunction)) – LTI system whose
data will be returned
Returns (num, den) – Transfer function coefficients (SISO only)
Return type numerator and denominator arrays
5.3.1 control.matlab.series
control.matlab.series(sys1, *sysn)
Return the series connection (sysn * . . . *) sys2 * sys1
Parameters
• sys1 (scalar, StateSpace, TransferFunction, or FRD) –
• *sysn (other scalars, StateSpaces, TransferFunctions, or FRDs)
–
Returns out
Return type scalar, StateSpace, or TransferFunction
Raises ValueError – if sys2.inputs does not equal sys1.outputs if sys1.dt is not compatible with
sys2.dt
See also:
parallel(), feedback()
Notes
This function is a wrapper for the __mul__ function in the StateSpace and TransferFunction classes. The output
type is usually the type of sys2. If sys2 is a scalar, then the output type is the type of sys1.
If both systems have a defined timebase (dt = 0 for continuous time, dt > 0 for discrete time), then the timebase
for both systems must match. If only one of the system has a timebase, the return timebase will be set to match
it.
Examples
5.3.2 control.matlab.parallel
control.matlab.parallel(sys1, *sysn)
Return the parallel connection sys1 + sys2 (+ . . . + sysn)
Parameters
• sys1 (scalar, StateSpace, TransferFunction, or FRD) –
• *sysn (other scalars, StateSpaces, TransferFunctions, or FRDs)
–
Returns out
Return type scalar, StateSpace, or TransferFunction
Raises ValueError – if sys1 and sys2 do not have the same numbers of inputs and outputs
See also:
series(), feedback()
Notes
This function is a wrapper for the __add__ function in the StateSpace and TransferFunction classes. The output
type is usually the type of sys1. If sys1 is a scalar, then the output type is the type of sys2.
If both systems have a defined timebase (dt = 0 for continuous time, dt > 0 for discrete time), then the timebase
for both systems must match. If only one of the system has a timebase, the return timebase will be set to match
it.
Examples
5.3.3 control.matlab.feedback
Notes
This function is a wrapper for the feedback function in the StateSpace and TransferFunction classes. It calls
TransferFunction.feedback if sys1 is a TransferFunction object, and StateSpace.feedback if sys1 is a StateSpace
object. If sys1 is a scalar, then it is converted to sys2’s type, and the corresponding feedback function is used. If
sys1 and sys2 are both scalars, then TransferFunction.feedback is used.
5.3.4 control.matlab.negate
control.matlab.negate(sys)
Return the negative of a system.
Parameters sys (StateSpace, TransferFunction or FRD) –
Returns out
Return type StateSpace or TransferFunction
Notes
This function is a wrapper for the __neg__ function in the StateSpace and TransferFunction classes. The output
type is the same as the input type.
Examples
5.3.5 control.matlab.connect
Examples
>>> sys1 = ss([[1., -2], [3., -4]], [[5.], [7]], [[6, 8]], [[9.]])
>>> sys2 = ss([[-1.]], [[1.]], [[1.]], [[0.]])
>>> sys = append(sys1, sys2)
>>> Q = [[1, 2], [2, -1]] # negative feedback interconnection
>>> sysc = connect(sys, Q, [2], [1, 2])
5.3.6 control.matlab.append
Examples
>>> sys1 = ss([[1., -2], [3., -4]], [[5.], [7]]", [[6., 8]], [[9.]])
>>> sys2 = ss([[-1.]], [[1.]], [[1.]], [[0.]])
>>> sys = append(sys1, sys2)
5.4.1 control.matlab.dcgain
control.matlab.dcgain(*args)
Compute the gain of the system in steady state.
The function takes either 1, 2, 3, or 4 parameters:
Parameters
• B, C, D (A,) – A linear system in state space form.
• P, k (Z,) – A linear system in zero, pole, gain form.
• den (num,) – A linear system in transfer function form.
• sys (LTI (StateSpace or TransferFunction)) – A linear system object.
Returns gain – The gain of each output versus each input: 𝑦 = 𝑔𝑎𝑖𝑛 · 𝑢
Return type ndarray
Notes
This function is only useful for systems with invertible system matrix A.
All systems are first converted to state space form. The function then computes:
𝑔𝑎𝑖𝑛 = −𝐶 · 𝐴−1 · 𝐵 + 𝐷
5.4.2 control.matlab.pole
control.matlab.pole(sys)
Compute system poles.
Parameters sys (StateSpace or TransferFunction) – Linear system
Returns poles – Array that contains the system’s poles.
Return type ndarray
5.4.3 control.matlab.zero
control.matlab.zero(sys)
Compute system zeros.
Parameters sys (StateSpace or TransferFunction) – Linear system
Returns zeros – Array that contains the system’s zeros.
Return type ndarray
Raises NotImplementedError – when called on a MIMO system
See also:
pole(), StateSpace.zero(), TransferFunction.zero()
5.4.4 control.matlab.damp
control.matlab.damp(sys, doprint=True)
Compute natural frequency, damping ratio, and poles of a system
The function takes 1 or 2 parameters
Parameters
• sys (LTI (StateSpace or TransferFunction)) – A linear system object
• doprint – if true, print table with values
Returns
• wn (array) – Natural frequencies of the poles
• damping (array) – Damping values
• poles (array) – Pole locations
• Algorithm
• ———
• If the system is continuous, – wn = abs(poles) Z = -real(poles)/poles.
• If the system is discrete, the discrete poles are mapped to their
• equivalent location in the s-plane via – s = log10(poles)/dt
• and – wn = abs(s) Z = -real(s)/wn.
See also:
pole()
5.4.5 control.matlab.pzmap
5.5.1 control.matlab.step
See also:
lsim(), initial(), impulse()
Examples
5.5.2 control.matlab.impulse
Examples
5.5.3 control.matlab.initial
Examples
5.5.4 control.matlab.lsim
Examples
bode(syslist[, omega, dB, Hz, deg, . . . ]) Bode plot of the frequency response
nyquist(syslist[, omega, plot, label_freq, . . . ]) Nyquist plot for a system
nichols(sys_list[, omega, grid]) Nichols plot for a system
margin(sysdata) Calculate gain and phase margins and associated
crossover frequencies
freqresp(sys, omega) Frequency response of an LTI system at multiple angu-
lar frequencies.
evalfr(sys, x) Evaluate the transfer function of an LTI system for a
single complex number x.
5.6.1 control.matlab.bode
Examples
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> mag, phase, omega = bode(sys)
• >>> bode(sys, w)
5.6.2 control.matlab.nyquist
Examples
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> real, imag, freq = nyquist_plot(sys)
5.6.3 control.matlab.nichols
• sys_list (list of LTI, or LTI) – List of linear input/output systems (single sys-
tem is OK)
• omega (array_like) – Range of frequencies (list or bounds) in rad/sec
• grid (boolean, optional) – True if the plot should include a Nichols-chart grid.
Default is True.
Returns
Return type None
5.6.4 control.matlab.margin
control.matlab.margin(sysdata)
Calculate gain and phase margins and associated crossover frequencies
Parameters sysdata (LTI system or (mag, phase, omega) sequence) –
sys [StateSpace or TransferFunction] Linear SISO system
mag, phase, omega [sequence of array_like] Input magnitude, phase (in deg.), and frequencies
(rad/sec) from bode frequency response data
Returns
• gm (float) – Gain margin
• pm (float) – Phase margin (in degrees)
• wg (float) – Frequency for gain margin (at phase crossover, phase = -180 degrees)
• wp (float) – Frequency for phase margin (at gain crossover, gain = 1)
• Margins are calculated for a SISO open-loop system.
• If there is more than one gain crossover, the one at the smallest
• margin (deviation from gain = 1), in absolute sense, is
• returned. Likewise the smallest phase margin (in absolute sense)
• is returned.
Examples
5.6.5 control.matlab.freqresp
control.matlab.freqresp(sys, omega)
Frequency response of an LTI system at multiple angular frequencies.
Parameters
• sys (StateSpace or TransferFunction) – Linear system
• omega (array_like) – List of frequencies
Returns
• mag (ndarray)
• phase (ndarray)
• omega (list, tuple, or ndarray)
See also:
evalfr(), bode()
Notes
This function is a wrapper for StateSpace.freqresp and TransferFunction.freqresp. The output omega is a sorted
version of the input omega.
Examples
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> mag, phase, omega = freqresp(sys, [0.1, 1., 10.])
>>> mag
array([[[ 58.8576682 , 49.64876635, 13.40825927]]])
>>> phase
array([[[-0.05408304, -0.44563154, -0.66837155]]])
5.6.6 control.matlab.evalfr
control.matlab.evalfr(sys, x)
Evaluate the transfer function of an LTI system for a single complex number x.
To evaluate at a frequency, enter x = omega*j, where omega is the frequency in radians
Parameters
• sys (StateSpace or TransferFunction) – Linear system
• x (scalar) – Complex number
Returns fresp
Return type ndarray
See also:
freqresp(), bode()
Notes
Examples
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> evalfr(sys, 1j)
array([[ 44.8-21.4j]])
>>> # This is the transfer function matrix evaluated at s = i.
5.7.1 control.matlab.rlocus
5.7.2 control.matlab.sisotool
Examples
5.7.3 control.matlab.place
control.matlab.place(A, B, p)
Place closed loop eigenvalues K = place(A, B, p)
Parameters
• A (2-d array) – Dynamics matrix
• B (2-d array) – Input matrix
Examples
See also:
place_varga(), acker()
5.7.4 control.matlab.lqr
control.matlab.lqr(A, B, Q, R[, N ])
Linear quadratic regulator design
The lqr() function computes the optimal state feedback controller that minimizes the quadratic cost
∫︁ ∞
𝐽= (𝑥′ 𝑄𝑥 + 𝑢′ 𝑅𝑢 + 2𝑥′ 𝑁 𝑢)𝑑𝑡
0
Parameters
• B (A,) – Dynamics and input matrices
• sys (LTI (StateSpace or TransferFunction)) – Linear I/O system
• R (Q,) – State and input weight matrices
• N (2-d array, optional) – Cross weight matrix
Returns
• K (2D array) – State feedback gains
• S (2D array) – Solution to Riccati equation
• E (1D array) – Eigenvalues of the closed loop system
Examples
See also:
lqe()
rss([states, outputs, inputs]) Create a stable continuous random state space object.
drss([states, outputs, inputs]) Create a stable discrete random state space object.
ctrb(A, B) Controllabilty matrix
obsv(A, C) Observability matrix
gram(sys, type) Gramian (controllability or observability)
5.8.1 control.matlab.ctrb
control.matlab.ctrb(A, B)
Controllabilty matrix
Parameters B (A,) – Dynamics and input matrix of the system
Returns C – Controllability matrix
Return type matrix
Examples
>>> C = ctrb(A, B)
5.8.2 control.matlab.obsv
control.matlab.obsv(A, C)
Observability matrix
Examples
>>> O = obsv(A, C)
5.8.3 control.matlab.gram
control.matlab.gram(sys, type)
Gramian (controllability or observability)
Parameters
• sys (StateSpace) – State-space system to compute Gramian for
• type (String) – Type of desired computation. type is either ‘c’ (controllability) or ‘o’
(observability). To compute the Cholesky factors of gramians use ‘cf’ (controllability) or
‘of’ (observability)
Returns gram – Gramian of system
Return type array
Raises
• ValueError – * if system is not instance of StateSpace class * if type is not ‘c’, ‘o’, ‘cf’
or ‘of’ * if system is unstable (sys.A has eigenvalues not in left half plane)
• ImportError – if slycot routine sb03md cannot be found if slycot routine sb03od cannot
be found
Examples
>>> Wc = gram(sys,'c')
>>> Wo = gram(sys,'o')
>>> Rc = gram(sys,'cf'), where Wc=Rc'*Rc
>>> Ro = gram(sys,'of'), where Wo=Ro'*Ro
5.9.1 control.matlab.minreal
5.9.2 control.matlab.hsvd
control.matlab.hsvd(sys)
Calculate the Hankel singular values.
Parameters sys (StateSpace) – A state space system
Returns H – A list of Hankel singular values
Return type array
See also:
gram()
Notes
The Hankel singular values are the singular values of the Hankel operator. In practice, we compute the square
root of the eigenvalues of the matrix formed by taking the product of the observability and controllability grami-
ans. There are other (more efficient) methods based on solving the Lyapunov equation in a particular way (more
details soon).
Examples
>>> H = hsvd(sys)
5.9.3 control.matlab.balred
sys has unstable modes, they are removed, the balanced realization is done on the stable part, then reinserted in
accordance with the reference below.
Reference: Hsu,C.S., and Hou,D., 1991, Reducing unstable linear control systems via real Schur transformation.
Electronics Letters, 27, 984-986.
Parameters
• sys (StateSpace) – Original system to reduce
• orders (integer or array of integer) – Desired order of reduced order model
(if a vector, returns a vector of systems)
• method (string) – Method of removing states, either 'truncate' or 'matchdc'.
• alpha (float) – Redefines the stability boundary for eigenvalues of the system matrix
A. By default for continuous-time systems, alpha <= 0 defines the stability boundary for
the real part of A’s eigenvalues and for discrete-time systems, 0 <= alpha <= 1 defines the
stability boundary for the modulus of A’s eigenvalues. See SLICOT routines AB09MD and
AB09ND for more information.
Returns rsys – A reduced order model or a list of reduced order models if orders is a list
Return type StateSpace
Raises
• ValueError – * if method is not 'truncate' or 'matchdc'
• ImportError – if slycot routine ab09ad, ab09md, or ab09nd is not found
• ValueError – if there are more unstable modes than any value in orders
Examples
5.9.4 control.matlab.modred
Examples
5.9.5 control.matlab.era
Parameters
• YY (array) – nout x nin dimensional impulse-response data
• m (integer) – Number of rows in Hankel matrix
• n (integer) – Number of columns in Hankel matrix
• nin (integer) – Number of input variables
• nout (integer) – Number of output variables
• r (integer) – Order of model
Returns sys – A reduced order model sys=ss(Ar,Br,Cr,Dr)
Return type StateSpace
Examples
5.9.6 control.matlab.markov
control.matlab.markov(Y, U, m)
Calculate the first M Markov parameters [D CB CAB . . . ] from input U, output Y.
Parameters
• Y (array_like) – Output data
• U (array_like) – Input data
• m (int) – Number of Markov parameters to output
Returns H – First m Markov parameters
Return type ndarray
Notes
Examples
>>> H = markov(Y, U, m)
5.10.1 control.matlab.pade
Notes
Based on:
1. Algorithm 11.3.1 in Golub and van Loan, “Matrix Computation” 3rd. Ed. pp. 572-574
2. M. Vajta, “Some remarks on Padé-approximations”, 3rd TEMPUS-INTCOM Symposium
5.11.1 control.matlab.lyap
𝐴𝑋 + 𝑋𝐴𝑇 + 𝑄 = 0
where A and Q are square matrices of the same dimension. Further, Q must be symmetric.
X = lyap(A,Q,C) solves the Sylvester equation
𝐴𝑋 + 𝑋𝑄 + 𝐶 = 0
where A and Q are square matrices.
X = lyap(A,Q,None,E) solves the generalized continuous-time Lyapunov equation
𝐴𝑋𝐸 𝑇 + 𝐸𝑋𝐴𝑇 + 𝑄 = 0
where Q is a symmetric matrix and A, Q and E are square matrices of the same dimension.
5.11.2 control.matlab.dlyap
5.11.3 control.matlab.care
5.11.4 control.matlab.dare
where A and Q are square matrices of the same dimension. Further, Q is a symmetric matrix. The function
returns the solution X, the gain matrix G = (B^T X B + R)^-1 B^T X A and the closed loop eigenvalues L, i.e.,
the eigenvalues of A - B G.
(X,L,G) = dare(A,B,Q,R,S,E) solves the generalized discrete-time algebraic Riccati equation
𝐴𝑇 𝑋𝐴 − 𝐸 𝑇 𝑋𝐸 − (𝐴𝑇 𝑋𝐵 + 𝑆)(𝐵 𝑇 𝑋𝐵 + 𝑅)−1 (𝐵 𝑇 𝑋𝐴 + 𝑆 𝑇 ) + 𝑄 = 0
where A, Q and E are square matrices of the same dimension. Further, Q and R are symmetric matrices. The
function returns the solution X, the gain matrix 𝐺 = (𝐵 𝑇 𝑋𝐵 + 𝑅)−1 (𝐵 𝑇 𝑋𝐴 + 𝑆 𝑇 ) and the closed loop
eigenvalues L, i.e., the eigenvalues of A - B G , E.
gangof4(P, C[, omega]) Plot the “Gang of 4” transfer functions for a system
unwrap(angle[, period]) Unwrap a phase angle to give a continuous curve
5.12.1 control.matlab.gangof4
5.12.2 control.matlab.unwrap
control.matlab.unwrap(angle, period=6.283185307179586)
Unwrap a phase angle to give a continuous curve
Parameters
• angle (array_like) – Array of angles to be unwrapped
• period (float, optional) – Period (defaults to 2*pi)
Returns angle_out – Output array, with jumps of period/2 eliminated
Return type array_like
Examples
linspace(start, stop[, num, endpoint, . . . ]) Return evenly spaced numbers over a specified interval.
logspace(start, stop[, num, endpoint, base, . . . ]) Return numbers spaced evenly on a log scale.
ss2zpk(A, B, C, D[, input]) State-space representation to zero-pole-gain representa-
tion.
tf2zpk(b, a) Return zero, pole, gain (z, p, k) representation from a
numerator, denominator representation of a linear filter.
zpk2ss(z, p, k) Zero-pole-gain representation to state-space representa-
tion
zpk2tf(z, p, k) Return polynomial transfer function representation from
zeros and poles
The control.flatsys package contains a set of classes and functions that can be used to compute trajectories for
differentially flat systems.
A differentially flat system is defined by creating an object using the FlatSystem class, which has member functions
for mapping the system state and input into and out of flat coordinates. The point_to_point() function can be
used to create a trajectory between two endpoints, written in terms of a set of basis functions defined using the
BasisFamily class. The resulting trajectory is return as a SystemTrajectory object and can be evaluated
using the eval() member function.
𝑥˙ = 𝑓 (𝑥, 𝑢), 𝑥 ∈ 𝑅𝑛 , 𝑢 ∈ 𝑅𝑚
𝑧 = 𝛼(𝑥, 𝑢, 𝑢˙ . . . , 𝑢(𝑝) )
and we can write the solutions of the nonlinear system as functions of 𝑧 and a finite number of derivatives
˙ . . . , 𝑧 (𝑞) )
𝑥 = 𝛽(𝑧, 𝑧,
˙ . . . , 𝑧 (𝑞) ).
𝑢 = 𝛾(𝑧, 𝑧,
For a differentially flat system, all of the feasible trajectories for the system can be written as functions of a flat output
𝑧(·) and its derivatives. The number of flat outputs is always equal to the number of system inputs.
Differentially flat systems are useful in situations where explicit trajectory generation is required. Since the behavior
of a flat system is determined by the flat outputs, we can plan trajectories in output space, and then map these to
appropriate inputs. Suppose we wish to generate a feasible trajectory for the the nonlinear system
113
Python Control Library Documentation, Release dev
. . . , 𝑧 (𝑞) (0) = 𝑥0 ,
(︀ )︀
𝑥(0) = 𝛽 𝑧(0), 𝑧(0),
˙
˙ ), . . . , 𝑧 (𝑞) (𝑇 ) = 𝑥𝑓 ,
(︀ )︀
𝑥(𝑇 ) = 𝛾 𝑧(𝑇 ), 𝑧(𝑇
and we see that the initial and final condition in the full state space depends on just the output 𝑧 and its derivatives at
the initial and final times. Thus any trajectory for 𝑧 that satisfies these boundary conditions will be a feasible trajectory
for the system, using equation~eqref{eq:trajgen:flat2state} to determine the full state space and input trajectories.
In particular, given initial and final conditions on 𝑧 and its derivatives that satisfy the initial and final conditions any
curve 𝑧(·) satisfying those conditions will correspond to a feasible trajectory of the system. We can parameterize the
flat output trajectory using a set of smooth basis functions 𝜓𝑖 (𝑡):
𝑁
∑︁
𝑧(𝑡) = 𝛼𝑖 𝜓𝑖 (𝑡), 𝛼𝑖 ∈ 𝑅
𝑖=1
We seek a set of coefficients 𝛼𝑖 , 𝑖 = 1, . . . , 𝑁 such that 𝑧(𝑡) satisfies the boundary conditions for 𝑥(0) and 𝑥(𝑇 ). The
derivatives of the flat output can be computed in terms of the derivatives of the basis functions:
𝑁
∑︁
𝑧(𝑡)
˙ = 𝛼𝑖 𝜓˙ 𝑖 (𝑡)
𝑖=1
..
.
𝑁
(𝑞)
∑︁
𝑧˙ (𝑞) (𝑡) = 𝛼𝑖 𝜓𝑖 (𝑡).
𝑖=1
We can thus write the conditions on the flat outputs and their derivatives as
⎡ ⎤
𝜓1 (0) 𝜓2 (0) . . . 𝜓𝑁 (0)
⎡ ⎤
𝑧(0)
⎢ 𝜓˙ 1 (0) ˙ ˙
𝜓2 (0) . . . 𝜓𝑁 (0) ⎥ ⎢ 𝑧(0)
⎢ ˙
⎥ ⎥
⎢
. . .
⎥
⎢
.. .. ..
⎥
⎥⎡ ⎤ ⎢ . ⎥
⎢ .
.
⎢ ⎥
⎥ 𝛼1
⎢ ⎥
⎢ (𝑞) (𝑞) (𝑞)
⎢
(𝑞)
⎥
⎢ 𝜓1 (0) 𝜓2 (0) . . . 𝜓𝑁 (0) ⎥ ⎢ . ⎥ ⎢ 𝑧 (0) ⎥
⎥⎣ . ⎦ = ⎢
⎢ ⎥
⎥ .
⎢ ⎥
⎢ 𝜓 (𝑇 ) 𝜓 (𝑇 ) . . . 𝜓 (𝑇 ) 𝑧(𝑇 )
⎢ 1 2 𝑁 ⎢ ⎥
⎥ 𝛼𝑁
⎥
⎢ ˙ ˙ ˙
⎢
𝑧(𝑇
˙ )
⎥
⎢ 𝜓1 (𝑇 ) 𝜓2 (𝑇 ) . . . 𝜓𝑁 (𝑇 ) ⎥ ⎢ ⎥
.
⎢ ⎥
⎢ .
. .
. .
.
⎥ ⎢ . ⎥
⎢
⎣ . . .
⎥
⎦ ⎣ . ⎦
(𝑞) (𝑞)
𝜓 (𝑇 ) 𝜓 (𝑇 ) . . . 𝜓 (𝑇 )
(𝑞) 𝑧 (𝑞) (𝑇 )
1 2 𝑁
where 𝑧¯ is called the flat flag for the system. Assuming that 𝑀 has a sufficient number of columns and that it is full
column rank, we can solve for a (possibly non-unique) 𝛼 that solves the trajectory generation problem.
To create a trajectory for a differentially flat system, a FlatSystem object must be created. This is done by spec-
ifying the forward and reverse mappings between the system state/input and the differentially flat outputs and their
derivatives (“flat flag”).
The forward() method computes the flat flag given a state and input:
zflag = sys.forward(x, u)
The reverse() method computes the state and input given the flat flag:
x, u = sys.reverse(zflag)
The flag 𝑧¯ is implemented as a list of flat outputs 𝑧𝑖 and their derivatives up to order 𝑞𝑖 :
(𝑗)
zflag[i][j] = 𝑧𝑖
The number of flat outputs must match the number of system inputs.
For a linear system, a flat system representation can be generated using the LinearFlatSystem class:
flatsys = control.flatsys.LinearFlatSystem(linsys)
For more general systems, the FlatSystem object must be created manually
flatsys = control.flatsys.FlatSystem(nstate, ninputs, forward, reverse)
In addition to the flat system descriptionn, a set of basis functions 𝜑𝑖 (𝑡) must be chosen. The FlatBasis class is used
to represent the basis functions. A polynomial basis function of the form 1, 𝑡, 𝑡2 :, ...𝑐𝑎𝑛𝑏𝑒𝑐𝑜𝑚𝑝𝑢𝑡𝑒𝑑𝑢𝑠𝑖𝑛𝑔𝑡ℎ𝑒 class,
which is initialized by passing the desired order of the polynomial basis set:
polybasis = control.flatsys.PolyBasis(N)
Once the system and basis function have been defined, the point_to_point() function can be used to compute a
trajectory between initial and final states and inputs:
traj = control.flatsys.point_to_point(x0, u0, xf, uf, Tf, basis=polybasis)
The returned object has class SystemTrajectory and can be used to compute the state and input trajectory be-
tween the initial and final condition:
xd, ud = traj.eval(T)
where T is a list of times on which the trajectory should be evaluated (e.g., T = numpy.linspace(0, Tf, M).
6.3 Example
To illustrate how we can use a two degree-of-freedom design to improve the performance of the system, consider the
problem of steering a car to change lanes on a road. We use the non-normalized form of the dynamics, which are
derived Feedback Systems by Astrom and Murray, Example 3.11.
import control.flatsys as fs
# Create a list of arrays to store the flat output and its derivatives
zflag = [np.zeros(3), np.zeros(3)]
return zflag
return x, u
vehicle_flat = fs.FlatSystem(
3, 2, forward=vehicle_flat_forward, reverse=vehicle_flat_reverse)
To find a trajectory from an initial state 𝑥0 to a final state 𝑥f in time 𝑇f we solve a point-to-point trajectory generation
problem. We also set the initial and final inputs, whi ch sets the vehicle velocity 𝑣 and steering wheel angle 𝛿 at the
endpoints.
# Find a trajectory between the initial condition and the final condition
traj = fs.point_to_point(vehicle_flat, x0, u0, xf, uf, Tf, basis=poly)
BasisFamily(N) Base class for implementing basis functions for flat sys-
tems.
FlatSystem(forward, reverse[, updfcn, . . . ]) Base class for representing a differentially flat system.
LinearFlatSystem(linsys[, inputs, outputs, . . . ])
PolyFamily(N) Polynomial basis functions.
SystemTrajectory(sys, basis[, coeffs, flaglen]) Class representing a system trajectory.
control.flatsys.BasisFamily
class control.flatsys.BasisFamily(N)
Base class for implementing basis functions for flat systems.
A BasisFamily object is used to construct trajectories for a flat system. The class must implement a single
function that computes the jth derivative of the ith basis function at a time t:
(𝑞)
𝑧𝑖 (𝑡) = basis.eval_deriv(self, i, j, t)
__init__(N)
Create a basis family of order N.
Methods
control.flatsys.FlatSystem
The FlatIOSystem constructor is used to create an input/output system object that also represents a differ-
entially flat system. The output of the system does not need to be the differentially flat output.
Parameters
• forward (callable) – A function to compute the flat flag given the states and input.
• reverse (callable) – A function to compute the states and input given the flat flag.
• updfcn (callable, optional) – Function returning the state update function
updfcn(t, x, u[, param]) -> array
where x is a 1-D array with shape (nstates,), u is a 1-D array with shape (ninputs,), t is a
float representing the currrent time, and param is an optional dict containing the values of
parameters used by the function. If not specified, the state space update will be computed
using the flat system coordinates.
• outfcn (callable) – Function returning the output at the given state
outfcn(t, x, u[, param]) -> array
where the arguments are the same as for upfcn. If not specified, the output will be the flat
outputs.
• inputs (int, list of str, or None) – Description of the system inputs. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form s[i] (where s is
one of u, y, or x). If this parameter is not given or given as None, the relevant quantity will
be determined when possible based on other information provided to functions using the
system.
• outputs (int, list of str, or None) – Description of the system outputs.
Same format as inputs.
• states (int, list of str, or None) – Description of the system states. Same
format as inputs.
• dt (None, True or float, optional) – System timebase. None (default) indi-
cates continuous time, True indicates discrete time with undefined sampling time, positive
number is discrete time with specified sampling time.
• params (dict, optional) – Parameter values for the systems. Passed to the evalu-
ation functions for the system as default values, overriding internal defaults.
• name (string, optional) – System name (used for specifying signals)
Returns Input/output system object
Return type InputOutputSystem
Methods
copy()
Make a copy of an input/output system.
feedback(other=1, sign=-1, params={})
Feedback interconnection between two input/output systems
Parameters
• sys1 (InputOutputSystem) – The primary process.
• sys2 (InputOutputSystem) – The feedback process (often a feedback controller).
• sign (scalar, optional) – The sign of feedback. sign = -1 indicates negative feed-
back, and sign = 1 indicates positive feedback. sign is an optional argument; it assumes a
value of -1 if not specified.
Returns out
Return type InputOutputSystem
Raises ValueError – if the inputs, outputs, or timebases of the systems are incompatible.
find_input(name)
Find the index for an input given its name (None if not found)
find_output(name)
Find the index for an output given its name (None if not found)
find_state(name)
Find the index for a state given its name (None if not found)
forward(x, u, params={})
Compute the flat flag given the states and input.
Given the states and inputs for a system, compute the flat outputs and their derivatives (the flat “flag”) for
the system.
Parameters
• x (list or array) – The state of the system.
• u (list or array) – The input to the system.
• params (dict, optional) – Parameter values for the system. Passed to the evalua-
tion functions for the system as default values, overriding internal defaults.
Returns zflag – For each flat output 𝑧𝑖 , zflag[i] should be an ndarray of length 𝑞𝑖 that contains
the flat output and its first 𝑞𝑖 derivatives.
Return type list of 1D arrays
control.flatsys.LinearFlatSystem
Methods
__init__(linsys[, inputs, outputs, states, name]) Define a flat system from a SISO LTI system.
append(other) Append a second model to the present model.
copy() Make a copy of an input/output system.
damp() Natural frequency, damping ratio of system poles
dcgain() Return the zero-frequency gain
evalfr(omega) Evaluate a SS system’s transfer function at a single
frequency.
feedback([other, sign, params]) Feedback interconnection between two input/output
systems
find_input(name) Find the index for an input given its name (None if
not found)
find_output(name) Find the index for an output given its name (None if
not found)
Continued on next page
append(other)
Append a second model to the present model. The second model is converted to state-space if necessary,
inputs and outputs are appended and their order is preserved
copy()
Make a copy of an input/output system.
damp()
Natural frequency, damping ratio of system poles
Returns
• wn (array) – Natural frequencies for each system pole
• zeta (array) – Damping ratio for each system pole
• poles (array) – Array of system poles
dcgain()
Return the zero-frequency gain
The zero-frequency gain of a continuous-time state-space system is given by:
and of a discrete-time state-space system by:
Returns gain – An array of shape (outputs,inputs); the array will either be the zero-frequency
(or DC) gain, or, if the frequency response is singular, the array will be filled with np.nan.
Return type ndarray
evalfr(omega)
Evaluate a SS system’s transfer function at a single frequency.
self._evalfr(omega) returns the value of the transfer function matrix with input value s = i * omega.
Parameters omega (array) – A list of frequencies in radians/sec at which the system should
be evaluated. The list can be either a python list or a numpy array and will be sorted before
evaluation.
Returns
• mag (float) – The magnitude (absolute value, not dB or log10) of the system frequency
response.
• phase (float) – The wrapped phase in radians of the system frequency response.
• omega (array) – The list of sorted frequencies at which the response was evaluated.
horner(s)
Evaluate the systems’s transfer function for a complex variable
Returns a matrix of values evaluated at complex variable s.
isctime(strict=False)
Check to see if a system is a continuous-time system
Parameters
• sys (LTI system) – System to be checked
• strict (bool, optional) – If strict is True, make sure that timebase is not None.
Default is False.
isdtime(strict=False)
Check to see if a system is a discrete-time system
Parameters strict (bool, optional) – If strict is True, make sure that timebase is not
None. Default is False.
issiso()
Check to see if a system is single input, single output
lft(other, nu=-1, ny=-1)
Return the Linear Fractional Transformation.
A definition of the LFT operator can be found in Appendix A.7, page 512 in the 2nd Edition, Multivariable
Feedback Control by Sigurd Skogestad.
An alternative definition can be found here: https://www.mathworks.com/help/control/ref/lft.html
Parameters
• other (LTI) – The lower LTI system
• ny (int, optional) – Dimension of (plant) measurement output.
• nu (int, optional) – Dimension of (plant) control input.
linearize(x0, u0, t=0, params={}, eps=1e-06)
Linearize an input/output system at a given state and input.
Return the linearization of an input/output system at a given state and input value as a StateSpace system.
See linearize() for complete documentation.
minreal(tol=0.0)
Calculate a minimal realization, removes unobservable and uncontrollable states
pole()
Compute the poles of a state space system.
returnScipySignalLTI()
Return a list of a list of scipy.signal.lti objects.
For instance,
is a signal.scipy.lti object corresponding to the transfer function from the 6th input to the 4th output.
reverse(zflag)
Compute the states and input given the flat flag.
See control.flatsys.FlatSystem.reverse() for more info.
sample(Ts, method=’zoh’, alpha=None)
Convert a continuous time system to discrete time
Creates a discrete-time system from a continuous-time system by sampling. Multiple methods of conver-
sion are supported.
Parameters
Notes
Examples
set_inputs(inputs, prefix=’u’)
Set the number/names of the system inputs.
Parameters
• inputs (int, list of str, or None) – Description of the system inputs. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If inputs is an integer, create the names of the states
using the given prefix (default = ‘u’). The names of the input will be of the form prefix[i].
set_outputs(outputs, prefix=’y’)
Set the number/names of the system outputs.
Parameters
• outputs (int, list of str, or None) – Description of the system outputs.
This can be given as an integer count or as a list of strings that name the individual signals.
If an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If outputs is an integer, create the names of the states
using the given prefix (default = ‘y’). The names of the input will be of the form prefix[i].
set_states(states, prefix=’x’)
Set the number/names of the system states.
Parameters
• states (int, list of str, or None) – Description of the system states. This
can be given as an integer count or as a list of strings that name the individual signals. If
an integer count is specified, the names of the signal will be of the form u[i] (where the
prefix u can be changed using the optional prefix parameter).
• prefix (string, optional) – If states is an integer, create the names of the states
using the given prefix (default = ‘x’). The names of the input will be of the form prefix[i].
zero()
Compute the zeros of a state space system.
control.flatsys.PolyFamily
class control.flatsys.PolyFamily(N)
Polynomial basis functions.
This class represents the family of polynomials of the form
𝜑𝑖 (𝑡) = 𝑡𝑖
__init__(N)
Create a polynomial basis of order N.
Methods
eval_deriv(i, k, t)
Evaluate the kth derivative of the ith basis function at time t.
control.flatsys.SystemTrajectory
• flaglen (list of ints, optional) – For each flat output, the number of deriva-
tives of the flat output used to define the trajectory. Defaults to an empty list.
Methods
eval(tlist)
Return the state and input for a trajectory at a list of times.
Evaluate the trajectory at a list of time points, returning the state and input vectors for the trajectory:
x, u = traj.eval(tlist)
point_to_point(sys, x0, u0, xf, uf, Tf[, . . . ]) Compute trajectory between an initial and final condi-
tions.
Input/output systems
The iosys module contains the InputOutputSystem class that represents (possibly nonlinear) input/output sys-
tems. The InputOutputSystem class is a general class that defines any continuous or discrete time dynamical
system. Input/output systems can be simulated and also used to compute equilibrium points and linearizations.
An input/output system is defined as a dynamical system that has a system state as well as inputs and outputs (either
inputs or states can be empty). The dynamics of the system can be in continuous or discrete time. To simulate an
input/output system, use the input_output_response() function:
An input/output system can be linearized around an equilibrium point to obtain a StateSpace linear system. Use
the find_eqpt() function to obtain an equilibrium point and the linearize() function to linearize about that
equilibrium point:
Input/output systems can be created from state space LTI systems by using the LinearIOSystem class‘:
io_sys = LinearIOSystem(ss_sys)
Nonlinear input/output systems can be created using the NonlinearIOSystem class, which requires the defini-
tion of an update function (for the right hand side of the differential or different equation) and and output function
(computes the outputs from the state):
More complex input/output systems can be constructed by using the InterconnectedSystem class, which allows
a collection of input/output subsystems to be combined with internal connections between the subsystems and a set of
overall system inputs and outputs that link to the subsystems:
129
Python Control Library Documentation, Release dev
steering = ct.InterconnectedSystem(
(plant, controller), name='system',
connections=(('controller.e', '-plant.y')),
inplist=('controller.e'), inputs='r',
outlist=('plant.y'), outputs='y')
Interconnected systems can also be created using block diagram manipulations such as the series(),
parallel(), and feedback() functions. The InputOutputSystem class also supports various algebraic
operations such as * (series interconnection) and + (parallel interconnection).
7.2 Example
To illustrate the use of the input/output systems module, we create a model for a predator/prey system, following the
notation and parameter values in FBS2e.
We begin by defining the dynamics of the system
import control
import numpy as np
import matplotlib.pyplot as plt
io_predprey = control.NonlinearIOSystem(
predprey_rhs, None, inputs=('u'), outputs=('H', 'L'),
states=('H', 'L'), name='predprey')
Note that since we have not specified an output function, the entire state will be used as the output of the system.
The io_predprey system can now be simulated to obtain the open loop dynamics of the system:
We can also create a feedback controller to stabilize a desired population of the system. We begin by finding the
(unstable) equilibrium point for the system and computing the linearization about that point.
We next compute a controller that stabilizes the equilibrium point using eigenvalue placement and computing the
feedforward gain using the number of lynxes as the desired output (following FBS2e, Example 7.5):
To construct the control law, we build a simple input/output system that applies a corrective input based on deviations
from the equilibrium point. This system has no dynamics, since it is a static (affine) map, and can constructed using
the ~control.ios.NonlinearIOSystem class:
io_controller = control.NonlinearIOSystem(
None,
lambda t, x, u, params: -K @ (u[1:] - xeq) + kf * (u[0] - xeq[1]),
inputs=('Ld', 'u1', 'u2'), outputs=1, name='control')
The input to the controller is u, consisting of the vector of hare and lynx populations followed by the desired lynx
population.
To connect the controller to the predatory-prey model, we create an InterconnectedSystem:
io_closed = control.InterconnectedSystem(
(io_predprey, io_controller), # systems
connections=(
('predprey.u', 'control.y[0]'),
('control.u1', 'predprey.H'),
('control.u2', 'predprey.L')
),
inplist=('control.Ld'),
outlist=('predprey.H', 'predprey.L', 'control.y[0]')
)
find_eqpt(sys, x0[, u0, y0, t, params, iu, . . . ]) Find the equilibrium point for an input/output system.
linearize(sys, xeq[, ueq, t, params]) Linearize an input/output system at a given state and in-
put.
input_output_response(sys, T[, U, X0, . . . ]) Compute the output response of a system to a given in-
put.
ss2io(*args, **kw) Create an I/O system from a state space linear system.
tf2io(*args, **kw) Convert a transfer function into an I/O system
Examples
The source code for the examples below are available in the examples/ subdirecory of the source code distribu-
tion. The can also be accessed online via the [python-control GitHub repository](https://github.com/python-control/
python-control/tree/master/examples).
The following Python scripts document the use of a variety of methods in the Python Control Toolbox on examples
drawn from standard control textbooks and other sources.
This example computes time and frequency responses for a second-order system using the MATLAB compatibility
module.
Code
4 import os
5 import matplotlib.pyplot as plt # MATLAB plotting functions
6 from control.matlab import * # MATLAB-like functions
7
13 # System matrices
(continues on next page)
133
Python Control Library Documentation, Release dev
Notes
1. The environment variable PYCONTROL_TEST_EXAMPLES is used for testing to turn off plotting of the outputs.
8.1.2 Inner/outer control design for vertical takeoff and landing aircraft
This script demonstrates the use of the python-control package for analysis and design of a controller for a vectored
thrust aircraft model that is used as a running example through the text Feedback Systems by Astrom and Murray.
This example makes use of MATLAB compatible commands.
Code
13 import os
(continues on next page)
18 # System parameters
19 m = 4 # mass of aircraft
20 J = 0.0475 # inertia around pitch axis
21 r = 0.25 # distance to center of force
22 g = 9.8 # gravitational constant
23 c = 0.05 # damping factor (estimated)
24
29 #
30 # Inner loop control design
31 #
32 # This is the controller for the pitch dynamics. Goal is to have
33 # fast response for the pitch dynamics so that we can use this as a
34 # control for the lateral dynamics
35 #
36
62 # Compute out the actual transfer function from u1 to v1 (see L8.2 notes)
63 # Hi = Ci*(1-m*g*Pi)/(1+Ci*Pi)
64 Hi = parallel(feedback(Ci, Pi), -m*g*feedback(Ci*Pi, 1))
65
66 plt.figure(4)
67 plt.clf()
68 plt.subplot(221)
69 bode(Hi)
70
(continues on next page)
76 plt.figure(5)
77 bode(Lo) # margin(Lo)
78
89 plt.figure(6)
90 plt.clf()
91 bode(L, np.logspace(-4, 3))
92
109 #
110 # Replot phase starting at -90 degrees
111 #
112 # Get the phase plot axes
113 for ax in plt.gcf().axes:
114 if ax.get_label() == 'control-bode-phase':
115 break
116
130 #
131 # Nyquist plot for complete design
132 #
133 plt.figure(7)
134 plt.clf()
135 nyquist(L, (0.0001, 1000))
136 plt.axis([-700, 5300, -3000, 3000])
137
160 plt.figure(9)
161 Yvec, Tvec = step(T, np.linspace(0, 20))
162 plt.plot(Tvec.T, Yvec.T)
163
167 plt.figure(10)
168 plt.clf()
169 P, Z = pzmap(T, plot=True, grid=True)
170 print("Closed loop poles and zeros: ", P, Z)
171
Notes
1. Importing print_function from __future__ in line 11 is only required if using Python 2.7.
2. The environment variable PYCONTROL_TEST_EXAMPLES is used for testing to turn off plotting of the outputs.
8.1.3 LQR control design for vertical takeoff and landing aircraft
This script demonstrates the use of the python-control package for analysis and design of a controller for a vectored
thrust aircraft model that is used as a running example through the text Feedback Systems by Astrom and Murray.
This example makes use of MATLAB compatible commands.
Code
10 import os
11 import numpy as np
12 import matplotlib.pyplot as plt # MATLAB plotting functions
13 from control.matlab import * # MATLAB-like functions
14
15 #
16 # System dynamics
17 #
18 # These are the dynamics for the PVTOL system, written in state space
19 # form.
20 #
21
22 # System parameters
23 m = 4 # mass of aircraft
24 J = 0.0475 # inertia around pitch axis
25 r = 0.25 # distance to center of force
26 g = 9.8 # gravitational constant
27 c = 0.05 # damping factor (estimated)
28
47 # Input matrix
48 B = np.matrix(
49 [[0, 0], [0, 0], [0, 0],
50 [np.cos(xe[2])/m, -np.sin(xe[2])/m],
51 [np.sin(xe[2])/m, np.cos(xe[2])/m],
52 [r/J, 0]]
53 )
54
55 # Output matrix
56 C = np.matrix([[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0]])
57 D = np.matrix([[0, 0], [0, 0]])
58
59 #
60 # Construct inputs and outputs corresponding to steps in xy position
61 #
62 # The vectors xd and yd correspond to the states that are the desired
63 # equilibrium states for the system. The matrices Cx and Cy are the
64 # corresponding outputs.
65 #
66 # The way these vectors are used is to compute the closed loop system
67 # dynamics as
68 #
69 # xdot = Ax + B u => xdot = (A-BK)x + K xd
70 # u = -K(x - xd) y = Cx
71 #
72 # The closed loop dynamics can be simulated using the "step" command,
73 # with K*xd as the input vector (assumes that the "input" is unit size,
74 # so that xd corresponds to the desired steady state.
75 #
76
80 #
81 # Extract the relevant dynamics for use with SISO library
82 #
83 # The current python-control library only supports SISO transfer
84 # functions, so we have to modify some parts of the original MATLAB
85 # code to extract out SISO systems. To do this, we define the 'lat' and
86 # 'alt' index vectors to consist of the states that are are relevant
87 # to the lateral (x) and vertical (y) dynamics.
88 #
89
94 # Decoupled dynamics
95 Ax = (A[lat, :])[:, lat] # ! not sure why I have to do it this way
96 Bx = B[lat, 0]
97 Cx = C[0, lat]
98 Dx = D[0, 0]
99
100 Ay = (A[alt, :])[:, alt] # ! not sure why I have to do it this way
101 By = B[alt, 1]
102 Cy = C[1, alt]
(continues on next page)
109 #
110 # LQR design
111 #
112
124 # TODO: The following equations will need modifying when converting from np.matrix to
˓→np.array
125 # because the results and even intermediate calculations will be different with numpy
˓→arrays
132 # For reference, here is a list of the correct shapes of these objects:
133 # A: (6, 6)
134 # B: (6, 2)
135 # C: (2, 6)
136 # D: (2, 2)
137 # xd: (6, 1)
138 # yd: (6, 1)
139 # Ax: (4, 4)
140 # Bx: (4, 1)
141 # Cx: (1, 4)
142 # Dx: ()
143 # Ay: (2, 2)
144 # By: (2, 1)
145 # Cy: (1, 2)
146
155 plt.subplot(221)
156 plt.title("Identity weights")
157 # plt.plot(T, Y[:,1, 1], '-', T, Y[:,2, 2], '--')
(continues on next page)
182 plt.subplot(222)
183 plt.title("Effect of input weights")
184 plt.plot(T1.T, Y1.T, 'b-')
185 plt.plot(T2.T, Y2.T, 'b-')
186 plt.plot(T3.T, Y3.T, 'b-')
187 plt.plot([0, 10], [1, 1], 'k-')
188
200 H2x = ss(Ax - Bx*K2[0, lat], Bx*K2[0, lat]*xd[lat, :], Cx, Dx)
201 H2y = ss(Ay - By*K2[1, alt], By*K2[1, alt]*yd[alt, :], Cy, Dy)
202
203 plt.subplot(223)
204 plt.title("Output weighting")
205 [Y2x, T2x] = step(H2x, T=np.linspace(0, 10, 100))
206 [Y2y, T2y] = step(H2y, T=np.linspace(0, 10, 100))
207 plt.plot(T2x.T, Y2x.T, T2y.T, Y2y.T)
208 plt.ylabel('position')
209 plt.xlabel('time')
210 plt.ylabel('position')
211 plt.legend(('x', 'y'), loc='lower right')
212
213 #
214 # Physically motivated weighting
(continues on next page)
226 H3x = ss(Ax - Bx*K3[0, lat], Bx*K3[0, lat]*xd[lat, :], Cx, Dx)
227 H3y = ss(Ay - By*K3[1, alt], By*K3[1, alt]*yd[alt, :], Cy, Dy)
228 plt.subplot(224)
229 # step(H3x, H3y, 10)
230 [Y3x, T3x] = step(H3x, T=np.linspace(0, 10, 100))
231 [Y3y, T3y] = step(H3y, T=np.linspace(0, 10, 100))
232 plt.plot(T3x.T, Y3x.T, T3y.T, Y3y.T)
233 plt.title("Physically motivated weights")
234 plt.xlabel('time')
235 plt.legend(('x', 'y'), loc='lower right')
236
Notes
1. The environment variable PYCONTROL_TEST_EXAMPLES is used for testing to turn off plotting of the outputs.
Code
1 #!/usr/bin/env python
2
3 import os
4
5 import numpy as np
6 import control.modelsimp as msimp
7 import control.matlab as mt
8 from control.statesp import StateSpace
9 import matplotlib.pyplot as plt
10
11 plt.close('all')
12
48 # Comparison of the impulse responses of the full and reduced random systems
49 plt.figure(2)
50 yrand, trand = mt.impulse(sysrand)
51 yrandr, trandr = mt.impulse(rsysrand)
52 plt.plot(trand.T, yrand.T, trandr.T, yrandr.T)
53
Notes
1. The environment variable PYCONTROL_TEST_EXAMPLES is used for testing to turn off plotting of the outputs.
Code
7 import os
8
9 import numpy as np
(continues on next page)
17 #
18 # Inverted pendulum
19 #
20
25
32 # Outer trajectories
33 phase_plot(
34 invpend_ode,
35 X0=[[-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1],
36 [-1, 2.1], [4.2, 2.1], [5, 2.1],
37 [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1],
38 [1, -2.1], [-4.2, -2.1], [-5, -2.1]],
39 T=np.linspace(0, 40, 200),
40 logtime=(3, 0.7)
41 )
42
43 # Separatrices
44 phase_plot(invpend_ode, X0=[[-2.3056, 2.1], [2.3056, -2.1]], T=6, lingrid=0)
45
46 #
47 # Systems of ODEs: damped oscillator example (simulation + phase portrait)
48 #
49
53
83 #
84 # Stability definitions
85 #
86 # This set of plots illustrates the various types of equilibrium points.
87 #
88
89
94
95 # Asy stable
96 m = 1
97 b = 1
98 k = 1 # default values
99 plt.figure()
100 plt.clf()
101 plt.axis([-1, 1, -1, 1]) # set(gca, 'DataAspectRatio', [1 1 1]);
102 phase_plot(
103 oscillator_ode,
104 X0=[
105 [-1, 1], [-0.3, 1], [0, 1], [0.25, 1], [0.5, 1], [0.7, 1], [1, 1], [1.3, 1],
106 [1, -1], [0.3, -1], [0, -1], [-0.25, -1], [-0.5, -1], [-0.7, -1], [-1, -1],
107 [-1.3, -1]
108 ],
109 T=np.linspace(0, 10, 100),
110 timepts=[0.3, 1, 2, 3],
111 parms=(m, b, k)
112 )
113 plt.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3)
114 # plt.set(gca,'FontSize', 16)
115 plt.xlabel('$x_1$')
116 plt.ylabel('$x_2$')
117 plt.title('Asymptotically stable point')
118
119 # Saddle
120 plt.figure()
121 plt.clf()
122 plt.axis([-1, 1, -1, 1]) # set(gca, 'DataAspectRatio', [1 1 1])
123 phase_plot(
(continues on next page)
Notes
1. The environment variable PYCONTROL_TEST_EXAMPLES is used for testing to turn off plotting of the outputs.
Code
1 """robust_siso.py
2
9 import os
10
11 import numpy as np
12 import matplotlib.pyplot as plt
13
16 s = tf([1, 0], 1)
17 # the plant
18 g = 200/(10*s + 1) / (0.05*s + 1)**2
19 # disturbance plant
20 gd = 100/(10*s + 1)
21
22 # first design
23 # sensitivity weighting
24 M = 1.5
25 wb = 10
26 A = 1e-4
27 ws1 = (s/M + wb) / (s + wb*A)
28 # KS weighting
29 wu = tf(1, 1)
30
38 # second design
39 # this weighting differs from the text, where A**0.5 is used; if you use that,
40 # the frequency response doesn't match the figure. The time responses
41 # are similar, though.
42 ws2 = (s/M ** 0.5 + wb)**2 / (s + wb*A)**2
43 # the KS weighting is the same as for the first design
44
51 # frequency response
52 omega = np.logspace(-2, 2, 101)
53 ws1mag, _, _ = ws1.freqresp(omega)
54 s1mag, _, _ = s1.freqresp(omega)
55 ws2mag, _, _ = ws2.freqresp(omega)
56 s2mag, _, _ = s2.freqresp(omega)
57
66 plt.ylim([-80, 10])
67 plt.xlim([1e-2, 1e2])
68 plt.xlabel('freq [rad/s]')
69 plt.ylabel('mag [dB]')
70 plt.legend()
71 plt.title('Sensitivity and sensitivity weighting frequency responses')
72
73 # time response
74 time = np.linspace(0, 3, 201)
75 _, y1 = step_response(t1, time)
76 _, y2 = step_response(t2, time)
77
78 # gd injects into the output (that is, g and gd are summed), and the
79 # closed loop mapping from output disturbance->output is S.
80 _, y1d = step_response(s1*gd, time)
81 _, y2d = step_response(s2*gd, time)
82
83 plt.figure(2)
84 plt.subplot(1, 2, 1)
85 plt.plot(time, y1, label='$y_1(t)$')
86 plt.plot(time, y2, label='$y_2(t)$')
87
88 plt.ylim([-0.1, 1.5])
89 plt.xlim([0, 3])
90 plt.xlabel('time [s]')
91 plt.ylabel('signal [1]')
92 plt.legend()
93 plt.title('Tracking response')
94
95 plt.subplot(1, 2, 2)
96 plt.plot(time, y1d, label='$y_1(t)$')
97 plt.plot(time, y2d, label='$y_2(t)$')
98
99 plt.ylim([-0.1, 1.5])
100 plt.xlim([0, 3])
101 plt.xlabel('time [s]')
102 plt.ylabel('signal [1]')
103 plt.legend()
104 plt.title('Disturbance response')
105
Notes
1. The environment variable PYCONTROL_TEST_EXAMPLES is used for testing to turn off plotting of the outputs.
Code
1 """robust_mimo.py
2
5 Based on Example 3.8 from Multivariable Feedback Control, Skogestad and Postlethwaite,
˓→ 1st Edition.
6 """
7
8 import os
9
10 import numpy as np
11 import matplotlib.pyplot as plt
12
15
26
27 def plant():
28 """plant() -> g
29 g - LTI object; 2x2 plant with a RHP zero, at s=0.5.
30 """
31 den = [0.2, 1.2, 1]
32 gtf = tf([[[1], [1]],
33 [[2, 1], [2]]],
34 [[den, den],
35 [den, den]])
36 return ss(gtf)
37
38
51
52 def analysis():
(continues on next page)
60 yu1 = yu1
61 yu2 = yu2
62
67 plt.figure(1)
68 plt.subplot(1, 3, 1)
69 plt.plot(t, yu1[0], label='$y_1$')
70 plt.plot(t, yu1[1], label='$y_2$')
71 plt.xlabel('time')
72 plt.ylabel('output')
73 plt.ylim([-1.1, 2.1])
74 plt.legend()
75 plt.title('o/l response\nto input [1,0]')
76
77 plt.subplot(1, 3, 2)
78 plt.plot(t, yu2[0], label='$y_1$')
79 plt.plot(t, yu2[1], label='$y_2$')
80 plt.xlabel('time')
81 plt.ylabel('output')
82 plt.ylim([-1.1, 2.1])
83 plt.legend()
84 plt.title('o/l response\nto input [0,1]')
85
86 plt.subplot(1, 3, 3)
87 plt.plot(t, yuz[0], label='$y_1$')
88 plt.plot(t, yuz[1], label='$y_2$')
89 plt.xlabel('time')
90 plt.ylabel('output')
91 plt.ylim([-1.1, 2.1])
92 plt.legend()
93 plt.title('o/l response\nto input [1,-1]')
94
95
112
119
145 plt.figure(2)
146
147 plt.subplot(1, 2, 1)
148 plt.semilogx(w, 20*np.log10(sv1[:, 0]), label=r'$\sigma_1(S_1)$')
149 plt.semilogx(w, 20*np.log10(sv1[:, 1]), label=r'$\sigma_2(S_1)$')
150 plt.semilogx(w, 20*np.log10(sv2[:, 0]), label=r'$\sigma_1(S_2)$')
151 plt.semilogx(w, 20*np.log10(sv2[:, 1]), label=r'$\sigma_2(S_2)$')
152 plt.ylim([-60, 10])
153 plt.ylabel('magnitude [dB]')
154 plt.xlim([1e-2, 1e2])
155 plt.xlabel('freq [rad/s]')
156 plt.legend()
157 plt.title('Singular values of S')
158
171 plt.subplot(1, 2, 2)
172 plt.plot(time, y1[0], label='des. 1 $y_1(t))$')
173 plt.plot(time, y1[1], label='des. 1 $y_2(t))$')
174 plt.plot(time, y2[0], label='des. 2 $y_1(t))$')
175 plt.plot(time, y2[1], label='des. 2 $y_2(t))$')
176 plt.xlabel('time [s]')
177 plt.ylabel('response [1]')
178 plt.legend()
179 plt.title('c/l response to reference [1,-1]')
180
181
Notes
1. The environment variable PYCONTROL_TEST_EXAMPLES is used for testing to turn off plotting of the outputs.
Code
16 import numpy as np
17 import matplotlib.pyplot as plt
18 from math import pi
19 import control as ct
20
21 #
22 # Section 4.1: Cruise control modeling and control
23 #
(continues on next page)
36 Parameters
37 ----------
38 x : array
39 System state: car velocity in m/s
40 u : array
41 System input: [throttle, gear, road_slope], where throttle is
42 a float between 0 and 1, gear is an integer between 1 and 5,
43 and road_slope is in rad.
44
45 Returns
46 -------
47 float
48 Vehicle acceleration
49
50 """
51 from math import copysign, sin
52 sign = lambda x: copysign(1, x) # define the sign() function
53
75 # Disturbance forces
76 #
77 # The disturbance force Fd has three major components: Fg, the forces due
78 # to gravity; Fr, the forces due to rolling friction; and Fa, the
79 # aerodynamic drag.
80
(continues on next page)
84 Fg = m * g * sin(theta)
85
90 Fr = m * g * Cr * sign(v)
91
103 return dv
104
125 # Figure 1.11: A feedback system for controlling the speed of a vehicle. In
126 # this example, the speed of the vehicle is measured and compared to the
127 # desired speed. The controller is a PI controller represented as a transfer
128 # function. In the textbook, the simulations are done for LTI systems, but
129 # here we simulate the full nonlinear system.
130
173 t, y = ct.input_output_response(
174 cruise_tf, T, [vref, gear, theta_hill], X0, params={'m':m})
175
189 plt.sca(inp_axes)
190 plt.ylabel('Throttle')
191 plt.xlabel('Time [s]')
192
193 # Figure 4.2: Torque curves for a typical car engine. The graph on the
194 # left shows the torque generated by the engine as a function of the
(continues on next page)
198 plt.figure()
199 plt.suptitle('Torque curves for typical car engine')
200
231 plt.show(block=False)
232
233 # Figure 4.3: Car with cruise control encountering a sloping road
234
270 # PI controller
271 return kp * (vref - v) + ki * z
272
287 # Figure 4.3b shows the response of the closed loop system. The figure shows
288 # that even if the hill is so steep that the throttle changes from 0.17 to
289 # almost full throttle, the largest speed error is less than 1 m/s, and the
290 # desired velocity is recovered after 20 s.
291
343 # Compute the equilibrium throttle setting for the desired speed (solve for x
344 # and u given the gear, slope, and desired output velocity)
345 X0, U0, Y0 = ct.find_eqpt(
346 cruise_pi, [vref[0], 0], [vref[0], gear[0], theta0[0]],
347 y0=[0, vref[0]], iu=[1, 2], iy=[1], return_y=True)
348
359 #
360 # Example 7.8: State space feedback with integral action
361 #
362
403 # Create the closed loop system for the state space controller
404 cruise_sf = ct.InterconnectedSystem(
405 (vehicle, control_sf), name='cruise',
406 connections=(
407 ('vehicle.u', 'control.u'),
408 ('control.x', 'vehicle.v'),
409 ('control.y', 'vehicle.v')),
410 inplist=('control.r', 'vehicle.gear', 'vehicle.theta'),
411 outlist=('control.u', 'vehicle.v'), outputs=['u', 'v'])
412
413 # Compute the linearization of the dynamics around the equilibrium point
414
415 # Y0 represents the steady state with PI control => we can use it to
416 # identify the steady state velocity and required throttle setting.
417 xd = Y0[1]
418 ud = Y0[0]
419 yd = Y0[1]
420
456 plt.figure()
457 plt.suptitle('Cruise control with integrator windup')
458 T = np.linspace(0, 70, 101)
459 vref = 20 * np.ones(T.shape)
460 theta_hill = [
461 0 if t <= 5 else
462 6./180. * pi * (t-5) if t <= 6 else
463 6./180. * pi for t in T]
464 t, y = ct.input_output_response(
465 cruise_pi, T, [vref, gear, theta_hill], X0,
466 params={'kaw':0})
467 cruise_plot(cruise_pi, t, y, antiwindup=True)
468
476 plt.figure()
477 plt.suptitle('Cruise control with integrator anti-windup protection')
478 t, y = ct.input_output_response(
479 cruise_pi, T, [vref, gear, theta_hill], X0,
(continues on next page)
483 # If running as a standalone program, show plots and wait before closing
484 import os
485 if __name__ == '__main__' and 'PYCONTROL_TEST_EXAMPLES' not in os.environ:
486 plt.show()
487 else:
488 plt.show(block=False)
Notes
1. The environment variable PYCONTROL_TEST_EXAMPLES is used for testing to turn off plotting of the outputs.
Code
10 import numpy as np
11 import control as ct
12 from cmath import sqrt
13 import matplotlib.pyplot as mpl
14
15 #
16 # Vehicle steering dynamics
17 #
18 # The vehicle dynamics are given by a simple bicycle model. We take the state
19 # of the system as (x, y, theta) where (x, y) is the position of the vehicle
20 # in the plane and theta is the angle of the vehicle with respect to
21 # horizontal. The vehicle input is given by (v, phi) where v is the forward
22 # velocity of the vehicle and phi is the angle of the steering wheel. The
23 # model includes saturation of the vehicle steering angle.
24 #
25 # System state: x, y, theta
26 # System input: v, phi
27 # System output: x, y
28 # System parameters: wheelbase, maxsteer
29 #
30 def vehicle_update(t, x, u, params):
31 # Get the parameters for the model
32 l = params.get('wheelbase', 3.) # vehicle wheelbase
33 phimax = params.get('maxsteer', 0.5) # max steering angle (rad)
34
54 #
55 # Gain scheduled controller
56 #
57 # For this system we use a simple schedule on the forward vehicle velocity and
58 # place the poles of the system at fixed values. The controller takes the
59 # current vehicle position and orientation plus the velocity velocity as
60 # inputs, and returns the velocity and steering commands.
61 #
62 # System state: none
63 # System input: ex, ey, etheta, vd, phid
64 # System output: v, phi
65 # System parameters: longpole, latpole1, latpole2
66 #
67 def control_output(t, x, u, params):
68 # Get the controller parameters
69 longpole = params.get('longpole', -2.)
70 latpole1 = params.get('latpole1', -1/2 + sqrt(-7)/2)
71 latpole2 = params.get('latpole2', -1/2 - sqrt(-7)/2)
72 l = params.get('wheelbase', 3)
73
98 #
99 # Reference trajectory subsystem
100 #
101 # The reference trajectory block generates a simple trajectory for the system
102 # given the desired speed (vref) and lateral position (yref). The trajectory
103 # consists of a straight line of the form (vref * t, yref, 0) with nominal
104 # input (vref, 0).
105 #
106 # System state: none
107 # System input: vref, yref
108 # System output: xd, yd, thetad, vd, phid
109 # System parameters: none
110 #
111 def trajgen_output(t, x, u, params):
112 vref, yref = u
113 return np.array([vref * t, yref, 0, vref, 0])
114
121 #
122 # System construction
123 #
124 # The input to the full closed loop system is the desired lateral position and
125 # the desired forward velocity. The output for the system is taken as the
126 # full vehicle state plus the velocity of the vehicle. The following diagram
127 # summarizes the interconnections:
128 #
129 # +---------+ +---------------> v
130 # | | |
131 # [ yref ] | v |
132 # [ ] ---> trajgen -+-+-> controller -+-> vehicle -+-> [x, y, theta]
133 # [ vref ] ^ |
134 # | |
135 # +----------- [-1] -----------+
136 #
137 # We construct the system using the InterconnectedSystem constructor and using
138 # signal labels to keep track of everything.
139
Notes
This example demonstrates the use of the flatsys module for generating trajectories for differentially flat systems. The
example is drawn from Chapter 8 of FBS2e.
Code
8 import os
9 import numpy as np
10 import matplotlib.pyplot as plt
11 import control as ct
12 import control.flatsys as fs
13
14
20 # Create a list of arrays to store the flat output and its derivatives
21 zflag = [np.zeros(3), np.zeros(3)]
22
38 return zflag
39
40
60 return x, u
61
62
73
88 # Find a trajectory between the initial condition and the final condition
89 traj = fs.point_to_point(vehicle_flat, x0, u0, xf, uf, Tf, basis=poly)
90
91 # Create the desired trajectory between the initial and final condition
92 T = np.linspace(0, Tf, 500)
93 xd, ud = traj.eval(T)
94
115 plt.subplot(2, 4, 6)
116 plt.plot(t, x[2])
117 plt.ylabel('theta [rad]')
118
119 plt.subplot(2, 4, 7)
120 plt.plot(t, ud[0])
121 plt.xlabel('Time t [sec]')
122 plt.ylabel('v [m/s]')
123 plt.axis([0, Tf, u0[0] - 1, uf[0] + 1])
124
125 plt.subplot(2, 4, 8)
126 plt.plot(t, ud[1])
127 plt.xlabel('Ttime t [sec]')
128 plt.ylabel('$\delta$ [rad]')
129 plt.tight_layout()
130
Notes
1. The environment variable PYCONTROL_TEST_EXAMPLES is used for testing to turn off plotting of the outputs.
The examples below use python-control in a Jupyter notebook environment. These notebooks demonstrate the use of
modeling, anaylsis, and design tools using running examples in FBS2e.
The cruise control system of a car is a common feedback system encountered in everyday life. The system attempts to
maintain a constant velocity in the presence of disturbances primarily caused by changes in the slope of a road. The
controller compensates for these unknowns by measuring the speed of the car and adjusting the throttle appropriately.
This notebook explores the dynamics and control of the cruise control system, following the material presenting in
Feedback Systems by Astrom and Murray. A nonlinear model of the vehicle dynamics is used, with both state space
and frequency domain control laws. The process model is presented in Section 1, and a controller based on state
feedback is discussed in Section 2, where we also add integral action to the controller. In Section 3 we explore
the behavior with PI control including the effect of actuator saturation and how it is avoided by windup protection.
Different methods of constructing control systems are shown, all using the InputOutputSystem class (and subclasses).
Process Model
Vehicle Dynamics
To develop a mathematical model we start with a force balance for the car body. Let 𝑣 be the speed of the car, 𝑚
the total mass (including passengers), 𝐹 the force generated by the contact of the wheels with the road, and 𝐹𝑑 the
disturbance force due to gravity, friction, and aerodynamic drag.
Parameters
----------
x : array
System state: car velocity in m/s
u : array
System input: [throttle, gear, road_slope], where throttle is
a float between 0 and 1, gear is an integer between 1 and 5,
and road_slope is in rad.
Returns
-------
float
Vehicle acceleration
"""
from math import copysign, sin
sign = lambda x: copysign(1, x) # define the sign() function
# Disturbance forces
(continues on next page)
# Letting the slope of the road be \theta (theta), gravity gives the
# force Fg = m g sin \theta.
Fg = m * g * sin(theta)
Fr = m * g * Cr * sign(v)
return dv
Engine model
The force F is generated by the engine, whose torque is proportional to the rate of fuel injection, which is itself
proportional to a control signal 0 <= u <= 1 that controls the throttle position. The torque also depends on engine
speed omega.
Torque curves for a typical car engine. The graph on the left shows the torque generated by the engine as a function
of the angular velocity of the engine, while the curve on the right shows torque as a function of car speed for different
gears.
# Add labels
plt.text(11.5, 120, '$n$=1')
plt.text(24, 120, '$n$=2')
plt.text(42.5, 120, '$n$=3')
plt.text(58.5, 120, '$n$=4')
plt.text(58.5, 185, '$n$=5')
plt.xlabel('Velocity $v$ [m/s]')
plt.ylabel('Torque $T$ [Nm]')
plt.tight_layout()
plt.suptitle('Torque curves for typical car engine');
We now create an input/output model for the vehicle system that takes the throttle input 𝑢, the gear and the angle of
the road 𝜃 as input. The output of this model is the current vehicle velocity 𝑣.
[5]: vehicle = ct.NonlinearIOSystem(
vehicle_update, None, name='vehicle',
inputs = ('u', 'gear', 'theta'), outputs = ('v'), states=('v'))
# Velocity profile
if subplot_axes[0] is None:
subplot_axes[0] = plt.subplot(2, 1, 1)
else:
plt.sca(subplots[0])
plt.plot(t, y[v_ind], linetype)
plt.plot(t, vref*np.ones(t.shape), 'k-')
plt.plot([t_hill, t_hill], [v_min, v_max], 'k--')
plt.axis([0, t[-1], v_min, v_max])
plt.xlabel('Time $t$ [s]')
plt.ylabel('Velocity $v$ [m/s]')
return subplot_axes
Construct a state space controller with integral action, linearized around an equilibrium point. The controller is con-
structed around the equilibrium point (𝑥𝑑 , 𝑢𝑑 ) and includes both feedforward and feedback compensation.
• Controller inputs - (𝑥, 𝑦, 𝑟): system states, system output, reference
• Controller state - 𝑧: integrated error (𝑦 − 𝑟)
• Controller output - 𝑢: state feedback control
Note: to make the structure of the controller more clear, we implement this as a “nonlinear” input/output module, even
though the actual input/output system is linear. This also allows the use of parameters to set the operating point and
gains for the controller.
# Create the closed loop system for the state space controller
cruise_sf = ct.InterconnectedSystem(
(vehicle, control_sf), name='cruise',
connections=(
('vehicle.u', 'control.u'),
('control.x', 'vehicle.v'),
('control.y', 'vehicle.v')),
inplist=('control.r', 'vehicle.gear', 'vehicle.theta'),
outlist=('control.u', 'vehicle.v'), outputs=['u', 'v'])
Pole/zero cancellation
The transfer function for the linearized dynamics of the cruise control system is given by 𝑃 (𝑠) = 𝑏/(𝑠 + 𝑎). A simple
(but not necessarily good) way to design a PI controller is to choose the parameters of the PI controller as 𝑘i = 𝑎𝑘p .
The controller transfer function is then 𝐶(𝑠) = 𝑘p + 𝑘i /𝑠 = 𝑘i (𝑠 + 𝑎)/𝑠. It has a zero at 𝑠 = −𝑘i /𝑘p = −𝑎 that
cancels the process pole at 𝑠 = −𝑎. We have 𝑃 (𝑠)𝐶(𝑠) = 𝑘i /𝑠 giving the transfer function from reference to vehicle
velocity as 𝐺𝑦𝑟 (𝑠) = 𝑏𝑘p /(𝑠 + 𝑏𝑘p ), and control design is then simply a matter of choosing the gain 𝑘p . The closed
loop system dynamics are of first order with the time constant 1/(𝑏𝑘p ).
[8]: # Get the transfer function from throttle input + hill to vehicle speed
P = ct.ss2tf(cruise_linearized[0, 0])
PI Controller
In this example, the speed of the vehicle is measured and compared to the desired speed. The controller is a PI
controller represented as a transfer function. In the textbook, the simulations are done for LTI systems, but here we
simulate the full nonlinear system.
To illustrate the design of a PI controller, we choose the gains 𝑘p and 𝑘i so that the characteristic polynomial has the
form
𝑠2 + 2𝜁𝜔0 𝑠 + 𝜔02
[9]: # Values of the first order transfer function P(s) = b/(s + a) are set above
cruise_tf = ct.InterconnectedSystem(
(vehicle, control_tf), name='cruise',
connections = [('control.u', '-vehicle.v'), ('vehicle.u', 'control.y')],
inplist = ('control.u', 'vehicle.gear', 'vehicle.theta'), inputs = ('vref', 'gear
˓→', 'theta'),
t, y = ct.input_output_response(
cruise_tf, T, [vref, gear, theta_hill], X0, params={'m':m})
plt.sca(subplots[1])
plt.ylabel('Throttle')
plt.xlabel('Time [s]');
We now create a more complicated feedback controller that includes anti-windup protection.
# PI controller
return kp * (vref - v) + ki * z
control_pi = ct.NonlinearIOSystem(
pi_update, pi_output, name='control',
inputs = ['v', 'vref'], outputs = ['u'], states = ['z'],
params = {'kp':0.5, 'ki':0.1})
Figure 4.3b shows the response of the closed loop system. The figure shows that even if the hill is so steep that the
throttle changes from 0.17 to almost full throttle, the largest speed error is less than 1 m/s, and the desired velocity is
recovered after 20 s.
[14]: # Compute the equilibrium throttle setting for the desired speed
X0, U0, Y0 = ct.find_eqpt(
cruise_pi, [vref[0], 0], [vref[0], gear[0], theta0[0]],
(continues on next page)
Effect of Windup
The windup effect occurs when a car encounters a hill that is so steep (6∘ ) that the throttle saturates when the cruise
controller attempts to maintain speed.
[15]: plt.figure()
plt.suptitle('Cruise control with integrator windup')
T = np.linspace(0, 50, 101)
vref = 20 * np.ones(T.shape)
theta_hill = [
0 if t <= 5 else
6./180. * pi * (t-5) if t <= 6 else
6./180. * pi for t in T]
t, y = ct.input_output_response(
cruise_pi, T, [vref, gear, theta_hill], X0,
params={'kaw':0})
cruise_plot(cruise_pi, t, y, antiwindup=True);
Anti-windup can be applied to the system to improve the response. Because of the feedback from the actuator model,
the output of the integrator is quickly reset to a value such that the controller output is at the saturation limit.
[16]: plt.figure()
plt.suptitle('Cruise control with integrator anti-windup protection')
t, y = ct.input_output_response(
cruise_pi, T, [vref, gear, theta_hill], X0,
params={'kaw':2.})
cruise_plot(cruise_pi, t, y, antiwindup=True);
[ ]:
This notebook contains the computations for the vehicle steering running example in Feedback Systems.
RMM comments to Karl, 27 Jun 2019 * I’m using this notebook to walk through all of the vehicle steering examples
and make sure that all of the parameters, conditions, and maximum steering angles are consitent and reasonable.
* Please feel free to send me comments on the contents as well as the bulletted notes, in whatever form is most
convenient. * Once we have sorted out all of the settings we want to use, I’ll copy over the changes into the MATLAB
files that we use for creating the figures in the book. * These notes will be removed from the notebook once we have
finalized everything.
[1]: import numpy as np
import matplotlib.pyplot as plt
import control as ct
ct.use_fbs_defaults()
ct.use_numpy_matrix(False)
The vehicle dynamics are given by a simple bicycle model. We take the state of the system as (𝑥, 𝑦, 𝜃) where (𝑥, 𝑦) is
the position of the reference point of the vehicle in the plane and 𝜃 is the angle of the vehicle with respect to horizontal.
The vehicle input is given by (𝑣, 𝛿) where 𝑣 is the forward velocity of the vehicle and 𝛿 is the angle of the steering
wheel. We take as parameters the wheelbase 𝑏 and the offset 𝑎 between the rear wheels and the reference point. The
model includes saturation of the vehicle steering angle (maxsteer).
• System state: x, y, theta
• System input: v, delta
• System output: x, y
• System parameters: wheelbase, refoffset, maxsteer
Assuming no slipping of the wheels, the motion of the vehicle is given by a rotation around a point O that depends
on the steering angle 𝛿. To compute the angle 𝛼 of the velocity of the reference point with respect to the axis of the
vehicle, we let the distance from the center of rotation O to the contact point of the rear wheel be 𝑟r and it the follows
from Figure 3.17 in FBS that 𝑏 = 𝑟r tan 𝛿 and 𝑎 = 𝑟r tan 𝛼, which implies that tan 𝛼 = (𝑎/𝑏) tan 𝛿.
Reasonable limits for the steering angle depend on the speed. The physical limit is given in our model as 0.5 radians
(about 30 degrees). However, this limit is rarely possible when the car is driving since it would cause the tires to
slide on the pavement. We us a limit of 0.1 radians (about 6 degrees) at 10 m/s (≈ 35 kph) and 0.05 radians (about
3 degrees) at 30 m/s (≈ 110 kph). Note that a steering angle of 0.05 rad gives a cross acceleration of (𝑣 2 /𝑏) tan 𝛿 ≈
(100/3)0.05 = 1.7 m/s2 at 10 m/s and 15 m/s2 at 30 m/s (≈ 1.5 times the force of gravity).
[2]: def vehicle_update(t, x, u, params):
# Get the parameters for the model
a = params.get('refoffset', 1.5) # offset to vehicle reference point
b = params.get('wheelbase', 3.) # vehicle wheelbase
maxsteer = params.get('maxsteer', 0.5) # max steering angle (rad)
To illustrate the dynamics of the system, we create an input that correspond to driving down a curvy road. This
trajectory will be used in future simulations as a reference trajectory for estimation and control.
RMM notes, 27 Jun 2019: * The figure below appears in Chapter 8 (output feedback) as Example 8.3, but I’ve put
it here in the notebook since it is a good way to demonstrate the dynamics of the vehicle. * In the book, this figure
is created for the linear model and in a manner that I can’t quite understand, since the linear model that is used
is only for the lateral dynamics. The original file is OutputFeedback/figures/steering_obs.m. * To
create the figure here, I set the initial vehicle angle to be 𝜃(0) = 0.75 rad and then used an input that gives a figure
approximating Example 8.3 To create the lateral offset, I think subtracted the trajectory from the averaged straight line
trajectory, shown as a dashed line in the 𝑥𝑦 figure below. * I find the approach that we used in the MATLAB version
to be confusing, but I also think the method of creating the lateral error here is a hart to follow. We might instead
consider choosing a trajectory that goes mainly vertically, with the 2D dynamics being the 𝑥, 𝜃 dynamics instead of
the 𝑦, 𝜃 dynamics.
KJA comments, 1 Jul 2019:
0. I think we should point out that the reference point is typically the projection of the center of mass of the whole
vehicle.
1. The heading angle 𝜃 must be marked in Figure 3.17b.
2. I think it is useful to start with a curvy road that you have done here but then to specialized to a trajectory that is
essentially horizontal, where 𝑦 is the deviation from the nominal horizontal 𝑥 axis. Assuming that 𝛼 and 𝜃 are
small we get the natural linearization of (3.26) 𝑥˙ = 𝑣 and 𝑦˙ = 𝑣(𝛼 + 𝜃)
RMM response, 16 Jul 2019: * I’ve changed the trajectory to be about the horizontal axis, but I am ploting things
vertically for better figure layout. This corresponds to what is done in Example 9.10 in the text, which I think looks
OK.
KJA response, 20 Jul 2019: Fig 8.6a is fine
# Control inputs
T_curvy = np.linspace(0, 7, 500)
v_curvy = v0*np.ones(T_curvy.shape)
delta_curvy = 0.1*np.sin(T_curvy)*np.cos(4*T_curvy) + 0.0025*np.sin(T_curvy*np.pi/7)
u_curvy = [v_curvy, delta_curvy]
X0_curvy = [0, 0.8, 0]
plt.xlabel('y [m]')
plt.ylabel('x [m]');
plt.axis('Equal')
We are interested in the motion of the vehicle about a straight-line path (𝜃 = 𝜃0 ) with constant velocity 𝑣0 ̸= 0. To
find the relevant equilibrium point, we first set 𝜃˙ = 0 and we see that we must have 𝛿 = 0, corresponding to the
steering wheel being straight. The motion in the xy plane is by definition not at equilibrium and so we focus on lateral
deviation of the vehicle from a straight line. For simplicity, we let 𝜃e = 0, which corresponds to driving along the 𝑥
axis. We can then focus on the equations of motion in the 𝑦 and 𝜃 directions with input 𝑢 = 𝛿.
[4]: # Define the lateral dynamics as a subset of the full vehicle steering dynamics
lateral = ct.NonlinearIOSystem(
lambda t, x, u, params: vehicle_update(
t, [0., x[0], x[1]], [params.get('velocity', 1), u[0]], params)[1:],
lambda t, x, u, params: vehicle_output(
t, [0., x[0], x[1]], [params.get('velocity', 1), u[0]], params)[1:],
states=2, name='lateral', inputs=('phi'), outputs=('y')
)
A = [[0. 1.]
[0. 0.]]
B = [[0.5]
[1. ]]
C = [[1. 0.]]
D = [[0.]]
We want to design a controller that stabilizes the dynamics of the vehicle and tracks a given reference value 𝑟 of
the lateral position of the vehicle. We use feedback to design the dynamics of the system to have the characteristic
polynomial 𝑝(𝑠) = 𝑠2 + 2𝜁c 𝜔c + 𝜔c2 .
To find reasonable values of 𝜔c we observe that the initial response of the steering angle to a unit step change in the
steering command is 𝜔c2 𝑟, where 𝑟 is the commanded lateral transition. Recall that the model is normalized so that the
length unit is the wheelbase 𝑏 and the time unit is the time 𝑏/𝑣0 to travel one wheelbase. A typical car has a wheelbase
of about 3 m and, assuming a speed of 30 m/s, a normalized time unit corresponds to 0.1 s. To determine a reasonable
steering angle when making a gentle lane change, we assume that the turning radius is 𝑅 = 600 m. For a wheelbase
of 3 m this corresponds to a steering angle 𝛿 ≈ 3/600 = 0.005 rad and a lateral acceleration of 𝑣√2 /𝑅 = 302/600 = 1.5
m/s2 . Assuming that a lane change corresponds to a translation of one wheelbase we find 𝜔c = 0.005 = 0.07 rad/s.
The unit step responses for the closed loop system for different values of the design parameters are shown below. The
effect of 𝜔𝑐 is shown on the left, which shows that the response speed increases with increasing 𝜔c . All responses have
overshoot less than 5% (15 cm), as indicated by the dashed lines. The settling times range from 30 to 60 normalized
time units, which corresponds to about 3–6 s, and are limited by the acceptable lateral acceleration of the vehicle. The
effect of 𝜁c is shown on the right. The response speed and the overshoot increase with decreasing damping. Using
these plots, we conclude that a reasonable design choice is 𝜔c = 0.07 and 𝜁c = 0.7.
RMM note, 27 Jun 2019: * The design guidelines are for 𝑣0 = 30 m/s (highway speeds) but most of the examples
below are done at lower speed (typically 10 m/s). Also, the eigenvalue locations above are not the same ones that we
use in the output feedback example below. We should probably make things more consistent.
KJA comment, 1 Jul 2019: * I am all for maikng it consist and choosing e.g. v0 = 30 m/s
RMM comment, 17 Jul 2019: * I’ve updated the examples below to use v0 = 30 m/s for everything except the
forward/reverse example. This corresponds to ~105 kph (freeway speeds) and a reasonable bound for the steering
angle to avoid slipping is 0.05 rad.
[5]: # Utility function to place poles for the normalized vehicle steering system
def normalized_place(wc, zc):
# Get the dynamics and input matrices, for later use
A, B = lateral_normalized.A, lateral_normalized.B
# Compute the feedforward gain based on the zero frequency gain of the closed loop
kf = np.real(1/clsys.evalfr(0))
# Utility function to plot simulation results for normalized vehicle steering system
def normalized_plot(t, y, u, inpfig, outfig):
plt.sca(outfig)
plt.plot(t, y)
plt.sca(inpfig)
plt.plot(t, u[0])
plt.sca(outfig)
plt.ylabel('Lateral position $y/b$')
plt.plot([0, 20], [0.95, 0.95], 'k--')
plt.plot([0, 20], [1.05, 1.05], 'k--')
RMM notes, 17 Jul 2019 * These step responses are very slow. Note that the steering wheel angles are about 10X
less than a resonable bound (0.05 rad at 30 m/s). A consequence of these low gains is that the tracking controller in
Example 8.4 has to use a different set of gains. We could update, but the gains listed here have a rationale that we
would have to update as well. * Based on the discussion below, I think we should make 𝜔c range from 0.5 to 1 (10X
faster).
KJA response, 20 Jul 2019: Makes a lot of sense to make 𝜔c range from 0.5 to 1 (10X faster). The plots were still in
the range 0.05 to 0.1 in the note you sent me.
RMM response: 23 Jul 2019: Updated 𝜔c to 10X faster. Note that this makes size of the inputs for the step response
quite large, but that is in part because a unit step in the desired position produces an (instantaneous) error of 𝑏 = 3 m
=⇒ quite a large error. A lateral error of 10 cm with 𝜔𝑐 = 0.7 would produce an (initial) input of 0.015 rad.
We construct an estimator for the (normalized) lateral dynamics by assigning the eigenvalues of the estimator dynamics
to desired value, specifified in terms of the second order characteristic equation for the estimator dynamics.
A simulation of the observer for a vehicle driving on a curvy road is shown below. The first figure shows the trajectory
of the vehicle on the road, as viewed from above. The response of the observer is shown on the right, where time is
normalized to the vehicle length. We see that the observer error settles in about 4 vehicle lengths.
RMM note, 27 Jun 2019: * As an alternative, we can attempt to estimate the state of the full nonlinear system using a
linear estimator. This system does not necessarily converge to zero since there will be errors in the nominal dynamics
of the system for the linear estimator. * The limits on the 𝑥 axis for the time plots are different to show the error over
the entire trajectory. * We should decide whether we want to keep the figure above or the one below for the text.
KJA comment, 1 Jul 2019: * I very much like your observation about the nonlinear system. I think it is a very good
idea to use your new simulation
RMM comment, 17 Jul 2019: plan to use this version in the text.
KJA comment, 20 Jul 2019: I think this is a big improvement we show that an observer based on a linearized model
works on a nonlinear simulation, If possible we could add a line telling why the linear model works and that this is
standard procedure in control engineering.
ax = plt.subplot(2, 2, 2)
plt.plot(t, x_est[0] - y_ref)
ax.set(xlim=[0, 10])
plt.ylabel('Lateral error')
ax = plt.subplot(2, 2, 3)
plt.plot(t, theta_ref)
plt.plot(t, x_est[1])
ax.set(xlim=[0, 10])
plt.xlabel('Normalized time $v_0 t / b$')
plt.ylabel('Vehicle angle $\\theta$')
ax = plt.subplot(2, 2, 4)
plt.plot(t, x_est[1] - theta_ref)
ax.set(xlim=[0, 10])
plt.xlabel('Normalized time $v_0 t / b$')
plt.ylabel('Angle error')
plt.tight_layout()
RMM note, 27 Jun 2019 * The feedback gains for the controller below are different that those computed in the
eigenvalue placement example (from Ch 7), where an argument was given for the choice of the closed loop eigenvalues.
Should we choose a single, consistent set of gains in both places? * This plot does not quite match Example 8.4 because
a different reference is being used for the laterial position. * The transient in 𝛿 is quiet large. This appears to be due to
the error in 𝜃(0), which is initialized to zero intead of to theta_curvy.
KJA comment, 1 Jul 2019: 1. The large initial errors dominate the plots.
2. There is somehing funny happening at the end of the simulation, may be due to the small curvature at the end of
the path?
RMM comment, 17 Jul 2019: * Updated to use the new trajectory * We will have the issue that the gains here are
different than the gains that we used in Chapter 7. I think that what we need to do is update the gains in Ch 7 (they are
too sluggish, as noted above). * Note that unlike the original example in the book, the errors do not converge to zero.
This is because we are using pure state feedback (no feedforward) => the controller doesn’t apply any input until there
is an error.
KJA comment, 20 Jul 2019: We may add that state feedback is a proportional controller which does not guarantee
that the error goes to zero for example by changing the line “The tracking error . . . ” to “The tracking error can be
improved by adding integral action (Section7.4), later in this chapter “Disturbance Modeling” or feedforward (Section
8,5). Should we do an exercises?
ax = plt.subplot(2, 2, 2)
plt.plot(t, x[1])
plt.plot(t, x[3])
plt.plot(t, theta_ref, 'k-.')
ax.set(xlim=[0, 15])
plt.ylabel('Vehicle angle $\\theta$')
ax = plt.subplot(2, 2, 4)
plt.plot(t, u_sfb[0])
(continues on next page)
To illustrate how we can use a two degree-of-freedom design to improve the performance of the system, consider the
problem of steering a car to change lanes on a road. We use the non-normalized form of the dynamics, which were
derived in Example 3.11.
KJA comment, 1 Jul 2019: 1. I think the reference trajectory is too much curved in the end compare with Example
3.11
In summary I think it is OK to change the reference trajectories but we should make sure that the curvature is less than
𝜌 = 600𝑚 not to have too high acceleratarion.
RMM response, 16 Jul 2019: * Not sure if the comment about the trajectory being too curved is referring to this
example. The steering angles (and hence radius of curvature/acceleration) are quite low. ??
KJA response, 20 Jul 2019: You are right the curvature is not too small. We could add the sentence “The small
deviations can be eliminated by adding feedback.”
RMM response, 23 Jul 2019: I think the small deviation you are referring to is in the velocity trace. This occurs
because I gave a fixed endpoint in time and so the velocity had to be adjusted to hit that exact point at that time. This
doesn’t show up in the book, so it won’t be a problem ( =⇒ no additional explanation required).
[9]: import control.flatsys as fs
# Create a list of arrays to store the flat output and its derivatives
zflag = [np.zeros(3), np.zeros(3)]
return zflag
return x, u
To find a trajectory from an initial state 𝑥0 to a final state 𝑥f in time 𝑇f we solve a point-to-point trajectory generation
problem. We also set the initial and final inputs, which sets the vehicle velocity 𝑣 and steering wheel angle 𝛿 at the
endpoints.
# Find a trajectory between the initial condition and the final condition
traj = fs.point_to_point(vehicle_flat, x0, u0, xf, uf, Tf, basis=poly)
plt.subplot(2, 4, 4)
plt.plot(t, x[2])
plt.ylabel('theta [rad]')
plt.subplot(2, 4, 7)
plt.plot(t, u[0])
plt.xlabel('Time t [sec]')
plt.ylabel('v [m/s]')
plt.axis([0, Tf, u0[0] - 1, uf[0] +1])
plt.subplot(2, 4, 8)
plt.plot(t, u[1]);
plt.xlabel('Time t [sec]')
plt.ylabel('$\delta$ [rad]')
plt.tight_layout()
Vehicle transfer functions for forward and reverse driving (Example 10.11)
The vehicle steering model has different properties depending on whether we are driving forward or in reverse. The
figures below show step responses from steering angle to lateral translation for a the linearized model when driving
forward (dashed) and reverse (solid). In this simulation we have added an extra pole with the time constant 𝑇 = 0.1
to approximately account for the dynamics in the steering system.
With rear-wheel steering the center of mass first moves in the wrong direction and the overall response with rear-
wheel steering is significantly delayed compared with that for front-wheel steering. (b) Frequency response for driving
forward (dashed) and reverse (solid). Notice that the gain curves are identical, but the phase curve for driving in reverse
has non-minimum phase.
RMM note, 27 Jun 2019: * I cannot recreate the figures in Example 10.11. Since we are looking at the lateral velocity,
there is a differentiator in the output and this takes the step function and creates an offset at 𝑡 = 0 (intead of a smooth
curve). * The transfer functions are also different, and I don’t quite understand why. Need to spend a bit more time on
this one.
KJA comment, 1 Jul 2019: The reason why you cannot recreate figures i Example 10.11 is because the caption in
figure is wrong, sorry my fault, the y-axis should be lateral position not lateral velocity. The approximate expression
for the transfer functions
𝑎𝑣0 𝑠 + 𝑣02 1.5𝑠 + 1 0.5𝑠 + 0.33
𝐺𝑦𝛿 = = 2
=
𝑏𝑠 3𝑠 𝑠
are quite close to the values that you get numerically
In this case I think it is useful to have v=1 m/s because we do not drive to fast backwards.
RMM response, 17 Jul 2019 * Updated figures below use the same parameters as the running example (the current text
uses different parameters) * Following the material in the text, a pole is added at s = -1 to approximate the dynamics
of the steering system. This is not strictly needed, so we could decide to take it out (and update the text)
KJA comment, 20 Jul 2019: I have been oscillating a bit about this example. Of course it does not make sense to drive
in reverse in 30 m/s but it seems a bit silly to change parameters just in this case (if we do we have to motivate it). On
the other hand what we are doing is essentially based on transfer functions and a RHP zero. My current view which
has changed a few times is to keep the standard parameters. In any case we should eliminate the extra time constant.
A small detail, I could not see the time response in the file you sent, do not resend it!, I will look at the final version.
RMM comment, 23 Jul 2019: I think it is OK to have the speed be different and just talk about this in the text. I have
removed the extra time constant in the current version.
Reverse TF =
-s + 1.333
-----------------------------
s^2 - 7.828e-16 s - 1.848e-16
# Forward motion
t, y = ct.step_response(forward_tf * Msteer, np.linspace(0, 4, 500))
plt.plot(t, y, 'b--')
# Reverse motion
t, y = ct.step_response(reverse_tf * Msteer, np.linspace(0, 4, 500))
plt.plot(t, y, 'b-')
For a lane transfer system we would like to have a nice response without overshoot, and we therefore consider the
use of feedforward compensation to provide a reference trajectory for the closed loop system. We choose the desired
response as 𝐹m (𝑠) = 𝑎2 2/(𝑠 + 𝑎)2 , where the response speed or aggressiveness of the steering is governed by the
parameter 𝑎.
RMM note, 27 Jun 2019: * 𝑎 was used in the original description of the dynamics as the reference offset. Perhaps
choose a different symbol here? * In current version of Ch 12, the 𝑦 axis is labeled in absolute units, but it should
actually be in normalized units, I think. * The steering angle input for this example is quite high. Compare to Example
8.8, above. Also, we should probably make the size of the “lane change” from this example match whatever we use in
Example 8.8
KJA comments, 1 Jul 2019: Chosen parameters look good to me
RMM response, 17 Jul 2019 * I changed the time constant for the feedforward model to give something that is more
reasonable in terms of turning angle at the speed of 𝑣0 = 30 m/s. Note that this takes about 30 body lengths to change
lanes (= 9 seconds at 105 kph). * The time to change lanes is about 2X what it is using the differentially flat trajectory
above. This is mainly because the feedback controller applies a large pulse at the beginning of the trajectory (based
on the input error), whereas the differentially flat trajectory spreads the turn over a longer interval. Since are living the
steering angle, we have to limit the size of the pulse => slow down the time constant for the reference model.
KJA response, 20 Jul 2019: I think the time for lane change is too long, which may depend on the small steering angles
used. The largest steering angle is about 0.03 rad, but we have admitted larger values in previous examples. I suggest
that we change the design so that the largest sterring angel is closer to 0.05, see the remark from Bjorn O a lane change
could take about 5 s at 30m/s.
RMM response, 23 Jul 2019: I reset the time constant to 0.2, which gives something closer to what we had for
trajectory generation. It is still slower, but this is to be expected since it is a linear controller. We now finish the
trajectory in 20 body lengths, which is about 6 seconds.
# Overhead view
plt.subplot(1, 2, 1)
plt.plot(y_ffwd, t)
plt.plot(-1*np.ones(t.shape), t, 'k-', linewidth=1)
plt.plot(0*np.ones(t.shape), t, 'k--', linewidth=1)
plt.plot(1*np.ones(t.shape), t, 'k-', linewidth=1)
plt.axis([-5, 5, -2, 27])
plt.subplot(2, 2, 4)
plt.plot(t, delta_ffwd)
# plt.axis([0, 10, -1, 1])
plt.ylabel('$\\delta$ [rad]')
plt.xlabel('Normalized time $v_0 t / b$');
plt.tight_layout()
Consider a controller based on state feedback combined with an observer where we want a faster closed loop system
and choose 𝜔c = 10, 𝜁c = 0.707, 𝜔o = 20, and 𝜁o = 0.707.
KJA comment, 20 Jul 2019: This is a really troublesome case. If we keep it as a vehicle steering problem we must
have an order of magnitude lower valuer for 𝜔𝑐 and 𝜔𝑜 and then the zero will not be slow. My recommendation is to
keep it as a general system with the transfer function. 𝑃 (𝑠) = (𝑠 + 1)/𝑠2 . The text then has to be reworded.
RMM response, 23 Jul 2019: I think the way we have it is OK. Our current value for the controller and observer is
𝜔c = 0.7 and 𝜔o = 1. Here we way we want something faster and so we got to 𝜔c = 7 (10X) and 𝜔o = 10 (10X).
K = [100. -35.86]
L = [ 28.28 400. ]
C(s) =
-1.152e+04 s + 4e+04
--------------------
s^2 + 42.42 s + 6658
K = [100. 2.]
C(s) =
3628 s + 4e+04
---------------------
s^2 + 80.28 s + 156.6
[ ]:
This notebook demonstrates the use of the python-control package for analysis and design of a controller for a vectored
thrust aircraft model that is used as a running example through the text Feedback Systems by Astrom and Murray. This
example makes use of MATLAB compatible commands.
Additional information on this system is available at
http://www.cds.caltech.edu/~murray/wiki/index.php/Python-control/Example:_Vertical_takeoff_and_landing_
aircraft
System Description
This example uses a simplified model for a (planar) vertical takeoff and landing aircraft (PVTOL), as shown below:
The position and orientation of the center of mass of the aircraft is denoted by (𝑥, 𝑦, 𝜃), 𝑚 is the mass of the vehicle,
𝐽 the moment of inertia, 𝑔 the gravitational constant and 𝑐 the damping coefficient. The forces generated by the main
downward thruster and the maneuvering thrusters are modeled as a pair of forces 𝐹1 and 𝐹2 acting at a distance 𝑟
below the aircraft (determined by the geometry of the thrusters).
Letting 𝑧 = (𝑥, 𝑦, 𝜃, 𝑥,
˙ 𝑦, ˙ the equations can be written in state space form as:
˙ 𝜃),
⎡ ⎤ ⎡ ⎤
𝑧4 0
⎢
⎢ 𝑧5 ⎥ ⎢
⎥ ⎢ 0 ⎥
⎥
𝑑𝑧 ⎢ 𝑧6
⎥ ⎢ 0 ⎥
=⎢ ⎢ 𝑐
⎥ +⎢1
⎢ 1
⎥
𝑑𝑡 ⎢ − 𝑧
𝑚 4 ⎥
⎥
𝑚 cos 𝜃𝐹1 + 𝑚 sin 𝜃𝐹2⎥
⎥
⎣−𝑔 − 𝑐 𝑧5 ⎦ ⎣ 1 sin 𝜃𝐹1 + 1 cos 𝜃𝐹2 ⎦
⎢
𝑚 𝑚 𝑚
𝑟
0 𝐽 𝐹1
This section demonstrates the design of an LQR state feedback controller for the vectored thrust aircraft example.
This example is pulled from Chapter 6 (Linear Systems, Example 6.4) and Chapter 7 (State Feedback, Example 7.9)
of Astrom and Murray. The python code listed here are contained the the file pvtol-lqr.py.
To execute this example, we first import the libraries for SciPy, MATLAB plotting and the python-control package:
𝑑𝑧
Choosing equilibrium inputs to be 𝑢𝑒 = (0, 𝑚𝑔), the dynamics of the system 𝑑𝑡 , and their linearization 𝐴 about
[4]: # Dynamics matrix (use matrix type so that * works for multiplication)
# Note that we write A and B here in full generality in case we want
# to test different xe and ue.
A = matrix(
[[ 0, 0, 0, 1, 0, 0],
[ 0, 0, 0, 0, 1, 0],
[ 0, 0, 0, 0, 0, 1],
[ 0, 0, (-ue[0]*sin(xe[2]) - ue[1]*cos(xe[2]))/m, -c/m, 0, 0],
[ 0, 0, (ue[0]*cos(xe[2]) - ue[1]*sin(xe[2]))/m, 0, -c/m, 0],
[ 0, 0, 0, 0, 0, 0 ]])
# Input matrix
B = matrix(
[[0, 0], [0, 0], [0, 0],
[cos(xe[2])/m, -sin(xe[2])/m],
[sin(xe[2])/m, cos(xe[2])/m],
[r/J, 0]])
# Output matrix
C = matrix([[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0]])
D = matrix([[0, 0], [0, 0]])
To compute a linear quadratic regulator for the system, we write the cost function as
∫︁ ∞
𝐽= (𝜉 𝑇 𝑄𝜉 𝜉 + 𝑣 𝑇 𝑄𝑣 𝑣)𝑑𝑡,
0
where 𝜉 = 𝑧 − 𝑧𝑒 and 𝑣 = 𝑢 − 𝑢𝑒 represent the local coordinates around the desired equilibrium point (𝑧𝑒 , 𝑢𝑒 ). We
begin with diagonal matrices for the state and input costs:
This gives a control law of the form 𝑣 = −𝐾𝜉, which can then be used to derive the control law in terms of the original
variables:
𝑢 = 𝑣 + 𝑢𝑒 = −𝐾(𝑧 − 𝑧𝑑 ) + 𝑢𝑑 .
𝑤ℎ𝑒𝑟𝑒 : 𝑚𝑎𝑡ℎ : ‘𝑢𝑒 = (0, 𝑚𝑔)‘𝑎𝑛𝑑 : 𝑚𝑎𝑡ℎ : ‘𝑧𝑑 = (𝑥𝑑 , 𝑦𝑑 , 0, 0, 0, 0)‘
The way we setup the dynamics above, 𝐴 is already hardcoding 𝑢𝑑 , so we don’t need to include it as an external input.
So we just need to cascade the −𝐾(𝑧 − 𝑧𝑑 ) controller with the PVTOL aircraft’s dynamics to control it. For didactic
purposes, we will cheat in two small ways:
• First, we will only interface our controller with the linearized dynamics. Using the nonlinear dynamics would
require the NonlinearIOSystem functionalities, which we leave to another notebook to introduce.
2. Second, as written, our controller requires full state feedback (𝐾 multiplies full state vectors 𝑧), which we do
not have access to because our system, as written above, only returns 𝑥 and 𝑦 (because of 𝐶 matrix). Hence, we
would need a state observer, such as a Kalman Filter, to track the state variables. Instead, we assume that we
have access to the full state.
The following code implements the closed loop system:
[6]: # Our input to the system will only be (x_d, y_d), so we need to
# multiply it by this matrix to turn it into z_d.
Xd = matrix([[1,0,0,0,0,0],
[0,1,0,0,0,0]]).T
[7]: plot(t,x,'-',t,y,'--')
plot([0, 10], [1, 1], 'k-')
ylabel('Position')
xlabel('Time (s)')
title('Step Response for Inputs')
legend(('Yx', 'Yy'), loc='lower right')
show()
The plot above shows the 𝑥 and 𝑦 positions of the aircraft when it is commanded to move 1 m in each direction. The
following shows the 𝑥 motion for control weights 𝜌 = 1, 102 , 104 . A higher weight of the input term in the cost
function causes a more sluggish response. It is created using the code:
[9]: plot(T1, Y1.T, 'b-', T2, Y2.T, 'r-', T3, Y3.T, 'g-')
plot([0 ,10], [1, 1], 'k-')
title('Step Response for Inputs')
ylabel('Position')
xlabel('Time (s)')
legend(('Y1','Y2','Y3'),loc='lower right')
axis([0, 10, -0.1, 1.4])
show()
This section demonstrates the design of loop shaping controller for the vectored thrust aircraft example. This example
is pulled from Chapter 11 (Frequency Domain Design) of Astrom and Murray.
To design a controller for the lateral dynamics of the vectored thrust aircraft, we make use of a “inner/outer” loop
design methodology. We begin by representing the dynamics using the block diagram
where
The controller is constructed by splitting the process dynamics and controller into two components: an inner loop
consisting of the roll dynamics 𝑃𝑖 and control 𝐶𝑖 and an outer loop consisting of the lateral position dynamics 𝑃𝑜 and
controller 𝐶𝑜 .
The closed
inner loop dynamics 𝐻𝑖 control the roll angle of the aircraft using the vectored thrust while the outer loop controller
𝐶𝑜 commands the roll angle to regulate the lateral position.
The following code imports the libraries that are required and defines the dynamics:
[14]: k = 200
a = 2
b = 50
Ci = k*tf([1, a], [1, b]) # lead compensator
Li = Pi*Ci
The performance of the system can be characterized using the sensitivity function and the complementary sensitivity
function:
[17]: L = Co*Hi*Po
S = feedback(1, L)
T = feedback(L, 1)
The frequency response and Nyquist plot for the loop transfer function are computed using the commands
[19]: bode(L)
show()
• genindex
Development
You can check out the latest version of the source code with the command:
You can run a set of unit tests to make sure that everything is working correctly. After installation, run:
Your contributions are welcome! Simply fork the GitHub repository and send a pull request.
Links
c
control, 11
control.flatsys, 113
control.iosys, 129
control.matlab, 81
211
Python Control Library Documentation, Release dev
213
Python Control Library Documentation, Release dev
214 Index
Python Control Library Documentation, Release dev
Index 215
Python Control Library Documentation, Release dev
216 Index
Python Control Library Documentation, Release dev
U
unwrap() (in module control), 54
unwrap() (in module control.matlab), 111
use_fbs_defaults() (in module control), 8
use_matlab_defaults() (in module control), 9
use_numpy_matrix() (in module control), 9
Z
zero() (control.flatsys.LinearFlatSystem method), 126
zero() (control.iosys.LinearIOSystem method), 74
zero() (control.StateSpace method), 64
zero() (control.TransferFunction method), 60
zero() (in module control), 31
zero() (in module control.matlab), 93
Index 217