Skip to content

Commit 08e55b1

Browse files
committed
add backward compatibility for matlab.{rlocus,pzmap} + suppress warnings
1 parent 0137056 commit 08e55b1

5 files changed

Lines changed: 110 additions & 5 deletions

File tree

control/matlab/wrappers.py

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
from ..lti import LTI
1313
from ..exception import ControlArgument
1414

15-
__all__ = ['bode', 'nyquist', 'ngrid', 'dcgain', 'connect']
15+
__all__ = ['bode', 'nyquist', 'ngrid', 'rlocus', 'pzmap', 'dcgain', 'connect']
1616

1717
def bode(*args, **kwargs):
1818
"""bode(syslist[, omega, dB, Hz, deg, ...])
1919
2020
Bode plot of the frequency response.
2121
22-
Plots a bode gain and phase diagram
22+
Plots a bode gain and phase diagram.
2323
2424
Parameters
2525
----------
@@ -195,6 +195,104 @@ def _parse_freqplot_args(*args):
195195
return syslist, omega, plotstyle, other
196196

197197

198+
def rlocus(*args, **kwargs):
199+
"""rlocus(sys[, klist, xlim, ylim, ...])
200+
201+
Root locus diagram.
202+
203+
Calculate the root locus by finding the roots of 1 + k * G(s) where G
204+
is a linear system with transfer function num(s)/den(s) and each k is
205+
an element of kvect.
206+
207+
Parameters
208+
----------
209+
sys : LTI object
210+
Linear input/output systems (SISO only, for now).
211+
kvect : array_like, optional
212+
Gains to use in computing plot of closed-loop poles.
213+
xlim : tuple or list, optional
214+
Set limits of x axis, normally with tuple
215+
(see :doc:`matplotlib:api/axes_api`).
216+
ylim : tuple or list, optional
217+
Set limits of y axis, normally with tuple
218+
(see :doc:`matplotlib:api/axes_api`).
219+
220+
Returns
221+
-------
222+
roots : ndarray
223+
Closed-loop root locations, arranged in which each row corresponds
224+
to a gain in gains.
225+
gains : ndarray
226+
Gains used. Same as kvect keyword argument if provided.
227+
228+
Notes
229+
-----
230+
This function is a wrapper for :func:`~control.root_locus_plot`,
231+
with legacy return arguments.
232+
233+
"""
234+
from ..rlocus import root_locus_plot
235+
236+
# Use the plot keyword to get legacy behavior
237+
kwargs = dict(kwargs) # make a copy since we modify this
238+
if 'plot' not in kwargs:
239+
kwargs['plot'] = True
240+
241+
# Turn off deprecation warning
242+
with warnings.catch_warnings():
243+
warnings.filterwarnings(
244+
'ignore', message='.* return values of .* is deprecated',
245+
category=DeprecationWarning)
246+
retval = root_locus_plot(*args, **kwargs)
247+
248+
return retval
249+
250+
251+
def pzmap(*args, **kwargs):
252+
"""pzmap(sys[, grid, plot])
253+
254+
Plot a pole/zero map for a linear system.
255+
256+
Parameters
257+
----------
258+
sys: LTI (StateSpace or TransferFunction)
259+
Linear system for which poles and zeros are computed.
260+
plot: bool, optional
261+
If ``True`` a graph is generated with Matplotlib,
262+
otherwise the poles and zeros are only computed and returned.
263+
grid: boolean (default = False)
264+
If True plot omega-damping grid.
265+
266+
Returns
267+
-------
268+
poles: array
269+
The system's poles.
270+
zeros: array
271+
The system's zeros.
272+
273+
Notes
274+
-----
275+
This function is a wrapper for :func:`~control.pole_zero_plot`,
276+
with legacy return arguments.
277+
278+
"""
279+
from ..pzmap import pole_zero_plot
280+
281+
# Use the plot keyword to get legacy behavior
282+
kwargs = dict(kwargs) # make a copy since we modify this
283+
if 'plot' not in kwargs:
284+
kwargs['plot'] = True
285+
286+
# Turn off deprecation warning
287+
with warnings.catch_warnings():
288+
warnings.filterwarnings(
289+
'ignore', message='.* return values of .* is deprecated',
290+
category=DeprecationWarning)
291+
retval = pole_zero_plot(*args, **kwargs)
292+
293+
return retval
294+
295+
198296
from ..nichols import nichols_grid
199297
def ngrid():
200298
return nichols_grid()
@@ -254,6 +352,7 @@ def dcgain(*args):
254352

255353
from ..bdalg import connect as ct_connect
256354
def connect(*args):
355+
257356
"""Index-based interconnection of an LTI system.
258357
259358
The system `sys` is a system typically constructed with `append`, with

