Skip to content

a first implementation of the singular value plot as discussed in #592 #593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
Apr 29, 2021

Conversation

forgi86
Copy link
Contributor

@forgi86 forgi86 commented Mar 27, 2021

  • added singular values plot (function singular_values_plot in freqplot.py)
  • added a test of the new function (test_singular_values_plot in freqresp_test.py)
  • added an example jupyter notebook (singular-values-plot.ipynb)

- added singular values plot (function singular_values_plot in freqplot.py)
- added a test of the new function (test_singular_values_plot  in freqresp_test.py)
- added an example jupyter notebook (singular-values-plot.ipynb)
Copy link
Contributor

@bnavigator bnavigator left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

I left some comments in the code.

The Notebook looks like omega exceeds the Nyquist frequency

@bnavigator
Copy link
Contributor

The test suite failure is unrelated and will be fixed by #588

Co-authored-by: Ben Greiner <code@bnavigator.de>
@coveralls
Copy link

coveralls commented Mar 28, 2021

Coverage Status

Coverage increased (+0.1%) to 89.602% when pulling 649c394 on forgi86:singular-values-plot into a6a5bee on python-control:master.

forgi86 and others added 3 commits March 28, 2021 13:05
Co-authored-by: Ben Greiner <code@bnavigator.de>
- removed deprecated handling 'Plot'
- fixed docstring for argument plot the singular value plot
@bnavigator
Copy link
Contributor

            fresp = sys(1j*omega if sys.isctime() else np.exp(1j * omega * sys.dt))
    
>           fresp = fresp.transpose((2, 0, 1))
E           ValueError: axes don't match array

use squeeze=False

- added default settings for singular_values_plot
@forgi86
Copy link
Contributor Author

forgi86 commented Mar 28, 2021

Something strange about the return shape of the frequency response. For a square 2x2 system:

sys(np.array(0.0), squeeze=False).shape
(2, 2)

sys(0.0, squeeze=False).shape
(2, 2, 1)

Is it expected? Perhaps I should do an np.atleast_1d(omega) inside singular_values_plot anyways?

@bnavigator
Copy link
Contributor

Is it expected? Perhaps I should do an np.atleast_1d(omega) inside singular_values_plot anyways?

Nope. Opened #594.

You can work around with atleast_1d.

forgi86 added 2 commits March 28, 2021 23:13
- added np.atleast_1d(omega) to handle scalar omega parameter
- reshape output of frequency response to handle MIMO/SISO systems in the same way
- if plot condition added to set gridlines and axes labels
forgi86 added 3 commits March 31, 2021 20:55
- in singular_values_plot: the complex argument to be evaluated for the frequency response is now computed in the if branch
- fixed typos in freqresp_test.py: the siso system is now also tested
- added documentation for parameters Hz and dB of singular_values_plot
- result of singular_values_plot transposed to be in line with the "channel first" format
- tests also updated consequently
@bnavigator
Copy link
Contributor

Whishlist:
Can we (optionally) have the left and right singular vectors, too?

- use omega_sys to compute omega_complex!
@forgi86
Copy link
Contributor Author

forgi86 commented Mar 31, 2021

Whishlist:
Can we (optionally) have the left and right singular vectors, too?

Sounds reasonable. From a control perspective they correspond to the output/input directions associated with the corresponding singular value. There's no way to plot them in a nice way, but they can indeed be optionally returned.

forgi86 added 3 commits April 1, 2021 01:14
- added discrete-time example
- added tests with more than one frequency point
- added a test that generates a plot
…tion used by bode_plot and singular_values_plot
Comment on lines 1031 to 1034
'singular_values_plot.dB': False, # Plot singular values in dB
'singular_values_plot.deg': True, # Plot phase in degrees
'singular_values_plot.Hz': False, # Plot frequency in Hertz
'singular_values_plot.grid': True, # Turn on grid for gain and phase
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a bit odd to me to have to set these separately from the equivalent bode configuration variable. Is someone going to use one set of defaults for Bode and a separate one for singular values? (Also note that gang_of_four uses the Bode plot defaults.)

If we don't want to use bode.dB, etc, we could also change all of them to freqplot.dB (though perhaps with some backward compatibility??).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add the properties dB, Hz, and grid to freqplot and use these for bode, singular_values_plot, and gang_of_four.
The property _singular_values_plot_default would then disappear, and _bode_defaults would still contain bode.deg and bode.wrap_phase (and maybe unused dB, Hz, grid for backward compatibility, at least for the moment).

Is this OK?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems fine. Make sure also to update the use_matlab_defaults and use_fbs_defaults functions in config.py. I'm not sure about what to do with bode.deg. On the one hand, it is true that this is the only function that plots phase, but at the same time seems odd to use freqplot for everything except that. I would probably just use freqplot for everything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a new version where all the settings for bode_plot and singular_values_plot are in _freqplot_defaults

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still see a _singular_values_plot_default with a comment for "Bode" above the definition and then used with_get_param('freqplot'). That's very confusing.

Also, personally, I would still prefer that we provide some backwards compatibility through an alias of config.defaults['bode'], so that old code does not break right away. Maybe including a warning message. I am not sure how to achieve this with a dict outside of set_defaults and _get_param in an elegant way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to remove all references to the previous structure _singular_values_plot_default (new push).
Still have to handle backward compatibility in some way.

forgi86 added 5 commits April 3, 2021 15:10
- changed line plot = config._get_param('bode', 'grid', plot, True) to config._get_param('bode', 'grid', plot, True)
- changed logic in _determine_omega_vector: if Hz = True, omega_in is interpreted in Hz units (as it is with omega_limits)
- jupyter notebook singular-values-plot.ipynb output fixed
DEV: improved color cycling logic for superimposed singular_values_plot on the same axes: do not repeat the same color
TST: tests in config_test modified to interpret omega in Hz if the option Hz is set to True
@forgi86
Copy link
Contributor Author

forgi86 commented Apr 18, 2021

Variables renamed in conventions.rst (bode -> freqplot)

@sawyerbfuller sawyerbfuller linked an issue Apr 20, 2021 that may be closed by this pull request
@bnavigator
Copy link
Contributor

Thank you @forgi86 for the hard work and also for the patience with all the picky reviews.

I will submit a PR shortly which addresses the backwards compatibility with the old name for the bode defaults.

@bnavigator bnavigator merged commit db174b7 into python-control:master Apr 29, 2021
@forgi86
Copy link
Contributor Author

forgi86 commented May 15, 2021

Thank you for the review and for your kind message, @bnavigator. Was my first PR to python-control, I hope I will be able to contribute again in the future!

@murrayrm murrayrm added this to the 0.9.1 milestone Dec 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Singular values plot missing
5 participants