You can subscribe to this list here.
2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(19) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(11) |
Dec
(5) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2011 |
Jan
|
Feb
(113) |
Mar
(12) |
Apr
(27) |
May
(2) |
Jun
(16) |
Jul
(6) |
Aug
(6) |
Sep
|
Oct
(3) |
Nov
(9) |
Dec
(2) |
2012 |
Jan
(5) |
Feb
(11) |
Mar
|
Apr
(3) |
May
|
Jun
|
Jul
|
Aug
(3) |
Sep
(7) |
Oct
(18) |
Nov
(18) |
Dec
|
2013 |
Jan
(4) |
Feb
(1) |
Mar
(3) |
Apr
(1) |
May
|
Jun
(33) |
Jul
(2) |
Aug
(5) |
Sep
|
Oct
|
Nov
|
Dec
(1) |
2014 |
Jan
(1) |
Feb
|
Mar
(8) |
Apr
|
May
(3) |
Jun
(3) |
Jul
(9) |
Aug
(5) |
Sep
(6) |
Oct
|
Nov
|
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(4) |
2017 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(5) |
Nov
|
Dec
|
2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2019 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(6) |
Sep
|
Oct
|
Nov
(2) |
Dec
|
2020 |
Jan
(1) |
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2021 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(4) |
Oct
|
Nov
|
Dec
|
From: Gustavo G. <gor...@mi...> - 2011-11-25 20:49:22
|
Hi Roberto, Thanks for the quick reply! Regarding the dlqr function in yottalab.py -- it doesn't seem to depend on the sampling time of the discrete time system and this appears to produce incorrect result, or perhaps maybe I am misusing the function. Thank you, Gustavo On Fri, Nov 25, 2011 at 3:38 PM, Roberto Bucher <rob...@su...> wrote: > Hi Gustavo > > yottalab.py requires some changes in some python control files. I'll > check ASAP my last modifications and I send you the required files. > > Best regards > > Roberto > > On 11/25/2011 09:21 PM, Gustavo Goretkin wrote: >> Hey list, >> >> I'd like to try use some discrete-time in python-control. >> Specifically, I want MATLAB's c2d and dlqr. >> >> I'm aware of the discussion here [1] and code here [2]. yottalab.py >> has a all the functionality I want (thanks!) but I'm not sure which >> branch of python-control it is assuming. Specifically in c2d, line >> line 173, there is a call to construct a statespace object which takes >> 5 arguments A,B,C,D,Ts, but no such constructor seems to exist in >> python-control. From the rest of the code (i.e. d2c), I infer that all >> it seems to do is add a field called "Tsamp" to the statespace object. >> >> If the statespace object can represent both continuous and >> discrete-time systems, what then should the semantics be? It looks >> like Tsamp=0 for continuous time systems. >> >> It also looks like there is a repository here [3]. Is it going to be >> merged with the sourceforge repository eventually, or other way >> around? >> >> Thanks! >> Gustavo >> >> [1] http://mail.scipy.org/pipermail/scipy-dev/2010-August/015468.html and >> [2] www.dti.supsi.ch/~bucher/wp-content/uploads/2011/03/yottalab.py >> [3] https://bitbucket.org/eike_welk/python-control >> >> ------------------------------------------------------------------------------ >> All the data continuously generated in your IT infrastructure >> contains a definitive record of customers, application performance, >> security threats, fraudulent activity, and more. Splunk takes this >> data and makes sense of it. IT sense. And common sense. >> http://p.sf.net/sfu/splunk-novd2d >> _______________________________________________ >> python-control-discuss mailing list >> pyt...@li... >> https://lists.sourceforge.net/lists/listinfo/python-control-discuss > > > ------------------------------------------------------------------------------ > All the data continuously generated in your IT infrastructure > contains a definitive record of customers, application performance, > security threats, fraudulent activity, and more. Splunk takes this > data and makes sense of it. IT sense. And common sense. > http://p.sf.net/sfu/splunk-novd2d > _______________________________________________ > python-control-discuss mailing list > pyt...@li... > https://lists.sourceforge.net/lists/listinfo/python-control-discuss > |
From: Roberto B. <rob...@su...> - 2011-11-25 20:39:03
|
Hi Gustavo yottalab.py requires some changes in some python control files. I'll check ASAP my last modifications and I send you the required files. Best regards Roberto On 11/25/2011 09:21 PM, Gustavo Goretkin wrote: > Hey list, > > I'd like to try use some discrete-time in python-control. > Specifically, I want MATLAB's c2d and dlqr. > > I'm aware of the discussion here [1] and code here [2]. yottalab.py > has a all the functionality I want (thanks!) but I'm not sure which > branch of python-control it is assuming. Specifically in c2d, line > line 173, there is a call to construct a statespace object which takes > 5 arguments A,B,C,D,Ts, but no such constructor seems to exist in > python-control. From the rest of the code (i.e. d2c), I infer that all > it seems to do is add a field called "Tsamp" to the statespace object. > > If the statespace object can represent both continuous and > discrete-time systems, what then should the semantics be? It looks > like Tsamp=0 for continuous time systems. > > It also looks like there is a repository here [3]. Is it going to be > merged with the sourceforge repository eventually, or other way > around? > > Thanks! > Gustavo > > [1] http://mail.scipy.org/pipermail/scipy-dev/2010-August/015468.html and > [2] www.dti.supsi.ch/~bucher/wp-content/uploads/2011/03/yottalab.py > [3] https://bitbucket.org/eike_welk/python-control > > ------------------------------------------------------------------------------ > All the data continuously generated in your IT infrastructure > contains a definitive record of customers, application performance, > security threats, fraudulent activity, and more. Splunk takes this > data and makes sense of it. IT sense. And common sense. > http://p.sf.net/sfu/splunk-novd2d > _______________________________________________ > python-control-discuss mailing list > pyt...@li... > https://lists.sourceforge.net/lists/listinfo/python-control-discuss |
From: Gustavo G. <gor...@mi...> - 2011-11-25 20:21:28
|
Hey list, I'd like to try use some discrete-time in python-control. Specifically, I want MATLAB's c2d and dlqr. I'm aware of the discussion here [1] and code here [2]. yottalab.py has a all the functionality I want (thanks!) but I'm not sure which branch of python-control it is assuming. Specifically in c2d, line line 173, there is a call to construct a statespace object which takes 5 arguments A,B,C,D,Ts, but no such constructor seems to exist in python-control. From the rest of the code (i.e. d2c), I infer that all it seems to do is add a field called "Tsamp" to the statespace object. If the statespace object can represent both continuous and discrete-time systems, what then should the semantics be? It looks like Tsamp=0 for continuous time systems. It also looks like there is a repository here [3]. Is it going to be merged with the sourceforge repository eventually, or other way around? Thanks! Gustavo [1] http://mail.scipy.org/pipermail/scipy-dev/2010-August/015468.html and [2] www.dti.supsi.ch/~bucher/wp-content/uploads/2011/03/yottalab.py [3] https://bitbucket.org/eike_welk/python-control |
From: Gustavo G. <gor...@mi...> - 2011-10-31 19:37:01
|
Installing pydare had nothing to do with it. I just had forgotten to change directory out of the slycot directory. Sorry for the noise! On Mon, Oct 31, 2011 at 7:17 AM, Gustavo Goretkin <gor...@mi...> wrote: > I installed the pydare package and now slycot seems to work fine... > > On Mon, Oct 31, 2011 at 5:55 AM, Gustavo Goretkin <gor...@mi...> wrote: >> I'd like to use the LQR routine in python-control. I just cloned the >> Slycot repo from here [1] and am having an issue that is certainly not >> due to python-control, but I thought I might get a helpful response >> anyway. >> >> When I (or python-control) issues "import slycot", here's the result: >> >> Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56) >> [GCC 4.4.5] on linux2 >> Type "help", "copyright", "credits" or "license" for more information. >>>>> import slycot >> Traceback (most recent call last): >> File "<stdin>", line 1, in <module> >> File "slycot/__init__.py", line 4, in <module> >> from slycot.analysis import ab01nd,ab05md,ab05nd,ab07nd,ab08nd, ab09ad >> File "slycot/analysis.py", line 21, in <module> >> from slycot import _wrapper >> ImportError: cannot import name _wrapper >> >> >> There is a file called slycot/src/_wrapper.pyf, which is presumably >> the file that wants to be imported. >> >> Any suggestions? >> >> Thanks, >> Gustavo >> >> >> [1] https://github.com/avventi/Slycot >> > |
From: Gustavo G. <gor...@mi...> - 2011-10-31 11:18:05
|
I installed the pydare package and now slycot seems to work fine... On Mon, Oct 31, 2011 at 5:55 AM, Gustavo Goretkin <gor...@mi...> wrote: > I'd like to use the LQR routine in python-control. I just cloned the > Slycot repo from here [1] and am having an issue that is certainly not > due to python-control, but I thought I might get a helpful response > anyway. > > When I (or python-control) issues "import slycot", here's the result: > > Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56) > [GCC 4.4.5] on linux2 > Type "help", "copyright", "credits" or "license" for more information. >>>> import slycot > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > File "slycot/__init__.py", line 4, in <module> > from slycot.analysis import ab01nd,ab05md,ab05nd,ab07nd,ab08nd, ab09ad > File "slycot/analysis.py", line 21, in <module> > from slycot import _wrapper > ImportError: cannot import name _wrapper > > > There is a file called slycot/src/_wrapper.pyf, which is presumably > the file that wants to be imported. > > Any suggestions? > > Thanks, > Gustavo > > > [1] https://github.com/avventi/Slycot > |
From: Gustavo G. <gor...@mi...> - 2011-10-31 09:56:19
|
I'd like to use the LQR routine in python-control. I just cloned the Slycot repo from here [1] and am having an issue that is certainly not due to python-control, but I thought I might get a helpful response anyway. When I (or python-control) issues "import slycot", here's the result: Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import slycot Traceback (most recent call last): File "<stdin>", line 1, in <module> File "slycot/__init__.py", line 4, in <module> from slycot.analysis import ab01nd,ab05md,ab05nd,ab07nd,ab08nd, ab09ad File "slycot/analysis.py", line 21, in <module> from slycot import _wrapper ImportError: cannot import name _wrapper There is a file called slycot/src/_wrapper.pyf, which is presumably the file that wants to be imported. Any suggestions? Thanks, Gustavo [1] https://github.com/avventi/Slycot |
From: Richard M. <mu...@cd...> - 2011-08-18 15:57:04
|
A couple of quick comments on Yuchen's log message: * At some point we should think about function naming conventions in TuLiP. It looks like we have gone with a C/C++ mixed case style. PEP 8 suggests functions of the form write_states_to_file rather than mixedCase. * For the representation of automatons: we should talk about this at some upcoming meeting. Obviously being able to use standard libraries to do useful computations is a good way to go. * Is there a tutorial for using the gephi functions? I took a quick look but didn't see it in any of the obvious places. -richard On 17 Aug 2011, at 15:16 , yuc...@us... wrote: > Revision: 164 > http://tulip-control.svn.sourceforge.net/tulip-control/?rev=164&view=rev > Author: yuchennil > Date: 2011-08-17 22:16:46 +0000 (Wed, 17 Aug 2011) > > Log Message: > ----------- > Merging the graph-tulip branch back into trunk. All examples should be able to run with or without graph visualization (which requires Gephi to be installed). \n\n -- Read the instructions given in trunk/tulip/gephi to install the Gephi plugin I have written. (These directions should be moved to trunk/docs, but I don't know how to change the documentation.) \n\n -- 'grsim' and 'writeStatesToFile' in 'grsim.py' have been refactored with new arguments, and are now *incompatible* with TuLiP 0.1b. Read their docstrings or look at the examples to see how they are now used. \n\n -- 'automaton.py' has a few new methods: 'writeFile' writes a rudimentary '.aut' file from the current automaton. 'trimDeadStates' removes dead-end states. 'trimUnconnectedStates' removes all states that are inaccessible from a given automaton state. 'createPygraphRepr' creates a python-graph representation of the current automaton, and 'loadPygraphRepr' replaces the current list of states with what is curr > ently in the python-graph representation. \n\n -- trunk/tools now contains a short script to trim states from a '.aut' file. \n\n Should we consider changing the underlying representation of Automatons to python-graph digraphs? Doing so would eliminate some Automaton indexing issues and provide access to many of the graph manipulation tools in python-graph. |
From: <mur...@us...> - 2011-08-07 15:37:43
|
Revision: 176 http://python-control.svn.sourceforge.net/python-control/?rev=176&view=rev Author: murrayrm Date: 2011-08-07 15:37:37 +0000 (Sun, 07 Aug 2011) Log Message: ----------- updated version information for sphinx documentation Modified Paths: -------------- trunk/ChangeLog Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-08-07 15:37:25 UTC (rev 175) +++ trunk/ChangeLog 2011-08-07 15:37:37 UTC (rev 176) @@ -1,3 +1,9 @@ +2011-08-07 Richard Murray <murray@malabar.local> + + * doc/conf.py: Updated version numbers to 0.5a, regenerated + documentation and reposted on web (note that 0.5a tag and source + distribution have this wrong) + ---- control-0.5a released ----- 2011-08-07 Richard Murray <murray@malabar.local> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-08-07 15:37:31
|
Revision: 175 http://python-control.svn.sourceforge.net/python-control/?rev=175&view=rev Author: murrayrm Date: 2011-08-07 15:37:25 +0000 (Sun, 07 Aug 2011) Log Message: ----------- updated version information for sphinx documentation Modified Paths: -------------- trunk/doc/conf.py Modified: trunk/doc/conf.py =================================================================== --- trunk/doc/conf.py 2011-08-07 15:21:38 UTC (rev 174) +++ trunk/doc/conf.py 2011-08-07 15:37:25 UTC (rev 175) @@ -57,9 +57,9 @@ # built documents. # # The short X.Y version. -version = '0.4d' +version = '0.5a' # The full version, including alpha/beta/rc tags. -release = '0.4d' +release = '0.5a' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-08-07 15:21:47
|
Revision: 174 http://python-control.svn.sourceforge.net/python-control/?rev=174&view=rev Author: murrayrm Date: 2011-08-07 15:21:38 +0000 (Sun, 07 Aug 2011) Log Message: ----------- tagging 0.5a Modified Paths: -------------- trunk/ChangeLog Added Paths: ----------- tags/control-0.5a/ tags/control-0.5a/ChangeLog tags/control-0.5a/doc/Makefile tags/control-0.5a/doc/README tags/control-0.5a/doc/conf.py tags/control-0.5a/doc/index.rst tags/control-0.5a/doc/intro.rst tags/control-0.5a/doc/matlab_strings.rst tags/control-0.5a/examples/README tags/control-0.5a/examples/genswitch.py tags/control-0.5a/examples/phaseplots.py tags/control-0.5a/examples/pvtol-lqr.py tags/control-0.5a/examples/pvtol-nested-ss.py tags/control-0.5a/examples/pvtol-nested.py tags/control-0.5a/examples/secord-matlab.py tags/control-0.5a/examples/test-response.py tags/control-0.5a/setup.py tags/control-0.5a/src/__init__.py tags/control-0.5a/src/ctrlutil.py tags/control-0.5a/src/delay.py tags/control-0.5a/src/freqplot.py tags/control-0.5a/src/margins.py tags/control-0.5a/src/mateqn.py tags/control-0.5a/src/matlab.py tags/control-0.5a/src/modelsimp.py tags/control-0.5a/src/nichols.py tags/control-0.5a/src/phaseplot.py tags/control-0.5a/src/pzmap.py tags/control-0.5a/src/rlocus.py tags/control-0.5a/src/statefbk.py tags/control-0.5a/src/statesp.py tags/control-0.5a/src/timeresp.py tags/control-0.5a/src/xferfcn.py tags/control-0.5a/tests/convert_test.py tags/control-0.5a/tests/margin_test.py tags/control-0.5a/tests/matlab_test.py tags/control-0.5a/tests/phaseplot_test.py tags/control-0.5a/tests/test_all.py tags/control-0.5a/tests/timeresp_test.py Removed Paths: ------------- tags/control-0.5a/ChangeLog tags/control-0.5a/doc/Makefile tags/control-0.5a/doc/README tags/control-0.5a/doc/conf.py tags/control-0.5a/doc/control.tex tags/control-0.5a/doc/index.rst tags/control-0.5a/doc/intro.rst tags/control-0.5a/doc/matlab_strings.rst tags/control-0.5a/examples/pvtol-lqr.py tags/control-0.5a/examples/pvtol-nested-ss.py tags/control-0.5a/examples/pvtol-nested.py tags/control-0.5a/examples/secord-matlab.py tags/control-0.5a/examples/test-response.py tags/control-0.5a/setup.py tags/control-0.5a/src/__init__.py tags/control-0.5a/src/ctrlutil.py tags/control-0.5a/src/delay.py tags/control-0.5a/src/freqplot.py tags/control-0.5a/src/mateqn.py tags/control-0.5a/src/matlab.py tags/control-0.5a/src/modelsimp.py tags/control-0.5a/src/nichols.py tags/control-0.5a/src/pzmap.py tags/control-0.5a/src/rlocus.py tags/control-0.5a/src/statefbk.py tags/control-0.5a/src/statesp.py tags/control-0.5a/src/timeresp.py tags/control-0.5a/src/xferfcn.py tags/control-0.5a/tests/convert_test.py tags/control-0.5a/tests/matlab_test.py tags/control-0.5a/tests/test_all.py tags/control-0.5a/tests/timeresp_test.py Deleted: tags/control-0.5a/ChangeLog =================================================================== --- trunk/ChangeLog 2011-06-18 19:13:09 UTC (rev 161) +++ tags/control-0.5a/ChangeLog 2011-08-07 15:21:38 UTC (rev 174) @@ -1,366 +0,0 @@ -2011-06-18 Richard Murray <murray@malabar.local> - - * src/timeresp.py, src/matlab.py: moved documentation about time - series convention from matlab.py to timeresp.py - - * examples/pvtol-nested-ss.py: Fixed bug in call to step (wrong - second argument) - - * tests/matlab_test.py: Updated tests to use MATLAB time response - conventions. - - * tests/timeresp_test.py: Created unit tests for timeresp module, - based on matlab_test.py - -2011-06-17 Richard Murray <murray@malabar.local> - - * src/timeresp.py (ForcedResponse): swapped order of input and time - arguments for linear response, following Eike's comment "T must - always be supplied by the user, but U has a useful default value of - 0." - - * src/matlab.py: moved code for lsim, initial, step, and impulse to - timeresp.py and put in new routes that call timeresp.* versions of - the functions with transposeData set to True. - - * src/timesim.py (_check_convert_array): added transpose argument - that will transpose input data before processing it. - - * src/timesim.py: renamed lsim, initial, step, and impulse functions - to ForcedResponse, InitialResponse, StepResponse and - ImpulseResponse. These versions use Eike Welk's input ordering. - - * examples/pvtol-nested.py: calls to step() had screwed up inputs. - Fixed. - -2011-06-17 Richard Murray <murray@malabar.local> - - * src/matlab.py: added MIMO extensions from Eike Welk on 12 Jun - 2011: adds MIMO capabilities for ``lsim``, ``step``, ``impulse``, - ``initial`` - - * src/matlab.py: added changes from Eike Welk on 12 May 2011: - - - An implementation of the four simulation functions ``lsim``, - ``step``, ``initial``, and ``impulse`` of the module ``matlab``. - - - Adds a function ``dcgain`` to the ``matlab`` module, which - computes the gain of a linear system for steady state and - constant input. - - - The patch contains a bug fix for class ``StateSpace``, which - enables it to work properly together with Scipy's ``signal`` - module. - - - The simulation functions' return values are changed (back?) to - arrays, because matrices confuse Matplotlib. - - - New times series convention: see _time-series-convention section - of matlab documentation - - - SISO simulation data are squeezed on output. To turn this off, - pass the option squeeze=False - ----- control-0.4c released ----- - -2011-06-17 Richard Murray <mu...@dh...> - - * examples/tfvis.py: Added tfvis, Simple GUI application for - visualizing how the poles/zeros of the transfer function effects the - bode, nyquist and step response of a SISO system. Contributed by - Vanessa Romero Segovia, Ola Johnsson, Jerker Nordh. - -2011-06-16 Richard Murray <murray@malabar.local> - - * src/matlab.py: import mateqn functions - - * src/__init__.py: import mateqn functions - - * tests/test_all.py: added unit tests for matrix solvers, converting - to standard format along the way. Seems to work even if slycot - routines are not in place, but I'm not sure if this is for the right - reasons... - - * src/mateqn.py: added matrix solvers from LTH (Ola Johnsson, Jerker - Nordh, Bjorn Olofsson, Vanessa Romero). Moved slycot function - checks to the portion of the code where they are used, so that - missing slycot doesn't mess up initialization if proper version of - slycot is not available. - -2011-04-02 Richard Murray <murray@malabar.local> - - * src/xferfcn.py (TransferFunction.__add__): fixed bug when adding a - transfer function to state space system; _convertToTransferFunction - was being called with input/output keywords. Picked up in unit test. - - * tests/matlab_test.py: added calls to all of the functions that are - currently implemented in the library, to make sure there are no - hidden issues. These calls do *not* test functionality, they just - make sure that MATLAB compatibility functions accept the right types - of arguments. - - * examples/secord-matlab.py: added root locus plot to list of - figures that are produced - - * src/__init__.py: added rlocus to list of modules that are imported - by control module - - * src/exception.py (ControlMIMONotImplemented): added exception for - functions that are not yet implemented for MIMO systems - - * src/xferfcn.py (TransferFunction.__init__): convert integer - numerator and denominator objects to floats to eliminate errors when - creating common denominator (also used on pole command). This fixes - and error were tf([1], [1, 2, 1]).pole() would generate an error. - - * src/freqplot.py (bode): Tweaked documentation string to remove 'h' - from mag and phase return arguments - - * src/rlocus.py (RootLocus): removed commands that set figure number - inside of RootLocus command, for consistency with other frequency - plot routines. Added Plot=True argument and updated documentation. - - * src/matlab.py: added rlocus() command (calls RootLocus) - - * MANIFEST.in: Added MANIFEST.in file to include examples and tests - in source distribution - - * README: Updated to include information on how to run unit tests. - - * setup.py: updated version number to 0.4c - ----- control-0.4b released ----- - -2011-04-02 Richard Murray <murray@malabar.local> - - * src/__init__.py: removed import of tests module (moved to tests/) - - * src/matlab.py: Added hsvd, balred, modred to list of functions - that are imported for use as is. Updated documentation string to - indicate that these are implemented, along with a few other - functions (zero, lqr) that weren't properly listed. - - * src/modelsimp.py (balred): Removed extraneous print statements - (modred): Set method to be 'matchdc' by default (to match MATLAB) - - * src/__init__.py: added missing import of modelsimp functions - - * tests/slycot_convert_test.py (TestSlycot.testTF): turned off print - statements in unit test to make it easier to see results. Use - verbose=True to turn back on. - - * tests/convert_test.py (TestConvert.testConvert): got rid of print - statements in unittest; clutters the output so that you can't see - the errors clearly. Use verbose=True to turn back on. - - * src/statesp.py (_convertToStateSpace): removed "buggy" print - statements - - * src/xferfcn.py (_convertToTransferFunction): removed "buggy" print - statements - - * tests/nichols_test.py (TestStateSpace.testNgrid): updated testcode - to turn off grid in initial Nichols chart plot. - - * src/freqplot.py: updated comments at top of file to reflect - nichols chart move - - * src/nichols.py: transferred over changes from v0.3d - - * src/matlab.py (ngrid): moved import to function - -2011-03-31 Richard Murray <murray@malabar.local> - - * examples/pvtol-nested.py: updated stability margin plot to use - proper calling format for bode(). - - * src/statesp.py (_convertToStateSpace): moved slycot import - to the location where it is actually needed (allows running some - commands without slycot installed) - - * src/xferfcn.py (_convertToTransferFunction): moved slycot import - to the location where it is actually needed (allows running some - commands without slycot installed) - - * src/nichols.py: new file for Nichols plot routines; move - nichols(), nichols_grid(), closed_loop_contours(), m_circles(), - n_circles() - - * src/__init__.py, src/freqresp.py, src/matlab.py: updated to match - new file structure for Nichols charts - - * src/nichols.py (nichols): updated processing of freqresp to take - into account the fact that return arguments are now a matrix of - results (even for a SISO system) - -2011-03-30 Richard Murray <murray@malabar.local> - - * tests/: added top level subdirectory, to be used for unit tests. - The idea in putting the code here is that you can do 'setup.py test' - during installation to make sure everything is working correctly. - The test code would normally *not* be callable from the installed - module. - - * tests/*_test.py: moved from src/Test*.py - - * setup.py: updated version number. - -2011-02-13 Richard Murray <murray@sumatra.local> - - * src/*.py: added svn:keywords Id properly - - * src/matlab.py (ngrid): added ngrid() from v0.3d - - * src/freqplot.py (nichols_grid, closed_loop_contours, m_circles, - n_circles): copied over changes from Allan McInnes in v0.3d; ngrid() - functiality + split out some of the nichols chart code into separate - functions - -2011-02-12 Richard Murray <murray@sumatra.local> - - * setup.py: updated version number to 0.4a - -2010-11-05 Richard Murray <murray@sumatra.local> - - * external/yottalab.py: New file containing Roberto Bucher's control - library functions. OK to start pulling these into the main library, - with attribution, but note that they use modifications of the - default library => some rewrites will be needed. - -2010-09-11 Richard Murray <murray@sumatra.local> - - * src/matlab.py (step): Added local step response function that uses - lsim2() instead of signal.step (which can't handle integrators). - This function may not be needed when new scipy step2() function is - available. - (impulse): Added local impulse response function that sets the - initial condition based on the input matrix and then uses the - lsim2() function to compute the response. - - * examples/test-response.py: Added test script for making sure that - time repsonse functions are working as desired - - * src/matlab.py (lsim): Added local version of lsim that calls - signal.lsim2 (actual ODE integrator) - -2010-09-06 Richard Murray <murray@sumatra.local> - - * src/statefbk.py (ctrb): new function for testing controllability - * src/statefbk.py (obsv): new function for testing observabiilty - -2010-09-02 Richard Murray <murray@sumatra.local> - - * src/statefbk.py (place): Use np.size() instead of len() for - finding length of placed_eigs for better compatability with - different python versions [courtesy of Roberto Bucher] - - * src/delay.py (pade): New file for delay-based computations + - initial implementation of pade() [courtesy Sawyer Fuller] - -2010-06-17 Richard Murray <murray@sumatra.local> - - * src/rlocus.py: changed num, den to nump, denp for clarity - * src/rlocus.py: new file with Ryan Krauss's root locus code - -2010-06-06 Richard Murray <murray@sumatra.local> - - * examples/pvtol-lqr.py: Added example to test out LQR routines - - * src/matlab.py (bode): created a wrapper that allows MATLAB style - arguments for bode (eg, bode(sys1, sys2)) - - * src/ctrlutil.py (issys): added new function to check if an object - is a system (state space or transfer function). Will generalize - this latter to look for other compatible classes. - - * src/freqplot.py (bode): Compute frequency range of bode plot based - on poles and zeros - (bode): Allow bode plot to be passed a list (or tuple) as the first - argument, in which case multiple bode plots are generated - - * src/statesp.py (StateSpace.zeros): new function to compute zeros - for a state space system - (StateSpace): defined new functions to compute poles of a state - space system - - * src/xferfcn.py (TransferFunction): defined new functions to - compute poles and zeros of a transfer function. - -2010-05-31 Richard Murray <murray@sumatra.local> - - * src/exception.py (ControlNotImplemented): added new exception, to - be used for functions that are not yet implemented - - * src/statefbk.py (lqr): added lqr function (using slycot). Still - needs to be verified to make sure calculations are correct. - - * ChangeLog: converted to standard GNU formation (old style below) - * setup.py: updated package number to v0.3, changed URL to - sourceforge wiki - ------------------- -31 May 2010, RMM: added place() function using slycot - * New module: statefbk - functions to design state feedback controllers - * Uses Enrico Avventi slycot wrappers (http://github.com/avventi/Slycot) - * Also added some exception types: ControlSlycot and ControlDimension - * Added new example to test slycot interface (directly) - -29 May 2010, RMM: updated function documentation - * Added __doc__ strings for all current functions - * Added __doc__ string to matlab module, listing control toolbox functions - -22 May 2010, RMM: tweaked comments and released v0.3a - * Changed copyright information on modified files to 2010 - * Updated "to do" comments to use "#! TODO:" as prefix - -11 Feb 2010, GR: implemented and tested state space feedback -15 Jan 2010, GR: added new example, improved bode - -4 Jan 2010, GR: updated bode plots - * made bode plot more like matlab - * added options for plotting in dB, Hz - -27 Dec 2009, GR: important bug fix: feedback TFs were being divided by two - -10 Oct 09, RMM: reset matplotlib import in secord-matlab - * Using 'from matplotlib import *' causes error with figures - * On my other computer, got error when trying to import 'matplotlib.pyplot' - * Need to sort out versions and figure out proper import structure - -13 Sep 09, RMM: added basic state space functionality - * Updated StateSpace routines to allow BD algebra with constants - * Updated pvtol-nested example to try to use state space representation - (not completely working yet) - -12 Sep 09, RMM: code restructuring for transfer functions - * Implemented feedback() method in bldalg; partially working - for mixture of TF, SS and numbers (not thoroughly tested yet) - * New feedback method for TransferFunctions - * Updated gangof4 to use new feedback function - -9 Sep 09, RMM: updated pzmap to generate a plot (turn off with Plot=False) - -8 Sep 09, RMM: rewrite of xferfcn to handle type casting better - * Appropriate functions now call convertToTransferFunction - * Restricted transfer function to SISO only - -7 Sep 09, RMM: additional fixes - * Implemented block diagram operations for SISO transfer functions - * Modified frequency response functions for transfer functions - * Added rudimentary pole/zero computations - * Added comments on things that need to be fixed (search for !) - -5 Sep 09, RMM: updates to get standard examples working - * Copied and converted pvtol_nested.py from AM08, Chapter 11 - * Updated freqresp to use poly1d for computing values - * Added outputs to bode plot - return mag and phase subplot handles - -2009-05-24 Richard Murray <murray@kona-2.local> - * ./ Initial creation of package files and ChangeLog - * Using simpler text format since emacs python mode doesn't support - ChangeLog entries anyway - - -Local Variables: -mode:text -End: Copied: tags/control-0.5a/ChangeLog (from rev 172, trunk/ChangeLog) =================================================================== --- tags/control-0.5a/ChangeLog (rev 0) +++ tags/control-0.5a/ChangeLog 2011-08-07 15:21:38 UTC (rev 174) @@ -0,0 +1,541 @@ +---- control-0.5a released ----- + +2011-08-07 Richard Murray <murray@malabar.local> + + * setup.py: updated version number; next release will be 0.5a since + the changes in function names and argument/return value order (for + time reponses) require small updates in code + + * examples/secord-matlab.py, examples/pvtol-nested-ss.py, + examples/test-response.py, examples/pvtol-nested.py: fixed small bug + in order of output arguments for step command + +2011-08-06 Richard Murray <murray@malabar.local> + + * src/matlab.py (ngrid): copy documentation from nichols_grid + + * src/__init__.py: changed import commands to import specific + functions rather than '*' (better modularity) + + * src/freqplot.py: default function names are now bode_plot, + nyquist_plot and gangof4_plot (still with aliases to non-"_plot" + versions) + + * src/nichols.py (nichols_plot): updated nichols to nichols_plot for + consistency with other python-control plotting functions. Set up + alias for original name + + * src/margins.py: StabilityMargins, PhaseCrossoverFrequencies -> + stability_margins, phase_crossover_frequencies + + * src/phaseplot.py: changed PhasePlot and boxgrid to phase_plot, + box_grid + + * src/timeresp.py: changed ForcedReponse, InitialReponse, + ImpulseReponse and StepResponse to forced_response, + initial_response, impulse_response and step_response. + + * src/rlocus.py: changed RootLocus to root_locus for better + compatability with PEP 8. Also updated unit tests and examples. + +2011-07-25 Richard Murray <murray@malabar.local> + + * tests/phaseplot_test.py: updated unit tests to use new call + signatures + + * examples/phaseplots.py: updated calls to PhasePlot to use new + argument structure + + * src/phaseplot.py (PhasePlot): Updated call signature to be + more pythonic and fixed up documentation. + + * examples/genswitch.py (genswitch): added new example showing + PhasePlot functionality + + * src/phaseplot.py (boxgrid): added function to compute initial + conditions around the edges of a box + +2011-07-24 Richard Murray <murray@malabar.local> + + * tests/margin_test.py: added simple unit tests for margin functions + (initial versions just call functions; some comparisons missing) + + * examples/README: added missing README file + + * examples/phaseplots.py: FBS examples for phaseplot + + * tests/phaseplot_test.py: unit tests for phaseplot + + * src/phaseplot.py: initial cut at phase portrait function, built + from amphaseplot (Feeback Systems [FBS], Astrom and Murray, 2008) + +2011-07-15 Richard Murray <murray@malabar.local> + + * tests/matlab_test.py (TestMatlab): added unittest for margin() + commands (calling format only) + + * src/statesp.py (StateSpace): updated comments + + * tests/margin_test.py: set up unit tests for StabilityMargins() and + PhaseCrossoverFrequencies() + + * src/__init__.py: added margins.py to __init__ + +2011-07-14 Richard Murray <murray@malabar.local> + + * src/margins.py (GainPhaseMargin): moved freqplot.MarginPlot to + margin.StabilityMargins (MarginPlot didn't actually plot anything) + + * src/margins.py (PhaseCrossoverFrequencies): added new function to + compute frequencies that we cross real axis. Contributed by Steffen + Waldherr <wal...@is...> + +2011-07-11 Richard Murray <murray@malabar.local> + + * src/rlocus.py: added real() and imag() to list of functions + imported from numpy + + * src/freqplot.py: renamed plotting functions to BodePlot, + NyquistPlot, GangOf4Plot and MarginPlot. Set up aliases to the more + common names (bode, nyquest, gangof4, margin). Mainly playing + around with idea for the eventual interface to use. + + * tests/matlab_test.py: updated timeresp outputs to match MATLAB + + * src/matlab.py (impulse, initial, lsim, step): switched outputs + from step, impulse, initial, lsim to match MATLAB standard + +2011-07-01 Richard Murray <murray@malabar.local> + + * src/rlocus.py: modified scipy import to only import those + functions that we actually use. This fixes a problem pointed out by + Carsten Knoll (TU Dresden) where control.place could be overwritten + by numpy.place (because of an "from scipy import *" in rlocus.py + + * doc/intro.rst: Added link to scipy web page talking about the + differences between numpy and MATLAB (contributed by Shuo Han). + +2011-06-25 Richard Murray <murray@malabar.local> + + * src/xferfcn.py (TransferFunction._common_den): changed tolerance + for detecting complex valued poles to a user-settable parameter, + with default value 1e-8. This was an attempt to fix errors in the + convert_test.py unittest script (conversion routine was + misclassifying some poles as imaginary when they weren't). + + * src/xferfcn.py (_convertToTransferFunction): converted arguments + to tb04ad to numpy arrays; fixes a unit test error in convert_test.py. + + * src/statefbk.py (gram): convert system matrix passed to sb03md to + numpy array; this fixes a unit test error in modelsimp_test.py. + + * src/matlab.py (impulse): got rid of X0 argument for impulse + response (not implemented in MATLAB). + + * doc/intro.rst: added some quick start information + + * src/matlab.py: added documentation for step, impulse, initial, lsim + + * src/timeresp.py: fixed some MATLAB specific function names in + function doc strings + +2011-06-22 Richard Murray <murray@malabar.local> + + * doc/intro.rst: fixed some small types + + * doc/control.tex: removed (no longer needed) + +2011-06-22 Richard Murray <murray@malabar.local> + + * doc/intro.rst: Added a slightly more general introduction, with a + pointer to the python-control wiki (on sf.net) + + * doc/Makefile: Changed path to sphinx-build to assume it is in the + users path (as opposed to an explicit path) + + * doc/conf.py: Added release information into documentation file + +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 + series convention from matlab.py to timeresp.py + + * examples/pvtol-nested-ss.py: Fixed bug in call to step (wrong + second argument) + + * tests/matlab_test.py: Updated tests to use MATLAB time response + conventions. + + * tests/timeresp_test.py: Created unit tests for timeresp module, + based on matlab_test.py + +2011-06-17 Richard Murray <murray@malabar.local> + + * src/timeresp.py (ForcedResponse): swapped order of input and time + arguments for linear response, following Eike's comment "T must + always be supplied by the user, but U has a useful default value of + 0." + + * src/matlab.py: moved code for lsim, initial, step, and impulse to + timeresp.py and put in new routes that call timeresp.* versions of + the functions with transposeData set to True. + + * src/timesim.py (_check_convert_array): added transpose argument + that will transpose input data before processing it. + + * src/timesim.py: renamed lsim, initial, step, and impulse functions + to ForcedResponse, InitialResponse, StepResponse and + ImpulseResponse. These versions use Eike Welk's input ordering. + + * examples/pvtol-nested.py: calls to step() had screwed up inputs. + Fixed. + +2011-06-17 Richard Murray <murray@malabar.local> + + * src/matlab.py: added MIMO extensions from Eike Welk on 12 Jun + 2011: adds MIMO capabilities for ``lsim``, ``step``, ``impulse``, + ``initial`` + + * src/matlab.py: added changes from Eike Welk on 12 May 2011: + + - An implementation of the four simulation functions ``lsim``, + ``step``, ``initial``, and ``impulse`` of the module ``matlab``. + + - Adds a function ``dcgain`` to the ``matlab`` module, which + computes the gain of a linear system for steady state and + constant input. + + - The patch contains a bug fix for class ``StateSpace``, which + enables it to work properly together with Scipy's ``signal`` + module. + + - The simulation functions' return values are changed (back?) to + arrays, because matrices confuse Matplotlib. + + - New times series convention: see _time-series-convention section + of matlab documentation + + - SISO simulation data are squeezed on output. To turn this off, + pass the option squeeze=False + +---- control-0.4c released ----- + +2011-06-17 Richard Murray <mu...@dh...> + + * examples/tfvis.py: Added tfvis, Simple GUI application for + visualizing how the poles/zeros of the transfer function effects the + bode, nyquist and step response of a SISO system. Contributed by + Vanessa Romero Segovia, Ola Johnsson, Jerker Nordh. + +2011-06-16 Richard Murray <murray@malabar.local> + + * src/matlab.py: import mateqn functions + + * src/__init__.py: import mateqn functions + + * tests/test_all.py: added unit tests for matrix solvers, converting + to standard format along the way. Seems to work even if slycot + routines are not in place, but I'm not sure if this is for the right + reasons... + + * src/mateqn.py: added matrix solvers from LTH (Ola Johnsson, Jerker + Nordh, Bjorn Olofsson, Vanessa Romero). Moved slycot function + checks to the portion of the code where they are used, so that + missing slycot doesn't mess up initialization if proper version of + slycot is not available. + +2011-04-02 Richard Murray <murray@malabar.local> + + * src/xferfcn.py (TransferFunction.__add__): fixed bug when adding a + transfer function to state space system; _convertToTransferFunction + was being called with input/output keywords. Picked up in unit test. + + * tests/matlab_test.py: added calls to all of the functions that are + currently implemented in the library, to make sure there are no + hidden issues. These calls do *not* test functionality, they just + make sure that MATLAB compatibility functions accept the right types + of arguments. + + * examples/secord-matlab.py: added root locus plot to list of + figures that are produced + + * src/__init__.py: added rlocus to list of modules that are imported + by control module + + * src/exception.py (ControlMIMONotImplemented): added exception for + functions that are not yet implemented for MIMO systems + + * src/xferfcn.py (TransferFunction.__init__): convert integer + numerator and denominator objects to floats to eliminate errors when + creating common denominator (also used on pole command). This fixes + and error were tf([1], [1, 2, 1]).pole() would generate an error. + + * src/freqplot.py (bode): Tweaked documentation string to remove 'h' + from mag and phase return arguments + + * src/rlocus.py (RootLocus): removed commands that set figure number + inside of RootLocus command, for consistency with other frequency + plot routines. Added Plot=True argument and updated documentation. + + * src/matlab.py: added rlocus() command (calls RootLocus) + + * MANIFEST.in: Added MANIFEST.in file to include examples and tests + in source distribution + + * README: Updated to include information on how to run unit tests. + + * setup.py: updated version number to 0.4c + +---- control-0.4b released ----- + +2011-04-02 Richard Murray <murray@malabar.local> + + * src/__init__.py: removed import of tests module (moved to tests/) + + * src/matlab.py: Added hsvd, balred, modred to list of functions + that are imported for use as is. Updated documentation string to + indicate that these are implemented, along with a few other + functions (zero, lqr) that weren't properly listed. + + * src/modelsimp.py (balred): Removed extraneous print statements + (modred): Set method to be 'matchdc' by default (to match MATLAB) + + * src/__init__.py: added missing import of modelsimp functions + + * tests/slycot_convert_test.py (TestSlycot.testTF): turned off print + statements in unit test to make it easier to see results. Use + verbose=True to turn back on. + + * tests/convert_test.py (TestConvert.testConvert): got rid of print + statements in unittest; clutters the output so that you can't see + the errors clearly. Use verbose=True to turn back on. + + * src/statesp.py (_convertToStateSpace): removed "buggy" print + statements + + * src/xferfcn.py (_convertToTransferFunction): removed "buggy" print + statements + + * tests/nichols_test.py (TestStateSpace.testNgrid): updated testcode + to turn off grid in initial Nichols chart plot. + + * src/freqplot.py: updated comments at top of file to reflect + nichols chart move + + * src/nichols.py: transferred over changes from v0.3d + + * src/matlab.py (ngrid): moved import to function + +2011-03-31 Richard Murray <murray@malabar.local> + + * examples/pvtol-nested.py: updated stability margin plot to use + proper calling format for bode(). + + * src/statesp.py (_convertToStateSpace): moved slycot import + to the location where it is actually needed (allows running some + commands without slycot installed) + + * src/xferfcn.py (_convertToTransferFunction): moved slycot import + to the location where it is actually needed (allows running some + commands without slycot installed) + + * src/nichols.py: new file for Nichols plot routines; move + nichols(), nichols_grid(), closed_loop_contours(), m_circles(), + n_circles() + + * src/__init__.py, src/freqresp.py, src/matlab.py: updated to match + new file structure for Nichols charts + + * src/nichols.py (nichols): updated processing of freqresp to take + into account the fact that return arguments are now a matrix of + results (even for a SISO system) + +2011-03-30 Richard Murray <murray@malabar.local> + + * tests/: added top level subdirectory, to be used for unit tests. + The idea in putting the code here is that you can do 'setup.py test' + during installation to make sure everything is working correctly. + The test code would normally *not* be callable from the installed + module. + + * tests/*_test.py: moved from src/Test*.py + + * setup.py: updated version number. + +2011-02-13 Richard Murray <murray@sumatra.local> + + * src/*.py: added svn:keywords Id properly + + * src/matlab.py (ngrid): added ngrid() from v0.3d + + * src/freqplot.py (nichols_grid, closed_loop_contours, m_circles, + n_circles): copied over changes from Allan McInnes in v0.3d; ngrid() + functiality + split out some of the nichols chart code into separate + functions + +2011-02-12 Richard Murray <murray@sumatra.local> + + * setup.py: updated version number to 0.4a + +2010-11-05 Richard Murray <murray@sumatra.local> + + * external/yottalab.py: New file containing Roberto Bucher's control + library functions. OK to start pulling these into the main library, + with attribution, but note that they use modifications of the + default library => some rewrites will be needed. + +2010-09-11 Richard Murray <murray@sumatra.local> + + * src/matlab.py (step): Added local step response function that uses + lsim2() instead of signal.step (which can't handle integrators). + This function may not be needed when new scipy step2() function is + available. + (impulse): Added local impulse response function that sets the + initial condition based on the input matrix and then uses the + lsim2() function to compute the response. + + * examples/test-response.py: Added test script for making sure that + time repsonse functions are working as desired + + * src/matlab.py (lsim): Added local version of lsim that calls + signal.lsim2 (actual ODE integrator) + +2010-09-06 Richard Murray <murray@sumatra.local> + + * src/statefbk.py (ctrb): new function for testing controllability + * src/statefbk.py (obsv): new function for testing observabiilty + +2010-09-02 Richard Murray <murray@sumatra.local> + + * src/statefbk.py (place): Use np.size() instead of len() for + finding length of placed_eigs for better compatability with + different python versions [courtesy of Roberto Bucher] + + * src/delay.py (pade): New file for delay-based computations + + initial implementation of pade() [courtesy Sawyer Fuller] + +2010-06-17 Richard Murray <murray@sumatra.local> + + * src/rlocus.py: changed num, den to nump, denp for clarity + * src/rlocus.py: new file with Ryan Krauss's root locus code + +2010-06-06 Richard Murray <murray@sumatra.local> + + * examples/pvtol-lqr.py: Added example to test out LQR routines + + * src/matlab.py (bode): created a wrapper that allows MATLAB style + arguments for bode (eg, bode(sys1, sys2)) + + * src/ctrlutil.py (issys): added new function to check if an object + is a system (state space or transfer function). Will generalize + this latter to look for other compatible classes. + + * src/freqplot.py (bode): Compute frequency range of bode plot based + on poles and zeros + (bode): Allow bode plot to be passed a list (or tuple) as the first + argument, in which case multiple bode plots are generated + + * src/statesp.py (StateSpace.zeros): new function to compute zeros + for a state space system + (StateSpace): defined new functions to compute poles of a state + space system + + * src/xferfcn.py (TransferFunction): defined new functions to + compute poles and zeros of a transfer function. + +2010-05-31 Richard Murray <murray@sumatra.local> + + * src/exception.py (ControlNotImplemented): added new exception, to + be used for functions that are not yet implemented + + * src/statefbk.py (lqr): added lqr function (using slycot). Still + needs to be verified to make sure calculations are correct. + + * ChangeLog: converted to standard GNU formation (old style below) + * setup.py: updated package number to v0.3, changed URL to + sourceforge wiki + +------------------ +31 May 2010, RMM: added place() function using slycot + * New module: statefbk - functions to design state feedback controllers + * Uses Enrico Avventi slycot wrappers (http://github.com/avventi/Slycot) + * Also added some exception types: ControlSlycot and ControlDimension + * Added new example to test slycot interface (directly) + +29 May 2010, RMM: updated function documentation + * Added __doc__ strings for all current functions + * Added __doc__ string to matlab module, listing control toolbox functions + +22 May 2010, RMM: tweaked comments and released v0.3a + * Changed copyright information on modified files to 2010 + * Updated "to do" comments to use "#! TODO:" as prefix + +11 Feb 2010, GR: implemented and tested state space feedback +15 Jan 2010, GR: added new example, improved bode + +4 Jan 2010, GR: updated bode plots + * made bode plot more like matlab + * added options for plotting in dB, Hz + +27 Dec 2009, GR: important bug fix: feedback TFs were being divided by two + +10 Oct 09, RMM: reset matplotlib import in secord-matlab + * Using 'from matplotlib import *' causes error with figures + * On my other computer, got error when trying to import 'matplotlib.pyplot' + * Need to sort out versions and figure out proper import structure + +13 Sep 09, RMM: added basic state space functionality + * Updated StateSpace routines to allow BD algebra with constants + * Updated pvtol-nested example to try to use state space representation + (not completely working yet) + +12 Sep 09, RMM: code restructuring for transfer functions + * Implemented feedback() method in bldalg; partially working + for mixture of TF, SS and numbers (not thoroughly tested yet) + * New feedback method for TransferFunctions + * Updated gangof4 to use new feedback function + +9 Sep 09, RMM: updated pzmap to generate a plot (turn off with Plot=False) + +8 Sep 09, RMM: rewrite of xferfcn to handle type casting better + * Appropriate functions now call convertToTransferFunction + * Restricted transfer function to SISO only + +7 Sep 09, RMM: additional fixes + * Implemented block diagram operations for SISO transfer functions + * Modified frequency response functions for transfer functions + * Added rudimentary pole/zero computations + * Added comments on things that need to be fixed (search for !) + +5 Sep 09, RMM: updates to get standard examples working + * Copied and converted pvtol_nested.py from AM08, Chapter 11 + * Updated freqresp to use poly1d for computing values + * Added outputs to bode plot - return mag and phase subplot handles + +2009-05-24 Richard Murray <murray@kona-2.local> + * ./ Initial creation of package files and ChangeLog + * Using simpler text format since emacs python mode doesn't support + ChangeLog entries anyway + + +Local Variables: +mode:text +End: Deleted: tags/control-0.5a/doc/Makefile =================================================================== --- trunk/doc/Makefile 2011-06-18 19:13:09 UTC (rev 161) +++ tags/control-0.5a/doc/Makefile 2011-08-07 15:21:38 UTC (rev 174) @@ -1,130 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = /Applications/Sphinx-1.0.6/sphinx-build.py -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest - -help: - @echo "Please use \`make <target>' where <target> is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PythonControl.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PythonControl.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/PythonControl" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PythonControl" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." Copied: tags/control-0.5a/doc/Makefile (from rev 163, trunk/doc/Makefile) =================================================================== --- tags/control-0.5a/doc/Makefile (rev 0) +++ tags/control-0.5a/doc/Makefile 2011-08-07 15:21:38 UTC (rev 174) @@ -0,0 +1,130 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PythonControl.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PythonControl.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/PythonControl" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PythonControl" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + make -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." Deleted: tags/control-0.5a/doc/README =================================================================== --- trunk/doc/README 2011-06-18 19:13:09 UTC (rev 161) +++ tags/control-0.5a/doc/README 2011-08-07 15:21:38 UTC (rev 174) @@ -1,15 +0,0 @@ -Sphinx Documentation --------------------- - -Note: Sphinx actually runs and imports python code, so broken code, or code not in conf.py sys.path, cannot be documented! - -1. Get Sphinx [http://sphinx.pocoo.org/] - [python setup.py build/install] - -2. Install numpydoc [http://pypi.python.org/pypi/numpydoc] - -3. In Makefile point to your own copy of sphinx-build, e.g. - [SPHINXBUILD = /Users/steve/CODES/Sphinx-1.0.6/sphinx-build.py] - -4. >> touch *.rst - >> make html [or make latex] Copied: tags/control-0.5a/doc/README (from rev 164, trunk/doc/README) =================================================================== --- tags/control-0.5a/doc/README (rev 0) +++ tags/control-0.5a/doc/README 2011-08-07 15:21:38 UTC (rev 174) @@ -0,0 +1,20 @@ +Sphinx Documentation +-------------------- + +Note: Sphinx actually runs and imports python code, so broken code, or code not in conf.py sys.path, cannot be documented! + +1. Get Sphinx [http://sphinx.pocoo.org/] + [python setup.py build/install] + +2. Install numpydoc [http://pypi.python.org/pypi/numpydoc] + +3. In Makefile point to your own copy of sphinx-build, e.g. + [SPHINXBUILD = /Users/steve/CODES/Sphinx-1.0.6/sphinx-build.py] + +4. >> touch *.rst + >> make html [or make latex] + +Creating/updating manual on sourceforge: + +5. >> rsync -rav _build/html/ us...@sh...:/home/project-web/python-control/htdocs/manual-N.mx/ + Deleted: tags/control-0.5a/doc/conf.py =================================================================== --- trunk/doc/conf.py 2011-06-18 19:13:09 UTC (rev 161) +++ tags/control-0.5a/doc/conf.py 2011-08-07 15:21:38 UTC (rev 174) @@ -1,222 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Python Control documentation build configuration file, created by -# sphinx-quickstart on Tue Jan 11 16:11:31 2011. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -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. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'numpydoc', 'sphinx.ext.pngmath', - 'sphinx.ext.intersphinx'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Python Control' -copyright = u'2011, Richard M. Murray et al.' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.0' -# The full version, including alpha/beta/rc tags. -release = '0.0' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -#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)} - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# "<project> v<release> documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a <link> tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'PythonControldoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -# The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'PythonControl.tex', u'Python Control Documentation', - u'Python Control Developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Additional stuff for the LaTeX preamble. -#latex_preamble = '' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'pythoncontrol', u'Python Control Documentation', - [u'Python Control Developers'], 1) -] Copied: tags/control-0.5a/doc/conf.py (from rev 163, trunk/doc/conf.py) =================================================================== --- tags/control-0.5a/doc/conf.py (rev 0) +++ tags/control-0.5a/doc/conf.py 2011-08-07 15:21:38 UTC (rev 174) @@ -0,0 +1,235 @@ +# -*- coding: utf-8 -*- +# +# Python Control documentation build configuration file, created by +# sphinx-quickstart on Tue Jan 11 16:11:31 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +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. +#needs_sphinx = '1.0' + +# 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.todo'] + +# Add any paths that contain templates here, relative to this directory. +templ... [truncated message content] |
From: <mur...@us...> - 2011-08-07 15:18:41
|
Revision: 173 http://python-control.svn.sourceforge.net/python-control/?rev=173&view=rev Author: murrayrm Date: 2011-08-07 15:18:35 +0000 (Sun, 07 Aug 2011) Log Message: ----------- add blank line before list to fix formatting bug Modified Paths: -------------- trunk/doc/intro.rst Modified: trunk/doc/intro.rst =================================================================== --- trunk/doc/intro.rst 2011-08-07 15:12:58 UTC (rev 172) +++ trunk/doc/intro.rst 2011-08-07 15:18:35 UTC (rev 173) @@ -28,6 +28,7 @@ In terms of the python-control package more specifically, here are some thing to keep in mind: + * You must include commas in vectors. So [1 2 3] must be [1, 2, 3]. * Functions that return multiple arguments use tuples * Can't use braces for collections; use tuples instead This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-08-07 15:13:05
|
Revision: 172 http://python-control.svn.sourceforge.net/python-control/?rev=172&view=rev Author: murrayrm Date: 2011-08-07 15:12:58 +0000 (Sun, 07 Aug 2011) Log Message: ----------- * Changed function names to be more consistent with python coding standards (PEP 8): StepReponse is now step_response, etc. No changes in control.matlab interface. * Changed version number (for next release) to 0.5a due to changes in call signatures. Modified Paths: -------------- trunk/ChangeLog trunk/examples/genswitch.py trunk/examples/phaseplots.py trunk/examples/pvtol-lqr.py trunk/examples/pvtol-nested-ss.py trunk/examples/pvtol-nested.py trunk/examples/secord-matlab.py trunk/examples/test-response.py trunk/setup.py trunk/src/__init__.py trunk/src/freqplot.py trunk/src/margins.py trunk/src/matlab.py trunk/src/nichols.py trunk/src/phaseplot.py trunk/src/rlocus.py trunk/src/timeresp.py trunk/tests/margin_test.py trunk/tests/phaseplot_test.py trunk/tests/test_all.py trunk/tests/timeresp_test.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/ChangeLog 2011-08-07 15:12:58 UTC (rev 172) @@ -1,3 +1,37 @@ +2011-08-07 Richard Murray <murray@malabar.local> + + * examples/secord-matlab.py, examples/pvtol-nested-ss.py, + examples/test-response.py, examples/pvtol-nested.py: fixed small bug + in order of output arguments for step command + +2011-08-06 Richard Murray <murray@malabar.local> + + * src/matlab.py (ngrid): copy documentation from nichols_grid + + * src/__init__.py: changed import commands to import specific + functions rather than '*' (better modularity) + + * src/freqplot.py: default function names are now bode_plot, + nyquist_plot and gangof4_plot (still with aliases to non-"_plot" + versions) + + * src/nichols.py (nichols_plot): updated nichols to nichols_plot for + consistency with other python-control plotting functions. Set up + alias for original name + + * src/margins.py: StabilityMargins, PhaseCrossoverFrequencies -> + stability_margins, phase_crossover_frequencies + + * src/phaseplot.py: changed PhasePlot and boxgrid to phase_plot, + box_grid + + * src/timeresp.py: changed ForcedReponse, InitialReponse, + ImpulseReponse and StepResponse to forced_response, + initial_response, impulse_response and step_response. + + * src/rlocus.py: changed RootLocus to root_locus for better + compatability with PEP 8. Also updated unit tests and examples. + 2011-07-25 Richard Murray <murray@malabar.local> * tests/phaseplot_test.py: updated unit tests to use new call Modified: trunk/examples/genswitch.py =================================================================== --- trunk/examples/genswitch.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/examples/genswitch.py 2011-08-07 15:12:58 UTC (rev 172) @@ -9,7 +9,7 @@ import matplotlib.pyplot as mpl from scipy.integrate import odeint from matplotlib.mlab import frange -from control import PhasePlot, boxgrid +from control import phase_plot, box_grid # Simple model of a genetic switch # @@ -68,7 +68,7 @@ # Phase portrait mpl.figure(2); mpl.clf(); # subplot(221); mpl.axis([0, 5, 0, 5]); # set(gca, 'DataAspectRatio', [1, 1, 1]); -PhasePlot(genswitch, X0 = boxgrid([0, 5, 6], [0, 5, 6]), T = 10, +phase_plot(genswitch, X0 = box_grid([0, 5, 6], [0, 5, 6]), T = 10, timepts = [0.2, 0.6, 1.2]) # Add the stable equilibrium points Modified: trunk/examples/phaseplots.py =================================================================== --- trunk/examples/phaseplots.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/examples/phaseplots.py 2011-08-07 15:12:58 UTC (rev 172) @@ -6,7 +6,7 @@ import numpy as np import matplotlib.pyplot as mpl -from control.phaseplot import PhasePlot +from control.phaseplot import phase_plot from numpy import pi # Clear out any figures that are present @@ -26,7 +26,7 @@ mpl.title('Inverted pendlum') # Outer trajectories -PhasePlot(invpend_ode, +phase_plot(invpend_ode, X0 = [ [-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1], [-1, 2.1], [4.2, 2.1], [5, 2.1], [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1], @@ -36,7 +36,7 @@ # Separatrices mpl.hold(True); -PhasePlot(invpend_ode, X0 = [[-2.3056, 2.1], [2.3056, -2.1]], T=6, lingrid=0) +phase_plot(invpend_ode, X0 = [[-2.3056, 2.1], [2.3056, -2.1]], T=6, lingrid=0) mpl.show(); # @@ -48,7 +48,7 @@ # Generate a vector plot for the damped oscillator mpl.figure(); mpl.clf(); -PhasePlot(oscillator_ode, [-1, 1, 10], [-1, 1, 10], 0.15); +phase_plot(oscillator_ode, [-1, 1, 10], [-1, 1, 10], 0.15); mpl.hold(True); mpl.plot([0], [0], '.'); # a=gca; set(a,'FontSize',20); set(a,'DataAspectRatio',[1,1,1]); mpl.xlabel('x1'); mpl.ylabel('x2'); @@ -56,7 +56,7 @@ # Generate a phase plot for the damped oscillator mpl.figure(); mpl.clf(); mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1, 1, 1]); -PhasePlot(oscillator_ode, +phase_plot(oscillator_ode, X0 = [ [-1, 1], [-0.3, 1], [0, 1], [0.25, 1], [0.5, 1], [0.75, 1], [1, 1], [1, -1], [0.3, -1], [0, -1], [-0.25, -1], [-0.5, -1], [-0.75, -1], [-1, -1] @@ -81,7 +81,7 @@ m = 1; b = 1; k = 1; # default values mpl.figure(); mpl.clf(); mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); -PhasePlot(oscillator_ode, +phase_plot(oscillator_ode, X0 = [ [-1,1], [-0.3,1], [0,1], [0.25,1], [0.5,1], [0.7,1], [1,1], [1.3,1], [1,-1], [0.3,-1], [0,-1], [-0.25,-1], [-0.5,-1], [-0.7,-1], [-1,-1], @@ -95,7 +95,7 @@ # Saddle mpl.figure(); mpl.clf(); mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); -PhasePlot(saddle_ode, scale = 2, timepts = [0.2, 0.5, 0.8], X0 = +phase_plot(saddle_ode, scale = 2, timepts = [0.2, 0.5, 0.8], X0 = [ [-1, -1], [1, 1], [-1, -0.95], [-1, -0.9], [-1, -0.8], [-1, -0.6], [-1, -0.4], [-1, -0.2], [-0.95, -1], [-0.9, -1], [-0.8, -1], [-0.6, -1], [-0.4, -1], [-0.2, -1], @@ -111,7 +111,7 @@ m = 1; b = 0; k = 1; # zero damping mpl.figure(); mpl.clf(); mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); -PhasePlot(oscillator_ode, timepts = +phase_plot(oscillator_ode, timepts = [pi/6, pi/3, pi/2, 2*pi/3, 5*pi/6, pi, 7*pi/6, 4*pi/3, 9*pi/6, 5*pi/3, 11*pi/6, 2*pi], X0 = [ [0.2,0], [0.4,0], [0.6,0], [0.8,0], [1,0], [1.2,0], [1.4,0] ], T = np.linspace(0, 20, 200), parms = (m, b, k)); Modified: trunk/examples/pvtol-lqr.py =================================================================== --- trunk/examples/pvtol-lqr.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/examples/pvtol-lqr.py 2011-08-07 15:12:58 UTC (rev 172) @@ -111,11 +111,11 @@ # Step response for the first input H1ax = ss(Ax - Bx*K1a[0,lat], Bx*K1a[0,lat]*xd[lat,:], Cx, Dx); -(Tx, Yx) = step(H1ax, T=linspace(0,10,100)); +(Yx, Tx) = step(H1ax, T=linspace(0,10,100)); # Step response for the second input H1ay = ss(Ay - By*K1a[1,alt], By*K1a[1,alt]*yd[alt,:], Cy, Dy); -(Ty, Yy) = step(H1ay, T=linspace(0,10,100)); +(Yy, Ty) = step(H1ay, T=linspace(0,10,100)); subplot(221); title("Identity weights") # plot(T, Y[:,1, 1], '-', T, Y[:,2, 2], '--'); hold(True); @@ -136,9 +136,9 @@ Qu1c = (200**2)*diag([1, 1]); (K1c, X, E) = lqr(A, B, Qx1, Qu1c); H1cx = ss(Ax - Bx*K1c[0,lat], Bx*K1c[0,lat]*xd[lat,:],Cx, Dx); -[T1, Y1] = step(H1ax, T=linspace(0,10,100)); -[T2, Y2] = step(H1bx, T=linspace(0,10,100)); -[T3, Y3] = step(H1cx, T=linspace(0,10,100)); +[Y1, T1] = step(H1ax, T=linspace(0,10,100)); +[Y2, T2] = step(H1bx, T=linspace(0,10,100)); +[Y3, T3] = step(H1cx, T=linspace(0,10,100)); subplot(222); title("Effect of input weights") plot(T1.T, Y1.T, 'b-'); hold(True); @@ -160,8 +160,8 @@ H2y = ss(Ay - By*K2[1,alt], By*K2[1,alt]*yd[alt,:], Cy, Dy); subplot(223); title("Output weighting") -[T2x, Y2x] = step(H2x, T=linspace(0,10,100)); -[T2y, Y2y] = step(H2y, T=linspace(0,10,100)); +[Y2x, T2x] = step(H2x, T=linspace(0,10,100)); +[Y2y, T2y] = step(H2y, T=linspace(0,10,100)); plot(T2x.T, Y2x.T, T2y.T, Y2y.T) ylabel('position'); xlabel('time'); ylabel('position'); @@ -183,8 +183,8 @@ H3y = ss(Ay - By*K3[1,alt], By*K3[1,alt]*yd[alt,:], Cy, Dy); subplot(224) # step(H3x, H3y, 10); -[T3x, Y3x] = step(H3x, T=linspace(0,10,100)); -[T3y, Y3y] = step(H3y, T=linspace(0,10,100)); +[Y3x, T3x] = step(H3x, T=linspace(0,10,100)); +[Y3y, T3y] = step(H3y, T=linspace(0,10,100)); plot(T3x.T, Y3x.T, T3y.T, Y3y.T) title("Physically motivated weights") xlabel('time'); Modified: trunk/examples/pvtol-nested-ss.py =================================================================== --- trunk/examples/pvtol-nested-ss.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/examples/pvtol-nested-ss.py 2011-08-07 15:12:58 UTC (rev 172) @@ -144,10 +144,10 @@ # 'EdgeColor', color, 'FaceColor', color); figure(9); -(Tvec, Yvec) = step(T, linspace(1, 20)); +(Yvec, Tvec) = step(T, linspace(1, 20)); plot(Tvec.T, Yvec.T); hold(True); -(Tvec, Yvec) = step(Co*S, linspace(1, 20)); +(Yvec, Tvec) = step(Co*S, linspace(1, 20)); plot(Tvec.T, Yvec.T); #TODO: PZmap for statespace systems has not yet been implemented. Modified: trunk/examples/pvtol-nested.py =================================================================== --- trunk/examples/pvtol-nested.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/examples/pvtol-nested.py 2011-08-07 15:12:58 UTC (rev 172) @@ -134,10 +134,10 @@ # 'EdgeColor', color, 'FaceColor', color); figure(9); -(Tvec, Yvec) = step(T, linspace(1, 20)); +(Yvec, Tvec) = step(T, linspace(0, 20)); plot(Tvec.T, Yvec.T); hold(True); -(Tvec, Yvec) = step(Co*S, linspace(1, 20)); +(Yvec, Tvec) = step(Co*S, linspace(0, 20)); plot(Tvec.T, Yvec.T); figure(10); clf(); Modified: trunk/examples/secord-matlab.py =================================================================== --- trunk/examples/secord-matlab.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/examples/secord-matlab.py 2011-08-07 15:12:58 UTC (rev 172) @@ -17,7 +17,7 @@ # Step response for the system figure(1) -T, yout = step(sys) +yout, T = step(sys) plot(T.T, yout.T) # Bode plot for the system Modified: trunk/examples/test-response.py =================================================================== --- trunk/examples/test-response.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/examples/test-response.py 2011-08-07 15:12:58 UTC (rev 172) @@ -10,9 +10,9 @@ sys2 = tf([1, 1], [1, 1, 0]) # Generate step responses -(T1a, y1a) = step(sys1) -(T1b, y1b) = step(sys1, T = arange(0, 10, 0.1)) -(T1c, y1c) = step(sys1, X0 = [1, 0]) -(T2a, y2a) = step(sys2, T = arange(0, 10, 0.1)) +(y1a, T1a) = step(sys1) +(y1b, T1b) = step(sys1, T = arange(0, 10, 0.1)) +(y1c, T1c) = step(sys1, X0 = [1, 0]) +(y2a, T2a) = step(sys2, T = arange(0, 10, 0.1)) plot(T1a, y1a, T1b, y1b, T1c, y1c, T2a, y2a) Modified: trunk/setup.py =================================================================== --- trunk/setup.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/setup.py 2011-08-07 15:12:58 UTC (rev 172) @@ -4,7 +4,7 @@ from setuptools import setup setup(name = 'control', - version = '0.4d', + version = '0.5a', description = 'Python Control Systems Library', author = 'Richard Murray', author_email = 'mu...@cd...', Modified: trunk/src/__init__.py =================================================================== --- trunk/src/__init__.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/src/__init__.py 2011-08-07 15:12:58 UTC (rev 172) @@ -57,17 +57,18 @@ # Import functions from within the control system library #! Should probably only import the exact functions we use... -from bdalg import * -from delay import * -from freqplot import * -from margins import * -from mateqn import * -from modelsimp import * -from nichols import * -from phaseplot import PhasePlot, boxgrid -from rlocus import * -from statefbk import * -from statesp import * -from timeresp import ForcedResponse, InitialResponse, StepResponse, \ - ImpulseResponse -from xferfcn import * +from bdalg import series, parallel, negate, feedback +from delay import pade +from freqplot import bode_plot, nyquist_plot, gangof4_plot +from freqplot import bode, nyquist, gangof4 +from margins import stability_margins, phase_crossover_frequencies +from mateqn import lyap, dlyap, care, dare +from modelsimp import hsvd, modred, balred, era, markov +from nichols import nichols_plot, nichols +from phaseplot import phase_plot, box_grid +from rlocus import root_locus +from statefbk import place, lqr, ctrb, obsv, gram +from statesp import StateSpace +from timeresp import forced_response, initial_response, step_response, \ + impulse_response +from xferfcn import TransferFunction Modified: trunk/src/freqplot.py =================================================================== --- trunk/src/freqplot.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/src/freqplot.py 2011-08-07 15:12:58 UTC (rev 172) @@ -55,7 +55,7 @@ # # Bode plot -def BodePlot(syslist, omega=None, dB=False, Hz=False, deg=True, +def bode_plot(syslist, omega=None, dB=False, Hz=False, deg=True, color=None, Plot=True): """Bode plot for a system @@ -178,7 +178,7 @@ return mags, phases, omegas # Nyquist plot -def NyquistPlot(syslist, omega=None, Plot=True): +def nyquist_plot(syslist, omega=None, Plot=True): """Nyquist plot for a system Plots a Nyquist plot for the system over a (optional) frequency range. @@ -245,7 +245,7 @@ # Gang of Four #! TODO: think about how (and whether) to handle lists of systems -def GangOf4Plot(P, C, omega=None): +def gangof4_plot(P, C, omega=None): """Plot the "Gang of 4" transfer functions for a system Generates a 2x2 plot showing the "Gang of 4" sensitivity functions @@ -363,6 +363,6 @@ return omega # Function aliases -bode = BodePlot -nyquist = NyquistPlot -gangof4 = GangOf4Plot +bode = bode_plot +nyquist = nyquist_plot +gangof4 = gangof4_plot Modified: trunk/src/margins.py =================================================================== --- trunk/src/margins.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/src/margins.py 2011-08-07 15:12:58 UTC (rev 172) @@ -4,8 +4,8 @@ Routeins in this module: -margin.StabilityMargins -margin.PhaseCrossoverFrequencies +margin.stability_margins +margin.phase_crossover_frequencies """ """Copyright (c) 2011 by California Institute of Technology @@ -54,13 +54,13 @@ # gain and phase margins # contributed by Sawyer B. Fuller <mi...@ca...> #! TODO - need to add unit test functions -def StabilityMargins(sysdata, deg=True): +def stability_margins(sysdata, deg=True): """Calculate gain, phase and stability margins and associated crossover frequencies. Usage: - gm, pm, sm, wg, wp, ws = StabilityMargins(sysdata, deg=True) + gm, pm, sm, wg, wp, ws = stability_margins(sysdata, deg=True) Parameters ---------- @@ -149,13 +149,13 @@ # Contributed by Steffen Waldherr <wal...@is...> #! TODO - need to add test functions -def PhaseCrossoverFrequencies(sys): +def phase_crossover_frequencies(sys): """ Compute frequencies and gains at intersections with real axis in Nyquist plot. Call as: - omega, gain = PhaseCrossoverFrequencies() + omega, gain = phase_crossover_frequencies() Returns ------- Modified: trunk/src/matlab.py =================================================================== --- trunk/src/matlab.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/src/matlab.py 2011-08-07 15:12:58 UTC (rev 172) @@ -62,6 +62,7 @@ # Libraries that we make use of import scipy as sp # SciPy library (used all over) import numpy as np # NumPy library +import re # regular expressions from copy import deepcopy # Import MATLAB-like functions that are defined in other packages @@ -990,15 +991,10 @@ return freqplot.bode(syslist, omega, **keywords) # Nichols chart grid +from nichols import nichols_grid def ngrid(): - """Nichols chart grid. - - Examples - -------- - >>> ngrid() - """ - from nichols import nichols_grid nichols_grid() +ngrid.__doc__ = re.sub('nichols_grid', 'ngrid', nichols_grid.__doc__) # Root locus plot def rlocus(sys, klist = None, **keywords): @@ -1018,12 +1014,12 @@ klist: list of gains used to compute roots """ - from rlocus import RootLocus + from rlocus import root_locus if (klist == None): #! TODO: update with a smart cacluation of the gains klist = logspace(-3, 3) - rlist = RootLocus(sys, klist, **keywords) + rlist = root_locus(sys, klist, **keywords) return rlist, klist def margin(*args): @@ -1060,9 +1056,9 @@ """ if len(args) == 1: sys = args[0] - margin = margins.StabilityMargins(sys) + margin = margins.stability_margins(sys) elif len(args) == 3: - margin = margins.StabilityMargins(args) + margin = margins.stability_margins(args) else: raise ValueError("Margin needs 1 or 3 arguments; received %i." % len(args)) @@ -1157,7 +1153,7 @@ **keywords: Additional keyword arguments control the solution algorithm for the differential equations. These arguments are passed on to the function - :func:`control.ForcedResponse`, which in turn passes them on to + :func:`control.forced_response`, which in turn passes them on to :func:`scipy.integrate.odeint`. See the documentation for :func:`scipy.integrate.odeint` for information about these arguments. @@ -1178,7 +1174,7 @@ -------- >>> T, yout = step(sys, T, X0) ''' - T, yout = timeresp.StepResponse(sys, T, X0, input, output, + T, yout = timeresp.step_response(sys, T, X0, input, output, transpose = True, **keywords) return yout, T @@ -1228,7 +1224,7 @@ -------- >>> T, yout = impulse(sys, T) ''' - T, yout = timeresp.ImpulseResponse(sys, T, 0, input, output, + T, yout = timeresp.impulse_response(sys, T, 0, input, output, transpose = True, **keywords) return yout, T @@ -1284,7 +1280,7 @@ -------- >>> T, yout = initial(sys, T, X0) ''' - T, yout = timeresp.InitialResponse(sys, T, X0, input, output, + T, yout = timeresp.initial_response(sys, T, X0, input, output, transpose = True, **keywords) return yout, T @@ -1338,6 +1334,6 @@ -------- >>> T, yout, xout = lsim(sys, U, T, X0) ''' - T, yout, xout = timeresp.ForcedResponse(sys, T, U, X0, + T, yout, xout = timeresp.forced_response(sys, T, U, X0, transpose = True, **keywords) return yout, T, xout Modified: trunk/src/nichols.py =================================================================== --- trunk/src/nichols.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/src/nichols.py 2011-08-07 15:12:58 UTC (rev 172) @@ -46,7 +46,7 @@ from freqplot import default_frequency_range # Nichols plot -def nichols(syslist, omega=None, grid=True): +def nichols_plot(syslist, omega=None, grid=True): """Nichols plot for a system Plots a Nichols plot for the system over a (optional) frequency range. @@ -294,3 +294,6 @@ mags = sp.linspace(10**(mag_min/20.0), 10**(mag_max/20.0), 2000) Gcl_phases, Gcl_mags = sp.meshgrid(sp.radians(phases), mags) return closed_loop_contours(Gcl_mags, Gcl_phases) + +# Function aliases +nichols = nichols_plot Modified: trunk/src/phaseplot.py =================================================================== --- trunk/src/phaseplot.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/src/phaseplot.py 2011-08-07 15:12:58 UTC (rev 172) @@ -39,7 +39,7 @@ from exception import ControlNotImplemented from scipy.integrate import odeint -def PhasePlot(odefun, X=None, Y=None, scale=1, X0=None, T=None, +def phase_plot(odefun, X=None, Y=None, scale=1, X0=None, T=None, lingrid=None, lintime=None, logtime=None, timepts=None, parms=(), verbose=True): """ @@ -48,12 +48,12 @@ Produces a vector field or stream line plot for a planar system. Call signatures: - PhasePlot(func, X, Y, ...) - display vector field on meshgrid - PhasePlot(func, X, Y, scale, ...) - scale arrows - PhasePlot(func. X0=(...), T=Tmax, ...) - display stream lines - PhasePlot(func, X, Y, X0=[...], T=Tmax, ...) - plot both - PhasePlot(func, X0=[...], T=Tmax, lingrid=N, ...) - plot both - PhasePlot(func, X0=[...], lintime=N, ...) - stream lines with arrows + phase_plot(func, X, Y, ...) - display vector field on meshgrid + phase_plot(func, X, Y, scale, ...) - scale arrows + phase_plot(func. X0=(...), T=Tmax, ...) - display stream lines + phase_plot(func, X, Y, X0=[...], T=Tmax, ...) - plot both + phase_plot(func, X0=[...], T=Tmax, lingrid=N, ...) - plot both + phase_plot(func, X0=[...], lintime=N, ...) - stream lines with arrows Parameters ---------- @@ -104,7 +104,7 @@ See also -------- - boxgrid(X, Y): construct box-shaped grid of initial conditions + box_grid(X, Y): construct box-shaped grid of initial conditions Examples -------- @@ -274,10 +274,10 @@ return; # Utility function for generating initial conditions around a box -def boxgrid(xlimp, ylimp): - """BOXGRID generate list of points on edge of box +def box_grid(xlimp, ylimp): + """box_grid generate list of points on edge of box - list = BOXGRID([xmin xmax xnum], [ymin ymax ynum]) generates a + list = box_grid([xmin xmax xnum], [ymin ymax ynum]) generates a list of points that correspond to a uniform grid at the end of the box defined by the corners [xmin ymin] and [xmax ymax]. """ Modified: trunk/src/rlocus.py =================================================================== --- trunk/src/rlocus.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/src/rlocus.py 2011-08-07 15:12:58 UTC (rev 172) @@ -52,7 +52,7 @@ import xferfcn # transfer function manipulation # Main function: compute a root locus diagram -def RootLocus(sys, kvect, xlim=None, ylim=None, plotstr='-', Plot=True): +def root_locus(sys, kvect, xlim=None, ylim=None, plotstr='-', Plot=True): """Calculate the root locus by finding the roots of 1+k*TF(s) where TF is self.num(s)/self.den(s) and each k is an element of kvect. Modified: trunk/src/timeresp.py =================================================================== --- trunk/src/timeresp.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/src/timeresp.py 2011-08-07 15:12:58 UTC (rev 172) @@ -53,8 +53,8 @@ This is a convention for function arguments and return values that represent time series: sequences of values that change over time. It is used throughout the library, for example in the functions -:func:`ForcedResponse`, :func:`StepResponse`, :func:`ImpulseResponse`, -and :func:`InitialResponse`. +:func:`forced_response`, :func:`step_response`, :func:`impulse_response`, +and :func:`initial_response`. .. note:: This convention is different from the convention used in the library @@ -235,7 +235,7 @@ return out_array # Forced response of a linear system -def ForcedResponse(sys, T=None, U=0., X0=0., transpose=False, **keywords): +def forced_response(sys, T=None, U=0., X0=0., transpose=False, **keywords): """Simulate the output of a linear system. As a convenience for parameters `U`, `X0`: @@ -285,11 +285,11 @@ See Also -------- - StepResponse, InitialResponse, ImpulseResponse + step_response, initial_response, impulse_response Examples -------- - >>> T, yout, xout = ForcedResponse(sys, T, u, X0) + >>> T, yout, xout = forced_response(sys, T, u, X0) """ if not isinstance(sys, Lti): raise TypeError('Parameter ``sys``: must be a ``Lti`` object. ' @@ -365,7 +365,7 @@ return T, yout, xout -def StepResponse(sys, T=None, X0=0., input=0, output=0, \ +def step_response(sys, T=None, X0=0., input=0, output=0, \ transpose = False, **keywords): #pylint: disable=W0622 """Step response of a linear system @@ -419,11 +419,11 @@ See Also -------- - ForcedResponse, InitialResponse, ImpulseResponse + forced_response, initial_response, impulse_response Examples -------- - >>> T, yout = StepResponse(sys, T, X0) + >>> T, yout = step_response(sys, T, X0) """ sys = _convertToStateSpace(sys) sys = _mimo2siso(sys, input, output, warn_conversion=True) @@ -431,13 +431,13 @@ T = _default_response_times(sys.A, 100) U = np.ones_like(T) - T, yout, _xout = ForcedResponse(sys, T, U, X0, + T, yout, _xout = forced_response(sys, T, U, X0, transpose=transpose, **keywords) return T, yout -def InitialResponse(sys, T=None, X0=0., input=0, output=0, transpose=False, +def initial_response(sys, T=None, X0=0., input=0, output=0, transpose=False, **keywords): #pylint: disable=W0622 """Initial condition response of a linear system @@ -491,26 +491,26 @@ See Also -------- - ForcedResponse, ImpulseResponse, StepResponse + forced_response, impulse_response, step_response Examples -------- - >>> T, yout = InitialResponse(sys, T, X0) + >>> T, yout = initial_response(sys, T, X0) """ sys = _convertToStateSpace(sys) sys = _mimo2siso(sys, input, output, warn_conversion=True) - #Create time and input vectors; checking is done in ForcedResponse(...) - #The initial vector X0 is created in ForcedResponse(...) if necessary + #Create time and input vectors; checking is done in forced_response(...) + #The initial vector X0 is created in forced_response(...) if necessary if T is None: T = _default_response_times(sys.A, 100) U = np.zeros_like(T) - T, yout, _xout = ForcedResponse(sys, T, U, X0, transpose=transpose, + T, yout, _xout = forced_response(sys, T, U, X0, transpose=transpose, **keywords) return T, yout -def ImpulseResponse(sys, T=None, X0=0., input=0, output=0, +def impulse_response(sys, T=None, X0=0., input=0, output=0, transpose=False, **keywords): #pylint: disable=W0622 """Impulse response of a linear system @@ -564,11 +564,11 @@ See Also -------- - ForcedReponse, InitialResponse, StepResponse + ForcedReponse, initial_response, step_response Examples -------- - >>> T, yout = ImpulseResponse(sys, T, X0) + >>> T, yout = impulse_response(sys, T, X0) """ sys = _convertToStateSpace(sys) sys = _mimo2siso(sys, input, output, warn_conversion=True) @@ -597,7 +597,7 @@ T = _default_response_times(sys.A, 100) U = np.zeros_like(T) - T, yout, _xout = ForcedResponse(sys, T, U, new_X0, \ + T, yout, _xout = forced_response(sys, T, U, new_X0, \ transpose=transpose, **keywords) return T, yout Modified: trunk/tests/margin_test.py =================================================================== --- trunk/tests/margin_test.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/tests/margin_test.py 2011-08-07 15:12:58 UTC (rev 172) @@ -7,7 +7,7 @@ import numpy as np from control.xferfcn import TransferFunction from control.statesp import StateSpace -from control.margin import * +from control.margins import * class TestMargin(unittest.TestCase): """These are tests for the margin commands in margin.py.""" @@ -18,25 +18,25 @@ self.sys3 = StateSpace([[1., 4.], [3., 2.]], [[1.], [-4.]], [[1., 0.]], [[0.]]) - def testGainPhaseMargin(self): - gm, pm, sm, wg, wp, ws = StabilityMargins(self.sys1); - gm, pm, sm, wg, wp, ws = StabilityMargins(self.sys2); - gm, pm, sm, wg, wp, ws = StabilityMargins(self.sys3); + def test_stability_margins(self): + gm, pm, sm, wg, wp, ws = stability_margins(self.sys1); + gm, pm, sm, wg, wp, ws = stability_margins(self.sys2); + gm, pm, sm, wg, wp, ws = stability_margins(self.sys3); - def testPhaseCrossoverFrequencies(self): - omega, gain = PhaseCrossoverFrequencies(self.sys2) + def test_phase_crossover_frequencies(self): + omega, gain = phase_crossover_frequencies(self.sys2) np.testing.assert_array_almost_equal(omega, [1.73205, 0.]) np.testing.assert_array_almost_equal(gain, [-0.5, 0.25]) tf = TransferFunction([1],[1,1]) - omega, gain = PhaseCrossoverFrequencies(tf) + omega, gain = phase_crossover_frequencies(tf) np.testing.assert_array_almost_equal(omega, [0.]) np.testing.assert_array_almost_equal(gain, [1.]) # testing MIMO, only (0,0) element is considered tf = TransferFunction([[[1],[2]],[[3],[4]]], [[[1, 2, 3, 4],[1,1]],[[1,1],[1,1]]]) - omega, gain = PhaseCrossoverFrequencies(tf) + omega, gain = phase_crossover_frequencies(tf) np.testing.assert_array_almost_equal(omega, [1.73205081, 0.]) np.testing.assert_array_almost_equal(gain, [-0.5, 0.25]) Modified: trunk/tests/phaseplot_test.py =================================================================== --- trunk/tests/phaseplot_test.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/tests/phaseplot_test.py 2011-08-07 15:12:58 UTC (rev 172) @@ -21,18 +21,18 @@ pass; def testInvPendNoSims(self): - PhasePlot(self.invpend_ode, (-6,6,10), (-6,6,10)); + phase_plot(self.invpend_ode, (-6,6,10), (-6,6,10)); def testInvPendSims(self): - PhasePlot(self.invpend_ode, (-6,6,10), (-6,6,10), + phase_plot(self.invpend_ode, (-6,6,10), (-6,6,10), X0 = ([1,1], [-1,1])); def testInvPendTimePoints(self): - PhasePlot(self.invpend_ode, (-6,6,10), (-6,6,10), + phase_plot(self.invpend_ode, (-6,6,10), (-6,6,10), X0 = ([1,1], [-1,1]), T=np.linspace(0,5,100)); def testInvPendLogtime(self): - PhasePlot(self.invpend_ode, X0 = + phase_plot(self.invpend_ode, X0 = [ [-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1], [-1, 2.1], [4.2, 2.1], [5, 2.1], [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1], @@ -42,12 +42,12 @@ verbose=False) def testInvPendAuto(self): - PhasePlot(self.invpend_ode, lingrid = 0, X0= + phase_plot(self.invpend_ode, lingrid = 0, X0= [[-2.3056, 2.1], [2.3056, -2.1]], T=6, verbose=False) def testOscillatorParams(self): m = 1; b = 1; k = 1; # default values - PhasePlot(self.oscillator_ode, timepts = [0.3, 1, 2, 3], X0 = + phase_plot(self.oscillator_ode, timepts = [0.3, 1, 2, 3], X0 = [[-1,1], [-0.3,1], [0,1], [0.25,1], [0.5,1], [0.7,1], [1,1], [1.3,1], [1,-1], [0.3,-1], [0,-1], [-0.25,-1], [-0.5,-1], [-0.7,-1], [-1,-1], [-1.3,-1]], Modified: trunk/tests/test_all.py =================================================================== --- trunk/tests/test_all.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/tests/test_all.py 2011-08-07 15:12:58 UTC (rev 172) @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# test_al.py - test suit for python-control +# test_all.py - test suit for python-control # RMM, 30 Mar 2011 import unittest # unit test module Modified: trunk/tests/timeresp_test.py =================================================================== --- trunk/tests/timeresp_test.py 2011-07-26 05:44:01 UTC (rev 171) +++ trunk/tests/timeresp_test.py 2011-08-07 15:12:58 UTC (rev 172) @@ -43,7 +43,7 @@ "0. 9. ") self.mimo_ss1 = StateSpace(A, B, C, D) - def testStepResponse(self): + def test_step_response(self): #Test SISO system sys = self.siso_ss1 t = np.linspace(0, 1, 10) @@ -51,64 +51,64 @@ 42.3227, 44.9694, 47.1599, 48.9776]) # SISO call - tout, yout = StepResponse(sys, T=t) + tout, yout = step_response(sys, T=t) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) # Play with arguments - tout, yout = StepResponse(sys, T=t, X0=0) + tout, yout = step_response(sys, T=t, X0=0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) X0 = np.array([0, 0]); - tout, yout = StepResponse(sys, T=t, X0=X0) + tout, yout = step_response(sys, T=t, X0=X0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) # Test MIMO system, which contains ``siso_ss1`` twice sys = self.mimo_ss1 - _t, y_00 = StepResponse(sys, T=t, input=0, output=0) - _t, y_11 = StepResponse(sys, T=t, input=1, output=1) + _t, y_00 = step_response(sys, T=t, input=0, output=0) + _t, y_11 = step_response(sys, T=t, input=1, output=1) np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4) np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4) - def testImpulseResponse(self): + def test_impulse_response(self): #Test SISO system sys = self.siso_ss1 t = np.linspace(0, 1, 10) youttrue = np.array([86., 70.1808, 57.3753, 46.9975, 38.5766, 31.7344, 26.1668, 21.6292, 17.9245, 14.8945]) - tout, yout = ImpulseResponse(sys, T=t) + tout, yout = impulse_response(sys, T=t) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) #Test MIMO system, which contains ``siso_ss1`` twice sys = self.mimo_ss1 - _t, y_00 = ImpulseResponse(sys, T=t, input=0, output=0) - _t, y_11 = ImpulseResponse(sys, T=t, input=1, output=1) + _t, y_00 = impulse_response(sys, T=t, input=0, output=0) + _t, y_11 = impulse_response(sys, T=t, input=1, output=1) np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4) np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4) - def testInitialResponse(self): + def test_initial_response(self): #Test SISO system sys = self.siso_ss1 t = np.linspace(0, 1, 10) x0 = np.array([[0.5], [1]]); youttrue = np.array([11., 8.1494, 5.9361, 4.2258, 2.9118, 1.9092, 1.1508, 0.5833, 0.1645, -0.1391]) - tout, yout = InitialResponse(sys, T=t, X0=x0) + tout, yout = initial_response(sys, T=t, X0=x0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) #Test MIMO system, which contains ``siso_ss1`` twice sys = self.mimo_ss1 x0 = np.matrix(".5; 1.; .5; 1.") - _t, y_00 = InitialResponse(sys, T=t, X0=x0, input=0, output=0) - _t, y_11 = InitialResponse(sys, T=t, X0=x0, input=1, output=1) + _t, y_00 = initial_response(sys, T=t, X0=x0, input=0, output=0) + _t, y_11 = initial_response(sys, T=t, X0=x0, input=1, output=1) np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4) np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4) - def testForcedResponse(self): + def test_forced_response(self): t = np.linspace(0, 1, 10) #compute step response - test with state space, and transfer function @@ -116,10 +116,10 @@ u = np.array([1., 1, 1, 1, 1, 1, 1, 1, 1, 1]) youttrue = np.array([9., 17.6457, 24.7072, 30.4855, 35.2234, 39.1165, 42.3227, 44.9694, 47.1599, 48.9776]) - tout, yout, _xout = ForcedResponse(self.siso_ss1, t, u) + tout, yout, _xout = forced_response(self.siso_ss1, t, u) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) - _t, yout, _xout = ForcedResponse(self.siso_tf2, t, u) + _t, yout, _xout = forced_response(self.siso_tf2, t, u) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) #test with initial value and special algorithm for ``U=0`` @@ -127,7 +127,7 @@ x0 = np.matrix(".5; 1.") youttrue = np.array([11., 8.1494, 5.9361, 4.2258, 2.9118, 1.9092, 1.1508, 0.5833, 0.1645, -0.1391]) - _t, yout, _xout = ForcedResponse(self.siso_ss1, t, u, x0) + _t, yout, _xout = forced_response(self.siso_ss1, t, u, x0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) #Test MIMO system, which contains ``siso_ss1`` twice @@ -139,7 +139,7 @@ 1.1508, 0.5833, 0.1645, -0.1391], [9., 17.6457, 24.7072, 30.4855, 35.2234, 39.1165, 42.3227, 44.9694, 47.1599, 48.9776]]) - _t, yout, _xout = ForcedResponse(self.mimo_ss1, t, u, x0) + _t, yout, _xout = forced_response(self.mimo_ss1, t, u, x0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) def suite(): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-07-26 05:44:07
|
Revision: 171 http://python-control.svn.sourceforge.net/python-control/?rev=171&view=rev Author: murrayrm Date: 2011-07-26 05:44:01 +0000 (Tue, 26 Jul 2011) Log Message: ----------- updated test suite for phaseplot Modified Paths: -------------- trunk/ChangeLog trunk/tests/phaseplot_test.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-07-26 02:41:03 UTC (rev 170) +++ trunk/ChangeLog 2011-07-26 05:44:01 UTC (rev 171) @@ -1,5 +1,8 @@ 2011-07-25 Richard Murray <murray@malabar.local> + * tests/phaseplot_test.py: updated unit tests to use new call + signatures + * examples/phaseplots.py: updated calls to PhasePlot to use new argument structure Modified: trunk/tests/phaseplot_test.py =================================================================== --- trunk/tests/phaseplot_test.py 2011-07-26 02:41:03 UTC (rev 170) +++ trunk/tests/phaseplot_test.py 2011-07-26 05:44:01 UTC (rev 171) @@ -25,32 +25,33 @@ def testInvPendSims(self): PhasePlot(self.invpend_ode, (-6,6,10), (-6,6,10), - xinit = ([1,1], [-1,1])); + X0 = ([1,1], [-1,1])); def testInvPendTimePoints(self): PhasePlot(self.invpend_ode, (-6,6,10), (-6,6,10), - xinit = ([1,1], [-1,1]), T=np.linspace(0,5,100)); + X0 = ([1,1], [-1,1]), T=np.linspace(0,5,100)); def testInvPendLogtime(self): - PhasePlot(self.invpend_ode, - 'logtime', (3, 0.7), None, + PhasePlot(self.invpend_ode, X0 = [ [-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1], [-1, 2.1], [4.2, 2.1], [5, 2.1], [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1], [1, -2.1], [-4.2, -2.1], [-5, -2.1] ], - np.linspace(0, 40, 200), verbose=False) + T = np.linspace(0, 40, 200), + logtime=(3, 0.7), + verbose=False) def testInvPendAuto(self): - PhasePlot(self.invpend_ode, 'auto', 0, None, - [[-2.3056, 2.1], [2.3056, -2.1]], 6, verbose=False) + PhasePlot(self.invpend_ode, lingrid = 0, X0= + [[-2.3056, 2.1], [2.3056, -2.1]], T=6, verbose=False) def testOscillatorParams(self): m = 1; b = 1; k = 1; # default values - PhasePlot(self.oscillator_ode, 'timepts', [0.3, 1, 2, 3], None, + PhasePlot(self.oscillator_ode, timepts = [0.3, 1, 2, 3], X0 = [[-1,1], [-0.3,1], [0,1], [0.25,1], [0.5,1], [0.7,1], [1,1], [1.3,1], [1,-1], [0.3,-1], [0,-1], [-0.25,-1], [-0.5,-1], [-0.7,-1], [-1,-1], [-1.3,-1]], - np.linspace(0, 10, 100), parms = (m, b, k)); + T = np.linspace(0, 10, 100), parms = (m, b, k)); # Sample dynamical systems - inverted pendulum def invpend_ode(self, x, t, m=1., l=1., b=0, g=9.8): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-07-26 02:41:10
|
Revision: 170 http://python-control.svn.sourceforge.net/python-control/?rev=170&view=rev Author: murrayrm Date: 2011-07-26 02:41:03 +0000 (Tue, 26 Jul 2011) Log Message: ----------- * Updated phaseplot module with new (more pythonic) call signature * Added boxplot function to generate initial conditions around a box * New genetic switch example (from FBS), demonstrating phase plots Modified Paths: -------------- trunk/ChangeLog trunk/examples/phaseplots.py trunk/src/__init__.py trunk/src/phaseplot.py Added Paths: ----------- trunk/examples/genswitch.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-07-25 05:00:41 UTC (rev 169) +++ trunk/ChangeLog 2011-07-26 02:41:03 UTC (rev 170) @@ -1,3 +1,17 @@ +2011-07-25 Richard Murray <murray@malabar.local> + + * examples/phaseplots.py: updated calls to PhasePlot to use new + argument structure + + * src/phaseplot.py (PhasePlot): Updated call signature to be + more pythonic and fixed up documentation. + + * examples/genswitch.py (genswitch): added new example showing + PhasePlot functionality + + * src/phaseplot.py (boxgrid): added function to compute initial + conditions around the edges of a box + 2011-07-24 Richard Murray <murray@malabar.local> * tests/margin_test.py: added simple unit tests for margin functions Added: trunk/examples/genswitch.py =================================================================== --- trunk/examples/genswitch.py (rev 0) +++ trunk/examples/genswitch.py 2011-07-26 02:41:03 UTC (rev 170) @@ -0,0 +1,81 @@ +# genswitch_plot.m - run the Collins genetic switch model +# RMM, 24 Jan 07 +# +# This file contains an example from FBS of a simple dynamical model +# of a genetic switch. Plots time traces and a phase portrait using +# the python-control library. + +import numpy as np +import matplotlib.pyplot as mpl +from scipy.integrate import odeint +from matplotlib.mlab import frange +from control import PhasePlot, boxgrid + +# Simple model of a genetic switch +# +# This function implements the basic model of the genetic switch +# Parameters taken from Gardner, Cantor and Collins, Nature, 2000 +def genswitch(y, t, mu=4, n=2): + return (mu / (1 + y[1]**n) - y[0], mu / (1 + y[0]**n) - y[1]) + +# Run a simulation from an initial condition +tim1 = np.linspace(0, 10, 100) +sol1 = odeint(genswitch, [1, 5], tim1) + +# Extract the equlibirum points +mu = 4; n = 2; # switch parameters +eqpt = np.empty(3); +eqpt[0] = sol1[0,-1] +eqpt[1] = sol1[1,-1] +eqpt[2] = 0; # fzero(@(x) mu/(1+x^2) - x, 2); + +# Run another simulation showing switching behavior +tim2 = np.linspace(11, 25, 100); +sol2 = odeint(genswitch, sol1[-1,:] + [2, -2], tim2) + +# First plot out the curves that define the equilibria +u = frange(0, 4.5, 0.1) +f = np.divide(mu, (1 + u**n)) # mu / (1 + u^n), elementwise + +mpl.figure(1); mpl.clf(); +mpl.axis([0, 5, 0, 5]); # box on; +mpl.plot(u, f, '-', f, u, '--') # 'LineWidth', AM_data_linewidth); +mpl.legend('z1, f(z1)', 'z2, f(z2)') # legend(lgh, 'boxoff'); +mpl.plot([0, 3], [0, 3], 'k-') # 'LineWidth', AM_ref_linewidth); +mpl.plot(eqpt[0], eqpt[1], 'k.', eqpt[1], eqpt[0], 'k.', + eqpt[2], eqpt[2], 'k.') # 'MarkerSize', AM_data_markersize*3); +mpl.xlabel('z1, f(z2)'); +mpl.ylabel('z2, f(z1)'); + +# Time traces +mpl.figure(3); mpl.clf(); # subplot(221); +mpl.plot(tim1, sol1[:,0], 'b-', tim1, sol1[:,1], 'g--'); +# set(pl, 'LineWidth', AM_data_linewidth); +mpl.hold(True); +mpl.plot([tim1[-1], tim1[-1]+1], + [sol1[-1,0], sol2[0,1]], 'ko:', + [tim1[-1], tim1[-1]+1], [sol1[-1,1], sol2[0,0]], 'ko:'); +# set(pl, 'LineWidth', AM_data_linewidth, 'MarkerSize', AM_data_markersize); +mpl.plot(tim2, sol2[:,0], 'b-', tim2, sol2[:,1], 'g--'); +# set(pl, 'LineWidth', AM_data_linewidth); +mpl.axis([0, 25, 0, 5]); + +mpl.xlabel('Time {\itt} [scaled]'); +mpl.ylabel('Protein concentrations [scaled]'); +mpl.legend('z1 (A)', 'z2 (B)') # 'Orientation', 'horizontal'); +# legend(legh, 'boxoff'); + +# Phase portrait +mpl.figure(2); mpl.clf(); # subplot(221); +mpl.axis([0, 5, 0, 5]); # set(gca, 'DataAspectRatio', [1, 1, 1]); +PhasePlot(genswitch, X0 = boxgrid([0, 5, 6], [0, 5, 6]), T = 10, + timepts = [0.2, 0.6, 1.2]) + +# Add the stable equilibrium points +mpl.hold(True); +mpl.plot(eqpt[0], eqpt[1], 'k.', eqpt[1], eqpt[0], 'k.', + eqpt[2], eqpt[2], 'k.') # 'MarkerSize', AM_data_markersize*3); + +mpl.xlabel('Protein A [scaled]'); +mpl.ylabel('Protein B [scaled]'); # 'Rotation', 90); + Modified: trunk/examples/phaseplots.py =================================================================== --- trunk/examples/phaseplots.py 2011-07-25 05:00:41 UTC (rev 169) +++ trunk/examples/phaseplots.py 2011-07-26 02:41:03 UTC (rev 170) @@ -27,16 +27,16 @@ # Outer trajectories PhasePlot(invpend_ode, - 'logtime', (3, 0.7), None, - [ [-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1], - [-1, 2.1], [4.2, 2.1], [5, 2.1], - [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1], - [1, -2.1], [-4.2, -2.1], [-5, -2.1] ], - np.linspace(0, 40, 200)) + X0 = [ [-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1], + [-1, 2.1], [4.2, 2.1], [5, 2.1], + [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1], + [1, -2.1], [-4.2, -2.1], [-5, -2.1] ], + T = np.linspace(0, 40, 200), + logtime = (3, 0.7) ) # Separatrices mpl.hold(True); -PhasePlot(invpend_ode, 'auto', 0, None, [[-2.3056, 2.1], [2.3056, -2.1]], 6) +PhasePlot(invpend_ode, X0 = [[-2.3056, 2.1], [2.3056, -2.1]], T=6, lingrid=0) mpl.show(); # @@ -57,10 +57,10 @@ mpl.figure(); mpl.clf(); mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1, 1, 1]); PhasePlot(oscillator_ode, - 'timepts', [0.25, 0.8, 2, 3], None, [ - [-1, 1], [-0.3, 1], [0, 1], [0.25, 1], [0.5, 1], [0.75, 1], [1, 1], - [1, -1], [0.3, -1], [0, -1], [-0.25, -1], [-0.5, -1], [-0.75, -1], [-1, -1] - ], np.linspace(0, 8, 80)) + X0 = [ + [-1, 1], [-0.3, 1], [0, 1], [0.25, 1], [0.5, 1], [0.75, 1], [1, 1], + [1, -1], [0.3, -1], [0, -1], [-0.25, -1], [-0.5, -1], [-0.75, -1], [-1, -1] + ], T = np.linspace(0, 8, 80), timepts = [0.25, 0.8, 2, 3]) mpl.hold(True); mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3); # set(gca,'DataAspectRatio',[1,1,1]); mpl.xlabel('x1'); mpl.ylabel('x2'); @@ -81,11 +81,13 @@ m = 1; b = 1; k = 1; # default values mpl.figure(); mpl.clf(); mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); -PhasePlot(oscillator_ode, 'timepts', [0.3, 1, 2, 3], None, - [[-1,1], [-0.3,1], [0,1], [0.25,1], [0.5,1], [0.7,1], [1,1], [1.3,1], - [1,-1], [0.3,-1], [0,-1], [-0.25,-1], [-0.5,-1], [-0.7,-1], [-1,-1], - [-1.3,-1]], - np.linspace(0, 10, 100), parms = (m, b, k)); +PhasePlot(oscillator_ode, + X0 = [ + [-1,1], [-0.3,1], [0,1], [0.25,1], [0.5,1], [0.7,1], [1,1], [1.3,1], + [1,-1], [0.3,-1], [0,-1], [-0.25,-1], [-0.5,-1], [-0.7,-1], [-1,-1], + [-1.3,-1] + ], T = np.linspace(0, 10, 100), + timepts = [0.3, 1, 2, 3], parms = (m, b, k)); mpl.hold(True); mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3); # set(gca,'FontSize', 16); mpl.xlabel('{\itx}_1'); mpl.ylabel('{\itx}_2'); @@ -93,14 +95,14 @@ # Saddle mpl.figure(); mpl.clf(); mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); -PhasePlot(saddle_ode, 'timepts', [0.2, 0.5, 0.8], None, +PhasePlot(saddle_ode, scale = 2, timepts = [0.2, 0.5, 0.8], X0 = [ [-1, -1], [1, 1], [-1, -0.95], [-1, -0.9], [-1, -0.8], [-1, -0.6], [-1, -0.4], [-1, -0.2], [-0.95, -1], [-0.9, -1], [-0.8, -1], [-0.6, -1], [-0.4, -1], [-0.2, -1], [1, 0.95], [1, 0.9], [1, 0.8], [1, 0.6], [1, 0.4], [1, 0.2], [0.95, 1], [0.9, 1], [0.8, 1], [0.6, 1], [0.4, 1], [0.2, 1], [-0.5, -0.45], [-0.45, -0.5], [0.5, 0.45], [0.45, 0.5], - [-0.04, 0.04], [0.04, -0.04] ], np.linspace(0, 2, 20)); + [-0.04, 0.04], [0.04, -0.04] ], T = np.linspace(0, 2, 20)); mpl.hold(True); mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3); # set(gca,'FontSize', 16); mpl.xlabel('{\itx}_1'); mpl.ylabel('{\itx}_2'); @@ -109,10 +111,10 @@ m = 1; b = 0; k = 1; # zero damping mpl.figure(); mpl.clf(); mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); -PhasePlot(oscillator_ode, 'timepts', - [pi/6, pi/3, pi/2, 2*pi/3, 5*pi/6, pi, 7*pi/6, 4*pi/3, 9*pi/6, 5*pi/3, 11*pi/6, 2*pi], None, - [ [0.2,0], [0.4,0], [0.6,0], [0.8,0], [1,0], [1.2,0], [1.4,0] ], - np.linspace(0, 20, 200), parms = (m, b, k)); +PhasePlot(oscillator_ode, timepts = + [pi/6, pi/3, pi/2, 2*pi/3, 5*pi/6, pi, 7*pi/6, 4*pi/3, 9*pi/6, 5*pi/3, 11*pi/6, 2*pi], + X0 = [ [0.2,0], [0.4,0], [0.6,0], [0.8,0], [1,0], [1.2,0], [1.4,0] ], + T = np.linspace(0, 20, 200), parms = (m, b, k)); mpl.hold(True); mpl.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3); # set(gca,'FontSize', 16); mpl.xlabel('{\itx}_1'); mpl.ylabel('{\itx}_2'); Modified: trunk/src/__init__.py =================================================================== --- trunk/src/__init__.py 2011-07-25 05:00:41 UTC (rev 169) +++ trunk/src/__init__.py 2011-07-26 02:41:03 UTC (rev 170) @@ -64,6 +64,7 @@ from mateqn import * from modelsimp import * from nichols import * +from phaseplot import PhasePlot, boxgrid from rlocus import * from statefbk import * from statesp import * Modified: trunk/src/phaseplot.py =================================================================== --- trunk/src/phaseplot.py 2011-07-25 05:00:41 UTC (rev 169) +++ trunk/src/phaseplot.py 2011-07-26 02:41:03 UTC (rev 170) @@ -1,7 +1,8 @@ # phaseplot.py - generate 2D phase portraits # # Author: Richard M. Murray -# Date: Fall 2002 (MATLAB version), based on a version by Kristi Morgansen +# Date: 24 July 2011, converted from MATLAB version (2002); based on +# a version by Kristi Morgansen # # Copyright (c) 2011 by California Institute of Technology # All rights reserved. @@ -38,99 +39,107 @@ from exception import ControlNotImplemented from scipy.integrate import odeint -def PhasePlot(odefun, xlimv, ylimv, scale=1, xinit=None, T=None, parms=(), - verbose=True): +def PhasePlot(odefun, X=None, Y=None, scale=1, X0=None, T=None, + lingrid=None, lintime=None, logtime=None, timepts=None, + parms=(), verbose=True): """ - PhasePlot Phase plot for 2D dynamical systems + Phase plot for 2D dynamical systems - PhasePlot(F, X1range, X2range, scale) produces a quiver plot for - the function F. X1range and X2range have the form [min, max, num] - and specify the axis limits for the plot, along with the number of - subdivisions in each axis, used to produce an quiver plot for the - vector field. The vector field is scaled by a factor 'scale' - (default = 1). + Produces a vector field or stream line plot for a planar system. - The function F should be the same for as used for scipy.integrate. - Namely, it should be a function of the form dxdt = F(x, t) that - accepts a state x of dimension 2 and returns a derivative dxdt of - dimension 2. + Call signatures: + PhasePlot(func, X, Y, ...) - display vector field on meshgrid + PhasePlot(func, X, Y, scale, ...) - scale arrows + PhasePlot(func. X0=(...), T=Tmax, ...) - display stream lines + PhasePlot(func, X, Y, X0=[...], T=Tmax, ...) - plot both + PhasePlot(func, X0=[...], T=Tmax, lingrid=N, ...) - plot both + PhasePlot(func, X0=[...], lintime=N, ...) - stream lines with arrows - PhasePlot(F, X1range, X2range, scale, Xinit) produces a phase - plot for the function F, consisting of the quiver plot plus stream - lines. The streamlines start at the initial conditions listed in - Xinit, which should be a matrix whose rows give the desired inital - conditions for x1 and x2. X1range or X2range is 'auto', the arrows - are produced based on the stream lines. If 'scale' is negative, - dots are placed at the base of the arrows. If 'scale' is zero, no - dots are produced. - - PhasePlot(F, X1range, X2range, scale, boxgrid(X1range2, X2range2)) - produces a phase plot with stream lines generated at the edges of - the rectangle defined by X1range2, X2range2. These ranges are in - the same form as X1range, X2range. + Parameters + ---------- + func : callable(x, t, ...) + Computes the time derivative of y (compatible with odeint). + The function should be the same for as used for + scipy.integrate. Namely, it should be a function of the form + dxdt = F(x, t) that accepts a state x of dimension 2 and + returns a derivative dx/dt of dimension 2. - PhasePlot(F, X1range, X2range, scale, Xinit, T) produces a phase - plot where the streamlines are simluted for time T (default = 50). + X, Y: ndarray, optional + Two 1-D arrays representing x and y coordinates of a grid. + These arguments are passed to meshgrid and generate the lists + of points at which the vector field is plotted. If absent (or + None), the vector field is not plotted. - PhasePlot(F, X1range, X2range, scale, Xinit, T, P1, P2, ...) - passes additional parameters to the function F, in the same way as - ODE45. + scale: float, optional + Scale size of arrows; default = 1 - Instead of drawing arrows on a grid, arrows can also be drawn on - streamlines by usinge the X1range and X2range arguments as follows: + X0: ndarray of initial conditions, optional + List of initial conditions from which streamlines are plotted. + Each initial condition should be a pair of numbers. - X1range X2range - ------- ------- - 'auto' N Draw N arrows using equally space time points - 'logtime' [N, lam] Draw N arrows using exponential time constant lam - 'timepts' [t1, t2, ...] Draw arrows at the list times - """ + T: array-like or number, optional + Length of time to run simulations that generate streamlines. + If a single number, the same simulation time is used for all + initial conditions. Otherwise, should be a list of length + len(X0) that gives the simulation time for each initial + condition. Default value = 50. - # - # Parameters defining the plot - # - # The constants below define the parameters that control how the - # plot looks. These can be modified to customize the look of the - # phase plot. - # + lingrid = N or (N, M): integer or 2-tuple of integers, optional + If X0 is given and X, Y are missing, a grid of arrows is + produced using the limits of the initial conditions, with N + grid points in each dimension or N grid points in x and M grid + points in y. - #! TODO: convert to keywords - #! TODO: eliminate old parameters that aren't used - # PP color = ['m', 'c', 'r', 'g', 'b', 'k', 'y']; - PP_stream_color = ('b'); # color array for streamlines - PP_stream_linewidth = 1; # line width for stream lines + lintime = N: integer, optional + Draw N arrows using equally space time points - PP_arrow_linewidth = 1; # line width for arrows (quiver) - PP_arrow_markersize = 10; # size of arrow base marker + logtime = (N, lambda): (integer, float), optional + Draw N arrows using exponential time constant lambda + timepts = [t1, t2, ...]: array-like, optional + Draw arrows at the given list times + + parms: tuple, optional + List of parameters to pass to vector field: func(x, t, *parms) + + See also + -------- + boxgrid(X, Y): construct box-shaped grid of initial conditions + + Examples + -------- + """ + # # Figure out ranges for phase plot (argument processing) # - auto = 0; logtime = 0; timepts = 0; Narrows = 0; - if (isinstance(xlimv, str) and xlimv == 'auto'): - auto = 1; - Narrows = ylimv; + #! TODO: need to add error checking to arguments + autoFlag = False; logtimeFlag = False; timeptsFlag = False; Narrows = 0; + if (lingrid != None): + autoFlag = True; + Narrows = lingrid; if (verbose): print 'Using auto arrows\n'; - elif (isinstance(xlimv, str) and xlimv == 'logtime'): - logtime = 1; - Narrows = ylimv[0]; - timefactor = ylimv[1]; + elif (logtime != None): + logtimeFlag = True; + Narrows = logtime[0]; + timefactor = logtime[1]; if (verbose): print 'Using logtime arrows\n'; - elif (isinstance(xlimv, str) and xlimv == 'timepts'): - timepts = 1; - Narrows = len(ylimv); + elif (timepts != None): + timeptsFlag = True; + Narrows = len(timepts); else: # Figure out the set of points for the quiver plot + #! TODO: Add sanity checks (x1, x2) = np.meshgrid( - frange(xlimv[0], xlimv[1], float(xlimv[1]-xlimv[0])/xlimv[2]), - frange(ylimv[0], ylimv[1], float(ylimv[1]-ylimv[0])/ylimv[2])); + frange(X[0], X[1], float(X[1]-X[0])/X[2]), + frange(Y[0], Y[1], float(Y[1]-Y[0])/Y[2])); - if ((not auto) and (not logtime) and (not timepts)): + if ((not autoFlag) and (not logtimeFlag) and (not timeptsFlag)): # Now calculate the vector field at those points (nr,nc) = x1.shape; dx = np.empty((nr, nc, 2)) @@ -151,16 +160,16 @@ #! TODO: Tweak the shape of the plot # a=gca; set(a,'DataAspectRatio',[1,1,1]); - # set(a,'XLim',xlimv(1:2)); set(a,'YLim',ylimv(1:2)); + # set(a,'XLim',X(1:2)); set(a,'YLim',Y(1:2)); mpl.xlabel('x1'); mpl.ylabel('x2'); # See if we should also generate the streamlines - if (xinit == None or len(xinit) == 0): + if (X0 == None or len(X0) == 0): return # Convert initial conditions to a numpy array - xinit = np.array(xinit); - (nr, nc) = np.shape(xinit); + X0 = np.array(X0); + (nr, nc) = np.shape(X0); # Generate some empty matrices to keep arrow information x1 = np.empty((nr, Narrows)); x2 = np.empty((nr, Narrows)); @@ -183,12 +192,12 @@ ymin = alim[2]; ymax = alim[3]; else: # Use the maximum extent of all trajectories - xmin = np.min(xinit[:,0]); xmax = np.max(xinit[:,0]); - ymin = np.min(xinit[:,1]); ymax = np.max(xinit[:,1]); + xmin = np.min(X0[:,0]); xmax = np.max(X0[:,0]); + ymin = np.min(X0[:,1]); ymax = np.max(X0[:,1]); # Generate the streamlines for each initial condition for i in range(nr): - state = odeint(odefun, xinit[i], TSPAN, args=parms); + state = odeint(odefun, X0[i], TSPAN, args=parms); time = TSPAN mpl.hold(True); mpl.plot(state[:,0], state[:,1]) @@ -197,7 +206,7 @@ # set(h[i], 'LineWidth', PP_stream_linewidth); # Plot arrows if quiver parameters were 'auto' - if (auto or logtime or timepts): + if (autoFlag or logtimeFlag or timeptsFlag): # Compute the locations of the arrows #! TODO: check this logic to make sure it works in python for j in range(Narrows): @@ -206,18 +215,18 @@ k = -1 if scale == None else 0; # Figure out what time index to use for the next point - if (auto): + if (autoFlag): # Use a linear scaling based on ODE time vector tind = np.floor((len(time)/Narrows) * (j-k)) + k; - elif (logtime): + elif (logtimeFlag): # Use an exponential time vector # MATLAB: tind = find(time < (j-k) / lambda, 1, 'last'); tarr = find(time < (j-k) / timefactor); tind = tarr[-1] if len(tarr) else 0; - elif (timepts): + elif (timeptsFlag): # Use specified time points - # MATLAB: tind = find(time < ylimv[j], 1, 'last'); - tarr = find(time < ylimv[j]); + # MATLAB: tind = find(time < Y[j], 1, 'last'); + tarr = find(time < timepts[j]); tind = tarr[-1] if len(tarr) else 0; # For tailless arrows, skip the first point @@ -263,3 +272,20 @@ # set(bp, 'MarkerSize', PP_arrow_markersize); return; + +# Utility function for generating initial conditions around a box +def boxgrid(xlimp, ylimp): + """BOXGRID generate list of points on edge of box + + list = BOXGRID([xmin xmax xnum], [ymin ymax ynum]) generates a + list of points that correspond to a uniform grid at the end of the + box defined by the corners [xmin ymin] and [xmax ymax]. + """ + + sx10 = frange(xlimp[0], xlimp[1], float(xlimp[1]-xlimp[0])/xlimp[2]) + sy10 = frange(ylimp[0], ylimp[1], float(ylimp[1]-ylimp[0])/ylimp[2]) + + sx1 = np.hstack((0, sx10, 0*sy10+sx10[0], sx10, 0*sy10+sx10[-1])) + sx2 = np.hstack((0, 0*sx10+sy10[0], sy10, 0*sx10+sy10[-1], sy10)) + + return np.transpose( np.vstack((sx1, sx2)) ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-07-25 05:00:48
|
Revision: 169 http://python-control.svn.sourceforge.net/python-control/?rev=169&view=rev Author: murrayrm Date: 2011-07-25 05:00:41 +0000 (Mon, 25 Jul 2011) Log Message: ----------- * Added first cut at phase portrait command (PhasePlot) from MATLAB code; needs more work to pythonize the call signatures * Added simple unit tests for margin command See ChangeLog for more detailed list of changes Modified Paths: -------------- trunk/ChangeLog Added Paths: ----------- trunk/examples/README trunk/examples/phaseplots.py trunk/src/phaseplot.py trunk/tests/margin_test.py trunk/tests/phaseplot_test.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-07-16 06:05:46 UTC (rev 168) +++ trunk/ChangeLog 2011-07-25 05:00:41 UTC (rev 169) @@ -1,3 +1,17 @@ +2011-07-24 Richard Murray <murray@malabar.local> + + * tests/margin_test.py: added simple unit tests for margin functions + (initial versions just call functions; some comparisons missing) + + * examples/README: added missing README file + + * examples/phaseplots.py: FBS examples for phaseplot + + * tests/phaseplot_test.py: unit tests for phaseplot + + * src/phaseplot.py: initial cut at phase portrait function, built + from amphaseplot (Feeback Systems [FBS], Astrom and Murray, 2008) + 2011-07-15 Richard Murray <murray@malabar.local> * tests/matlab_test.py (TestMatlab): added unittest for margin() Added: trunk/examples/README =================================================================== --- trunk/examples/README (rev 0) +++ trunk/examples/README 2011-07-25 05:00:41 UTC (rev 169) @@ -0,0 +1,4 @@ +This directory contains worked examples using the python-control +library. Each example should work by running 'ipython -pylab' and +then running the given file (make sure to have the python-control +module in your path). Added: trunk/examples/phaseplots.py =================================================================== --- trunk/examples/phaseplots.py (rev 0) +++ trunk/examples/phaseplots.py 2011-07-25 05:00:41 UTC (rev 169) @@ -0,0 +1,120 @@ +# phaseplots.py - examples of phase portraits +# RMM, 24 July 2011 +# +# This file contains examples of phase portraits pulled from "Feedback +# Systems" by Astrom and Murray (Princeton University Press, 2008). + +import numpy as np +import matplotlib.pyplot as mpl +from control.phaseplot import PhasePlot +from numpy import pi + +# Clear out any figures that are present +mpl.close('all') + +# +# Inverted pendulum +# + +# Define the ODEs for a damped (inverted) pendulum +def invpend_ode(x, t, m=1., l=1., b=0.2, g=1): + return (x[1], -b/m*x[1] + (g*l/m) * np.sin(x[0])) + +# Set up the figure the way we want it to look +mpl.figure(); mpl.clf(); +mpl.axis([-2*pi, 2*pi, -2.1, 2.1]); +mpl.title('Inverted pendlum') + +# Outer trajectories +PhasePlot(invpend_ode, + 'logtime', (3, 0.7), None, + [ [-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1], + [-1, 2.1], [4.2, 2.1], [5, 2.1], + [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1], + [1, -2.1], [-4.2, -2.1], [-5, -2.1] ], + np.linspace(0, 40, 200)) + +# Separatrices +mpl.hold(True); +PhasePlot(invpend_ode, 'auto', 0, None, [[-2.3056, 2.1], [2.3056, -2.1]], 6) +mpl.show(); + +# +# Systems of ODEs: damped oscillator example (simulation + phase portrait) +# + +def oscillator_ode(x, t, m=1., b=1, k=1): + return (x[1], -k/m*x[0] - b/m*x[1]) + +# Generate a vector plot for the damped oscillator +mpl.figure(); mpl.clf(); +PhasePlot(oscillator_ode, [-1, 1, 10], [-1, 1, 10], 0.15); +mpl.hold(True); mpl.plot([0], [0], '.'); +# a=gca; set(a,'FontSize',20); set(a,'DataAspectRatio',[1,1,1]); +mpl.xlabel('x1'); mpl.ylabel('x2'); + +# Generate a phase plot for the damped oscillator +mpl.figure(); mpl.clf(); +mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1, 1, 1]); +PhasePlot(oscillator_ode, + 'timepts', [0.25, 0.8, 2, 3], None, [ + [-1, 1], [-0.3, 1], [0, 1], [0.25, 1], [0.5, 1], [0.75, 1], [1, 1], + [1, -1], [0.3, -1], [0, -1], [-0.25, -1], [-0.5, -1], [-0.75, -1], [-1, -1] + ], np.linspace(0, 8, 80)) +mpl.hold(True); mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3); +# set(gca,'DataAspectRatio',[1,1,1]); +mpl.xlabel('x1'); mpl.ylabel('x2'); + +mpl.show() + +# +# Stability definitions +# +# This set of plots illustrates the various types of equilibrium points. +# + +# Saddle point vector field +def saddle_ode(x, t): + return (x[0] - 3*x[1], -3*x[0] + x[1]); + +# Asy stable +m = 1; b = 1; k = 1; # default values +mpl.figure(); mpl.clf(); +mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); +PhasePlot(oscillator_ode, 'timepts', [0.3, 1, 2, 3], None, + [[-1,1], [-0.3,1], [0,1], [0.25,1], [0.5,1], [0.7,1], [1,1], [1.3,1], + [1,-1], [0.3,-1], [0,-1], [-0.25,-1], [-0.5,-1], [-0.7,-1], [-1,-1], + [-1.3,-1]], + np.linspace(0, 10, 100), parms = (m, b, k)); +mpl.hold(True); mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3); +# set(gca,'FontSize', 16); +mpl.xlabel('{\itx}_1'); mpl.ylabel('{\itx}_2'); + +# Saddle +mpl.figure(); mpl.clf(); +mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); +PhasePlot(saddle_ode, 'timepts', [0.2, 0.5, 0.8], None, + [ [-1, -1], [1, 1], + [-1, -0.95], [-1, -0.9], [-1, -0.8], [-1, -0.6], [-1, -0.4], [-1, -0.2], + [-0.95, -1], [-0.9, -1], [-0.8, -1], [-0.6, -1], [-0.4, -1], [-0.2, -1], + [1, 0.95], [1, 0.9], [1, 0.8], [1, 0.6], [1, 0.4], [1, 0.2], + [0.95, 1], [0.9, 1], [0.8, 1], [0.6, 1], [0.4, 1], [0.2, 1], + [-0.5, -0.45], [-0.45, -0.5], [0.5, 0.45], [0.45, 0.5], + [-0.04, 0.04], [0.04, -0.04] ], np.linspace(0, 2, 20)); +mpl.hold(True); mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3); +# set(gca,'FontSize', 16); +mpl.xlabel('{\itx}_1'); mpl.ylabel('{\itx}_2'); + +# Stable isL +m = 1; b = 0; k = 1; # zero damping +mpl.figure(); mpl.clf(); +mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); +PhasePlot(oscillator_ode, 'timepts', + [pi/6, pi/3, pi/2, 2*pi/3, 5*pi/6, pi, 7*pi/6, 4*pi/3, 9*pi/6, 5*pi/3, 11*pi/6, 2*pi], None, + [ [0.2,0], [0.4,0], [0.6,0], [0.8,0], [1,0], [1.2,0], [1.4,0] ], + np.linspace(0, 20, 200), parms = (m, b, k)); +mpl.hold(True); mpl.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3); +# set(gca,'FontSize', 16); +mpl.xlabel('{\itx}_1'); mpl.ylabel('{\itx}_2'); + +mpl.show() Added: trunk/src/phaseplot.py =================================================================== --- trunk/src/phaseplot.py (rev 0) +++ trunk/src/phaseplot.py 2011-07-25 05:00:41 UTC (rev 169) @@ -0,0 +1,265 @@ +# phaseplot.py - generate 2D phase portraits +# +# Author: Richard M. Murray +# Date: Fall 2002 (MATLAB version), based on a version by Kristi Morgansen +# +# Copyright (c) 2011 by California Institute of Technology +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import numpy as np +import matplotlib.pyplot as mpl +from matplotlib.mlab import frange, find +from exception import ControlNotImplemented +from scipy.integrate import odeint + +def PhasePlot(odefun, xlimv, ylimv, scale=1, xinit=None, T=None, parms=(), + verbose=True): + """ + PhasePlot Phase plot for 2D dynamical systems + + PhasePlot(F, X1range, X2range, scale) produces a quiver plot for + the function F. X1range and X2range have the form [min, max, num] + and specify the axis limits for the plot, along with the number of + subdivisions in each axis, used to produce an quiver plot for the + vector field. The vector field is scaled by a factor 'scale' + (default = 1). + + The function F should be the same for as used for scipy.integrate. + Namely, it should be a function of the form dxdt = F(x, t) that + accepts a state x of dimension 2 and returns a derivative dxdt of + dimension 2. + + PhasePlot(F, X1range, X2range, scale, Xinit) produces a phase + plot for the function F, consisting of the quiver plot plus stream + lines. The streamlines start at the initial conditions listed in + Xinit, which should be a matrix whose rows give the desired inital + conditions for x1 and x2. X1range or X2range is 'auto', the arrows + are produced based on the stream lines. If 'scale' is negative, + dots are placed at the base of the arrows. If 'scale' is zero, no + dots are produced. + + PhasePlot(F, X1range, X2range, scale, boxgrid(X1range2, X2range2)) + produces a phase plot with stream lines generated at the edges of + the rectangle defined by X1range2, X2range2. These ranges are in + the same form as X1range, X2range. + + PhasePlot(F, X1range, X2range, scale, Xinit, T) produces a phase + plot where the streamlines are simluted for time T (default = 50). + + PhasePlot(F, X1range, X2range, scale, Xinit, T, P1, P2, ...) + passes additional parameters to the function F, in the same way as + ODE45. + + Instead of drawing arrows on a grid, arrows can also be drawn on + streamlines by usinge the X1range and X2range arguments as follows: + + X1range X2range + ------- ------- + 'auto' N Draw N arrows using equally space time points + 'logtime' [N, lam] Draw N arrows using exponential time constant lam + 'timepts' [t1, t2, ...] Draw arrows at the list times + """ + + # + # Parameters defining the plot + # + # The constants below define the parameters that control how the + # plot looks. These can be modified to customize the look of the + # phase plot. + # + + #! TODO: convert to keywords + #! TODO: eliminate old parameters that aren't used + # PP color = ['m', 'c', 'r', 'g', 'b', 'k', 'y']; + PP_stream_color = ('b'); # color array for streamlines + PP_stream_linewidth = 1; # line width for stream lines + + PP_arrow_linewidth = 1; # line width for arrows (quiver) + PP_arrow_markersize = 10; # size of arrow base marker + + # + # Figure out ranges for phase plot (argument processing) + # + auto = 0; logtime = 0; timepts = 0; Narrows = 0; + if (isinstance(xlimv, str) and xlimv == 'auto'): + auto = 1; + Narrows = ylimv; + if (verbose): + print 'Using auto arrows\n'; + + elif (isinstance(xlimv, str) and xlimv == 'logtime'): + logtime = 1; + Narrows = ylimv[0]; + timefactor = ylimv[1]; + if (verbose): + print 'Using logtime arrows\n'; + + elif (isinstance(xlimv, str) and xlimv == 'timepts'): + timepts = 1; + Narrows = len(ylimv); + + else: + # Figure out the set of points for the quiver plot + (x1, x2) = np.meshgrid( + frange(xlimv[0], xlimv[1], float(xlimv[1]-xlimv[0])/xlimv[2]), + frange(ylimv[0], ylimv[1], float(ylimv[1]-ylimv[0])/ylimv[2])); + + if ((not auto) and (not logtime) and (not timepts)): + # Now calculate the vector field at those points + (nr,nc) = x1.shape; + dx = np.empty((nr, nc, 2)) + for i in range(nr): + for j in range(nc): + dx[i, j, :] = np.squeeze(odefun((x1[i,j], x2[i,j]), 0, *parms)) + + # Plot the quiver plot + #! TODO: figure out arguments to make arrows show up correctly + if (scale == None): + mpl.quiver(x1, x2, dx[:,:,1], dx[:,:,2], angles='xy') + elif (scale != 0): + #! TODO: optimize parameters for arrows + #! TODO: figure out arguments to make arrows show up correctly + xy = mpl.quiver(x1, x2, dx[:,:,0]*np.abs(scale), + dx[:,:,1]*np.abs(scale), angles='xy') + # set(xy, 'LineWidth', PP_arrow_linewidth, 'Color', 'b'); + + #! TODO: Tweak the shape of the plot + # a=gca; set(a,'DataAspectRatio',[1,1,1]); + # set(a,'XLim',xlimv(1:2)); set(a,'YLim',ylimv(1:2)); + mpl.xlabel('x1'); mpl.ylabel('x2'); + + # See if we should also generate the streamlines + if (xinit == None or len(xinit) == 0): + return + + # Convert initial conditions to a numpy array + xinit = np.array(xinit); + (nr, nc) = np.shape(xinit); + + # Generate some empty matrices to keep arrow information + x1 = np.empty((nr, Narrows)); x2 = np.empty((nr, Narrows)); + dx = np.empty((nr, Narrows, 2)) + + # See if we were passed a simulation time + if (T == None): + T = 50 + + # Parse the time we were passed + TSPAN = T; + if (isinstance(T, (int, float))): + TSPAN = np.linspace(0, T, 100); + + # Figure out the limits for the plot + if (scale == None): + # Assume that the current axis are set as we want them + alim = mpl.axis(); + xmin = alim[0]; xmax = alim[1]; + ymin = alim[2]; ymax = alim[3]; + else: + # Use the maximum extent of all trajectories + xmin = np.min(xinit[:,0]); xmax = np.max(xinit[:,0]); + ymin = np.min(xinit[:,1]); ymax = np.max(xinit[:,1]); + + # Generate the streamlines for each initial condition + for i in range(nr): + state = odeint(odefun, xinit[i], TSPAN, args=parms); + time = TSPAN + mpl.hold(True); + mpl.plot(state[:,0], state[:,1]) + #! TODO: add back in colors for stream lines + # PP_stream_color(np.mod(i-1, len(PP_stream_color))+1)); + # set(h[i], 'LineWidth', PP_stream_linewidth); + + # Plot arrows if quiver parameters were 'auto' + if (auto or logtime or timepts): + # Compute the locations of the arrows + #! TODO: check this logic to make sure it works in python + for j in range(Narrows): + + # Figure out starting index; headless arrows start at 0 + k = -1 if scale == None else 0; + + # Figure out what time index to use for the next point + if (auto): + # Use a linear scaling based on ODE time vector + tind = np.floor((len(time)/Narrows) * (j-k)) + k; + elif (logtime): + # Use an exponential time vector + # MATLAB: tind = find(time < (j-k) / lambda, 1, 'last'); + tarr = find(time < (j-k) / timefactor); + tind = tarr[-1] if len(tarr) else 0; + elif (timepts): + # Use specified time points + # MATLAB: tind = find(time < ylimv[j], 1, 'last'); + tarr = find(time < ylimv[j]); + tind = tarr[-1] if len(tarr) else 0; + + # For tailless arrows, skip the first point + if (tind == 0 and scale == None): + continue; + + # Figure out the arrow at this point on the curve + x1[i,j] = state[tind, 0]; + x2[i,j] = state[tind, 1]; + + # Skip arrows outside of initial condition box + if (scale != None or + (x1[i,j] <= xmax and x1[i,j] >= xmin and + x2[i,j] <= ymax and x2[i,j] >= ymin)): + v = odefun((x1[i,j], x2[i,j]), 0, *parms) + dx[i, j, 0] = v[0]; dx[i, j, 1] = v[1]; + else: + dx[i, j, 0] = 0; dx[i, j, 1] = 0; + + # Set the plot shape before plotting arrows to avoid warping + # a=gca; + # if (scale != None): + # set(a,'DataAspectRatio', [1,1,1]); + # if (xmin != xmax and ymin != ymax): + # mpl.axis([xmin, xmax, ymin, ymax]); + # set(a, 'Box', 'on'); + + # Plot arrows on the streamlines + if (scale == None and Narrows > 0): + # Use a tailless arrow + #! TODO: figure out arguments to make arrows show up correctly + mpl.quiver(x1, x2, dx[:,:,0], dx[:,:,1], angles='xy') + elif (scale != 0 and Narrows > 0): + #! TODO: figure out arguments to make arrows show up correctly + xy = mpl.quiver(x1, x2, dx[:,:,0]*abs(scale), dx[:,:,1]*abs(scale), + angles='xy') + # set(xy, 'LineWidth', PP_arrow_linewidth); + # set(xy, 'AutoScale', 'off'); + # set(xy, 'AutoScaleFactor', 0); + + if (scale < 0): + bp = mpl.plot(x1, x2, 'b.'); # add dots at base + # set(bp, 'MarkerSize', PP_arrow_markersize); + + return; Added: trunk/tests/margin_test.py =================================================================== --- trunk/tests/margin_test.py (rev 0) +++ trunk/tests/margin_test.py 2011-07-25 05:00:41 UTC (rev 169) @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# margin_test.py - test suit for stability margin commands +# RMM, 15 Jul 2011 + +import unittest +import numpy as np +from control.xferfcn import TransferFunction +from control.statesp import StateSpace +from control.margin import * + +class TestMargin(unittest.TestCase): + """These are tests for the margin commands in margin.py.""" + + def setUp(self): + self.sys1 = TransferFunction([1, 2], [1, 2, 3]) + self.sys2 = TransferFunction([1], [1, 2, 3, 4]) + self.sys3 = StateSpace([[1., 4.], [3., 2.]], [[1.], [-4.]], + [[1., 0.]], [[0.]]) + + def testGainPhaseMargin(self): + gm, pm, sm, wg, wp, ws = StabilityMargins(self.sys1); + gm, pm, sm, wg, wp, ws = StabilityMargins(self.sys2); + gm, pm, sm, wg, wp, ws = StabilityMargins(self.sys3); + + def testPhaseCrossoverFrequencies(self): + omega, gain = PhaseCrossoverFrequencies(self.sys2) + np.testing.assert_array_almost_equal(omega, [1.73205, 0.]) + np.testing.assert_array_almost_equal(gain, [-0.5, 0.25]) + + tf = TransferFunction([1],[1,1]) + omega, gain = PhaseCrossoverFrequencies(tf) + np.testing.assert_array_almost_equal(omega, [0.]) + np.testing.assert_array_almost_equal(gain, [1.]) + + # testing MIMO, only (0,0) element is considered + tf = TransferFunction([[[1],[2]],[[3],[4]]], + [[[1, 2, 3, 4],[1,1]],[[1,1],[1,1]]]) + omega, gain = PhaseCrossoverFrequencies(tf) + np.testing.assert_array_almost_equal(omega, [1.73205081, 0.]) + np.testing.assert_array_almost_equal(gain, [-0.5, 0.25]) + +def suite(): + return unittest.TestLoader().loadTestsFromTestCase(TestMargin) + +if __name__ == "__main__": + unittest.main() Added: trunk/tests/phaseplot_test.py =================================================================== --- trunk/tests/phaseplot_test.py (rev 0) +++ trunk/tests/phaseplot_test.py 2011-07-25 05:00:41 UTC (rev 169) @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# +# phaseplot_test.py - test phase plot functions +# RMM, 17 24 2011 (based on TestMatlab from v0.4c) +# +# This test suite calls various phaseplot functions. Since the plots +# themselves can't be verified, this is mainly here to make sure all +# of the function arguments are handled correctly. If you run an +# individual test by itself and then type show(), it should pop open +# the figures so that you can check them visually. + +import unittest +import numpy as np +import scipy as sp +import matplotlib.pyplot as mpl +from control.phaseplot import * +from numpy import pi + +class TestPhasePlot(unittest.TestCase): + def setUp(self): + pass; + + def testInvPendNoSims(self): + PhasePlot(self.invpend_ode, (-6,6,10), (-6,6,10)); + + def testInvPendSims(self): + PhasePlot(self.invpend_ode, (-6,6,10), (-6,6,10), + xinit = ([1,1], [-1,1])); + + def testInvPendTimePoints(self): + PhasePlot(self.invpend_ode, (-6,6,10), (-6,6,10), + xinit = ([1,1], [-1,1]), T=np.linspace(0,5,100)); + + def testInvPendLogtime(self): + PhasePlot(self.invpend_ode, + 'logtime', (3, 0.7), None, + [ [-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1], + [-1, 2.1], [4.2, 2.1], [5, 2.1], + [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1], + [1, -2.1], [-4.2, -2.1], [-5, -2.1] ], + np.linspace(0, 40, 200), verbose=False) + + def testInvPendAuto(self): + PhasePlot(self.invpend_ode, 'auto', 0, None, + [[-2.3056, 2.1], [2.3056, -2.1]], 6, verbose=False) + + def testOscillatorParams(self): + m = 1; b = 1; k = 1; # default values + PhasePlot(self.oscillator_ode, 'timepts', [0.3, 1, 2, 3], None, + [[-1,1], [-0.3,1], [0,1], [0.25,1], [0.5,1], [0.7,1], + [1,1], [1.3,1], [1,-1], [0.3,-1], [0,-1], [-0.25,-1], + [-0.5,-1], [-0.7,-1], [-1,-1], [-1.3,-1]], + np.linspace(0, 10, 100), parms = (m, b, k)); + + # Sample dynamical systems - inverted pendulum + def invpend_ode(self, x, t, m=1., l=1., b=0, g=9.8): + import numpy as np + return (x[1], -b/m*x[1] + (g*l/m) * np.sin(x[0])) + + # Sample dynamical systems - oscillator + def oscillator_ode(self, x, t, m=1., b=1, k=1, extra=None): + return (x[1], -k/m*x[0] - b/m*x[1]) + +def suite(): + return unittest.TestLoader().loadTestsFromTestCase(TestPhasePlot) + +if __name__ == '__main__': + unittest.main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-07-16 06:05:52
|
Revision: 168 http://python-control.svn.sourceforge.net/python-control/?rev=168&view=rev Author: murrayrm Date: 2011-07-16 06:05:46 +0000 (Sat, 16 Jul 2011) Log Message: ----------- * Moved margin command from freqplot.py to margins.py (new file); updated matlab.py, init.py, etc to reflect changes * Added PhaseCrossoverFrequencies() function; contributed by Steffen Waldherr * Added initial unit tests for StabilityMargins(), PhaseCrossoverFrequencies() Modified Paths: -------------- trunk/ChangeLog trunk/src/__init__.py trunk/src/freqplot.py trunk/src/matlab.py trunk/src/statesp.py trunk/tests/matlab_test.py Added Paths: ----------- trunk/src/margins.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-07-13 16:03:32 UTC (rev 167) +++ trunk/ChangeLog 2011-07-16 06:05:46 UTC (rev 168) @@ -1,3 +1,24 @@ +2011-07-15 Richard Murray <murray@malabar.local> + + * tests/matlab_test.py (TestMatlab): added unittest for margin() + commands (calling format only) + + * src/statesp.py (StateSpace): updated comments + + * tests/margin_test.py: set up unit tests for StabilityMargins() and + PhaseCrossoverFrequencies() + + * src/__init__.py: added margins.py to __init__ + +2011-07-14 Richard Murray <murray@malabar.local> + + * src/margins.py (GainPhaseMargin): moved freqplot.MarginPlot to + margin.StabilityMargins (MarginPlot didn't actually plot anything) + + * src/margins.py (PhaseCrossoverFrequencies): added new function to + compute frequencies that we cross real axis. Contributed by Steffen + Waldherr <wal...@is...> + 2011-07-11 Richard Murray <murray@malabar.local> * src/rlocus.py: added real() and imag() to list of functions Modified: trunk/src/__init__.py =================================================================== --- trunk/src/__init__.py 2011-07-13 16:03:32 UTC (rev 167) +++ trunk/src/__init__.py 2011-07-16 06:05:46 UTC (rev 168) @@ -57,15 +57,16 @@ # Import functions from within the control system library #! Should probably only import the exact functions we use... -from xferfcn import * -from statesp import * -from freqplot import * -from nichols import * from bdalg import * -from statefbk import * from delay import * +from freqplot import * +from margins import * +from mateqn import * from modelsimp import * +from nichols import * from rlocus import * -from mateqn import * +from statefbk import * +from statesp import * from timeresp import ForcedResponse, InitialResponse, StepResponse, \ ImpulseResponse +from xferfcn import * Modified: trunk/src/freqplot.py =================================================================== --- trunk/src/freqplot.py 2011-07-13 16:03:32 UTC (rev 167) +++ trunk/src/freqplot.py 2011-07-16 06:05:46 UTC (rev 168) @@ -299,101 +299,6 @@ phase = np.squeeze(phase_tmp) plt.subplot(224); plt.loglog(omega, mag); - -# gain and phase margins -# contributed by Sawyer B. Fuller <mi...@ca...> -def MarginPlot(sysdata, deg=True): - """Calculate gain and phase margins and associated crossover frequencies - - Usage: - - gm, pm, sm, wg, wp, ws = margin(sysdata, deg=True) - - Parameters - ---------- - sysdata: linsys or (mag, phase, omega) sequence - sys : linsys - Linear SISO system - mag, phase, omega : sequence of array_like - Input magnitude, phase, and frequencies (rad/sec) sequence from - bode frequency response data - deg=True: boolean - If true, all input and output phases in degrees, else in radians - - Returns - ------- - gm, pm, sm, wg, wp, ws: float - Gain margin gm, phase margin pm, stability margin sm, and - associated crossover - frequencies wg, wp, and ws of SISO open-loop. If more than - one crossover frequency is detected, returns the lowest corresponding - margin. - """ - #TODO do this precisely without the effects of discretization of frequencies? - #TODO assumes SISO - #TODO unit tests, margin plot - - if (not getattr(sysdata, '__iter__', False)): - sys = sysdata - mag, phase, omega = bode(sys, deg=deg, Plot=False) - elif len(sysdata) == 3: - mag, phase, omega = sysdata - else: - raise ValueError("Margin sysdata must be either a linear system or a 3-sequence of mag, phase, omega.") - - if deg: - cycle = 360. - crossover = 180. - else: - cycle = 2 * np.pi - crossover = np.pi - - wrapped_phase = -np.mod(phase, cycle) - - # phase margin from minimum phase among all gain crossovers - neg_mag_crossings_i = np.nonzero(np.diff(mag < 1) > 0)[0] - mag_crossings_p = wrapped_phase[neg_mag_crossings_i] - if len(neg_mag_crossings_i) == 0: - if mag[0] < 1: # gain always less than one - wp = np.nan - pm = np.inf - else: # gain always greater than one - print "margin: no magnitude crossings found" - wp = np.nan - pm = np.nan - else: - min_mag_crossing_i = neg_mag_crossings_i[np.argmin(mag_crossings_p)] - wp = omega[min_mag_crossing_i] - pm = crossover + phase[min_mag_crossing_i] - if pm < 0: - print "warning: system unstable: negative phase margin" - - # gain margin from minimum gain margin among all phase crossovers - neg_phase_crossings_i = np.nonzero(np.diff(wrapped_phase < -crossover) > 0)[0] - neg_phase_crossings_g = mag[neg_phase_crossings_i] - if len(neg_phase_crossings_i) == 0: - wg = np.nan - gm = np.inf - else: - min_phase_crossing_i = neg_phase_crossings_i[ - np.argmax(neg_phase_crossings_g)] - wg = omega[min_phase_crossing_i] - gm = abs(1/mag[min_phase_crossing_i]) - if gm < 1: - print "warning: system unstable: gain margin < 1" - - # stability margin from minimum abs distance from -1 point - if deg: - phase_rad = phase * np.pi / 180. - else: - phase_rad = phase - L = mag * np.exp(1j * phase_rad) # complex loop response to -1 pt - min_Lplus1_i = np.argmin(np.abs(L + 1)) - sm = np.abs(L[min_Lplus1_i] + 1) - ws = phase[min_Lplus1_i] - - return gm, pm, sm, wg, wp, ws - # # Utility functions # @@ -461,4 +366,3 @@ bode = BodePlot nyquist = NyquistPlot gangof4 = GangOf4Plot -margin = MarginPlot Added: trunk/src/margins.py =================================================================== --- trunk/src/margins.py (rev 0) +++ trunk/src/margins.py 2011-07-16 06:05:46 UTC (rev 168) @@ -0,0 +1,193 @@ +"""margin.py + +Functions for computing stability margins and related functions. + +Routeins in this module: + +margin.StabilityMargins +margin.PhaseCrossoverFrequencies +""" + +"""Copyright (c) 2011 by California Institute of Technology +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the California Institute of Technology nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CALTECH +OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +Author: Richard M. Murray +Date: 14 July 2011 + +$Id: xferfcn.py 165 2011-06-26 02:44:09Z murrayrm $ + +""" + +import xferfcn +from freqplot import bode +import numpy as np + +# gain and phase margins +# contributed by Sawyer B. Fuller <mi...@ca...> +#! TODO - need to add unit test functions +def StabilityMargins(sysdata, deg=True): + """Calculate gain, phase and stability margins and associated + crossover frequencies. + + Usage: + + gm, pm, sm, wg, wp, ws = StabilityMargins(sysdata, deg=True) + + Parameters + ---------- + sysdata: linsys or (mag, phase, omega) sequence + sys : linsys + Linear SISO system + mag, phase, omega : sequence of array_like + Input magnitude, phase, and frequencies (rad/sec) sequence from + bode frequency response data + deg=True: boolean + If true, all input and output phases in degrees, else in radians + + Returns + ------- + gm, pm, sm, wg, wp, ws: float + Gain margin gm, phase margin pm, stability margin sm, and + associated crossover + frequencies wg, wp, and ws of SISO open-loop. If more than + one crossover frequency is detected, returns the lowest corresponding + margin. + """ + #TODO do this precisely without the effects of discretization of frequencies? + #TODO assumes SISO + #TODO unit tests, margin plot + + if (not getattr(sysdata, '__iter__', False)): + sys = sysdata + mag, phase, omega = bode(sys, deg=deg, Plot=False) + elif len(sysdata) == 3: + mag, phase, omega = sysdata + else: + raise ValueError("Margin sysdata must be either a linear system or a 3-sequence of mag, phase, omega.") + + if deg: + cycle = 360. + crossover = 180. + else: + cycle = 2 * np.pi + crossover = np.pi + + wrapped_phase = -np.mod(phase, cycle) + + # phase margin from minimum phase among all gain crossovers + neg_mag_crossings_i = np.nonzero(np.diff(mag < 1) > 0)[0] + mag_crossings_p = wrapped_phase[neg_mag_crossings_i] + if len(neg_mag_crossings_i) == 0: + if mag[0] < 1: # gain always less than one + wp = np.nan + pm = np.inf + else: # gain always greater than one + print "margin: no magnitude crossings found" + wp = np.nan + pm = np.nan + else: + min_mag_crossing_i = neg_mag_crossings_i[np.argmin(mag_crossings_p)] + wp = omega[min_mag_crossing_i] + pm = crossover + phase[min_mag_crossing_i] + if pm < 0: + print "warning: system unstable: negative phase margin" + + # gain margin from minimum gain margin among all phase crossovers + neg_phase_crossings_i = np.nonzero(np.diff(wrapped_phase < -crossover) > 0)[0] + neg_phase_crossings_g = mag[neg_phase_crossings_i] + if len(neg_phase_crossings_i) == 0: + wg = np.nan + gm = np.inf + else: + min_phase_crossing_i = neg_phase_crossings_i[ + np.argmax(neg_phase_crossings_g)] + wg = omega[min_phase_crossing_i] + gm = abs(1/mag[min_phase_crossing_i]) + if gm < 1: + print "warning: system unstable: gain margin < 1" + + # stability margin from minimum abs distance from -1 point + if deg: + phase_rad = phase * np.pi / 180. + else: + phase_rad = phase + L = mag * np.exp(1j * phase_rad) # complex loop response to -1 pt + min_Lplus1_i = np.argmin(np.abs(L + 1)) + sm = np.abs(L[min_Lplus1_i] + 1) + ws = phase[min_Lplus1_i] + + return gm, pm, sm, wg, wp, ws + +# Contributed by Steffen Waldherr <wal...@is...> +#! TODO - need to add test functions +def PhaseCrossoverFrequencies(sys): + """ + Compute frequencies and gains at intersections with real axis + in Nyquist plot. + + Call as: + omega, gain = PhaseCrossoverFrequencies() + + Returns + ------- + omega: 1d array of (non-negative) frequencies where Nyquist plot + intersects the real axis + + gain: 1d array of corresponding gains + + Examples + -------- + >>> tf = TransferFunction([1], [1, 2, 3, 4]) + >>> PhaseCrossoverFrequenies(tf) + (array([ 1.73205081, 0. ]), array([-0.5 , 0.25])) + """ + + # Convert to a transfer function + tf = xferfcn._convertToTransferFunction(sys) + + # if not siso, fall back to (0,0) element + #! TODO: should add a check and warning here + num = tf.num[0][0] + den = tf.den[0][0] + + # Compute frequencies that we cross over the real axis + numj = (1.j)**np.arange(len(num)-1,-1,-1)*num + denj = (-1.j)**np.arange(len(den)-1,-1,-1)*den + allfreq = np.roots(np.imag(np.polymul(numj,denj))) + realfreq = np.real(allfreq[np.isreal(allfreq)]) + realposfreq = realfreq[realfreq >= 0.] + + # using real() to avoid rounding errors and results like 1+0j + # it would be nice to have a vectorized version of self.evalfr here + gain = np.real(np.asarray([tf.evalfr(f)[0][0] for f in realposfreq])) + + return realposfreq, gain Modified: trunk/src/matlab.py =================================================================== --- trunk/src/matlab.py 2011-07-13 16:03:32 UTC (rev 167) +++ trunk/src/matlab.py 2011-07-16 06:05:46 UTC (rev 168) @@ -72,6 +72,7 @@ import ctrlutil import freqplot import timeresp +import margins from statesp import StateSpace, _rss_generate, _convertToStateSpace from xferfcn import TransferFunction, _convertToTransferFunction from lti import Lti #base class of StateSpace, TransferFunction @@ -1025,7 +1026,6 @@ rlist = RootLocus(sys, klist, **keywords) return rlist, klist - def margin(*args): """Calculate gain and phase margins and associated crossover frequencies @@ -1060,16 +1060,15 @@ """ if len(args) == 1: sys = args[0] - margins = freqplot.margin(sys) + margin = margins.StabilityMargins(sys) elif len(args) == 3: - margins = freqplot.margin(args) + margin = margins.StabilityMargins(args) else: raise ValueError("Margin needs 1 or 3 arguments; received %i." % len(args)) - return margins[0], margins[1], margins[3], margins[4] + return margin[0], margin[1], margin[3], margin[4] - def dcgain(*args): ''' Compute the gain of the system in steady state. Modified: trunk/src/statesp.py =================================================================== --- trunk/src/statesp.py 2011-07-13 16:03:32 UTC (rev 167) +++ trunk/src/statesp.py 2011-07-16 06:05:46 UTC (rev 168) @@ -208,7 +208,7 @@ return StateSpace(self.A, self.B, -self.C, -self.D) - # Addition of two transfer functions (parallel interconnection) + # Addition of two state space systems (parallel interconnection) def __add__(self, other): """Add two LTI systems (parallel connection).""" @@ -244,7 +244,7 @@ return self + other - # Subtraction of two transfer functions (parallel interconnection) + # Subtraction of two state space systems (parallel interconnection) def __sub__(self, other): """Subtract two LTI systems.""" @@ -255,7 +255,7 @@ return other + (-self) - # Multiplication of two transfer functions (series interconnection) + # Multiplication of two state space systems (series interconnection) def __mul__(self, other): """Multiply two LTI objects (serial connection).""" @@ -284,7 +284,7 @@ return StateSpace(A, B, C, D) - # Right multiplication of two transfer functions (series interconnection) + # Right multiplication of two state space systems (series interconnection) # Just need to convert LH argument to a state space object def __rmul__(self, other): """Right multiply two LTI objects (serial connection).""" Modified: trunk/tests/matlab_test.py =================================================================== --- trunk/tests/matlab_test.py 2011-07-13 16:03:32 UTC (rev 167) +++ trunk/tests/matlab_test.py 2011-07-16 06:05:46 UTC (rev 168) @@ -186,6 +186,13 @@ [-0.1391, 48.9776]]) yout, _t, _xout = lsim(self.mimo_ss1, u, t, x0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) + + def testMargin(self): + #! TODO: check results to make sure they are OK + gm, pm, wg, wp = margin(self.siso_tf1); + gm, pm, wg, wp = margin(self.siso_tf2); + gm, pm, wg, wp = margin(self.siso_ss1); + gm, pm, wg, wp = margin(self.siso_ss2); def testDcgain(self): #Create different forms of a SISO system This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-07-13 16:03:38
|
Revision: 167 http://python-control.svn.sourceforge.net/python-control/?rev=167&view=rev Author: murrayrm Date: 2011-07-13 16:03:32 +0000 (Wed, 13 Jul 2011) Log Message: ----------- * Updated output arguments for matlab.py time response functions to match MATLAB conventions (they were switched) * Added long version names for frequency plots: BodePlot, NyquistPlot, etc * Fixed some import errors in rlocus.py Details in ChangeLog. Modified Paths: -------------- trunk/ChangeLog trunk/src/freqplot.py trunk/src/matlab.py trunk/src/rlocus.py trunk/tests/matlab_test.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-07-02 01:55:50 UTC (rev 166) +++ trunk/ChangeLog 2011-07-13 16:03:32 UTC (rev 167) @@ -1,3 +1,18 @@ +2011-07-11 Richard Murray <murray@malabar.local> + + * src/rlocus.py: added real() and imag() to list of functions + imported from numpy + + * src/freqplot.py: renamed plotting functions to BodePlot, + NyquistPlot, GangOf4Plot and MarginPlot. Set up aliases to the more + common names (bode, nyquest, gangof4, margin). Mainly playing + around with idea for the eventual interface to use. + + * tests/matlab_test.py: updated timeresp outputs to match MATLAB + + * src/matlab.py (impulse, initial, lsim, step): switched outputs + from step, impulse, initial, lsim to match MATLAB standard + 2011-07-01 Richard Murray <murray@malabar.local> * src/rlocus.py: modified scipy import to only import those Modified: trunk/src/freqplot.py =================================================================== --- trunk/src/freqplot.py 2011-07-02 01:55:50 UTC (rev 166) +++ trunk/src/freqplot.py 2011-07-13 16:03:32 UTC (rev 167) @@ -55,7 +55,7 @@ # # Bode plot -def bode(syslist, omega=None, dB=False, Hz=False, deg=True, +def BodePlot(syslist, omega=None, dB=False, Hz=False, deg=True, color=None, Plot=True): """Bode plot for a system @@ -178,7 +178,7 @@ return mags, phases, omegas # Nyquist plot -def nyquist(syslist, omega=None, Plot=True): +def NyquistPlot(syslist, omega=None, Plot=True): """Nyquist plot for a system Plots a Nyquist plot for the system over a (optional) frequency range. @@ -245,7 +245,7 @@ # Gang of Four #! TODO: think about how (and whether) to handle lists of systems -def gangof4(P, C, omega=None): +def GangOf4Plot(P, C, omega=None): """Plot the "Gang of 4" transfer functions for a system Generates a 2x2 plot showing the "Gang of 4" sensitivity functions @@ -302,7 +302,7 @@ # gain and phase margins # contributed by Sawyer B. Fuller <mi...@ca...> -def margin(sysdata, deg=True): +def MarginPlot(sysdata, deg=True): """Calculate gain and phase margins and associated crossover frequencies Usage: @@ -457,3 +457,8 @@ return omega +# Function aliases +bode = BodePlot +nyquist = NyquistPlot +gangof4 = GangOf4Plot +margin = MarginPlot Modified: trunk/src/matlab.py =================================================================== --- trunk/src/matlab.py 2011-07-02 01:55:50 UTC (rev 166) +++ trunk/src/matlab.py 2011-07-13 16:03:32 UTC (rev 167) @@ -1165,12 +1165,12 @@ Returns ------- + yout: array + Response of the system + T: array Time values of the output - yout: array - Response of the system - See Also -------- lsim, initial, impulse @@ -1181,7 +1181,7 @@ ''' T, yout = timeresp.StepResponse(sys, T, X0, input, output, transpose = True, **keywords) - return T, yout + return yout, T def impulse(sys, T=None, input=0, output=0, **keywords): ''' @@ -1216,10 +1216,10 @@ Returns ------- + yout: array + Response of the system T: array Time values of the output - yout: array - Response of the system See Also -------- @@ -1231,7 +1231,7 @@ ''' T, yout = timeresp.ImpulseResponse(sys, T, 0, input, output, transpose = True, **keywords) - return T, yout + return yout, T def initial(sys, T=None, X0=0., input=0, output=0, **keywords): ''' @@ -1272,10 +1272,10 @@ Returns ------- + yout: array + Response of the system T: array Time values of the output - yout: array - Response of the system See Also -------- @@ -1287,7 +1287,7 @@ ''' T, yout = timeresp.InitialResponse(sys, T, X0, input, output, transpose = True, **keywords) - return T, yout + return yout, T def lsim(sys, U=0., T=None, X0=0., **keywords): ''' @@ -1324,10 +1324,10 @@ Returns ------- + yout: array + Response of the system. T: array Time values of the output. - yout: array - Response of the system. xout: array Time evolution of the state vector. @@ -1341,4 +1341,4 @@ ''' T, yout, xout = timeresp.ForcedResponse(sys, T, U, X0, transpose = True, **keywords) - return T, yout, xout + return yout, T, xout Modified: trunk/src/rlocus.py =================================================================== --- trunk/src/rlocus.py 2011-07-02 01:55:50 UTC (rev 166) +++ trunk/src/rlocus.py 2011-07-13 16:03:32 UTC (rev 167) @@ -46,7 +46,7 @@ # $Id$ # Packages used by this module -from scipy import array, poly1d, row_stack, zeros_like +from scipy import array, poly1d, row_stack, zeros_like, real, imag import scipy.signal # signal processing toolbox import pylab # plotting routines import xferfcn # transfer function manipulation Modified: trunk/tests/matlab_test.py =================================================================== --- trunk/tests/matlab_test.py 2011-07-02 01:55:50 UTC (rev 166) +++ trunk/tests/matlab_test.py 2011-07-13 16:03:32 UTC (rev 167) @@ -95,24 +95,24 @@ t = np.linspace(0, 1, 10) youttrue = np.array([9., 17.6457, 24.7072, 30.4855, 35.2234, 39.1165, 42.3227, 44.9694, 47.1599, 48.9776]) - tout, yout = step(sys, T=t) + yout, tout = step(sys, T=t) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) # Play with arguments - tout, yout = step(sys, T=t, X0=0) + yout, tout = step(sys, T=t, X0=0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) X0 = np.array([0, 0]); - tout, yout = step(sys, T=t, X0=X0) + yout, tout = step(sys, T=t, X0=X0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) #Test MIMO system, which contains ``siso_ss1`` twice sys = self.mimo_ss1 - _t, y_00 = step(sys, T=t, input=0, output=0) - _t, y_11 = step(sys, T=t, input=1, output=1) + y_00, _t = step(sys, T=t, input=0, output=0) + y_11, _t = step(sys, T=t, input=1, output=1) np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4) np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4) @@ -122,14 +122,14 @@ t = np.linspace(0, 1, 10) youttrue = np.array([86., 70.1808, 57.3753, 46.9975, 38.5766, 31.7344, 26.1668, 21.6292, 17.9245, 14.8945]) - tout, yout = impulse(sys, T=t) + yout, tout = impulse(sys, T=t) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) #Test MIMO system, which contains ``siso_ss1`` twice sys = self.mimo_ss1 - _t, y_00 = impulse(sys, T=t, input=0, output=0) - _t, y_11 = impulse(sys, T=t, input=1, output=1) + y_00, _t = impulse(sys, T=t, input=0, output=0) + y_11, _t = impulse(sys, T=t, input=1, output=1) np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4) np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4) @@ -140,15 +140,15 @@ x0 = np.matrix(".5; 1.") youttrue = np.array([11., 8.1494, 5.9361, 4.2258, 2.9118, 1.9092, 1.1508, 0.5833, 0.1645, -0.1391]) - tout, yout = initial(sys, T=t, X0=x0) + yout, tout = initial(sys, T=t, X0=x0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) #Test MIMO system, which contains ``siso_ss1`` twice sys = self.mimo_ss1 x0 = np.matrix(".5; 1.; .5; 1.") - _t, y_00 = initial(sys, T=t, X0=x0, input=0, output=0) - _t, y_11 = initial(sys, T=t, X0=x0, input=1, output=1) + y_00, _t = initial(sys, T=t, X0=x0, input=0, output=0) + y_11, _t = initial(sys, T=t, X0=x0, input=1, output=1) np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4) np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4) @@ -160,10 +160,10 @@ u = np.array([1., 1, 1, 1, 1, 1, 1, 1, 1, 1]) youttrue = np.array([9., 17.6457, 24.7072, 30.4855, 35.2234, 39.1165, 42.3227, 44.9694, 47.1599, 48.9776]) - tout, yout, _xout = lsim(self.siso_ss1, u, t) + yout, tout, _xout = lsim(self.siso_ss1, u, t) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) np.testing.assert_array_almost_equal(tout, t) - _t, yout, _xout = lsim(self.siso_tf3, u, t) + yout, _t, _xout = lsim(self.siso_tf3, u, t) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) #test with initial value and special algorithm for ``U=0`` @@ -171,7 +171,7 @@ x0 = np.matrix(".5; 1.") youttrue = np.array([11., 8.1494, 5.9361, 4.2258, 2.9118, 1.9092, 1.1508, 0.5833, 0.1645, -0.1391]) - _t, yout, _xout = lsim(self.siso_ss1, u, t, x0) + yout, _t, _xout = lsim(self.siso_ss1, u, t, x0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) #Test MIMO system, which contains ``siso_ss1`` twice @@ -184,7 +184,7 @@ [1.9092, 39.1165], [1.1508, 42.3227], [0.5833, 44.9694], [0.1645, 47.1599], [-0.1391, 48.9776]]) - _t, yout, _xout = lsim(self.mimo_ss1, u, t, x0) + yout, _t, _xout = lsim(self.mimo_ss1, u, t, x0) np.testing.assert_array_almost_equal(yout, youttrue, decimal=4) def testDcgain(self): @@ -206,7 +206,7 @@ #Compute the gain with a long simulation t = linspace(0, 1000, 1000) - _t, y = step(sys_ss, t) + y, _t = step(sys_ss, t) gain_sim = y[-1] print 'gain_sim:', gain_sim This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-07-02 01:55:56
|
Revision: 166 http://python-control.svn.sourceforge.net/python-control/?rev=166&view=rev Author: murrayrm Date: 2011-07-02 01:55:50 +0000 (Sat, 02 Jul 2011) Log Message: ----------- * Added link to numpy vs MATLAB page in scipy docs * Fixed a problem with import statements in rlocus (overwrote statesp.place) Modified Paths: -------------- trunk/ChangeLog trunk/doc/intro.rst trunk/src/__init__.py trunk/src/rlocus.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-06-26 02:44:09 UTC (rev 165) +++ trunk/ChangeLog 2011-07-02 01:55:50 UTC (rev 166) @@ -1,3 +1,13 @@ +2011-07-01 Richard Murray <murray@malabar.local> + + * src/rlocus.py: modified scipy import to only import those + functions that we actually use. This fixes a problem pointed out by + Carsten Knoll (TU Dresden) where control.place could be overwritten + by numpy.place (because of an "from scipy import *" in rlocus.py + + * doc/intro.rst: Added link to scipy web page talking about the + differences between numpy and MATLAB (contributed by Shuo Han). + 2011-06-25 Richard Murray <murray@malabar.local> * src/xferfcn.py (TransferFunction._common_den): changed tolerance Modified: trunk/doc/intro.rst =================================================================== --- trunk/doc/intro.rst 2011-06-26 02:44:09 UTC (rev 165) +++ trunk/doc/intro.rst 2011-07-02 01:55:50 UTC (rev 166) @@ -21,6 +21,13 @@ Some Differences from MATLAB ---------------------------- +The python-control package makes use of NumPy and SciPy. A list of +general differences between NumPy and MATLAB can be found here: + + http://www.scipy.org/NumPy_for_Matlab_Users + +In terms of the python-control package more specifically, here are +some thing to keep in mind: * You must include commas in vectors. So [1 2 3] must be [1, 2, 3]. * Functions that return multiple arguments use tuples * Can't use braces for collections; use tuples instead @@ -30,7 +37,7 @@ Getting Started --------------- -1. Download the latest release from http:sf.net/projects/python-control/files. +1. Download latest release from http://sf.net/projects/python-control/files. 2. Untar the source code in a temporary directory and run 'python setup.py install' to build and install the code 3. To see if things are working correctly, run ipython -pylab and run the @@ -38,8 +45,8 @@ Bode plot and Nyquist plot for a simple second order system. 4. To see the commands that are available, run the following commands in ipython:: - >>> import control - >>> ?control.matlab + >>> import control + >>> ?control.matlab 5. If you want to have a MATLAB-like environment for running the control toolbox, use:: - >>> from control.matlab import * + >>> from control.matlab import * Modified: trunk/src/__init__.py =================================================================== --- trunk/src/__init__.py 2011-06-26 02:44:09 UTC (rev 165) +++ trunk/src/__init__.py 2011-07-02 01:55:50 UTC (rev 166) @@ -56,6 +56,7 @@ """ # Import functions from within the control system library +#! Should probably only import the exact functions we use... from xferfcn import * from statesp import * from freqplot import * Modified: trunk/src/rlocus.py =================================================================== --- trunk/src/rlocus.py 2011-06-26 02:44:09 UTC (rev 165) +++ trunk/src/rlocus.py 2011-07-02 01:55:50 UTC (rev 166) @@ -46,7 +46,7 @@ # $Id$ # Packages used by this module -from scipy import * +from scipy import array, poly1d, row_stack, zeros_like import scipy.signal # signal processing toolbox import pylab # plotting routines import xferfcn # transfer function manipulation This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-06-26 02:44:16
|
Revision: 165 http://python-control.svn.sourceforge.net/python-control/?rev=165&view=rev Author: murrayrm Date: 2011-06-26 02:44:09 +0000 (Sun, 26 Jun 2011) Log Message: ----------- * Made fixes to documentation (intro, matlab) * Got rid of unit test error in hsvd (convert slycot args to numpy array) * Tracked down possible errors in convert_test (still in progress) See ChangeLog for more detailed list of code that was modified Modified Paths: -------------- trunk/ChangeLog trunk/doc/intro.rst trunk/src/matlab.py trunk/src/statefbk.py trunk/src/timeresp.py trunk/src/xferfcn.py trunk/tests/convert_test.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-06-22 19:26:01 UTC (rev 164) +++ trunk/ChangeLog 2011-06-26 02:44:09 UTC (rev 165) @@ -1,3 +1,27 @@ +2011-06-25 Richard Murray <murray@malabar.local> + + * src/xferfcn.py (TransferFunction._common_den): changed tolerance + for detecting complex valued poles to a user-settable parameter, + with default value 1e-8. This was an attempt to fix errors in the + convert_test.py unittest script (conversion routine was + misclassifying some poles as imaginary when they weren't). + + * src/xferfcn.py (_convertToTransferFunction): converted arguments + to tb04ad to numpy arrays; fixes a unit test error in convert_test.py. + + * src/statefbk.py (gram): convert system matrix passed to sb03md to + numpy array; this fixes a unit test error in modelsimp_test.py. + + * src/matlab.py (impulse): got rid of X0 argument for impulse + response (not implemented in MATLAB). + + * doc/intro.rst: added some quick start information + + * src/matlab.py: added documentation for step, impulse, initial, lsim + + * src/timeresp.py: fixed some MATLAB specific function names in + function doc strings + 2011-06-22 Richard Murray <murray@malabar.local> * doc/intro.rst: fixed some small types Modified: trunk/doc/intro.rst =================================================================== --- trunk/doc/intro.rst 2011-06-22 19:26:01 UTC (rev 164) +++ trunk/doc/intro.rst 2011-06-26 02:44:09 UTC (rev 165) @@ -8,9 +8,10 @@ that implement common operations for the analysis and design of feedback control systems. The initial goal is to implement all of the functionality required to work through the examples in the textbook -Feedback Systems by \xC5str\xF6m and Murray. A MATLAB compatibility package -(control.matlab) is available that provides functions corresponding to -the commands available in the MATLAB Control Systems Toolbox. +Feedback Systems by Astrom and Murray. A MATLAB compatibility package +(control.matlab) is available that provides many of the common +functions corresponding to commands available in the MATLAB Control +Systems Toolbox. In addition to the documentation here, there is a project wiki that contains some additional information about how to use the package @@ -26,3 +27,19 @@ * Transfer functions are only implemented for SISO systems (due to limitations in the underlying signals.lti class); use state space representations for MIMO systems. + +Getting Started +--------------- +1. Download the latest release from http:sf.net/projects/python-control/files. +2. Untar the source code in a temporary directory and run 'python setup.py + install' to build and install the code +3. To see if things are working correctly, run ipython -pylab and run the + script 'examples/secord-matlab.py'. This should generate a set response, + Bode plot and Nyquist plot for a simple second order system. +4. To see the commands that are available, run the following commands in + ipython:: + >>> import control + >>> ?control.matlab +5. If you want to have a MATLAB-like environment for running the control + toolbox, use:: + >>> from control.matlab import * Modified: trunk/src/matlab.py =================================================================== --- trunk/src/matlab.py 2011-06-22 19:26:01 UTC (rev 164) +++ trunk/src/matlab.py 2011-06-26 02:44:09 UTC (rev 165) @@ -1128,21 +1128,217 @@ # Call corresponding functions in timeresp, with arguments transposed def step(sys, T=None, X0=0., input=0, output=0, **keywords): + ''' + Step response of a linear system + + If the system has multiple inputs or outputs (MIMO), one input and one + output have to be selected for the simulation. The parameters `input` + and `output` do this. All other inputs are set to 0, all other outputs + are ignored. + + Parameters + ---------- + sys: StateSpace, or TransferFunction + LTI system to simulate + + T: array-like object, optional + Time vector (argument is autocomputed if not given) + + X0: array-like or number, optional + Initial condition (default = 0) + + Numbers are converted to constant arrays with the correct shape. + + input: int + Index of the input that will be used in this simulation. + + output: int + Index of the output that will be used in this simulation. + + **keywords: + Additional keyword arguments control the solution algorithm for the + differential equations. These arguments are passed on to the function + :func:`control.ForcedResponse`, which in turn passes them on to + :func:`scipy.integrate.odeint`. See the documentation for + :func:`scipy.integrate.odeint` for information about these + arguments. + + Returns + ------- + T: array + Time values of the output + + yout: array + Response of the system + + See Also + -------- + lsim, initial, impulse + + Examples + -------- + >>> T, yout = step(sys, T, X0) + ''' T, yout = timeresp.StepResponse(sys, T, X0, input, output, transpose = True, **keywords) return T, yout -def impulse(sys, T=None, X0=0., input=0, output=0, **keywords): - T, yout = timeresp.ImpulseResponse(sys, T, X0, input, output, +def impulse(sys, T=None, input=0, output=0, **keywords): + ''' + Impulse response of a linear system + + If the system has multiple inputs or outputs (MIMO), one input and + one output must be selected for the simulation. The parameters + `input` and `output` do this. All other inputs are set to 0, all + other outputs are ignored. + + Parameters + ---------- + sys: StateSpace, TransferFunction + LTI system to simulate + + T: array-like object, optional + Time vector (argument is autocomputed if not given) + + input: int + Index of the input that will be used in this simulation. + + output: int + Index of the output that will be used in this simulation. + + **keywords: + Additional keyword arguments control the solution algorithm for the + differential equations. These arguments are passed on to the function + :func:`lsim`, which in turn passes them on to + :func:`scipy.integrate.odeint`. See the documentation for + :func:`scipy.integrate.odeint` for information about these + arguments. + + Returns + ------- + T: array + Time values of the output + yout: array + Response of the system + + See Also + -------- + lsim, step, initial + + Examples + -------- + >>> T, yout = impulse(sys, T) + ''' + T, yout = timeresp.ImpulseResponse(sys, T, 0, input, output, transpose = True, **keywords) return T, yout def initial(sys, T=None, X0=0., input=0, output=0, **keywords): + ''' + Initial condition response of a linear system + + If the system has multiple inputs or outputs (MIMO), one input and one + output have to be selected for the simulation. The parameters `input` + and `output` do this. All other inputs are set to 0, all other outputs + are ignored. + + Parameters + ---------- + sys: StateSpace, or TransferFunction + LTI system to simulate + + T: array-like object, optional + Time vector (argument is autocomputed if not given) + + X0: array-like object or number, optional + Initial condition (default = 0) + + Numbers are converted to constant arrays with the correct shape. + + input: int + Index of the input that will be used in this simulation. + + output: int + Index of the output that will be used in this simulation. + + **keywords: + Additional keyword arguments control the solution algorithm for the + differential equations. These arguments are passed on to the function + :func:`lsim`, which in turn passes them on to + :func:`scipy.integrate.odeint`. See the documentation for + :func:`scipy.integrate.odeint` for information about these + arguments. + + + Returns + ------- + T: array + Time values of the output + yout: array + Response of the system + + See Also + -------- + lsim, step, impulse + + Examples + -------- + >>> T, yout = initial(sys, T, X0) + ''' T, yout = timeresp.InitialResponse(sys, T, X0, input, output, transpose = True, **keywords) return T, yout def lsim(sys, U=0., T=None, X0=0., **keywords): + ''' + Simulate the output of a linear system. + + As a convenience for parameters `U`, `X0`: + Numbers (scalars) are converted to constant arrays with the correct shape. + The correct shape is inferred from arguments `sys` and `T`. + + Parameters + ---------- + sys: Lti (StateSpace, or TransferFunction) + LTI system to simulate + + U: array-like or number, optional + Input array giving input at each time `T` (default = 0). + + If `U` is ``None`` or ``0``, a special algorithm is used. This special + algorithm is faster than the general algorithm, which is used otherwise. + + T: array-like + Time steps at which the input is defined, numbers must be (strictly + monotonic) increasing. + + X0: array-like or number, optional + Initial condition (default = 0). + + **keywords: + Additional keyword arguments control the solution algorithm for the + differential equations. These arguments are passed on to the function + :func:`scipy.integrate.odeint`. See the documentation for + :func:`scipy.integrate.odeint` for information about these + arguments. + + Returns + ------- + T: array + Time values of the output. + yout: array + Response of the system. + xout: array + Time evolution of the state vector. + + See Also + -------- + step, initial, impulse + + Examples + -------- + >>> T, yout, xout = lsim(sys, U, T, X0) + ''' T, yout, xout = timeresp.ForcedResponse(sys, T, U, X0, transpose = True, **keywords) return T, yout, xout Modified: trunk/src/statefbk.py =================================================================== --- trunk/src/statefbk.py 2011-06-22 19:26:01 UTC (rev 164) +++ trunk/src/statefbk.py 2011-06-26 02:44:09 UTC (rev 165) @@ -328,7 +328,7 @@ raise ControlSlycot("can't find slycot module 'sb03md'") n = sys.states U = np.zeros((n,n)) - A = sys.A + A = np.array(sys.A) # convert to NumPy array for slycot X,scale,sep,ferr,w = sb03md(n, C, A, U, dico, job='X', fact='N', trana=tra) gram = X return gram Modified: trunk/src/timeresp.py =================================================================== --- trunk/src/timeresp.py 2011-06-22 19:26:01 UTC (rev 164) +++ trunk/src/timeresp.py 2011-06-26 02:44:09 UTC (rev 165) @@ -419,11 +419,11 @@ See Also -------- - lsim, initial, impulse + ForcedResponse, InitialResponse, ImpulseResponse Examples -------- - >>> T, yout = step(sys, T, X0) + >>> T, yout = StepResponse(sys, T, X0) """ sys = _convertToStateSpace(sys) sys = _mimo2siso(sys, input, output, warn_conversion=True) @@ -491,11 +491,11 @@ See Also -------- - lsim, step, impulse + ForcedResponse, ImpulseResponse, StepResponse Examples -------- - >>> T, yout = InitialResponsesys, T, X0) + >>> T, yout = InitialResponse(sys, T, X0) """ sys = _convertToStateSpace(sys) sys = _mimo2siso(sys, input, output, warn_conversion=True) @@ -564,7 +564,7 @@ See Also -------- - lsim, step, initial + ForcedReponse, InitialResponse, StepResponse Examples -------- Modified: trunk/src/xferfcn.py =================================================================== --- trunk/src/xferfcn.py 2011-06-22 19:26:01 UTC (rev 164) +++ trunk/src/xferfcn.py 2011-06-26 02:44:09 UTC (rev 165) @@ -527,22 +527,46 @@ return out - def _common_den(self): - """Compute MIMO common denominator; return it and an adjusted numerator. + def _common_den(self, imag_tol=None): + """ + Compute MIMO common denominator; return it and an adjusted numerator. + This function computes the single denominator containing all + the poles of sys.den, and reports it as the array d. The + output numerator array n is modified to use the common + denominator; the coefficient arrays are also padded with zeros + to be the same size as d. n is an sys.outputs by sys.inputs + by len(d) array. + + Parameters + ---------- + imag_tol: float + Threshold for the imaginary part of a root to use in detecting + complex poles + + Returns + ------- + num: array + Multi-dimensional array of numerator coefficients. num[i][j] + gives the numerator coefficient array for the ith input and jth + output + + den: array + Array of coefficients for common denominator polynomial + + Examples + -------- >>> n, d = sys._common_den() - - computes the single denominator containing all the poles of sys.den, and - reports it as the array d. The output numerator array n is modified to - use the common denominator; the coefficient arrays are also padded with - zeros to be the same size as d. n is an sys.outputs-by-sys.inputs-by- - len(d) array. - + """ # Machine precision for floats. eps = finfo(float).eps + # Decide on the tolerance to use in deciding of a pole is complex + if (imag_tol == None): + imag_tol = 1e-8 #! TODO: figure out the right number to use + # A sorted list to keep track of cumulative poles found as we scan # self.den. poles = [] @@ -615,8 +639,9 @@ # To prevent buildup of imaginary part error, handle complex # pole pairs together. quad = polymul([1., -poles[n]], [1., -poles[n+1]]) - assert all(quad.imag < eps), "The quadratic has a nontrivial \ -imaginary part: %g" % quad.imag.max() + assert all(quad.imag < 10 * eps), \ + "The quadratic has a nontrivial imaginary part: %g" \ + % quad.imag.max() quad = quad.real den = polymul(den, quad) @@ -747,10 +772,10 @@ raise TypeError("If sys is a StateSpace, _convertToTransferFunction \ cannot take keywords.") - # Use Slycot to make the transformation. TODO: this is still somewhat - # buggy! - tfout = tb04ad(sys.states, sys.inputs, sys.outputs, sys.A, sys.B, sys.C, - sys.D,tol1=0.0) + # Use Slycot to make the transformation + # Make sure to convert system matrices to numpy arrays + tfout = tb04ad(sys.states, sys.inputs, sys.outputs, array(sys.A), + array(sys.B), array(sys.C), array(sys.D), tol1=0.0) # Preallocate outputs. num = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] Modified: trunk/tests/convert_test.py =================================================================== --- trunk/tests/convert_test.py 2011-06-22 19:26:01 UTC (rev 164) +++ trunk/tests/convert_test.py 2011-06-26 02:44:09 UTC (rev 165) @@ -29,9 +29,9 @@ # Maximum number of states to test + 1 self.maxStates = 20 # Maximum number of inputs and outputs to test + 1 - self.maxIO = 20 + self.maxIO = 10 # Set to True to print systems to the output. - self.debug = True + self.debug = False def printSys(self, sys, ind): """Print system to the standard output.""" @@ -40,9 +40,10 @@ print "sys%i:\n" % ind print sys - def testConvert(self, verbose=0): + def testConvert(self): """Test state space to transfer function conversion.""" #Currently it only tests that a TF->SS->TF generates an unchanged TF + verbose = self.debug #print __doc__ @@ -70,12 +71,14 @@ for inputNum in range(inputs): for outputNum in range(outputs): np.testing.assert_array_almost_equal(\ - tfOriginal.num[outputNum][inputNum],\ - tfTransformed.num[outputNum][inputNum]) + tfOriginal.num[outputNum][inputNum], \ + tfTransformed.num[outputNum][inputNum], \ + err_msg='numerator mismatch') np.testing.assert_array_almost_equal(\ - tfOriginal.den[outputNum][inputNum],\ - tfTransformed.den[outputNum][inputNum]) + tfOriginal.den[outputNum][inputNum], \ + tfTransformed.den[outputNum][inputNum], + err_msg='denominator mismatch') #To test the ss systems is harder because they aren't the same #realization. This could be done with checking that they have the This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-06-22 19:26:08
|
Revision: 164 http://python-control.svn.sourceforge.net/python-control/?rev=164&view=rev Author: murrayrm Date: 2011-06-22 19:26:01 +0000 (Wed, 22 Jun 2011) Log Message: ----------- Fixed up some typos in documentation + instructions for copying to sf.net Modified Paths: -------------- trunk/ChangeLog trunk/doc/README trunk/doc/intro.rst Removed Paths: ------------- trunk/doc/control.tex Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-06-22 18:59:13 UTC (rev 163) +++ trunk/ChangeLog 2011-06-22 19:26:01 UTC (rev 164) @@ -1,5 +1,11 @@ 2011-06-22 Richard Murray <murray@malabar.local> + * doc/intro.rst: fixed some small types + + * doc/control.tex: removed (no longer needed) + +2011-06-22 Richard Murray <murray@malabar.local> + * doc/intro.rst: Added a slightly more general introduction, with a pointer to the python-control wiki (on sf.net) Modified: trunk/doc/README =================================================================== --- trunk/doc/README 2011-06-22 18:59:13 UTC (rev 163) +++ trunk/doc/README 2011-06-22 19:26:01 UTC (rev 164) @@ -13,3 +13,8 @@ 4. >> touch *.rst >> make html [or make latex] + +Creating/updating manual on sourceforge: + +5. >> rsync -rav _build/html/ us...@sh...:/home/project-web/python-control/htdocs/manual-N.mx/ + Deleted: trunk/doc/control.tex =================================================================== --- trunk/doc/control.tex 2011-06-22 18:59:13 UTC (rev 163) +++ trunk/doc/control.tex 2011-06-22 19:26:01 UTC (rev 164) @@ -1,21 +0,0 @@ -\documentclass{manual} - -\release{0.1} - -\begin{document} -\sectionauthor{Richard Murray}{mu...@cd...} - -\section{\module{control}} -This is some information on the control module. - -\section{Differences from MATLAB} -\begin{itemize} - \item You must include commas in vectors. So [1 2 3] must be [1, 2, 3]. - \item Functions that return multiple arguments use tuples - \item Can't use braces for collections; use tuples instead - \item Transfer functions are only implemented for SISO systems (due - to limitations in the underlying signals.lti class); use state space - representations for MIMO systems. -\end{itemize} - -\end{document} Modified: trunk/doc/intro.rst =================================================================== --- trunk/doc/intro.rst 2011-06-22 18:59:13 UTC (rev 163) +++ trunk/doc/intro.rst 2011-06-22 19:26:01 UTC (rev 164) @@ -13,7 +13,7 @@ the commands available in the MATLAB Control Systems Toolbox. In addition to the documentation here, there is a project wiki that -contains some addional informaiton about how to use the package +contains some additional information about how to use the package (including some detailed worked examples): http://python-control.sourceforge.net This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mur...@us...> - 2011-06-22 18:59:20
|
Revision: 163 http://python-control.svn.sourceforge.net/python-control/?rev=163&view=rev Author: murrayrm Date: 2011-06-22 18:59:13 +0000 (Wed, 22 Jun 2011) Log Message: ----------- Small modifications to sphinx documentation: * Updated intro material and added link to wiki * Added version information to doc/conf.py * Got rid of path dependency for sphinx (requires proper path) Documentation for 0.4d is now posted at http://python-control.sf.net/manual Modified Paths: -------------- trunk/ChangeLog trunk/doc/Makefile trunk/doc/conf.py trunk/doc/intro.rst Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2011-06-22 06:02:02 UTC (rev 162) +++ trunk/ChangeLog 2011-06-22 18:59:13 UTC (rev 163) @@ -1,3 +1,13 @@ +2011-06-22 Richard Murray <murray@malabar.local> + + * doc/intro.rst: Added a slightly more general introduction, with a + pointer to the python-control wiki (on sf.net) + + * doc/Makefile: Changed path to sphinx-build to assume it is in the + users path (as opposed to an explicit path) + + * doc/conf.py: Added release information into documentation file + 2011-06-21 Richard Murray <murray@malabar.local> * src/statesp.py (_mimo2siso): Moved function from matlab.py. Modified: trunk/doc/Makefile =================================================================== --- trunk/doc/Makefile 2011-06-22 06:02:02 UTC (rev 162) +++ trunk/doc/Makefile 2011-06-22 18:59:13 UTC (rev 163) @@ -3,7 +3,7 @@ # You can set these variables from the command line. SPHINXOPTS = -SPHINXBUILD = /Applications/Sphinx-1.0.6/sphinx-build.py +SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build Modified: trunk/doc/conf.py =================================================================== --- trunk/doc/conf.py 2011-06-22 06:02:02 UTC (rev 162) +++ trunk/doc/conf.py 2011-06-22 18:59:13 UTC (rev 163) @@ -57,9 +57,9 @@ # built documents. # # The short X.Y version. -version = '0.0' +version = '0.4d' # The full version, including alpha/beta/rc tags. -release = '0.0' +release = '0.4d' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. Modified: trunk/doc/intro.rst =================================================================== --- trunk/doc/intro.rst 2011-06-22 06:02:02 UTC (rev 162) +++ trunk/doc/intro.rst 2011-06-22 18:59:13 UTC (rev 163) @@ -3,15 +3,26 @@ ============ Welcome to the Python-Control project. -This is sample documentation and will include our Princeton University APC524 contribution. -We can incorporate any existing documentation as well. For example from R.Murray's earlier tex document: +The python-control package is a set of python classes and functions +that implement common operations for the analysis and design of +feedback control systems. The initial goal is to implement all of the +functionality required to work through the examples in the textbook +Feedback Systems by \xC5str\xF6m and Murray. A MATLAB compatibility package +(control.matlab) is available that provides functions corresponding to +the commands available in the MATLAB Control Systems Toolbox. -Differences from MATLAB ------------------------ -* You must include commas in vectors. So [1 2 3] must be [1, 2, 3]. -* Functions that return multiple arguments use tuples -* Can't use braces for collections; use tuples instead -* Transfer functions are only implemented for SISO systems (due to limitations in the underlying signals.lti class); use state space representations for MIMO systems. +In addition to the documentation here, there is a project wiki that +contains some addional informaiton about how to use the package +(including some detailed worked examples): + http://python-control.sourceforge.net +Some Differences from MATLAB +---------------------------- +* You must include commas in vectors. So [1 2 3] must be [1, 2, 3]. +* Functions that return multiple arguments use tuples +* Can't use braces for collections; use tuples instead +* Transfer functions are only implemented for SISO systems (due to + limitations in the underlying signals.lti class); use state space + representations for MIMO systems. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
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] |
From: Eike W. <eik...@gm...> - 2011-06-21 01:37:59
|
Hello list! I have created a new patch, which converts many function doc-strings to proper Sphinx format. All functions in ``matlab`` now have documentation. Go to: https://sourceforge.net/tracker/?func=detail&aid=3323572&group_id=282523&atid=1198311 Eike. |
From: Richard M. <mu...@cd...> - 2011-06-19 06:03:30
|
Hi Eike. Thanks for the comments. I'm cc'ing the discussion list since it would be useful to get the perspective of others as well before making a final decision. I agree that the default behavior should be something that is well thought out and consistent. Then the question is whether in cases where that conflicts with MATLAB, we provide any sort of support for the MATLAB convention. -richard On 18 Jun 2011, at 17:24 , Eike Welk wrote: > Hello Richard! > > On Saturday 18.06.2011 03:02:07 you wrote: >> Eike, >> >> I'm working on integrating some of the functionality that you contributed >> to the python-control package. Your new convention for simulation inputs >> and outputs has a lot of nice features, but it does "break" current code >> (eg, try running examples/pvtol-nested.py). In addition, it is not >> compatible with the way MATLAB or scipy.signal does things, which could be >> confusing. > > You should devise a convention, and I'll convert my code to this convention. > > A good alternative IMHO would be to transpose all matrices of my convention. > This is compatible to Matlab's ``lsim`` and ``scipy.integrate.odeint``. Also > Matplotlib is OK with it, if it's done right. > > I personally don't like to use matrices as return values for ``lsim``, because > of their confusing behavior. Also you usually don't do linear algebra with a > time series of values. On the other hand, the users (who are probably not > experienced programmers) might be confused if they have to consider different > data types (matrices and arrays). > > But make sure, that simple things are simple. For example this should work: > >>>> t, y = step(sys) >>>> plot(t, y) > > For the compatibility of matrices with Matplotlib see: > > #This works: > In [7]: t1 = array([1, 2, 3]) > > In [8]: t2 = matrix('1; 2; 3') > > In [9]: y = matrix('1; 4; 9') > > In [10]: plot(t1, y) > Out[10]: [<matplotlib.lines.Line2D object at 0x26d3d90>] > > In [11]: plot(t2, y) > Out[11]: [<matplotlib.lines.Line2D object at 0x26de850>] > > > #But this results in a ``ValueError``: > In [12]: t3 = matrix('1, 2, 3') > > In [13]: plot(t3, y) > > >> >> As a general principle, I think that if a user imports control.matlab, they >> should get as MATLAB like an environment as possible (since control.matlab >> is the MATLAB emulation module in the package). However, I see now reason >> why we need to maintain MATLAB compatibility within the underlying library >> itself, where we can do things in a more python-like way. But breaking >> the convention used by scipy.signal could get confusing... > > Trying to emulate Matlab closely is IMHO unnecessary, and also impossible. You > will never get the elegance of Matlab, since the language is optimized for its > specific task. > > Especially: > * Python has no ``.*`` operator. > * Python functions don't know how many return values are requested. > > I think the functions should have the same names as in Matlab, so that Matlab > users can quickly find the functionality that they need. The arguments need > only to be roughly equivalent. For details, the users should be educated to > type ``function_name?`` in IPython, or to look at the documentation website. > > Instead of closely emulating Matlab you should strive for a consistent user > interface, and good integration with the rest of Numpy, Scipy and Matplotlib. > >> >> Here is one possible fix: >> > ... > ... >> Let me know what you think about this (others on the list as well). If we >> do decide to switch the way time series are represented from the current >> version, we would have to update the version number to something like 0.5a >> (instead of 0.4d) since we would be breaking existing code. > > Just tell me how you think it would be best, and I'll port it to this form. A > library of incongruous parts, is IMHO less useful than a parameter > convention, that I find somewhat impractical. > > There don't seem to be many users currently, so breaking the interface should > be not very problematic. > > I have an other patch, that converts big part of the module documentation to > proper Sphinx markup, so that you can soon put the generated documentation on > a server. Something which I find very important. > > > Yours, > Eike. |
From: Richard M. <mu...@cd...> - 2011-06-18 19:22:45
|
Following up on the message thread below, from several months back: in the current trunk release of python-control, which I just committed, *time* response functions for SISO systems return 'squeezed' responses. For the python version of the functions (eg, StepResponse), you can turn this off by passing the argument 'squeeze=False'. If someone has time to do something similar for the frequency response routines, let me know. I'll put it on my list, but won't be able to get to it for a week or two. -richard On 7 Apr 2011, at 11:11 , Sawyer Fuller wrote: > What Ryan and Richard have suggested seem like pretty good solutions to me: maybe a property of the system that defaults to being SISO if the system has only input and one output (but can be set to MIMO if desired), and a way to override that setting in the calling function? > > Sawyer > > ------------------------ > Sawyer B. Fuller > Ph.D. Candidate, Bioengineering > California Institute of Technology > http://www.cds.caltech.edu/~minster/ > > > > > On Thu, Apr 7, 2011 at 10:18 AM, Ryan Krauss <rk...@si...> wrote: > I think the idea of having toSISO be a property of the system makes a > lot of sense. At worst, I would have to override it once for each > system that I analyze. We could allow it to be overwritten in the > function calls if we wanted to, but default to the instance property > if it is not passed in: > > def bode(self, ...., toSISO=None): > if toSISO is None: > toSISO = self.toSISO > > Just my thoughts. > > Ryan > > > > On Thu, Apr 7, 2011 at 11:47 AM, Steve Brunton <sbr...@pr...> wrote: > > Hi All, > > > > This idea of having keywords to change the output format is what we had in mind when extending to MIMO (as well as whether to plot or just return output for a command like 'bode'). A a nice interface might have a SISO system default toSISO=True, a MIMO system would default toMIMO=True, and there would be the option to have a SISO system output as a MIMO system (for example if you have scripts that work on both SISO and MIMO outputs). > > > > Even Matlab doesn't have this completely sorted out. When I do [m,p,w]=bode(sys,w), I still have to squeeze the output for a SISO system. > > > > -S,L,K,B > > > > > > On Apr 7, 2011, at 11:15 AM, Ryan Krauss wrote: > > > >> I think this essentially makes sense, but I use the toolbox with my > >> undergrads who are new to python. They might find it annoying to have > >> to pass in the extra keyword argument toSISO=True every time they > >> generate a Bode plot or something. Can we try to intelligently guess > >> what toSISO should be in the code? i.e. if the system has only one > >> input and one output, assume toSISO=True. We may be able to make this > >> work by using numpy.squeeze on all array outputs. > >> > >> Ryan > >> > >> -- > >> Ryan Krauss, Ph.D. > >> Assistant Professor > >> Mechanical Engineering > >> Southern Illinois University Edwardsville > >> > >> > >> > >> On Thu, Apr 7, 2011 at 9:56 AM, Richard Murray <mu...@cd...> wrote: > >>> I noticed this change as well. If you are just using the various functions in python-control, everything works fine (eg, none of the examples had to change). But if you are extracting frequency responses or otherwise playing with data generated from your system, this is a bit of a hassle. > >>> > >>> Here is a proposal: > >>> > >>> * For all functions in python-control that accept MIMO systems (all of them eventually), we add two keywords: > >>> > >>> - toSISO=True will force output to be SISO-like (v0.3) if inputs==1, outputs==1 > >>> - toSISO=(n, m) will give you SISO-like output for the nth input to mth output > >>> - toMIMO=True will force the output to be MIMO-like even if inputs==1, outputs==1 > >>> > >>> * For the Python interface, the default will be toMIMO=True, so that you get the current behavior. If you want the scalar version of the outputs, you just add toSISO=True as a keyword. > >>> > >>> * For the MATLAB interface, the default will toSISO=True, so that you get MATLAB-like behavior if you extract data from bode(), freqresp(), etc. > >>> > >>> One problem with this is that you can have conflicts if you give *both* sets of keywords. Sometimes this makes sense ("toSISO=(2,3) toMIMO=True"), but sometimes it doesn't ("toSISO=True, toMIMO=True"). So probably needs a bit more thought. But the idea is that the following code: > >>> > >>> (mag, phase, omega) = bode(sys) > >>> plot(omega[0][0]), mag[0][0]) > >>> > >>> becomes > >>> > >>> (mag, phase, omega) = bode(sys, toSISO=True) > >>> plot(omega, mag) > >>> > >>> which I think is a bit cleaner. > >>> > >>> Comments, suggestions? > >>> > >>> -richard > >>> > >>> > >>> > >>> On 6 Apr 2011, at 14:19 , Sawyer Fuller wrote: > >>> > >>>> Hey i just downloaded the latest version of python-control and it looks like everything has gone MIMO. Pretty cool, but is there any way to way to stick to SISO, eg a subclass or flag? A little bit of a drag to constantly be appending [0][0] to every frequency response for the most common use case. I think matlab does a special-case for SISO. Anything like that in the works or somewhere i'm not finding it? > >>>> > >>>> S > >>>> > >>>> > >>>> ------------------------ > >>>> Sawyer B. Fuller > >>>> Ph.D. Candidate, Bioengineering > >>>> California Institute of Technology > >>>> http://www.cds.caltech.edu/~minster/ |