|
| 1 | +.. _conventions-ref: |
| 2 | + |
| 3 | +.. currentmodule:: control |
| 4 | + |
| 5 | +******************* |
| 6 | +Library conventions |
| 7 | +******************* |
| 8 | + |
| 9 | +The python-control library uses a set of standard conventions for the |
| 10 | +way that different types of standard information used by the library. |
| 11 | +Throughout this manual, we assume the `control` package has been |
| 12 | +imported as `ct`. |
| 13 | + |
| 14 | +LTI system representation |
| 15 | +========================= |
| 16 | + |
| 17 | +Linear time invariant (LTI) systems are represented in python-control in |
| 18 | +state space, transfer function, or frequency response data (FRD) form. Most |
| 19 | +functions in the toolbox will operate on any of these data types, and |
| 20 | +functions for converting between compatible types are provided. |
| 21 | + |
| 22 | +State space systems |
| 23 | +------------------- |
| 24 | +The :class:`StateSpace` class is used to represent state-space realizations |
| 25 | +of linear time-invariant (LTI) systems: |
| 26 | + |
| 27 | +.. math:: |
| 28 | +
|
| 29 | + \frac{dx}{dt} &= A x + B u \\ |
| 30 | + y &= C x + D u |
| 31 | +
|
| 32 | +where u is the input, y is the output, and x is the state. |
| 33 | + |
| 34 | +To create a state space system, use the :func:`ss` function:: |
| 35 | + |
| 36 | + sys = ct.ss(A, B, C, D) |
| 37 | + |
| 38 | +State space systems can be manipulated using standard arithmetic operations |
| 39 | +as well as the :func:`feedback`, :func:`parallel`, and :func:`series` |
| 40 | +function. A full list of functions can be found in :ref:`function-ref`. |
| 41 | + |
| 42 | +Transfer functions |
| 43 | +------------------ |
| 44 | +The :class:`TransferFunction` class is used to represent input/output |
| 45 | +transfer functions |
| 46 | + |
| 47 | +.. math:: |
| 48 | +
|
| 49 | + G(s) = \frac{\text{num}(s)}{\text{den}(s)} |
| 50 | + = \frac{a_0 s^m + a_1 s^{m-1} + \cdots + a_m} |
| 51 | + {b_0 s^n + b_1 s^{n-1} + \cdots + b_n}, |
| 52 | +
|
| 53 | +where n is generally greater than or equal to m (for a proper transfer |
| 54 | +function). |
| 55 | + |
| 56 | +To create a transfer function, use the :func:`tf` function:: |
| 57 | + |
| 58 | + sys = ct.tf(num, den) |
| 59 | + |
| 60 | +Transfer functions can be manipulated using standard arithmetic operations |
| 61 | +as well as the :func:`feedback`, :func:`parallel`, and :func:`series` |
| 62 | +function. A full list of functions can be found in :ref:`function-ref`. |
| 63 | + |
| 64 | +Frequency response data (FRD) systems |
| 65 | +------------------------------------- |
| 66 | +The :class:`FrequencyResponseData` (FRD) class is used to represent systems in |
| 67 | +frequency response data form. |
| 68 | + |
| 69 | +The main data members are `omega` and `fresp`, where `omega` is a 1D array |
| 70 | +with the frequency points of the response, and `fresp` is a 3D array, with |
| 71 | +the first dimension corresponding to the output index of the system, the |
| 72 | +second dimension corresponding to the input index, and the 3rd dimension |
| 73 | +corresponding to the frequency points in omega. |
| 74 | + |
| 75 | +FRD systems can be created with the :func:`~control.frd` factory function. |
| 76 | +Frequency response data systems have a somewhat more limited set of |
| 77 | +functions that are available, although all of the standard algebraic |
| 78 | +manipulations can be performed. |
| 79 | + |
| 80 | +The FRD class is also used as the return type for the |
| 81 | +:func:`frequency_response` function (and the equivalent method for the |
| 82 | +:class:`StateSpace` and :class:`TransferFunction` classes). This |
| 83 | +object can be assigned to a tuple using:: |
| 84 | + |
| 85 | + mag, phase, omega = response |
| 86 | + |
| 87 | +where `mag` is the magnitude (absolute value, not dB or log10) of the |
| 88 | +system frequency response, `phase` is the wrapped phase in radians of |
| 89 | +the system frequency response, and `omega` is the (sorted) frequencies |
| 90 | +at which the response was evaluated. If the system is SISO and the |
| 91 | +`squeeze` argument to :func:`frequency_response` is not True, |
| 92 | +`magnitude` and `phase` are 1D, indexed by frequency. If the system |
| 93 | +is not SISO or `squeeze` is False, the array is 3D, indexed by the |
| 94 | +output, input, and frequency. If `squeeze` is True then |
| 95 | +single-dimensional axes are removed. The processing of the `squeeze` |
| 96 | +keyword can be changed by calling the response function with a new |
| 97 | +argument:: |
| 98 | + |
| 99 | + mag, phase, omega = response(squeeze=False) |
| 100 | + |
| 101 | +Frequency response objects are also available as named properties of the |
| 102 | +``response`` object: ``response.magnitude``, ``response.phase``, and |
| 103 | +``response.response`` (for the complex response). For MIMO systems, these |
| 104 | +elements of the frequency response can be accessed using the names of the |
| 105 | +inputs and outputs:: |
| 106 | + |
| 107 | + response.magnitude['y[0]', 'u[1]'] |
| 108 | + |
| 109 | +where the signal names are based on the system that generated the frequency |
| 110 | +response. |
| 111 | + |
| 112 | +Note: The ``fresp`` data member is stored as a NumPy array and cannot be |
| 113 | +accessed with signal names. Use ``response.response`` to access the |
| 114 | +complex frequency response using signal names. |
| 115 | + |
| 116 | +Discrete time systems |
| 117 | +--------------------- |
| 118 | +A discrete time system is created by specifying a nonzero 'timebase', dt. |
| 119 | +The timebase argument can be given when a system is constructed: |
| 120 | + |
| 121 | +* `dt = 0`: continuous time system (default) |
| 122 | +* `dt > 0`: discrete time system with sampling period 'dt' |
| 123 | +* `dt = True`: discrete time with unspecified sampling period |
| 124 | +* `dt = None`: no timebase specified |
| 125 | + |
| 126 | +Only the :class:`StateSpace`, :class:`TransferFunction`, and |
| 127 | +:class:`InputOutputSystem` classes allow explicit representation of |
| 128 | +discrete time systems. |
| 129 | + |
| 130 | +Systems must have compatible timebases in order to be combined. A discrete |
| 131 | +time system with unspecified sampling time (`dt = True`) can be combined with |
| 132 | +a system having a specified sampling time; the result will be a discrete time |
| 133 | +system with the sample time of the latter system. Similarly, a system with |
| 134 | +timebase `None` can be combined with a system having a specified timebase; the |
| 135 | +result will have the timebase of the latter system. For continuous time |
| 136 | +systems, the :func:`sample_system` function or the :meth:`StateSpace.sample` |
| 137 | +and :meth:`TransferFunction.sample` methods can be used to create a discrete |
| 138 | +time system from a continuous time system. See |
| 139 | +:ref:`utility-and-conversions`. The default value of `dt` can be changed by |
| 140 | +changing the value of `control.config.defaults['control.default_dt']`. |
| 141 | + |
| 142 | +Conversion between representations |
| 143 | +---------------------------------- |
| 144 | +LTI systems can be converted between representations either by calling the |
| 145 | +constructor for the desired data type using the original system as the sole |
| 146 | +argument or using the explicit conversion functions :func:`ss2tf` and |
| 147 | +:func:`tf2ss`. |
| 148 | + |
| 149 | +Subsystems |
| 150 | +---------- |
| 151 | +Subsets of input/output pairs for LTI systems can be obtained by indexing |
| 152 | +the system using either numerical indices (including slices) or signal |
| 153 | +names:: |
| 154 | + |
| 155 | + subsys = sys[[0, 2], 0:2] |
| 156 | + subsys = sys[['y[0]', 'y[2]'], ['u[0]', 'u[1]']] |
| 157 | + |
| 158 | +Signal names for an indexed subsystem are preserved from the original |
| 159 | +system and the subsystem name is set according to the values of |
| 160 | +``control.config.defaults['iosys.indexed_system_name_prefix']`` and |
| 161 | +``control.config.defaults['iosys.indexed_system_name_suffix']``. The default |
| 162 | +subsystem name is the original system name with '$indexed' appended. |
| 163 | + |
| 164 | +Simulating LTI systems |
| 165 | +====================== |
| 166 | + |
| 167 | +A number of functions are available for computing the output (and |
| 168 | +state) response of an LTI systems: |
| 169 | + |
| 170 | +.. autosummary:: |
| 171 | + :toctree: generated/ |
| 172 | + |
| 173 | + initial_response |
| 174 | + step_response |
| 175 | + impulse_response |
| 176 | + forced_response |
| 177 | + |
| 178 | +Each of these functions returns a :class:`TimeResponseData` object |
| 179 | +that contains the data for the time response (described in more detail |
| 180 | +in the next section). |
| 181 | + |
| 182 | +The :func:`forced_response` system is the most general and allows by |
| 183 | +the zero initial state response to be simulated as well as the |
| 184 | +response from a non-zero initial condition. |
| 185 | + |
| 186 | +For linear time invariant (LTI) systems, the :func:`impulse_response`, |
| 187 | +:func:`initial_response`, and :func:`step_response` functions will |
| 188 | +automatically compute the time vector based on the poles and zeros of |
| 189 | +the system. If a list of systems is passed, a common time vector will be |
| 190 | +computed and a list of responses will be returned in the form of a |
| 191 | +:class:`TimeResponseList` object. The :func:`forced_response` function can |
| 192 | +also take a list of systems, to which a single common input is applied. |
| 193 | +The :class:`TimeResponseList` object has a `plot()` method that will plot |
| 194 | +each of the responses in turn, using a sequence of different colors with |
| 195 | +appropriate titles and legends. |
| 196 | + |
| 197 | +In addition the :func:`input_output_response` function, which handles |
| 198 | +simulation of nonlinear systems and interconnected systems, can be |
| 199 | +used. For an LTI system, results are generally more accurate using |
| 200 | +the LTI simulation functions above. The :func:`input_output_response` |
| 201 | +function is described in more detail in the :ref:`iosys-module` section. |
| 202 | + |
| 203 | +.. currentmodule:: control |
| 204 | +.. _time-series-convention: |
| 205 | + |
| 206 | +Time series data |
| 207 | +---------------- |
| 208 | +A variety of functions in the library return time series data: sequences of |
| 209 | +values that change over time. A common set of conventions is used for |
| 210 | +returning such data: columns represent different points in time, rows are |
| 211 | +different components (e.g., inputs, outputs or states). For return |
| 212 | +arguments, an array of times is given as the first returned argument, |
| 213 | +followed by one or more arrays of variable values. This convention is used |
| 214 | +throughout the library, for example in the functions |
| 215 | +:func:`forced_response`, :func:`step_response`, :func:`impulse_response`, |
| 216 | +and :func:`initial_response`. |
| 217 | + |
| 218 | +.. note:: |
| 219 | + The convention used by python-control is different from the convention |
| 220 | + used in the `scipy.signal |
| 221 | + <https://docs.scipy.org/doc/scipy/reference/signal.html>`_ library. In |
| 222 | + Scipy's convention the meaning of rows and columns is interchanged. |
| 223 | + Thus, all 2D values must be transposed when they are used with functions |
| 224 | + from `scipy.signal`_. |
| 225 | + |
| 226 | +The time vector is a 1D array with shape (n, ):: |
| 227 | + |
| 228 | + T = [t1, t2, t3, ..., tn ] |
| 229 | + |
| 230 | +Input, state, and output all follow the same convention. Columns are different |
| 231 | +points in time, rows are different components:: |
| 232 | + |
| 233 | + U = [[u1(t1), u1(t2), u1(t3), ..., u1(tn)] |
| 234 | + [u2(t1), u2(t2), u2(t3), ..., u2(tn)] |
| 235 | + ... |
| 236 | + ... |
| 237 | + [ui(t1), ui(t2), ui(t3), ..., ui(tn)]] |
| 238 | + |
| 239 | +(and similarly for `X`, `Y`). So, `U[:, 2]` is the system's input at the |
| 240 | +third point in time; and `U[1]` or `U[1, :]` is the sequence of values for |
| 241 | +the system's second input. |
| 242 | + |
| 243 | +When there is only one row, a 1D object is accepted or returned, which adds |
| 244 | +convenience for SISO systems: |
| 245 | + |
| 246 | +The initial conditions are either 1D, or 2D with shape (j, 1):: |
| 247 | + |
| 248 | + X0 = [[x1] |
| 249 | + [x2] |
| 250 | + ... |
| 251 | + ... |
| 252 | + [xj]] |
| 253 | + |
| 254 | +Functions that return time responses (e.g., :func:`forced_response`, |
| 255 | +:func:`impulse_response`, :func:`input_output_response`, |
| 256 | +:func:`initial_response`, and :func:`step_response`) return a |
| 257 | +:class:`TimeResponseData` object that contains the data for the time |
| 258 | +response. These data can be accessed via the |
| 259 | +:attr:`~TimeResponseData.time`, :attr:`~TimeResponseData.outputs`, |
| 260 | +:attr:`~TimeResponseData.states` and :attr:`~TimeResponseData.inputs` |
| 261 | +properties:: |
| 262 | + |
| 263 | + sys = ct.rss(4, 1, 1) |
| 264 | + response = ct.step_response(sys) |
| 265 | + plt.plot(response.time, response.outputs) |
| 266 | + |
| 267 | +The dimensions of the response properties depend on the function being |
| 268 | +called and whether the system is SISO or MIMO. In addition, some time |
| 269 | +response function can return multiple "traces" (input/output pairs), |
| 270 | +such as the :func:`step_response` function applied to a MIMO system, |
| 271 | +which will compute the step response for each input/output pair. See |
| 272 | +:class:`TimeResponseData` for more details. |
| 273 | + |
| 274 | +The input, output, and state elements of the response can be accessed using |
| 275 | +signal names in place of integer offsets:: |
| 276 | + |
| 277 | + plt.plot(response. time, response.states['x[1]'] |
| 278 | + |
| 279 | +For multi-trace systems generated by :func:`step_response` and |
| 280 | +:func:`impulse_response`, the input name used to generate the trace can be |
| 281 | +used to access the appropriate input output pair:: |
| 282 | + |
| 283 | + plt.plot(response.time, response.outputs['y[0]', 'u[1]']) |
| 284 | + |
| 285 | +The time response functions can also be assigned to a tuple, which extracts |
| 286 | +the time and output (and optionally the state, if the `return_x` keyword is |
| 287 | +used). This allows simple commands for plotting:: |
| 288 | + |
| 289 | + t, y = ct.step_response(sys) |
| 290 | + plot(t, y) |
| 291 | + |
| 292 | +The output of a MIMO LTI system can be plotted like this:: |
| 293 | + |
| 294 | + t, y = ct.forced_response(sys, t, u) |
| 295 | + plot(t, y[0], label='y_0') |
| 296 | + plot(t, y[1], label='y_1') |
| 297 | + |
| 298 | +The convention also works well with the state space form of linear |
| 299 | +systems. If `D` is the feedthrough matrix (2D array) of a linear system, |
| 300 | +and `U` is its input (array), then the feedthrough part of the system's |
| 301 | +response, can be computed like this:: |
| 302 | + |
| 303 | + ft = D @ U |
| 304 | + |
| 305 | +Finally, the `to_pandas()` function can be used to create a pandas dataframe:: |
| 306 | + |
| 307 | + df = response.to_pandas() |
| 308 | + |
| 309 | +The column labels for the data frame are `time` and the labels for the input, |
| 310 | +output, and state signals (`u[i]`, `y[i]`, and `x[i]` by default, but these |
| 311 | +can be changed using the `inputs`, `outputs`, and `states` keywords when |
| 312 | +constructing the system, as described in :func:`ss`, :func:`tf`, and other |
| 313 | +system creation function. Note that when exporting to pandas, "rows" in the |
| 314 | +data frame correspond to time and "cols" (DataSeries) correspond to signals. |
| 315 | + |
| 316 | +.. currentmodule:: control |
| 317 | +.. _package-configuration-parameters: |
| 318 | + |
| 319 | +Package configuration parameters |
| 320 | +================================ |
| 321 | + |
| 322 | +The python-control library can be customized to allow for different default |
| 323 | +values for selected parameters. This includes the ability to set the style |
| 324 | +for various types of plots and establishing the underlying representation for |
| 325 | +state space matrices. |
| 326 | + |
| 327 | +To set the default value of a configuration variable, set the appropriate |
| 328 | +element of the `control.config.defaults` dictionary:: |
| 329 | + |
| 330 | + ct.config.defaults['module.parameter'] = value |
| 331 | + |
| 332 | +The :func:`~control.set_defaults` function can also be used to |
| 333 | +set multiple configuration parameters at the same time:: |
| 334 | + |
| 335 | + ct.set_defaults('module', param1=val1, param2=val2, ...] |
| 336 | + |
| 337 | +Finally, there are also functions available set collections of variables based |
| 338 | +on standard configurations. |
| 339 | + |
| 340 | +Selected variables that can be configured, along with their default values: |
| 341 | + |
| 342 | + * freqplot.dB (False): Bode plot magnitude plotted in dB (otherwise powers |
| 343 | + of 10) |
| 344 | + |
| 345 | + * freqplot.deg (True): Bode plot phase plotted in degrees (otherwise radians) |
| 346 | + |
| 347 | + * freqplot.Hz (False): Bode plot frequency plotted in Hertz (otherwise |
| 348 | + rad/sec) |
| 349 | + |
| 350 | + * freqplot.grid (True): Include grids for magnitude and phase plots |
| 351 | + |
| 352 | + * freqplot.number_of_samples (1000): Number of frequency points in Bode plots |
| 353 | + |
| 354 | + * freqplot.feature_periphery_decade (1.0): How many decades to include in |
| 355 | + the frequency range on both sides of features (poles, zeros). |
| 356 | + |
| 357 | + * statesp.default_dt and xferfcn.default_dt (None): set the default value |
| 358 | + of dt when constructing new LTI systems |
| 359 | + |
| 360 | + * statesp.remove_useless_states (True): remove states that have no effect |
| 361 | + on the input-output dynamics of the system |
| 362 | + |
| 363 | +Additional parameter variables are documented in individual functions |
| 364 | + |
| 365 | +Functions that can be used to set standard configurations: |
| 366 | + |
| 367 | +.. autosummary:: |
| 368 | + :toctree: generated/ |
| 369 | + |
| 370 | + reset_defaults |
| 371 | + use_fbs_defaults |
| 372 | + use_matlab_defaults |
| 373 | + use_legacy_defaults |
0 commit comments