control/rlocus.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def root_locus_plot(
112112
-------
113113
roots : ndarray
114114
Closed-loop root locations, arranged in which each row corresponds
115-
to a gain in gains
115+
to a gain in gains.
116116
gains : ndarray
117117
Gains used. Same as kvect keyword argument if provided.
118118
@@ -140,7 +140,7 @@ def root_locus_plot(
140140
#
141141
if plot is not None:
142142
warnings.warn(
143-
"`root_locus` return values of loci, gains is deprecated; "
143+
"`root_locus` return values of roots, gains is deprecated; "
144144
"use root_locus_map()", DeprecationWarning)
145145

146146
if plot is False:

control/tests/matlab_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,8 @@ def testBode(self, siso, mplcleanup):
424424
@pytest.mark.parametrize("subsys", ["ss1", "tf1", "tf2"])
425425
def testRlocus(self, siso, subsys, mplcleanup):
426426
"""Call rlocus()"""
427-
rlocus(getattr(siso, subsys))
427+
rlist, klist = rlocus(getattr(siso, subsys))
428+
np.testing.assert_equal(len(rlist), len(klist))
428429

429430
def testRlocus_list(self, siso, mplcleanup):
430431
"""Test rlocus() with list"""

control/tests/pzmap_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from control import TransferFunction, config, pzmap
1616

1717

18+
@pytest.mark.filterwarnings("ignore:.*return values.*:DeprecationWarning")
1819
@pytest.mark.parametrize("kwargs",
1920
[pytest.param(dict(), id="default"),
2021
pytest.param(dict(plot=False), id="plot=False"),

control/tests/rlocus_test.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def check_cl_poles(self, sys, pole_list, k_list):
4545
poles = np.sort(poles)
4646
np.testing.assert_array_almost_equal(poles, poles_expected)
4747

48+
@pytest.mark.filterwarnings("ignore:.*return values.*:DeprecationWarning")
4849
def testRootLocus(self, sys):
4950
"""Basic root locus (no plot)"""
5051
klist = [-1, 0, 1]
@@ -60,6 +61,7 @@ def testRootLocus(self, sys):
6061
np.testing.assert_allclose(klist, k_out)
6162
self.check_cl_poles(sys, roots, klist)
6263

64+
@pytest.mark.filterwarnings("ignore:.*return values.*:DeprecationWarning")
6365
def test_without_gains(self, sys):
6466
roots, kvect = root_locus(sys, plot=False)
6567
self.check_cl_poles(sys, roots, kvect)
@@ -79,6 +81,7 @@ def test_root_locus_plot_grid(self, sys, grid):
7981
assert n_gridlines > 2
8082
# TODO check validity of grid
8183

84+
@pytest.mark.filterwarnings("ignore:.*return values.*:DeprecationWarning")
8285
def test_root_locus_neg_false_gain_nonproper(self):
8386
""" Non proper TranferFunction with negative gain: Not implemented"""
8487
with pytest.raises(ValueError, match="with equal order"):
@@ -116,6 +119,7 @@ def test_root_locus_zoom(self):
116119
assert_array_almost_equal(zoom_x, zoom_x_valid)
117120
assert_array_almost_equal(zoom_y, zoom_y_valid)
118121

122+
@pytest.mark.filterwarnings("ignore:.*return values.*:DeprecationWarning")
119123
@pytest.mark.timeout(2)
120124
def test_rlocus_default_wn(self):
121125
"""Check that default wn calculation works properly"""

0 commit comments

Comments
 (0)