Developer Notes
This chapter contains notes for developers who wish to contribute to the Python Control Systems Library (python-control). It is mainly a listing of the practices that have evolved over the course of development since the package was created in 2009.
Package Structure
The python-control package is maintained on GitHub, with documentation hosted by ReadTheDocs and a mailing list on SourceForge:
Project home page: https://python-control.org
Source code repository: https://github.com/python-control/python-control
Documentation: https://python-control.readthedocs.io/
Issue tracker: https://github.com/python-control/python-control/issues
Mailing list: https://sourceforge.net/p/python-control/mailman/
- GitHub repository file and directory layout:
python-control/ - main repository
LICENSE, Manifest, pyproject.toml, README.rst - package information
control/ - primary package source code
__init__.py, _version.py, config.py - package definition and configuration
iosys.py, nlsys.py, lti.py, statesp.py, xferfcn.py, frdata.py - I/O system classes
bdalg.py, delay.py, canonical.py, margins.py, sysnorm.py, modelsimp.py, passivity.py, robust.py, statefbk.py, stochsys.py - analysis and synthesis routines
ctrlplot.py, descfcn.py, freqplot.py, grid.py, nichols.py, pzmap.py, rlocus.py, sisotool.py, timeplot.py, timeresp.py - response and plotting routines
ctrlutil.py, dtime.py, exception.py, mateqn.py - utility functions
phaseplot.py - phase plot module
optimal.py - optimal control module
flatsys/ - flat systems subpackage
__init__.py, basis.py, bezier.py, bspline.py, flatsys.py, linflat.py, poly.py, systraj.py - subpackage files
matlab/ - MATLAB compatibility subpackage
__init__.py, timeresp.py, wrappers.py - subpackage files
tests/ - unit tests
.github/ - GitHub workflows
benchmarks/ - benchmarking files (not well-maintained)
doc/ - user guide and reference manual
index.rst - main documentation index
conf.py, Makefile - sphinx configuration files
intro.rst, linear.rst, statesp.rst, xferfcn.rst, nonlinear.rst, flatsys.rst, iosys.rst, nlsys.rst, optimal.rst, phaseplot.rst, response.rst, descfcn.rst, stochastic.rst, examples.rst - User Guide
functions.rst, classes.rst, config.rst, matlab.rst, develop.rst - Reference Manual
examples/
*.py, *.rst - Python scripts (linked to ../examples/*.py)
*.ipynb - Jupyter notebooks (linked to ../examples.ipynb)
figures/
*.pdf, *.png - Figures for inclusion in documentation
examples/
*.py - Python scripts
*.ipynb - Jupyter notebooks
Naming Conventions
Generally speaking, standard Python and NumPy naming conventions are used throughout the package.
Python PEP 8 (code style): https://peps.python.org/pep-0008/
Filenames
Source files are lower case, usually less than 10 characters (and 8 or less is better).
Unit tests (in
control/tests/
) are of the formmodule_test.py
ormodule_function.py
.
Class names
Most class names are in camel case, with long form descriptions of the object purpose/contents (
TimeResponseData
).Input/output class names are written out in long form as they aren’t too long (
StateSpace
,TransferFunction
), but for very long names ‘IO’ can be used in place of ‘InputOutput’ (NonlinearIOSystem
) and ‘IC’ can be used in place of ‘Interconnected’ (LinearICSystem
).Some older classes don’t follow these guidelines (e.g.,
LTI
instead ofLinearTimeInvariantSystem
orLTISystem
).
Function names
Function names are lower case with words separated by underscores.
Function names usually describe what they do (
create_statefbk_iosystem
,find_operating_points
) or what they generate (input_output_response
,find_operating_point
).Some abbreviations and shortened versions are used when names get very long (e.g.,
create_statefbk_iosystem
instead ofcreate_state_feedback_input_output_system
.Factory functions for I/O systems use short names (partly from MATLAB conventions, partly because they are pretty frequently used):
frd
,flatsys
,nlsys
,ss
, andtf
.Short versions of common commands with longer names are created by creating an object with the shorter name as a copy of the main object:
bode = bode_plot
,step = step_response
, etc.The MATLAB compatibility library (
control.matlab
) uses names that try to line up with MATLAB (e.g.,lsim
instead offorced_response
).
Parameter names
Parameter names are not (yet) very uniform across the package. A few general patterns are emerging:
Use longer description parameter names that describe the action or role (e.g.,
trajectory_constraints
andprint_summary
inoptimal.solve_optimal_trajectory
.
System-creating commands:
Commands that create an I/O system should allow the use of the following standard parameters:
name
: system nameinputs
,outputs
,states
: number or names of inputs, outputs, stateinput_prefix
,output_prefix
,state_prefix
: change the default prefixes used for naming signals.dt
: set the timebase. This one takes a bit of care, since if it is not specified then it defaults toconfig.defaults['control.default_dt']
. This is different than settingdt
= None, sodt
should always be part of**kwargs
.
These keywords can be parsed in a consistent way using the
iosys._process_iosys_keywords
function.
System arguments:
sys
when an argument is a single input/output system (e.g.bandwidth
).syslist
when an argument is a list of systems (e.g.,interconnect
). A single system should also be OK.sysdata
when an argument can either be a system, a list of systems, or data describing a response (e.g,nyquist_response
).Todo
For a future release (v 0.11.x?) we should make this more consistent across the package.
Signal arguments:
Factory functions use
inputs
,outputs
, andstates
to provide either the number of each signal or a list of labels for the signals.
Order of arguments for functions taking inputs, outputs, state, time, frequency, etc:
The default order for providing arguments in state space models is
(t, x, u, params)
. This is the generic order that should be used in functions that take signals as parameters, but permuted so that required arguments go first, common arguments go next (as keywords, in the order listed above if they also work as positional arguments), and infrequent arguments go last (in order listed above). For example:def model_update(t, x, u, params) resp = initial_response(sys, timepts, x0) # x0 required resp = input_output_response(sys, timepts, u, x0) # u required resp = TimeResponseData( timepts, outputs, states=states, inputs=inputs)
In the last command, note that states precedes inputs because not all TimeResponseData elements have inputs (e.g.,
initial_response
).The default order for providing arguments in the frequency domain is system/response first, then frequency:
resp = frequency_response(sys, omega) sys_frd = frd(sys_tf, omega) sys = frd(response, omega)
Time and frequency responses:
Use
timepts
for lists of times andomega
for lists of frequencies at which systems are evaluated. For example:ioresp = ct.input_output_response(sys, timepts, U) cplt = ct.bode_plot(sys, omega)
Use
inputs
,outputs
,states
,time
for time response data attributes. These should be used as parameter names when creatingTimeResponseData
objects and also as attributes when retrieving response data (with dimensions dependent onsqueeze
processing). These are stored internally in non-squeezed form usingu
,y
,x
, andt
, but the internal data should generally not be accessed directly. For example:plt.plot(ioresp.time, ioresp.outputs[0]) tresp = ct.TimeResponseData(time, outputs, states, ...) # (internal call)
Note that the use of
inputs
,outputs
, andstates
for both factory function specifications as well as response function attributes is a bit confusing.
Use
frdata
,omega
for frequency response data attributes. These should be used as parameter names when creatingFrequencyResponseData
objects and also as attributes when retrieving response data. Thefrdata
attribute is stored as a 3D array indexed by outputs, inputs, frequency.Use
complex
,magnitude
,phase
for frequency response data attributes with squeeze processing. For example:ax = plt.subplots(2, 1) ax[0].loglog(fresp.omega, fresp.magnitude) ax[1].semilogx(fresp.omega, fresp.phase)
The frequency response is stored internally in non-squeezed form as
fresp
, but this is generally not accessed directly by users.Note that when creating time response data the independent variable (time) is the first argument whereas for frequency response data the independent variable (omega) is the second argument. This is because we also create frequency response data from a linear system using a call
frd(sys, omega)
, and rename frequency response data using a callfrd(sys, name='newname')
, so the system/data need to be the first argument. For time response data we use the convention that we start with time and then list the arguments in the most frequently used order.
Use
response
orresp
for generic response objects (time, frequency, describing function, Nyquist, etc).Note that when responses are evaluated as tuples, the ordering of the dependent and independent variables switches between time and frequency domain:
t, y = ct.step_response(sys) mag, phase, omega = ct.frequency_response(sys)
To avoid confusion, it is better to use response objects:
tresp = ct.step_response(sys) t, y = tresp.time, tresp.outputs fresp = ct.frequency_response(sys) omega, response = fresp.omega, fresp.response mag, phase, omega = fresp.magnitude, fresp.phase, fresp.omega
Parameter aliases
As described above, parameter names are generally longer strings that
describe the purpose of the parameter. Similar to matplotlib
(e.g.,
the use of lw
as an alias for linewidth
), some commonly used
parameter names can be specified using an “alias” that allows the use
of a shorter key.
Named parameter and keyword variable aliases are processed using the
config._process_kwargs()
and config._process_param()
functions. These functions allow the specification of a list of
aliases and a list of legacy keys for a given named parameter or
keyword. To make use of these functions, the
_process_kwargs()
is first called to update the kwargs
variable by replacing aliases with the full key:
_process_kwargs(kwargs, aliases)
The values for named parameters can then be assigned to a local
variable using a call to _process_param()
of the form:
var = _process_param('param', param, kwargs, aliases)
where param
is the named parameter used in the function signature
and var is the local variable in the function (may also be param
,
but doesn’t have to be).
For example, the following structure is used in input_output_response
:
def input_output_response(
sys, timepts=None, inputs=0., initial_state=0., params=None,
ignore_errors=False, transpose=False, return_states=False,
squeeze=None, solve_ivp_kwargs=None, evaluation_times='T', **kwargs):
"""Compute the output response of a system to a given input.
... rest of docstring ...
"""
_process_kwargs(kwargs, _timeresp_aliases)
T = _process_param('timepts', timepts, kwargs, _timeresp_aliases)
U = _process_param('inputs', inputs, kwargs, _timeresp_aliases, sigval=0.)
X0 = _process_param(
'initial_state', initial_state, kwargs, _timeresp_aliases, sigval=0.)
Note that named parameters that have a default value other than None
must given the signature value (sigval
) so that
_process_param
can detect if the value has been set (and
issue an error if there is an attempt to set the value multiple times
using alias or legacy keys).
The alias mapping is a dictionary that returns a tuple consisting of valid aliases and legacy aliases:
alias_mapping = {
'argument_name_1': (['alias', ...], ['legacy', ...]),
...}
If an alias is present in the dictionary of keywords, it will be used to set the value of the argument. If a legacy keyword is used, a warning is issued.
The following tables summarize the aliases that are currently in use through the python-control package:
Time response aliases (via timeresp._timeresp_aliases
):
Key
Aliases
Legacy keys
Comment
evaluation_times
t_eval
List of times to evaluate the time response (defaults to
timepts
).final_output
yfinal
Final value of the output (used for
step_info()
)initial_state
X0
x0
Initial value of the state variable.
input_indices
input
Index(es) to use for the input (used in
step_response()
,impulse_response()
.inputs
U
u
Value(s) of the input variable (time trace or individual point).
output_indices
output
Index(es) to use for the output (used in
step_response()
,impulse_response()
.outputs
Y
y
Value(s) of the output variable (time trace or individual point).
return_states
return_x
Return the state when accessing a response via a tuple.
timepts
T
List of time points for time response functions.
timepts_num
T_num
Number of points to use (e.g., if
timepts
is just the final time).
Optimal control aliases (via optimal._optimal_aliases
:
Key
Aliases
Comment
final_state
xf
Final state for trajectory generation problems (flatsys, optimal).
final_input
uf
Final input for trajectory generation problems (flatsys).
initial_state
x0, X0
Initial state for optimization problems (flatsys, optimal).
initial_input
u0, U0
Initial input for trajectory generation problems (flatsys).
initial_time
T0
Initial time for optimization problems.
integral_cost
trajectory_cost, cost
Cost function that is integrated along a trajectory.
return_states
return_x
Return the state when accessing a response via a tuple.
trajectory_constraints
constraints
List of constraints that hold along a trajectory (flatsys, optimal)
Documentation Guidelines
The python-control package is documented using docstrings and Sphinx.
Reference documentation (class and function descriptions, with details
on parameters) should all go in docstrings. User documentation in
more narrative form should be in the rst
files in doc/
, where it
can be incorporated into the User Guide. All significant
functionality should have a narrative description in the User Guide in
addition to docstrings.
Generally speaking, standard Python and NumPy documentation conventions are used throughout the package:
Python PEP 257 (docstrings): https://peps.python.org/pep-0257/
Numpydoc Style guide: https://numpydoc.readthedocs.io/en/latest/format.html
General docstring info
The guiding principle used to guide how docstrings are written is similar to NumPy (as articulated in the numpydoc style guide):
A guiding principle is that human readers of the text are given precedence over contorting docstrings so our tools produce nice output. Rather than sacrificing the readability of the docstrings, we have written pre-processors to assist Sphinx in its task.
To that end, docstrings in python-control
should use the following
guidelines:
Use single backticks around all Python objects. The Sphinx configuration file (
doc/conf.py
) definesdefault_role
to bepy:obj
, so everything in a single backtick will be rendered in code form and linked to the appropriate documentation if it exists.Note: consistent with numpydoc recommendations, parameters names for functions should be in single backticks, even though they don’t generate a link (but the font will still be OK).
The
doc/_static/custom.css
file defines the style for Python objects and is configured so that linked objects will appear in a bolder type, so that it is easier to see what things you can click on to get more information.By default, the string `sys` in docstrings would normally generate a link to the
sys
Python module. To avoid this,conf.py
includes code that converts `sys` in docstrings to :code:`sys`, which renders assys
(code style, with no link). In.rst
files this construction should be done manually, since.rst
files are not pre-processed as a docstring.
Use double backticks for inline code, such as a Python code fragments.
In principle single backticks might actually work OK given the way that the
py:obj
processing works in Sphinx, but the inclusion of code is somewhat rare and the extra two backticks seem like a small sacrifice (and far from a “contortion”).
Avoid the use of backticks and :math: for simple formulas where the additional annotation or formatting does not add anything. For example “-c <= x <= c” (without the double quotes) in
relay_hysteresis_nonlinearity
.Some of these formulas might be interpreted as Python code fragments, but they only need to be in double quotes if that makes the documentation easier to understand.
Examples:
`dt` > 0 not ``dt > 0`` (
dt
is a parameter)`squeeze` = True not ``squeeze = True`` nor squeeze = True.
-c <= x <= c not ``-c <= x <= c`` nor :math:`-c \leq x \leq c`.
:math:`|x| < \epsilon` (becomes
)
Built-in Python objects (True, False, None) should be written with no backticks and should be properly capitalized.
Another possibility here is to use a single backtick around built-in objects, and the
py:obj
processing will then generate a link back to the primary Python documentation. That seems distracting for built-ins likeTrue
,False
andNone
(written here in single backticks) and using double backticks looks fine in Sphinx (True
,False
,None
), but seemed to cross the “contortions” threshold.
Strings used as arguments to parameters should be in single (forward) ticks (‘eval’, ‘rows’, etc) and don’t need to be rendered as code if just listed as part of a docstring.
The rationale here is similar to built-ins: adding 4 backticks just to get them in a code font seems unnecessary.
Note that if a string is included in Python assignment statement (e.g.,
method='slycot'
) it looks quite ugly in text form to have it enclosed in double backticks (``method=’slycot’``), so OK to use method=’slycot’ (no backticks) ormethod
= ‘slycot’ (backticks with extra spaces).
References to the
defaults
dictionary should be of the form `config.defaults[‘module.param’]` (like a parameter), which renders asconfig.defaults['module.param']
in Sphinx.It would be nice to have the term show up as a link to the documentation for that parameter (in the Package Configuration Parameters section of the Reference Manual), but the special processing to do that hasn’t been implemented.
Depending on placement, you can end up with lots of white space around defaults parameters (also true in the docstrings).
Math formulas can be written as plain text unless the require special symbols (this is consistent with numpydoc) or include Python code. Use the
:math:
directive to handle symbols.
Examples of different styles:
Single backticks to a a function:
interconnect
Single backticks to a parameter (no link):
squeeze
Double backticks to a code fragment:
subsys = sys[i][j]
.Built-in Python objects: True, False, None
Defaults parameter:
config.defaults['control.squeeze_time_response']
Inline math:
Function docstrings
Follow numpydoc format with the following additional details:
All functions should have a short (< 64 character) summary line that starts with a capital letter and ends with a period.
All parameter descriptions should start with a capital letter and end with a period. An exception is parameters that have a list of possible values, in which case a phrase sending in a colon (:) followed by a list (without punctuation) is OK.
All parameters and keywords must be documented. The
docstrings_test.py
unit test tries to flag as many of these as possible.Include an “Examples” section for all non-trivial functions, in a form that can be checked by running
make doctest
in thedoc
directory. This is also part of the CI checks.
For functions that return a named tuple, bundle object, or class instance, the return documentation should include the primary elements of the return value:
Returns
-------
resp : `TimeResponseData`
Input/output response data object. When accessed as a tuple, returns
``time, outputs`` (default) or ``time, outputs, states`` if
`return_states` is True. The `~TimeResponseData.plot` method can be
used to create a plot of the time response(s) (see `time_response_plot`
for more information).
resp.time : array
Time values of the output.
resp.outputs : array
Response of the system. If the system is SISO and `squeeze` is not
True, the array is 1D (indexed by time). If the system is not SISO or
`squeeze` is False, the array is 2D (indexed by output and time).
resp.states : array
Time evolution of the state vector, represented as a 2D array indexed by
state and time.
resp.inputs : array
Input(s) to the system, indexed by input and time.
Class docstrings
Follow numpydoc format with the follow additional details:
Parameters used in creating an object go in the class docstring and not in the
__init__
docstring (which is not included in the Sphinx-based documentation). OK for the__init__
function to have no docstring.Parameters that are also attributes only need to be documented once (in the “Parameters” or “Additional Parameters” section of the class docstring).
Attributes that are created within a class and that might be of interest to the user should be documented in the “Attributes” section of the class docstring.
Classes should not include a “Returns” section (since they always return an instance of the class).
Functions and attributes that are not intended to be accessed by users should start with an underscore.
I/O system classes:
Subclasses of
InputOutputSystem
should always have a factory function that is used to create them. The class documentation only needs to document the required parameters; the full list of parameters (and optional keywords) can and should be documented in the factory function docstring.
User Guide
The purpose of the User Guide is provide a narrative description of the key functions of the package. It is not expected to cover every command, but should allow someone who knows about control system design to get up and running quickly.
The User Guide consists of chapters that are each their own separate
rst
file and each of them generates a separate page. Chapters are
divided into sections whose names appear in the index on the left of
the web page when that chapter is being viewed. In some cases a
section may be in its own file, included in the chapter page by using
the include
directive (see nlsys.py
for an example).
Sphinx files guidelines:
Each file should declare the
currentmodule
at or near the top of the file. Except for subpackages (control.flatsys
) and modules that need to be imported separately (control.optimal
),currentmodule
should be set to control.When possible, sample code in the User Guide should use Sphinx doctest directives so that the code is executed by
make doctest
. Two styles are possible: doctest-style blocks (showing code with a prompt and the expected response) and code blocks (using thetestcode
directive).When referring to the python-control package, several different forms can be used:
Full name: “the Python Control Systems Library (python-control)” (used sparingly, mainly at the tops of chapters).
Adjective form: “the python-control package” or “a python-control module” (this is the most common form).
Noun form: “
python-control
” (only used occasionally).
Unlike docstrings, the documentation in the User Guide should use backticks and :math: more liberally when it is appropriate to highlight/format code properly. However, Python built-ins should still just be written as True, False, and None (no backticks), for formatting consistency.
The Sphinx documentation is not read in “raw” form, so OK to add the additional annotations.
The Python built-ins occur frequently and are capitalized, and so the additional formatting doesn’t add much and would be inconsistent if you jump from the User Guide to the Reference Manual (e.g., to look at a function more closely via a link in the User Guide).
Reference Manual
The Reference Manual should provide a fairly comprehensive description of every class, function, and configuration variable in the package. All primary functions and classes bust be included here, since the Reference Manual generates the stub files used by Sphinx.
Modules and subpackages
When documenting (independent) modules and subpackages (refereed to here collectively as modules), use the following guidelines for documentation:
In module docstrings, refer to module functions and classes without including the module prefix. This will let Sphinx set up the links to the functions in the proper way and has the advantage that it keeps the docstrings shorter.
Objects in the parent (
control
) package should be referenced using thecontrol
prefix, so that Sphinx generates the links properly (otherwise it only looks within the package).In the User Guide, set
currentmodule
tocontrol
and refer to the module objects using the prefixprefix
in the text portions of the document butpx
(shortened prefix) in the code sections. This will let users copy and past code from the examples and is consistent with the use of thect
short prefix. Since this is in the User Guide, the additional characters are not as big an issue.If you include an
autosummary
of functions in the User Guide section, list the functions using the regular prefix (without~
) to remind everyone the function is in a module.When referring to a module function or class in a docstring or User Guide section that is not part of the module, use the fully qualified function or class ('prefix.function').
The main overarching principle should be to make sure that references to objects that have more detailed information should show up as a link, not as code.
Utility Functions
The following utility functions can be used to help with standard processing and parsing operations:
|
Utility function for processing legacy keywords. |
|
Process aliases and legacy keywords. |
|
Process named parameter, checking aliases and legacy usage. |
Return True if cvxopt is installed, otherwise False. |
|
Return True if pandas is installed, otherwise False. |
|
Return True if Slycot is installed, otherwise False. |
|
|
Process iosys specification. |
|
Check the shape and properties of a 2D array. |
|
Convert a system to state space form (if needed). |
|
Convert argument to a (possibly empty) 2D state space matrix. |
|
Convert a system to transfer function form (if needed). |
Sample Files
Code template
The following file is a template for a python-control module. It can
be found in python-control/doc/examples/template.py
.
1# template.py - template file for python-control module
2# RMM, 3 Jan 2024
3
4"""Template file for python-control module.
5
6This file provides a template that can be used when creating a new
7file/module in python-control. The key elements of a module are included
8in this template, following the suggestions in the Developer Guidelines.
9
10The first line of a module file should be the name of the file and a short
11description. The next few lines can contain information about who created
12the file (your name/initials and date). For this file I used the short
13version (initials, date), but a longer version would be to do something of
14the form::
15
16 # filename.py - short one line description
17 #
18 # Initial author: Full name
19 # Creation date: date the file was created
20
21After the header comments, the next item is the module docstring, which
22should be a multi-line comment, like this one. The first line of the
23comment is a one line summary phrase, starting with a capital letter and
24ending in a period (often the same as the line at the very top). The rest
25of the docstring is an extended summary (this one is a bit longer than
26would be typical).
27
28After the docstring, you should have the following elements (in Python):
29
30 * Package imports, using the `isort -m2` format (library, standard, custom)
31 * __all__ command, listing public objects in the file
32 * Class definitions (if any)
33 * Public function definitions
34 * Internal function definitions (starting with '_')
35 * Function aliases (short = long_name)
36
37The rest of this file contains examples of these elements.
38
39"""
40
41import warnings # Python packages
42
43import numpy as np # Standard external packages
44
45from . import config # Other modules/packages in python-control
46from .lti import LTI # Public function or class from a module
47
48__all__ = ['SampleClass', 'sample_function']
49
50
51class SampleClass():
52 """Sample class in the python-control package.
53
54 This is an example of a class definition. The docstring follows
55 numpydoc format. The first line should be a summary (which will show
56 up in `autosummary` entries in the Sphinx documentation) and then an
57 extended summary describing what the class does. Then the usual
58 sections, per numpydoc.
59
60 Additional guidelines on what should be listed in the various sections
61 can be found in the 'Class docstrings' section of the Developer
62 Guidelines.
63
64 Parameters
65 ----------
66 sys : InputOutputSystem
67 Short description of the parameter.
68
69 Attributes
70 ----------
71 data : array
72 Short description of an attribute.
73
74 """
75 def __init__(self, sys):
76 # No docstring required here
77 self.sys = sys # Parameter passed as argument
78 self.data = sys.name # Attribute created within class
79
80 def sample_method(self, data):
81 """Sample method within a class.
82
83 This is an example of a method within a class. Document using
84 numpydoc format.
85
86 """
87 return None
88
89
90def sample_function(data, option=False, **kwargs):
91 """Sample function in the template module.
92
93 This is an example of a public function within the template module.
94 This function will usually be placed in the `control` namespace by
95 updating `__init__.py` to import the function (often by importing the
96 entire module).
97
98 Docstring should be in standard numpydoc format. The extended summary
99 (this text) should describe the basic operation of the function, with
100 technical details in the "Notes" section.
101
102 Parameters
103 ----------
104 data : array
105 Sample parameter for sample function, with short docstring.
106 option : bool, optional
107 Optional parameter, with default value `False`.
108
109 Returns
110 -------
111 out : float
112 Short description of the function output.
113
114 Additional Parameters
115 ---------------------
116 inputs : int, str, or list of str
117 Parameters that are less commonly used, in this case a keyword
118 parameter.
119
120 See Also
121 --------
122 function1, function2
123
124 Notes
125 -----
126 This section can contain a more detailed description of how the system
127 works. OK to include some limited mathematics, either via inline math
128 directions for a short formula (like this: ..math:`x = \alpha y`) or via a
129 displayed equation:
130
131 ..math::
132
133 a = \int_0^t f(t) dt
134
135 The trick in the docstring is to write something that looks good in
136 pure text format but is also processed by sphinx correctly.
137
138 If you refer to parameters, such as the `data` argument to this
139 function, but them in single backticks (which will render them in code
140 style in Sphinx). Strings that should be interpreted as Python code
141 use double backticks: ``mag, phase, omega = response``. Python
142 built-in objects, like True, False, and None are written on their own.
143
144 """
145 inputs = kwargs['inputs']
146 if option is True:
147 return data
148 else:
149 return None
150
151#
152# Internal functions
153#
154# Functions that are not intended for public use can go anyplace, but I
155# usually put them at the bottom of the file (out of the way). Their name
156# should start with an underscore. Docstrings are optional, but if you
157# don't include a docstring, make sure to include comments describing how
158# the function works.
159#
160
161
162# Sample internal function to process data
163def _internal_function(data):
164 return None
165
166
167# Aliases (short versions of long function names)
168sf = sample_function
Documentation template
The following file is a template for a documentation file. It can be
found in python-control/doc/examples/template.rst
.
1.. currentmodule:: control
2
3**************
4Sample Chapter
5**************
6
7This is an example of a top-level documentation file, which serves a
8chapter in the User Guide or Reference Manual in the Sphinx
9documentation. It is not that likely we will create a lot more files
10of this sort, so it is probably the internal structure of the file
11that is most useful.
12
13The file in which a chapter is contained will usual start by declaring
14`currentmodule` to be `control`, which will allow text enclosed in
15backticks to be searched for class and function names and appropriate
16links inserted. The next element of the file is the chapter name,
17with asterisks above and below. Chapters should have a capitalized
18title and an introductory paragraph. If you need to add a reference
19to a chapter, insert a sphinx reference (`.. _ch-sample:`) above
20the chapter title.
21
22.. _sec-sample:
23
24Sample Section
25==============
26
27A chapter is made of up of multiple sections. Sections use equal
28signs below the section title. Following FBS2e, the section title
29should be capitalized. If you need to insert a reference to the
30section, put that above the section title (`.. _sec-sample:`), as
31shown here.
32
33
34Sample subsection
35-----------------
36
37Subsections use dashes below the subsection title. The first word of
38the title should be capitalized, but the rest of the subsection title
39is lower case (unless it has a proper noun). I usually leave two
40blank lines before the start up a subection and one blank line after
41the section markers.
42
43
44Mathematics
45-----------
46
47Mathematics can be uncluded using the `math` directive. This can be
48done inline using `:math:short formula` (e.g. :math:`a = b`) or as a
49displayed equation, using the `.. math::` directive::
50
51.. math::
52
53 a(t) = \int_0^t b(\tau) d\tau
54
55
56Function summaries
57------------------
58
59Use the `autosummary` directive to include a table with a list of
60function sinatures and summary descriptions::
61
62.. autosummary::
63
64 input_output_response
65 describing_function
66 some_other_function
67
68
69Module summaries
70----------------
71
72If you have a docstring at the top of a module that you want to pull
73into the documentation, you can do that with the `automodule`
74directive:
75
76.. automodule:: control.optimal
77 :noindex:
78 :no-members:
79 :no-inherited-members:
80 :no-special-members:
81
82.. currentmodule:: control
83
84The `:noindex:` option gets rid of warnings about a module being
85indexed twice. The next three options are used to just bring in the
86summary and extended summary in the module docstring, without
87including all of the documentation of the classes and functions in the
88module.
89
90Note that we `automodule` will set the current module to the one for
91which you just generated documentation, so the `currentmodule` should
92be reset to control afterwards (otherwise references to functions in
93the `control` namespace won't be recognized.