From: <mur...@us...> - 2011-06-22 06:02:10
|
Revision: 162 http://python-control.svn.sourceforge.net/python-control/?rev=162&view=rev Author: murrayrm Date: 2011-06-22 06:02:02 +0000 (Wed, 22 Jun 2011) Log Message: ----------- Added Eike Welk's documenation changes + a few small tweaks (see ChangeLog) Modified Paths: -------------- trunk/ChangeLog trunk/doc/conf.py trunk/doc/index.rst trunk/doc/matlab_strings.rst trunk/src/ctrlutil.py trunk/src/delay.py trunk/src/freqplot.py trunk/src/mateqn.py trunk/src/matlab.py trunk/src/modelsimp.py trunk/src/nichols.py trunk/src/pzmap.py trunk/src/statefbk.py trunk/src/statesp.py trunk/src/timeresp.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/ChangeLog 2011-06-22 06:02:02 UTC (rev 162) @@ -1,3 +1,21 @@ +2011-06-21 Richard Murray <murray@malabar.local> + + * src/statesp.py (_mimo2siso): Moved function from matlab.py. + + * src/timeresp.py: added file documentation + split out and updated + copyright info. Small corrections to documentation. + (InitialResponse): Added missing transpose argument in call to + ForcedResponse + + * src/matlab.py: minor changes to documentation to avoid line wraps + on standard (80 col) terminal window + + * src/matlab.py: removed time-series convention documentation from + matlab.py since current MATLAB version uses standard conventions. + This documentation is currently in timeresp.py. + + * src/*, doc/*: added Eike Welk's documentation modifications + 2011-06-18 Richard Murray <murray@malabar.local> * src/timeresp.py, src/matlab.py: moved documentation about time Modified: trunk/doc/conf.py =================================================================== --- trunk/doc/conf.py 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/doc/conf.py 2011-06-22 06:02:02 UTC (rev 162) @@ -19,6 +19,7 @@ sys.path.insert(0, os.path.abspath('.')) sys.path.append(os.path.abspath('../src')) + # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. @@ -26,8 +27,14 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +# Additional interesting extensions: +# ``sphinx.ext.autosummary`` : Generate function/method/attribute summary +# lists +# ``sphinx.ext.extlinks`` : Shorten external links +# ``sphinx.ext.viewcode`` : Include highlighted source code in the +# documentation extensions = ['sphinx.ext.autodoc', 'numpydoc', 'sphinx.ext.pngmath', - 'sphinx.ext.intersphinx'] + 'sphinx.ext.intersphinx', 'sphinx.ext.todo'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -90,9 +97,15 @@ #This config value contains the locations and names of other projects that #should be linked to in this documentation. -intersphinx_mapping = {'scipy':('http://docs.scipy.org/doc/scipy/reference/', None)} +intersphinx_mapping = \ + {'scipy':('http://docs.scipy.org/doc/scipy/reference/', None), + 'numpy':('http://docs.scipy.org/doc/numpy/reference/', None)} +#If this is True, todo and todolist produce output, else they produce nothing. +#The default is False. +todo_include_todos = True + # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for Modified: trunk/doc/index.rst =================================================================== --- trunk/doc/index.rst 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/doc/index.rst 2011-06-22 06:02:02 UTC (rev 162) @@ -23,3 +23,6 @@ * :ref:`modindex` * :ref:`search` +---------------------------------- + +.. todolist:: Modified: trunk/doc/matlab_strings.rst =================================================================== --- trunk/doc/matlab_strings.rst 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/doc/matlab_strings.rst 2011-06-22 06:02:02 UTC (rev 162) @@ -4,4 +4,24 @@ The Matlab Module ================= .. automodule:: matlab - :members: \ No newline at end of file + :members: + +.. todo:: + The following functions should be documented in their own modules! + This is only a temporary solution. + +.. autofunction:: pzmap.pzmap +.. autofunction:: freqplot.nyquist +.. autofunction:: nichols.nichols +.. autofunction:: statefbk.place +.. autofunction:: statefbk.lqr +.. autofunction:: statefbk.ctrb +.. autofunction:: statefbk.obsv +.. autofunction:: statefbk.gram +.. autofunction:: delay.pade +.. autofunction:: freqplot.gangof4 +.. autofunction:: ctrlutil.unwrap +.. autofunction:: mateqn.lyap +.. autofunction:: mateqn.dlyap +.. autofunction:: mateqn.care +.. autofunction:: mateqn.dare Modified: trunk/src/ctrlutil.py =================================================================== --- trunk/src/ctrlutil.py 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/src/ctrlutil.py 2011-06-22 06:02:02 UTC (rev 162) @@ -52,8 +52,6 @@ def unwrap(angle, period=2*pi): """Unwrap a phase angle to give a continuous curve - - Usage: Y = unwrap(X, period=2``*``pi) Parameters ---------- @@ -66,6 +64,14 @@ ------- Y : array_like Output array, with jumps of period/2 eliminated + + Examples + -------- + >>> import numpy as np + >>> X = [5.74, 5.97, 6.19, 0.13, 0.35, 0.57] + >>> unwrap(X, period=2 * np.pi) + [5.74, 5.97, 6.19, 6.413185307179586, 6.633185307179586, 6.8531853071795865] + """ wrap = 0; last = angle[0]; Modified: trunk/src/delay.py =================================================================== --- trunk/src/delay.py 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/src/delay.py 2011-06-22 06:02:02 UTC (rev 162) @@ -40,17 +40,29 @@ # # $Id$ +from __future__ import division + + def pade(T, n=1): """ + Create a linear system that approximates a delay. + Return the numerator and denominator coefficients of the Pade approximation. - Inputs: - T --> time delay - n --> order of approximation + Parameters + ---------- + T : number + time delay + n : integer + order of approximation - Outputs: - num, den --> arrays in descending powers of s. - + Returns + ------- + num, den : array + Polynomial coefficients of the delay model, in descending powers of s. + + Notes + ----- Based on an algorithm in Golub and van Loan, "Matrix Computation" 3rd. Ed. pp. 572-574. """ Modified: trunk/src/freqplot.py =================================================================== --- trunk/src/freqplot.py 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/src/freqplot.py 2011-06-22 06:02:02 UTC (rev 162) @@ -59,10 +59,6 @@ color=None, Plot=True): """Bode plot for a system - Usage - ===== - (mag, phase, omega) = bode(syslist, omega=None, dB=False, Hz=False, color=None, deg=True, Plot=True) - Plots a Bode plot for the system over a (optional) frequency range. Parameters @@ -82,17 +78,26 @@ Plot : boolean If True, plot magnitude and phase - Return values - ------------- - mag : magnitude array (list if len(syslist) > 1) - phase : phase array (list if len(syslist) > 1) - omega : frequency array (list if len(syslist) > 1) - + Returns + ------- + mag : array (list if len(syslist) > 1) + magnitude + phase : array (list if len(syslist) > 1) + phase + omega : array (list if len(syslist) > 1) + frequency + 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. + + Examples + -------- + >>> from matlab import ss + >>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") + >>> mag, phase, omega = bode(sys) """ # If argument was a singleton, turn it into a list if (not getattr(syslist, '__iter__', False)): @@ -176,26 +181,31 @@ def nyquist(syslist, omega=None, Plot=True): """Nyquist plot for a system - Usage - ===== - real, imag, freq = nyquist(sys, omega=None, Plot=True) - Plots a Nyquist plot for the system over a (optional) frequency range. Parameters ---------- - syslist : linsys + syslist : list of Lti List of linear input/output systems (single system is OK) omega : freq_range Range of frequencies (list or bounds) in rad/sec Plot : boolean if True, plot magnitude - Return values - ------------- - real : real part of the frequency response array - imag : imaginary part of the frequency response array - freq : frequencies + Returns + ------- + real : array + real part of the frequency response array + imag : array + imaginary part of the frequency response array + freq : array + frequencies + + Examples + -------- + >>> from matlab import ss + >>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") + >>> real, imag, freq = nyquist(sys) """ # If argument was a singleton, turn it into a list if (not getattr(syslist, '__iter__', False)): @@ -238,22 +248,18 @@ def gangof4(P, C, omega=None): """Plot the "Gang of 4" transfer functions for a system - Usage - ===== - gangof4(P, C, omega=None) - Generates a 2x2 plot showing the "Gang of 4" sensitivity functions [T, PS; CS, S] Parameters ---------- - P, C : linsys + P, C : Lti Linear input/output systems (process and control) - omega : freq_range + omega : array Range of frequencies (list or bounds) in rad/sec - Return values - ------------- + Returns + ------- None """ if (P.inputs > 1 or P.outputs > 1 or C.inputs > 1 or C.outputs >1): @@ -400,22 +406,24 @@ """Compute a reasonable default frequency range for frequency domain plots. - Usage - ===== - omega = default_frequency_range(syslist) - Finds a reasonable default frequency range by examining the features (poles and zeros) of the systems in syslist. Parameters ---------- - syslist : linsys + syslist : list of Lti List of linear input/output systems (single system is OK) - Return values - ------------- - omega : freq_range + Return + ------ + omega : array Range of frequencies in rad/sec + + Examples + -------- + >>> from matlab import ss + >>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") + >>> omega = default_frequency_range(sys) """ # This code looks at the poles and zeros of all of the systems that # we are plotting and sets the frequency range to be one decade above Modified: trunk/src/mateqn.py =================================================================== --- trunk/src/mateqn.py 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/src/mateqn.py 2011-06-22 06:02:02 UTC (rev 162) @@ -38,9 +38,9 @@ """ from numpy.linalg import inv -from scipy import shape,size,asarray,copy,zeros,eye,dot +from scipy import shape, size, asarray, copy, zeros, eye, dot -from control.exception import ControlSlycot,ControlArgument +from exception import ControlSlycot, ControlArgument #### Lyapunov equation solvers lyap and dlyap Modified: trunk/src/matlab.py =================================================================== --- trunk/src/matlab.py 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/src/matlab.py 2011-06-22 06:02:02 UTC (rev 162) @@ -21,6 +21,7 @@ Copyright (c) 2011 by Eike Welk + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -61,13 +62,11 @@ # Libraries that we make use of import scipy as sp # SciPy library (used all over) import numpy as np # NumPy library -from scipy.signal.ltisys import _default_response_times from copy import deepcopy -import warnings # Import MATLAB-like functions that are defined in other packages from scipy.signal import zpk2ss, ss2zpk, tf2zpk, zpk2tf -from scipy import linspace, logspace +from numpy import linspace, logspace # Control system library import ctrlutil @@ -89,39 +88,56 @@ from modelsimp import hsvd, balred, modred from mateqn import lyap, dlyap, dare, care -__doc__ += """ -The control.matlab module defines functions that are roughly the -equivalents of those in the MATLAB Control Toolbox. Items marked by a -``*`` are currently implemented; those marked with a ``-`` are not planned -for implementation. +__doc__ += r""" +The following tables give an overview of the module ``control.matlab``. +They also show the implementation progress and the planned features of the +module. -== ========================== ================================================ -**Creating linear models.** --------------------------------------------------------------------------------- +The symbols in the first column show the current state of a feature: + +* ``*`` : The feature is currently implemented. +* ``-`` : The feature is not planned for implementation. +* ``s`` : A similar feature from an other library (Scipy) is imported into + the module, until the feature is implemented here. + + +Creating linear models +---------------------------------------------------------------------------- + +== ========================== ============================================ \* :func:`tf` create transfer function (TF) models \ zpk create zero/pole/gain (ZPK) models. \* :func:`ss` create state-space (SS) models \ dss create descriptor state-space models \ delayss create state-space models with delayed terms \ frd create frequency response data (FRD) models -\ lti/exp create pure continuous-time delays (TF and ZPK - only) +\ lti/exp create pure continuous-time delays (TF and + ZPK only) \ filt specify digital filters \- lti/set set/modify properties of LTI models -\- setdelaymodel specify internal delay model (state space only) -\ -**Data extraction** --------------------------------------------------------------------------------- +\- setdelaymodel specify internal delay model (state space + only) +== ========================== ============================================ + + +Data extraction +---------------------------------------------------------------------------- + +== ========================== ============================================ \ lti/tfdata extract numerators and denominators \ lti/zpkdata extract zero/pole/gain data \ lti/ssdata extract state-space matrices \ lti/dssdata descriptor version of SSDATA \ frd/frdata extract frequency response data \ lti/get access values of LTI model properties -\ ss/getDelayModel access internal delay model (state space only) -\ -**Conversions** --------------------------------------------------------------------------------- +\ ss/getDelayModel access internal delay model (state space) +== ========================== ============================================ + + +Conversions +---------------------------------------------------------------------------- + +== ========================== ============================================ \* :func:`tf` conversion to transfer function \ zpk conversion to zero/pole/gain \* :func:`ss` conversion to state space @@ -131,133 +147,176 @@ \ d2d resample discrete-time model \ upsample upsample discrete-time LTI systems \* :func:`ss2tf` state space to transfer function -\ ss2zpk transfer function to zero-pole-gain +\s ss2zpk transfer function to zero-pole-gain \* :func:`tf2ss` transfer function to state space -\ tf2zpk transfer function to zero-pole-gain -\ zpk2ss zero-pole-gain to state space -\ zpk2tf zero-pole-gain to transfer function -\ -**System interconnections** --------------------------------------------------------------------------------- -\ append group LTI models by appending inputs and outputs -\* :func:`parallel` connect LTI models in parallel - (see also overloaded +) -\* :func:`series` connect LTI models in series - (see also overloaded \*) -\* :func:`feedback` connect lti models with a feedback loop +\s tf2zpk transfer function to zero-pole-gain +\s zpk2ss zero-pole-gain to state space +\s zpk2tf zero-pole-gain to transfer function +== ========================== ============================================ + + +System interconnections +---------------------------------------------------------------------------- + +== ========================== ============================================ +\ append group LTI models by appending inputs/outputs +\* :func:`~bdalg.parallel` connect LTI models in parallel + (see also overloaded ``+``) +\* :func:`~bdalg.series` connect LTI models in series + (see also overloaded ``*``) +\* :func:`~bdalg.feedback` connect lti models with a feedback loop \ lti/lft generalized feedback interconnection \ lti/connect arbitrary interconnection of lti models -\ sumblk specify summing junction (for use with connect) +\ sumblk summing junction (for use with connect) \ strseq builds sequence of indexed strings (for I/O naming) -\ -**System gain and dynamics** --------------------------------------------------------------------------------- +== ========================== ============================================ + + +System gain and dynamics +---------------------------------------------------------------------------- + +== ========================== ============================================ \* :func:`dcgain` steady-state (D.C.) gain \ lti/bandwidth system bandwidth \ lti/norm h2 and Hinfinity norms of LTI models \* :func:`pole` system poles \* :func:`zero` system (transmission) zeros \ lti/order model order (number of states) -\* :func:`pzmap` pole-zero map (TF only) +\* :func:`~pzmap.pzmap` pole-zero map (TF only) \ lti/iopzmap input/output pole-zero map -\ damp natural frequency and damping of system poles +\ damp natural frequency, damping of system poles \ esort sort continuous poles by real part \ dsort sort discrete poles by magnitude \ lti/stabsep stable/unstable decomposition \ lti/modsep region-based modal decomposition -\ -**Time-domain analysis** --------------------------------------------------------------------------------- +== ========================== ============================================ + + +Time-domain analysis +---------------------------------------------------------------------------- + +== ========================== ============================================ \* :func:`step` step response -\ stepinfo step response characteristics (rise time, ...) +\ stepinfo step response characteristics \* :func:`impulse` impulse response \* :func:`initial` free response with initial conditions \* :func:`lsim` response to user-defined input signal \ lsiminfo linear response characteristics \ gensig generate input signal for LSIM \ covar covariance of response to white noise -\ -**Frequency-domain analysis** --------------------------------------------------------------------------------- +== ========================== ============================================ + + +Frequency-domain analysis +---------------------------------------------------------------------------- + +== ========================== ============================================ \* :func:`bode` Bode plot of the frequency response \ lti/bodemag Bode magnitude diagram only \ sigma singular value frequency plot -\* :func:`nyquist` Nyquist plot -\* :func:`nichols` Nichols plot +\* :func:`~freqplot.nyquist` Nyquist plot +\* :func:`~nichols.nichols` Nichols plot \* :func:`margin` gain and phase margins -\ lti/allmargin all crossover frequencies and related gain/phase - margins +\ lti/allmargin all crossover frequencies and margins \* :func:`freqresp` frequency response over a frequency grid -\* :func:`evalfr` evaluate frequency response at given frequency -\ -**Model simplification** --------------------------------------------------------------------------------- -\ minreal minimal realization and pole/zero cancellation -\ ss/sminreal structurally minimal realization (state space) -\* :func:`lti/hsvd` hankel singular values (state contributions) -\* :func:`lti/balred` reduced-order approximations of LTI models -\* :func:`ss/modred` model order reduction -\ -**Compensator design** --------------------------------------------------------------------------------- +\* :func:`evalfr` frequency response at single frequency +== ========================== ============================================ + + +Model simplification +---------------------------------------------------------------------------- + +== ========================== ============================================ +\ minreal minimal realization; pole/zero cancellation +\ ss/sminreal structurally minimal realization +\* :func:`~modelsimp.hsvd` hankel singular values (state contributions) +\* :func:`~modelsimp.balred` reduced-order approximations of LTI models +\* :func:`~modelsimp.modred` model order reduction +== ========================== ============================================ + + +Compensator design +---------------------------------------------------------------------------- + +== ========================== ============================================ \* :func:`rlocus` evans root locus -\* :func:`place` pole placement +\* :func:`~statefbk.place` pole placement \ estim form estimator given estimator gain \ reg form regulator given state-feedback and estimator gains -\ -**LQR/LQG design** --------------------------------------------------------------------------------- +== ========================== ============================================ + + +LQR/LQG design +---------------------------------------------------------------------------- + +== ========================== ============================================ \ ss/lqg single-step LQG design -\* :func:`lqr` linear-Quadratic (LQ) state-feedback regulator +\* :func:`~statefbk.lqr` linear quadratic (LQ) state-fbk regulator \ dlqr discrete-time LQ state-feedback regulator -\ lqry lq regulator with output weighting +\ lqry LQ regulator with output weighting \ lqrd discrete LQ regulator for continuous plant -\ ss/lqi linear-Quadratic-Integral (LQI) controller +\ ss/lqi Linear-Quadratic-Integral (LQI) controller \ ss/kalman Kalman state estimator -\ ss/kalmd discrete Kalman estimator for continuous plant +\ ss/kalmd discrete Kalman estimator for cts plant \ ss/lqgreg build LQG regulator from LQ gain and Kalman estimator \ ss/lqgtrack build LQG servo-controller \ augstate augment output by appending states -\ -**State-space (SS) models** --------------------------------------------------------------------------------- -\* :func:`rss` random stable continuous-time state-space models -\* :func:`drss` random stable discrete-time state-space models +== ========================== ============================================ + + +State-space (SS) models +---------------------------------------------------------------------------- + +== ========================== ============================================ +\* :func:`rss` random stable cts-time state-space models +\* :func:`drss` random stable disc-time state-space models \ ss2ss state coordinate transformation \ canon canonical forms of state-space models -\* :func:`ctrb` controllability matrix -\* :func:`obsv` observability matrix -\* :func:`gram` controllability and observability gramians +\* :func:`~statefbk.ctrb` controllability matrix +\* :func:`~statefbk.obsv` observability matrix +\* :func:`~statefbk.gram` controllability and observability gramians \ ss/prescale optimal scaling of state-space models. \ balreal gramian-based input/output balancing \ ss/xperm reorder states. -\ -**Frequency response data (FRD) models** --------------------------------------------------------------------------------- +== ========================== ============================================ + + +Frequency response data (FRD) models +---------------------------------------------------------------------------- + +== ========================== ============================================ \ frd/chgunits change frequency vector units \ frd/fcat merge frequency responses \ frd/fselect select frequency range or subgrid \ frd/fnorm peak gain as a function of frequency -\ frd/abs entrywise magnitude of the frequency response +\ frd/abs entrywise magnitude of frequency response \ frd/real real part of the frequency response \ frd/imag imaginary part of the frequency response \ frd/interp interpolate frequency response data \ mag2db convert magnitude to decibels (dB) \ db2mag convert decibels (dB) to magnitude -\ -**Time delays** --------------------------------------------------------------------------------- +== ========================== ============================================ + + +Time delays +---------------------------------------------------------------------------- + +== ========================== ============================================ \ lti/hasdelay true for models with time delays \ lti/totaldelay total delay between each input/output pair \ lti/delay2z replace delays by poles at z=0 or FRD phase shift -\* :func:`pade` pade approximation of time delays -\ -**Model dimensions and characteristics** --------------------------------------------------------------------------------- +\* :func:`~delay.pade` pade approximation of time delays +== ========================== ============================================ + + +Model dimensions and characteristics +---------------------------------------------------------------------------- + +== ========================== ============================================ \ class model type ('tf', 'zpk', 'ss', or 'frd') \ isa test if model is of given type \ tf/size model sizes @@ -269,57 +328,95 @@ \ lti/issiso true for single-input/single-output models \ lti/isstable true for models with stable dynamics \ lti/reshape reshape array of linear models -\ -**Overloaded arithmetic operations** --------------------------------------------------------------------------------- -\* \+ and - add and subtract systems (parallel connection) +== ========================== ============================================ + +Overloaded arithmetic operations +---------------------------------------------------------------------------- + +== ========================== ============================================ +\* \+ and - add, subtract systems (parallel connection) \* \* multiply systems (series connection) -\ / right divide -- sys1/sys2 means sys1\*inv(sys2) -\- \\ left divide -- sys1\\sys2 means inv(sys1)\*sys2 +\ / right divide -- sys1\*inv(sys2) +\- \\ left divide -- inv(sys1)\*sys2 \ ^ powers of a given system \ ' pertransposition \ .' transposition of input/output map \ .\* element-by-element multiplication \ [..] concatenate models along inputs or outputs -\ lti/stack stack models/arrays along some array dimension +\ lti/stack stack models/arrays along some dimension \ lti/inv inverse of an LTI system \ lti/conj complex conjugation of model coefficients -\ -**Matrix equation solvers and linear algebra** --------------------------------------------------------------------------------- -\* lyap, dlyap solve Lyapunov equations +== ========================== ============================================ + +Matrix equation solvers and linear algebra +---------------------------------------------------------------------------- + +== ========================== ============================================ +\* :func:`~mateqn.lyap` solve continuous-time Lyapunov equations +\* :func:`~mateqn.dlyap` solve discrete-time Lyapunov equations \ lyapchol, dlyapchol square-root Lyapunov solvers -\* care, dare solve algebraic Riccati equations +\* :func:`~mateqn.care` solve continuous-time algebraic Riccati + equations +\* :func:`~mateqn.dare` solve disc-time algebraic Riccati equations \ gcare, gdare generalized Riccati solvers \ bdschur block diagonalization of a square matrix -\ -**Additional functions** --------------------------------------------------------------------------------- -\* :func:`gangof4` generate the Gang of 4 sensitivity plots -\* :func:`linspace` generate a set of numbers that are linearly +== ========================== ============================================ + + +Additional functions +---------------------------------------------------------------------------- + +== ========================== ============================================ +\* :func:`~freqplot.gangof4` generate the Gang of 4 sensitivity plots +\* :func:`~numpy.linspace` generate a set of numbers that are linearly spaced -\* :func:`logspace` generate a set of numbers that are +\* :func:`~numpy.logspace` generate a set of numbers that are logarithmically spaced -\* :func:`unwrap` unwrap a phase angle to give a continuous curve -== ========================== ================================================ +\* :func:`~ctrlutil.unwrap` unwrap phase angle to give continuous curve +== ========================== ============================================ + """ def ss(*args): """ Create a state space system. - + + The function accepts either 1 or 4 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: + + .. math:: + \dot x = A \cdot x + B \cdot u + + y = C \cdot x + D \cdot u + + The matrices can be given as *array like* data types or strings. + Everything that the constructor of :class:`numpy.matrix` accepts is + permissible here too. + Parameters ---------- - A: numpy matrix or matrix-like object - B: numpy matrix or matrix-like object - C: numpy matrix or matrix-like object - D: numpy matrix or matrix-like object - sys: StateSpace or TransferFunction object - ss accepts a set of `A`, `B`, `C`, `D` matrices or `sys`. + sys: Lti (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 Returns ------- - out: StateSpace object + out: StateSpace + The new linear system Raises ------ @@ -334,11 +431,15 @@ Examples -------- - >>> sys = ss(A, B, C, D) # Create a StateSpace object from these matrices. - >>> sys = ss(sys1) # Convert a TransferFunction to a StateSpace object. + >>> # Create a StateSpace object from four "matrices". + >>> sys1 = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") + + >>> # Convert a TransferFunction to a StateSpace object. + >>> sys_tf = tf([2.], [1., 3]) + >>> sys2 = ss(sys_tf) """ - + if len(args) == 4: return StateSpace(args[0], args[1], args[2], args[3]) elif len(args) == 1: @@ -353,20 +454,41 @@ else: raise ValueError("Needs 1 or 4 arguments; received %i." % len(args)) + def tf(*args): """ - Create a transfer function system. + Create a transfer function system. Can create MIMO systems. + + The function accepts either 1 or 2 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 coefficients. + + 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.) + Parameters ---------- - num: vector, or list of lists of vectors - den: vector, or list of lists of vectors - sys: StateSpace or TransferFunction object - tf accepts a `num` and `den`, or `sys``. + sys: Lti (StateSpace or TransferFunction) + A linear system + num: array_like, or list of list of array_like + Polynomial coefficients of the numerator + den: array_like, or list of list of array_like + Polynomial coefficients of the denominator Returns ------- - out: TransferFunction object + out: TransferFunction + The new linear system Raises ------ @@ -383,19 +505,34 @@ Notes -------- - `num`[`i`][`j`] is the vector of polynomial coefficients of the transfer - function numerator from the (`j`+1)st output to the (`i`+1)st input. - `den`[`i`][`j`] works the same way. + + .. todo:: + + The next paragraph contradicts the comment in the example! + Also "input" should come before "output" in the sentence: + + "from the (j+1)st output to the (i+1)st input" + + ``num[i][j]`` contains the polynomial coefficients of the numerator + for the transfer function from the (j+1)st output to the (i+1)st input. + ``den[i][j]`` works the same way. + + The coefficients ``[2, 3, 4]`` denote the polynomial + :math:`2 \cdot s^2 + 3 \cdot s + 4`. Examples -------- + >>> # Create a MIMO transfer function object + >>> # The transfer function from the 2nd input to the 1st output is + >>> # (3s + 4) / (6s^2 + 5s + 4). >>> num = [[[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]]] >>> den = [[[9., 8., 7.], [6., 5., 4.]], [[3., 2., 1.], [-1., -2., -3.]]] - >>> sys = tf(num, den) - The transfer function from the 2nd input to the 1st output is - (3s + 4) / (6s^2 + 5s + 4). - >>> sys = tf(sys1) # Convert a StateSpace to a TransferFunction object. + >>> sys1 = tf(num, den) + >>> # Convert a StateSpace to a TransferFunction object. + >>> sys_ss = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") + >>> sys2 = tf(sys1) + """ if len(args) == 2: @@ -412,22 +549,40 @@ else: raise ValueError("Needs 1 or 2 arguments; received %i." % len(args)) + def ss2tf(*args): """ 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: :func:`ss` + Parameters ---------- - A: numpy matrix or matrix-like object - B: numpy matrix or matrix-like object - C: numpy matrix or matrix-like object - D: numpy matrix or matrix-like object - sys: StateSpace object - ss accepts a set of `A`, `B`, `C`, `D` matrices, or `sys`. + 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 + Feed forward matrix Returns ------- - out: TransferFunction object + out: TransferFunction + New linear system in transfer function form Raises ------ @@ -445,8 +600,14 @@ Examples -------- - >>> sys = ss2tf(A, B, C, D) - >>> sys = ss2tf(sys1) # Convert a StateSpace to a TransferFunction object. + >>> A = [[1., -2], [3, -4]] + >>> B = [[5.], [7]] + >>> C = [[6., 8]] + >>> D = [[9.]] + >>> sys1 = ss2tf(A, B, C, D) + + >>> sys_ss = ss(A, B, C, D) + >>> sys2 = ss2tf(sys_ss) """ @@ -468,22 +629,37 @@ """ 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 coefficients. + + For details see: :func:`tf` + Parameters ---------- - num: vector, or list of lists of vectors - den: vector, or list of lists of vectors - sys: TransferFunction object - tf2ss accepts `num` and `den`, or `sys`. + sys: Lti (StateSpace or TransferFunction) + A linear system + num: array_like, or list of list of array_like + Polynomial coefficients of the numerator + den: array_like, or list of list of array_like + Polynomial coefficients of the denominator Returns ------- - out: StateSpace object + out: StateSpace + New linear system in state space form Raises ------ ValueError - if `num` and `den` have invalid or unequal dimensions, or if an invalid - number of arguments is passed in + 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 @@ -494,18 +670,14 @@ tf ss2tf - Notes - -------- - `num`[`i`][`j`] is the vector of polynomial coefficients of the transfer - function numerator from the (`j`+1)st output to the (`i`+1)st input. - `den`[`i`][`j`] works the same way. - Examples -------- >>> num = [[[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]]] >>> den = [[[9., 8., 7.], [6., 5., 4.]], [[3., 2., 1.], [-1., -2., -3.]]] - >>> sys = tf2ss(num, den) - >>> sys = tf2ss(sys1) # Convert a TransferFunction to a StateSpace object. + >>> sys1 = tf2ss(num, den) + + >>> sys_tf = tf(num, den) + >>> sys2 = tf2ss(sys_tf) """ @@ -523,17 +695,21 @@ def rss(states=1, inputs=1, outputs=1): """ - Create a stable continuous random state space object. + Create a stable **continuous** random state space object. Parameters ---------- states: integer + Number of state variables inputs: integer + Number of system inputs outputs: integer + Number of system outputs Returns ------- - sys: StateSpace object + sys: StateSpace + The randomly created linear system Raises ------ @@ -547,8 +723,8 @@ 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. + missing numbers are assumed to be 1. The poles of the returned system + will always have a negative real part. """ @@ -556,17 +732,21 @@ def drss(states=1, inputs=1, outputs=1): """ - Create a stable discrete random state space object. + Create a stable **discrete** random state space object. Parameters ---------- states: integer + Number of state variables inputs: integer + Number of system inputs outputs: integer + Number of system outputs Returns ------- - sys: StateSpace object + sys: StateSpace + The randomly created linear system Raises ------ @@ -580,8 +760,8 @@ 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. + missing numbers are assumed to be 1. The poles of the returned system + will always have a magnitude less than 1. """ @@ -589,15 +769,17 @@ def pole(sys): """ - Return system poles. + Compute system poles. Parameters ---------- - sys: StateSpace or TransferFunction object + sys: StateSpace or TransferFunction + Linear system Returns ------- poles: ndarray + Array that contains the system's poles. Raises ------ @@ -610,7 +792,8 @@ Notes ----- - This function is a wrapper for StateSpace.pole and TransferFunction.pole. + This function is a wrapper for StateSpace.pole and + TransferFunction.pole. """ @@ -618,15 +801,17 @@ def zero(sys): """ - Return system zeros. + Compute system zeros. Parameters ---------- - sys: StateSpace or TransferFunction object + sys: StateSpace or TransferFunction + Linear system Returns ------- zeros: ndarray + Array that contains the system's zeros. Raises ------ @@ -639,7 +824,8 @@ Notes ----- - This function is a wrapper for StateSpace.zero and TransferFunction.zero. + This function is a wrapper for StateSpace.zero and + TransferFunction.zero. """ @@ -651,8 +837,10 @@ Parameters ---------- - sys: StateSpace or TransferFunction object + sys: StateSpace or TransferFunction + Linear system omega: scalar + Frequency Returns ------- @@ -670,12 +858,12 @@ Examples -------- - >>> sys = rss(3, 2, 2) + >>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") >>> evalfr(sys, 1.) - array([[ 4.09376126 -6.2171555j , 23.71332080-35.24245284j], - [ 0.83405186 -1.82896006j, 8.10962251-12.66640309j]]) - This is the transfer function matrix evaluated at s = i. + array([[ 44.8-21.4j]]) + >>> # This is the transfer function matrix evaluated at s = i. + .. todo:: Add example with MIMO system """ return sys.evalfr(omega) @@ -686,8 +874,10 @@ Parameters ---------- - sys: StateSpace or TransferFunction object - omega: list or ndarray + sys: StateSpace or TransferFunction + Linear system + omega: array_like + List of frequencies Returns ------- @@ -708,16 +898,26 @@ Examples -------- - >>> sys = rss(3, 2, 2) + >>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") >>> mag, phase, omega = freqresp(sys, [0.1, 1., 10.]) - >>> mag[0, 1, :] - array([ 55.43747231, 42.47766549, 1.97225895]) - >>> phase[1, 0, :] - array([-0.12611087, -1.14294316, 2.5764547 ]) - This is the magnitude of the frequency response from the 2nd input to the - 1st output, and the phase (in radians) of the frequency response from the - 1st input to the 2nd output, for s = 0.1i, i, 10i. - + >>> mag + array([[[ 58.8576682 , 49.64876635, 13.40825927]]]) + >>> phase + array([[[-0.05408304, -0.44563154, -0.66837155]]]) + + .. todo:: + Add example with MIMO system + + #>>> sys = rss(3, 2, 2) + #>>> mag, phase, omega = freqresp(sys, [0.1, 1., 10.]) + #>>> mag[0, 1, :] + #array([ 55.43747231, 42.47766549, 1.97225895]) + #>>> phase[1, 0, :] + #array([-0.12611087, -1.14294316, 2.5764547 ]) + #>>> # This is the magnitude of the frequency response from the 2nd + #>>> # input to the 1st output, and the phase (in radians) of the + #>>> # frequency response from the 1st input to the 2nd output, for + #>>> # s = 0.1i, i, 10i. """ return sys.freqresp(omega) @@ -728,11 +928,17 @@ Examples -------- - >>> bode(sys) - >>> bode(sys, w) - >>> bode(sys1, sys2, ..., sysN) - >>> bode(sys1, sys2, ..., sysN, w) - >>> bode(sys1, 'plotstyle1', ..., sysN, 'plotstyleN') + >>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") + >>> mag, phase, omega = bode(sys) + + .. todo:: + + Document these use cases + + * >>> bode(sys, w) + * >>> bode(sys1, sys2, ..., sysN) + * >>> bode(sys1, sys2, ..., sysN, w) + * >>> bode(sys1, 'plotstyle1', ..., sysN, 'plotstyleN') """ # If the first argument is a list, then assume python-control calling format @@ -799,13 +1005,17 @@ Parameters ---------- - sys: StateSpace or TransferFunction object - klist: optional list of gains + sys: StateSpace or TransferFunction + Linear system + klist: + optional list of gains Returns ------- - rlist: list of roots for each gain - klist: list of gains used to compute roots + rlist: + list of roots for each gain + klist: + list of gains used to compute roots """ from rlocus import RootLocus if (klist == None): @@ -818,26 +1028,35 @@ def margin(*args): """Calculate gain and phase margins and associated crossover frequencies - - Usage: - gm, pm, wg, wp = margin(sys) - gm, pm, wg, wp = margin(mag,phase,w) + Function ``margin`` takes either 1 or 3 parameters. + Parameters ---------- - sys : linsys + sys : StateSpace or TransferFunction Linear SISO system mag, phase, w : array_like - Input magnitude, phase (in deg.), and frequencies (rad/sec) from bode - frequency response data + Input magnitude, phase (in deg.), and frequencies (rad/sec) from + bode frequency response data Returns ------- gm, pm, wg, wp : float Gain margin gm, phase margin pm (in deg), and associated crossover frequencies wg and wp (in rad/sec) of SISO open-loop. If more than - one crossover frequency is detected, returns the lowest corresponding - margin. + one crossover frequency is detected, returns the lowest + corresponding margin. + + Examples + -------- + >>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") + >>> gm, pm, wg, wp = margin(sys) + margin: no magnitude crossings found + + .. todo:: + better ecample system! + + #>>> gm, pm, wg, wp = margin(mag, phase, w) """ if len(args) == 1: sys = args[0] Modified: trunk/src/modelsimp.py =================================================================== --- trunk/src/modelsimp.py 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/src/modelsimp.py 2011-06-22 06:02:02 UTC (rev 162) @@ -47,17 +47,21 @@ from statesp import StateSpace # Hankel Singular Value Decomposition -# The following returns the Hankel singular values, which are singular values of the matrix formed by multiplying the controllability and observability grammians +# The following returns the Hankel singular values, which are singular values +#of the matrix formed by multiplying the controllability and observability +#grammians def hsvd(sys): - """Calculate the Hankel singular values + """Calculate the Hankel singular values. Parameters ---------- - sys : a state space system + sys : StateSpace + A state space system Returns ------- - H : a list of Hankel singular values + H : Matrix + A list of Hankel singular values See Also -------- @@ -65,7 +69,11 @@ 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 gramians. There are other (more efficient) methods based on solving the Lyapunov equation in a particular way (more details soon). + 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 + gramians. There are other (more efficient) methods based on solving the + Lyapunov equation in a particular way (more details soon). Examples -------- @@ -84,29 +92,36 @@ # Return the Hankel singular values return hsv -def modred(sys,ELIM,method='matchdc'): - """Model reduction of sys by eliminating the states in ELIM using a given method +def modred(sys, ELIM, method='matchdc'): + """ + Model reduction of `sys` by eliminating the states in `ELIM` using a given + method. Parameters ---------- - sys: original system to reduce - ELIM: vector of states to eliminate - method: method of removing states in ELIM (truncate or matchdc) + sys: StateSpace + Original system to reduce + ELIM: array + Vector of states to eliminate + method: string + Method of removing states in `ELIM`: either ``'truncate'`` or + ``'matchdc'``. Returns ------- - rsys: a reduced order model + rsys: StateSpace + A reduced order model Raises ------ ValueError - if `method` is not either `matchdc` or `truncate` - if eigenvalues of `sys.A` are not all in left half plane (sys must be stable) + * if `method` is not either ``'matchdc'`` or ``'truncate'`` + * if eigenvalues of `sys.A` are not all in left half plane + (`sys` must be stable) Examples -------- - >>> rsys = modred(sys,ELIM,method='truncate') - + >>> rsys = modred(sys, ELIM, method='truncate') """ #Check for ss system object, need a utility for this? @@ -168,30 +183,38 @@ rsys = StateSpace(Ar,Br,Cr,Dr) return rsys -def balred(sys,orders,method='truncate'): - """Balanced reduced order model of sys of a given order. States are eliminated based on Hankel singular value. +def balred(sys, orders, method='truncate'): + """ + Balanced reduced order model of sys of a given order. + States are eliminated based on Hankel singular value. Parameters ---------- - sys: original system to reduce - orders: desired order of reduced order model (if a vector, returns a vector of systems) - method: method of removing states (truncate or matchdc) + 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'``. Returns ------- - rsys: a reduced order model + rsys: StateSpace + A reduced order model Raises ------ ValueError - if `method` is not `truncate` - if eigenvalues of `sys.A` are not all in left half plane (sys must be stable) + * if `method` is not ``'truncate'`` + * if eigenvalues of `sys.A` are not all in left half plane + (`sys` must be stable) ImportError if slycot routine ab09ad is not found Examples -------- - >>> rsys = balred(sys,order,method='truncate') + >>> rsys = balred(sys, order, method='truncate') """ @@ -233,39 +256,56 @@ return rsys -def era(YY,m,n,nin,nout,r): - """Calculate an ERA model of order r based on the impulse-response data YY - +def era(YY, m, n, nin, nout, r): + """ + Calculate an ERA model of order `r` based on the impulse-response data `YY`. + + .. note:: This function is not implemented yet. + Parameters ---------- - YY: nout x nin dimensional impulse-response data - m: number of rows in Hankel matrix - n: number of columns in Hankel matrix - nin: number of input variables - nout: number of output variables - r: order of model + 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) + sys: StateSpace + A reduced order model sys=ss(Ar,Br,Cr,Dr) Examples -------- - >>> rsys = era(YY,m,n,nin,nout,r) + >>> rsys = era(YY, m, n, nin, nout, r) + """ + raise NotImplementedError('This function is not implemented yet.') +def markov(Y, U, M): """ -def markov(Y,U,M): - """Calculate the first M Markov parameters [D CB CAB ...] from input U, output Y + Calculate the first `M` Markov parameters [D CB CAB ...] + from input `U`, output `Y`. Parameters ---------- - Y: output data - U: input data - M: number of Markov parameters to output + Y: array_like + Output data + U: array_like + Input data + M: integer + Number of Markov parameters to output Returns ------- - H: first M Markov parameters + H: matrix + First M Markov parameters Notes ----- @@ -273,8 +313,7 @@ Examples -------- - >>> H = markov(Y,U,M) - + >>> H = markov(Y, U, M) """ # Convert input parameters to matrices (if they aren't already) Modified: trunk/src/nichols.py =================================================================== --- trunk/src/nichols.py 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/src/nichols.py 2011-06-22 06:02:02 UTC (rev 162) @@ -49,23 +49,19 @@ def nichols(syslist, omega=None, grid=True): """Nichols plot for a system - Usage - ===== - magh = nichols(sys, omega=None) - Plots a Nichols plot for the system over a (optional) frequency range. Parameters ---------- - syslist : linsys + syslist : list of Lti, or Lti List of linear input/output systems (single system is OK) - omega : freq_range + 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. - Return values - ------------- + Returns + ------- None """ Modified: trunk/src/pzmap.py =================================================================== --- trunk/src/pzmap.py 2011-06-18 19:13:09 UTC (rev 161) +++ trunk/src/pzmap.py 2011-06-22 06:02:02 UTC (rev 162) @@ -41,27 +41,54 @@ # $Id:pzmap.py 819 2009-05-29 21:28:07Z murray $ import matplotlib.pyplot as plt -import scipy as sp -import numpy as np -import xferfcn +#import scipy as sp +#import numpy as np +from numpy import real, imag +from lti import Lti -# Compute poles and zeros for a system -#! TODO: extend this to handle state space systems -def pzmap(sys, Plot=True): - """Plot a pole/zero map for a transfer function""" - if (isinstance(sys, xferfcn.TransferFunction)): - poles = sp.roots(np.squeeze(np.asarray(sys.den))); - zeros = sp.roots(np.squeeze(np.asarray(sys.num))); - else: - raise NotImplementedError("pzmap not implemented for state space systems yet.") +# TODO: Implement more elegant cross-style axes. See: +# http://matplotlib.sourceforge.net/examples/axes_grid/demo_axisline_style.html +# http://matplotlib.sourceforge.net/examples/axes_grid/demo_curvelinear_grid.html +def pzmap(sys, Plot=True, title='Pole Zero Map'): + """ + Plot a pole/zero map for a linear system. + + Parameters + ---------- + sys: Lti (StateSpace or TransferFunction) + Linear system for which poles and zeros are computed. + Plot: bool + If ``True`` a graph is generated with Matplotlib, + otherwise the poles and zeros are only computed and returned. + + Returns + ------- + pole: array + The systems poles + zeros: array + The system's zeros. + """ + if not isinstance(sys, Lti): + raise TypeError('Argument ``sys``: must be a linear system.') + + poles = sys.pole() + zeros = sys.zero() if (Plot): # Plot the locations of the poles and zeros - plt.plot(sp.real(poles), sp.imag(poles), 'x'); plt.hold(True); - plt.plot(sp.real(zeros), sp.imag(zeros), 'o'); - + if len(poles) > 0: + plt.scatter(real(poles), imag(poles), s=50, marker='x') + if len(zeros) > 0: + plt.scat... [truncated message content] |