GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Reimplementation of 2D phase plots by murrayrm · Pull Request #980 · python-control/python-control Conversation
Member
This PR reimplements the phase plot functionality of python-control by creating a new function From the documentation: The default method for generating a phase plane plot is to provide a 2D dynamical system along with a range of coordinates and time limit: By default, the plot includes streamlines generated from starting points on limits of the plot, with arrows showing the flow of the system, as well as any equilibrium points for the system. A variety of options are available to modify the information that is plotted, including plotting a grid of vectors instead of streamlines and turning on and off various features of the plot. To illustrate some of these possibilities, consider a phase plane plot for an inverted pendulum system, which is created using a mesh grid: This figure shows several features of more complex phase plane plots: multiple equilibrium points are shown, with saddle points showing separatrices, and streamlines generated along a 5x8 mesh of initial conditions. At each mesh point, a streamline is created that goes 5 time units forward and backward in time. A separate grid specification is used to find equilibrium points and separatrices (since the course grid spacing of 5x8 does not find all possible equilibrium points). Together, the multiple features in the phase plane plot give a good global picture of the topological strucrure of solutions of the dynamical system. Phase plots can be buit up by hand using a variety of helper functions that are part of the The following helper functions are available:
The Note that unlike other plotting function, phase plane plots do not involve computing a response and then plotting the result via a
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
This was
linked to
issues
Closed
7 tasks done
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was an error while loading. Please reload this page.
|
coverage: 94.467% (+0.05%) from 94.422% |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| # Date: 1 Jul 2019 | ||
|
|
||
| r"""The :mod:`control.flatsys` package contains a set of classes and functions | ||
| r"""The :mod:`control.flatsys` module contains a set of classes and functions |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
The original is correct: flatsys is a package according to standard terms: https://docs.python.org/3/glossary.html#term-package
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| import numpy as np | ||
| import matplotlib.pyplot as mpl | ||
| """The :mod:`control.phaseplot` module contains functions for generating 2D | ||
| phase plots. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Convention is for summary to be 1 line (https://peps.python.org/pep-0257/#multi-line-docstrings).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| @@ -0,0 +1,215 @@ | |||
| # phase_portraits.py - phase portrait examples | |||
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| # phase_portraits.py - phase portrait examples | |
| # phase_plane_plots.py - phase portrait examples |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| PYTHONPATH=.. python $< | ||
|
|
||
| phaseplot-dampedosc-default.png: ../control/tests/phaseplot_test.py | ||
| PYTHONPATH=.. python $< |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Should the other images generated by phaseplot_test.py (phaseplot-oscillator-helpers.png, phaseplot-invpend-meshgrid.png) be included here? It does not seem important because the PNG files are being committed, but I note this here in case you wanted to.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Agree that they could be listed, but I didn't list them all out since triggering on the one file will update all files => if the test generation script is updated, all PNG files are updated.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Good point! I will complete review tomorrow.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Fixes some very outdated code. Very nice!
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| return new_kwargs | ||
|
|
||
| # Create array for storing outputs | ||
| out = np.empty(3, dtype=object) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Docstring says this is a list. Seems like a list might be better/simpler here than a numpy array, e.g. out = [[], None, None]
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| Parameters | ||
| ---------- | ||
| sys : NonlinearIOSystem or callable(x, t, ...) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
What is motivation to maintain the old convention of (x, t, ...) argument order, rather than (t, x, ...) when called with a callable? Backwards compatibility? I am not aware of anywhere else we or scipy adheres to that convention anymore, but I might be missing something.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| vfdata = np.zeros((points.shape[0], 4)) | ||
| for i, x in enumerate(points): | ||
| vfdata[i, :2] = x | ||
| vfdata[i, 2:] = sys.dynamics(0, x, 0, params=params) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I think this wouldn't work if sys is just a function - is the callable intended to be a function if it is not a system?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| Parameters | ||
| ---------- | ||
| sys : NonlinearIOSystem or callable(x, t, ...) | ||
| Function used to generate phase plane data. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Relatedly, should there be a statement here that only two-state systems can be accepted? (and a test that gives a helpful error?)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
In addition to adressing comments, functionality for handling callables (versus systems) was missing; now added. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| # Create reverse time system, if needed | ||
| if dir != 'forward': | ||
| revsys = NonlinearIOSystem( | ||
| lambda t, x, u, params: -np.array(sys.updfcn(t, x, u, params)), |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| lambda t, x, u, params: -np.array(sys.updfcn(t, x, u, params)), | |
| lambda t, x, u, params: -np.asarray(sys.updfcn(t, x, u, params)), |
This won't re-create the array if it is already one.
relatedly, and this is more of a question: I am confused about the use of each of these methods, all of which do roughly the same thing. Is this correct: _rhs fast and low-level, updfcn just a reference to the function that was passed in, and dynamics: user-friendly function that may not be as fast? Just checking that this is the right one (speed is kind of important in this application)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Correct on the various versions. In general:
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Great work! I found a few more misprints, but nothing critical. Locally I merged this into the current tip of main branch and successfully ran the tests and example code, and built the documentation.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| # RMM, 25 Mar 2024 | ||
| # | ||
| # This file contains a number of examples of phase plane plots generated | ||
| # using the phaseplot module. Most of these figures lines up with examples |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| # using the phaseplot module. Most of these figures lines up with examples | |
| # using the phaseplot module. Most of these figures line up with examples |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| phase plots. The base function for creating phase plane portraits is | ||
| :func:`~control.phase_plane_plot`, which generates a phase plane portrait | ||
| for a 2 state I/O system (with no inputs). In addition, several other | ||
| functions are available to creat ecustomize phase plane plots: |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| functions are available to creat ecustomize phase plane plots: | |
| functions are available to customize phase plane plots: |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| Parameters | ||
| ---------- | ||
| sys : NonlinearIOSystem or callable(t, x, ...) | ||
| I/O systems or function used to generate phase plane data. If a |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| I/O systems or function used to generate phase plane data. If a | |
| I/O system or function used to generate phase plane data. If a |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| The :func:`~control.phase_plane_plot` function calls these helper functions | ||
| based on the options it is passed. | ||
|
|
||
| Note that unlike other plotting function, phase plane plots do not involve |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| Note that unlike other plotting function, phase plane plots do not involve | |
| Note that unlike other plotting functions, phase plane plots do not involve |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| plot_separatrices : bool or dict | ||
| If `True` (default) then plot separatrices starting from each | ||
| equilibrium point. If set to a dict, pass on the key-value pairs | ||
| in the dict as keywords to :func:`~control.phaseplot.streamlines`. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| in the dict as keywords to :func:`~control.phaseplot.streamlines`. | |
| in the dict as keywords to :func:`~control.phaseplot.separatrices`. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| import numpy as np | ||
| import matplotlib.pyplot as mpl | ||
| # Create a system form a callable |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| # Create a system form a callable | |
| # Create a system from a callable |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| # if not isinstance(pointdata, (list, tuple)) or len(pointdata) != 4: | ||
| # raise ValueError("invalid grid data specification") |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| # if not isinstance(pointdata, (list, tuple)) or len(pointdata) != 4: | |
| # raise ValueError("invalid grid data specification") |
This can be deleted, or the check in the comment can be expanded to handle case of isinstance(pointdata, np.ndarray).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks for the careful reviews, @sawyerbfuller and @slivingston! Will merge as soon as checks finish up (just in case). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
Strange nondeterministic issues when usingphase_plot with X, Y and X0 set
phase_plot ODE function signature is not compatible with solve_ivp and StateSpace.dynamics
There was an error while loading. Please reload this page.