From 0cafd688960765cde0dc3d16b20d1e475005c0bb Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Sun, 31 Mar 2024 09:00:49 -0700 Subject: [PATCH] fix unit tests that generate multiple warnings --- control/tests/freqresp_test.py | 36 +++++++++++++++++++++++++--------- control/tests/nyquist_test.py | 29 +++++++++++++++++++-------- control/tests/xferfcn_test.py | 20 ++++++++++++------- 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/control/tests/freqresp_test.py b/control/tests/freqresp_test.py index dd236769a..18c59384d 100644 --- a/control/tests/freqresp_test.py +++ b/control/tests/freqresp_test.py @@ -6,19 +6,21 @@ including bode plots. """ +import math +import re + import matplotlib.pyplot as plt import numpy as np -from numpy.testing import assert_allclose -import math import pytest +from numpy.testing import assert_allclose import control as ctrl +from control.freqplot import (bode_plot, nyquist_plot, nyquist_response, + singular_values_plot, singular_values_response) +from control.matlab import bode, rss, ss, tf from control.statesp import StateSpace -from control.xferfcn import TransferFunction -from control.matlab import ss, tf, bode, rss -from control.freqplot import bode_plot, nyquist_plot, nyquist_response, \ - singular_values_plot, singular_values_response from control.tests.conftest import slycotonly +from control.xferfcn import TransferFunction pytestmark = pytest.mark.usefixtures("mplcleanup") @@ -101,12 +103,17 @@ def test_nyquist_basic(ss_siso): response = nyquist_response(tf_siso, omega_num=20) assert len(response.contour) == 20 - with pytest.warns(UserWarning, match="encirclements was a non-integer"): + with pytest.warns() as record: count, contour = nyquist_plot( tf_siso, plot=False, omega_limits=(1, 100), return_contour=True) assert_allclose(contour[0], 1j) assert_allclose(contour[-1], 100j) + # Check known warnings happened as expected + assert len(record) == 2 + assert re.search("encirclements was a non-integer", str(record[0].message)) + assert re.search("return values .* deprecated", str(record[1].message)) + response = nyquist_response(tf_siso, omega=np.logspace(-1, 1, 10)) assert len(response.contour) == 10 @@ -428,14 +435,25 @@ def test_freqresp_warn_infinite(): np.testing.assert_almost_equal(sys_finite(0, warn_infinite=True), 100) # Transfer function with infinite zero frequency gain - with pytest.warns(RuntimeWarning, match="divide by zero"): + with pytest.warns() as record: np.testing.assert_almost_equal( sys_infinite(0), complex(np.inf, np.nan)) - with pytest.warns(RuntimeWarning, match="divide by zero"): + assert len(record) == 2 # generates two RuntimeWarnings + assert record[0].category is RuntimeWarning + assert re.search("divide by zero", str(record[0].message)) + assert record[1].category is RuntimeWarning + assert re.search("invalid value", str(record[1].message)) + + with pytest.warns() as record: np.testing.assert_almost_equal( sys_infinite(0, warn_infinite=True), complex(np.inf, np.nan)) np.testing.assert_almost_equal( sys_infinite(0, warn_infinite=False), complex(np.inf, np.nan)) + assert len(record) == 2 # generates two RuntimeWarnings + assert record[0].category is RuntimeWarning + assert re.search("divide by zero", str(record[0].message)) + assert record[1].category is RuntimeWarning + assert re.search("invalid value", str(record[1].message)) # Switch to state space sys_finite = ctrl.tf2ss(sys_finite) diff --git a/control/tests/nyquist_test.py b/control/tests/nyquist_test.py index 1100eb01e..a687ee61b 100644 --- a/control/tests/nyquist_test.py +++ b/control/tests/nyquist_test.py @@ -8,11 +8,13 @@ """ +import re import warnings -import pytest -import numpy as np import matplotlib.pyplot as plt +import numpy as np +import pytest + import control as ct pytestmark = pytest.mark.usefixtures("mplcleanup") @@ -66,9 +68,12 @@ def test_nyquist_basic(): assert _Z(sys) == N_sys + _P(sys) # With a larger indent_radius, we get a warning message + wrong answer - with pytest.warns(UserWarning, match="contour may miss closed loop pole"): + with pytest.warns() as rec: N_sys = ct.nyquist_response(sys, indent_radius=0.2) assert _Z(sys) != N_sys + _P(sys) + assert len(rec) == 2 + assert re.search("contour may miss closed loop pole", str(rec[0].message)) + assert re.search("encirclements does not match", str(rec[1].message)) # Unstable system sys = ct.tf([10], [1, 2, 2, 1]) @@ -104,11 +109,15 @@ def test_nyquist_basic(): sys, np.linspace(1e-4, 1e2, 100), indent_radius=1e-2, return_contour=True) assert not all(contour_indented.real == 0) - with pytest.warns(UserWarning, match="encirclements does not match"): + + with pytest.warns() as record: count, contour = ct.nyquist_response( sys, np.linspace(1e-4, 1e2, 100), indent_radius=1e-2, return_contour=True, indent_direction='none') np.testing.assert_almost_equal(contour, 1j*np.linspace(1e-4, 1e2, 100)) + assert len(record) == 2 + assert re.search("encirclements .* non-integer", str(record[0].message)) + assert re.search("encirclements does not match", str(record[1].message)) # Nyquist plot with poles at the origin, omega unspecified sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0]) @@ -264,7 +273,7 @@ def test_nyquist_indent_default(indentsys): def test_nyquist_indent_dont(indentsys): # first value of default omega vector was 0.1, replaced by 0. for contour # indent_radius is larger than 0.1 -> no extra quater circle around origin - with pytest.warns(UserWarning, match="encirclements does not match"): + with pytest.warns() as record: count, contour = ct.nyquist_response( indentsys, omega=[0, 0.2, 0.3, 0.4], indent_radius=.1007, plot=False, return_contour=True) @@ -272,6 +281,11 @@ def test_nyquist_indent_dont(indentsys): # second value of omega_vector is larger than indent_radius: not indented assert np.all(contour.real[2:] == 0.) + # Make sure warnings are as expected + assert len(record) == 2 + assert re.search("encirclements .* non-integer", str(record[0].message)) + assert re.search("encirclements does not match", str(record[1].message)) + def test_nyquist_indent_do(indentsys): plt.figure(); @@ -352,9 +366,8 @@ def test_nyquist_exceptions(): ct.nyquist_plot(sys, indent_direction='up') # Discrete time system sampled above Nyquist frequency - sys = ct.drss(2, 1, 1) - sys.dt = 0.01 - with pytest.warns(UserWarning, match="above Nyquist"): + sys = ct.ss([[-0.5, 0], [1, 0.5]], [[0], [1]], [[1, 0]], 0, 0.1) + with pytest.warns(UserWarning, match="evaluation above Nyquist"): ct.nyquist_plot(sys, np.logspace(-2, 3)) diff --git a/control/tests/xferfcn_test.py b/control/tests/xferfcn_test.py index 5fa9b3769..cb5b38cba 100644 --- a/control/tests/xferfcn_test.py +++ b/control/tests/xferfcn_test.py @@ -3,18 +3,19 @@ RMM, 30 Mar 2011 (based on TestXferFcn from v0.4a) """ +import operator +import re + import numpy as np import pytest -import operator import control as ct -from control import StateSpace, TransferFunction, rss, evalfr -from control import ss, ss2tf, tf, tf2ss, zpk -from control import isctime, isdtime, sample_system -from control import defaults, reset_defaults, set_defaults +from control import (StateSpace, TransferFunction, defaults, evalfr, isctime, + isdtime, reset_defaults, rss, sample_system, set_defaults, + ss, ss2tf, tf, tf2ss, zpk) from control.statesp import _convert_to_statespace -from control.xferfcn import _convert_to_transfer_function from control.tests.conftest import slycotonly +from control.xferfcn import _convert_to_transfer_function class TestXferFcn: @@ -836,9 +837,14 @@ def test_dcgain_discr(self): # differencer, with warning sys = TransferFunction(1, [1, -1], True) - with pytest.warns(RuntimeWarning, match="divide by zero"): + with pytest.warns() as record: np.testing.assert_equal( sys.dcgain(warn_infinite=True), np.inf) + assert len(record) == 2 # generates two RuntimeWarnings + assert record[0].category is RuntimeWarning + assert re.search("divide by zero", str(record[0].message)) + assert record[1].category is RuntimeWarning + assert re.search("invalid value", str(record[1].message)) # summer sys = TransferFunction([1, -1], [1], True) 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