Skip to content

Fix unit tests that generate multiple warnings #986

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 1 commit into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions control/tests/freqresp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
29 changes: 21 additions & 8 deletions control/tests/nyquist_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -264,14 +273,19 @@ 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)
np.testing.assert_allclose(contour[0], .1007+0.j)
# 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();
Expand Down Expand Up @@ -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))


Expand Down
20 changes: 13 additions & 7 deletions control/tests/xferfcn_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
Loading