diff --git a/control/rlocus.py b/control/rlocus.py index 4f83c019b..ee30fe489 100644 --- a/control/rlocus.py +++ b/control/rlocus.py @@ -137,7 +137,7 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None, print_gain = config._get_param( 'rlocus', 'print_gain', print_gain, _rlocus_defaults) - sys_loop = sys if sys.issiso() else sys[0,0] + sys_loop = sys if sys.issiso() else sys[0, 0] # Convert numerator and denominator to polynomials if they aren't (nump, denp) = _systopoly1d(sys_loop) @@ -232,16 +232,11 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None, ax.set_ylim(ylim) # Draw the grid - if grid and sisotool: - if isdtime(sys, strict=True): - zgrid(ax=ax) - else: - _sgrid_func(fig=fig) - elif grid: + if grid: if isdtime(sys, strict=True): zgrid(ax=ax) else: - _sgrid_func() + _sgrid_func(fig=fig if sisotool else None) else: ax.axhline(0., linestyle=':', color='k', linewidth=.75, zorder=-20) ax.axvline(0., linestyle=':', color='k', linewidth=.75, zorder=-20) diff --git a/control/setup.py b/control/setup.py deleted file mode 100644 index 3ed3e3a7e..000000000 --- a/control/setup.py +++ /dev/null @@ -1,5 +0,0 @@ -def configuration(parent_package='', top_path=None): - from numpy.distutils.misc_util import Configuration - config = Configuration('control', parent_package, top_path) - config.add_subpackage('tests') - return config diff --git a/control/tests/rlocus_test.py b/control/tests/rlocus_test.py index f7aff9ebe..ef9bd7ecb 100644 --- a/control/tests/rlocus_test.py +++ b/control/tests/rlocus_test.py @@ -15,16 +15,25 @@ from control.bdalg import feedback +@pytest.mark.usefixtures("mplcleanup") class TestRootLocus: """These are tests for the feedback function in rlocus.py.""" - @pytest.fixture(params=[(TransferFunction, ([1, 2], [1, 2, 3])), - (StateSpace, ([[1., 4.], [3., 2.]], - [[1.], [-4.]], - [[1., 0.]], [[0.]]))], - ids=["tf", "ss"]) + @pytest.fixture(params=[pytest.param((sysclass, sargs + (dt, )), + id=f"{systypename}-{dtstring}") + for sysclass, systypename, sargs in [ + (TransferFunction, 'TF', ([1, 2], + [1, 2, 3])), + (StateSpace, 'SS', ([[1., 4.], [3., 2.]], + [[1.], [-4.]], + [[1., 0.]], + [[0.]])), + ] + for dt, dtstring in [(0, 'ctime'), + (True, 'dtime')] + ]) def sys(self, request): - """Return some simple LTI system for testing""" + """Return some simple LTI systems for testing""" # avoid construction during collection time: prevent unfiltered # deprecation warning sysfn, args = request.param @@ -37,7 +46,7 @@ def check_cl_poles(self, sys, pole_list, k_list): np.testing.assert_array_almost_equal(poles, poles_expected) def testRootLocus(self, sys): - """Basic root locus plot""" + """Basic root locus (no plot)""" klist = [-1, 0, 1] roots, k_out = root_locus(sys, klist, plot=False) @@ -49,6 +58,33 @@ def test_without_gains(self, sys): roots, kvect = root_locus(sys, plot=False) self.check_cl_poles(sys, roots, kvect) + @pytest.mark.parametrize('grid', [None, True, False]) + def test_root_locus_plot_grid(self, sys, grid): + rlist, klist = root_locus(sys, grid=grid) + ax = plt.gca() + n_gridlines = sum([int(line.get_linestyle() in [':', 'dotted', + '--', 'dashed']) + for line in ax.lines]) + if grid is False: + assert n_gridlines == 2 + else: + assert n_gridlines > 2 + # TODO check validity of grid + + def test_root_locus_warnings(self): + sys = TransferFunction([1000], [1, 25, 100, 0]) + with pytest.warns(FutureWarning, match="Plot.*deprecated"): + rlist, klist = root_locus(sys, Plot=True) + with pytest.warns(FutureWarning, match="PrintGain.*deprecated"): + rlist, klist = root_locus(sys, PrintGain=True) + + def test_root_locus_neg_false_gain_nonproper(self): + """ Non proper TranferFunction with negative gain: Not implemented""" + with pytest.raises(ValueError, match="with equal order"): + root_locus(TransferFunction([-1, 2], [1, 2])) + + # TODO: cover and validate negative false_gain branch in _default_gains() + def test_root_locus_zoom(self): """Check the zooming functionality of the Root locus plot""" system = TransferFunction([1000], [1, 25, 100, 0]) @@ -96,4 +132,3 @@ def test_rlocus_default_wn(self): [-1e-2, 1-1e7j, 1+1e7j], [0, -1e7j, 1e7j], 1)) ct.root_locus(sys) - diff --git a/control/tests/sisotool_test.py b/control/tests/sisotool_test.py index 14e9692c1..ab5d546dd 100644 --- a/control/tests/sisotool_test.py +++ b/control/tests/sisotool_test.py @@ -17,14 +17,10 @@ class TestSisotool: """These are tests for the sisotool in sisotool.py.""" @pytest.fixture - def sys(self): + def tsys(self, request): """Return a generic SISO transfer function""" - return TransferFunction([1000], [1, 25, 100, 0]) - - @pytest.fixture - def sysdt(self): - """Return a generic SISO transfer function""" - return TransferFunction([1000], [1, 25, 100, 0], True) + dt = getattr(request, 'param', 0) + return TransferFunction([1000], [1, 25, 100, 0], dt) @pytest.fixture def sys222(self): @@ -50,8 +46,8 @@ def sys221(self): D221 = [[1., -1.]] return StateSpace(A222, B222, C221, D221) - def test_sisotool(self, sys): - sisotool(sys, Hz=False) + def test_sisotool(self, tsys): + sisotool(tsys, Hz=False) fig = plt.gcf() ax_mag, ax_rlocus, ax_phase, ax_step = fig.axes[:4] @@ -89,7 +85,7 @@ def test_sisotool(self, sys): event = type('test', (object,), {'xdata': 2.31206868287, 'ydata': 15.5983051046, 'inaxes': ax_rlocus.axes})() - _RLClickDispatcher(event=event, sys=sys, fig=fig, + _RLClickDispatcher(event=event, sys=tsys, fig=fig, ax_rlocus=ax_rlocus, sisotool=True, plotstr='-', bode_plot_params=bode_plot_params, tvect=None) @@ -118,10 +114,12 @@ def test_sisotool(self, sys): assert_array_almost_equal( ax_step.lines[0].get_data()[1][:10], step_response_moved, 4) - def test_sisotool_tvect(self, sys): + @pytest.mark.parametrize('tsys', [0, True], + indirect=True, ids=['ctime', 'dtime']) + def test_sisotool_tvect(self, tsys): # test supply tvect tvect = np.linspace(0, 1, 10) - sisotool(sys, tvect=tvect) + sisotool(tsys, tvect=tvect) fig = plt.gcf() ax_rlocus, ax_step = fig.axes[1], fig.axes[3] @@ -129,26 +127,11 @@ def test_sisotool_tvect(self, sys): event = type('test', (object,), {'xdata': 2.31206868287, 'ydata': 15.5983051046, 'inaxes': ax_rlocus.axes})() - _RLClickDispatcher(event=event, sys=sys, fig=fig, + _RLClickDispatcher(event=event, sys=tsys, fig=fig, ax_rlocus=ax_rlocus, sisotool=True, plotstr='-', bode_plot_params=dict(), tvect=tvect) assert_array_almost_equal(tvect, ax_step.lines[0].get_data()[0]) - def test_sisotool_tvect_dt(self, sysdt): - # test supply tvect - tvect = np.linspace(0, 1, 10) - sisotool(sysdt, tvect=tvect) - fig = plt.gcf() - ax_rlocus, ax_step = fig.axes[1], fig.axes[3] - - # Move the rootlocus to another point and confirm same tvect - event = type('test', (object,), {'xdata': 2.31206868287, - 'ydata': 15.5983051046, - 'inaxes': ax_rlocus.axes})() - _RLClickDispatcher(event=event, sys=sysdt, fig=fig, - ax_rlocus=ax_rlocus, sisotool=True, plotstr='-', - bode_plot_params=dict(), tvect=tvect) - assert_array_almost_equal(tvect, ax_step.lines[0].get_data()[0]) def test_sisotool_mimo(self, sys222, sys221): # a 2x2 should not raise an error: diff --git a/setup.cfg b/setup.cfg index c72ef19a8..5b1ce28a7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,4 +5,3 @@ universal=1 addopts = -ra filterwarnings = error:.*matrix subclass:PendingDeprecationWarning - pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy