10000 increase coverage; PEP8 cleanup · python-control/python-control@9a5759f · GitHub
[go: up one dir, main page]

Skip to content

Commit 9a5759f

Browse files
committed
increase coverage; PEP8 cleanup
1 parent 67c1f3f commit 9a5759f

File tree

2 files changed

+60
-37
lines changed

2 files changed

+60
-37
lines changed

control/freqplot.py

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,13 @@ def bode_plot(syslist, omega=None,
149149
the `deg` parameter. Default is -180 if wrap_phase is False, 0 if
150150
wrap_phase is True.
151151
wrap_phase : bool or float
152-
If wrap_phase is `False`, then the phase will be unwrapped so that it
153-
is continuously increasing or decreasing. If wrap_phase is `True` the
154-
phase will be restricted to the range [-180, 180) (or [:math:`-\\pi`,
155-
:math:`\\pi`) radians). If `wrap_phase` is specified as a float, the
156-
phase will be offset by 360 degrees if it falls below the specified
157-
value. Default to `False`, set by config.defaults['freqplot.wrap_phase'].
152+
If wrap_phase is `False` (default), then the phase will be unwrapped
153+
so that it is continuously increasing or decreasing. If wrap_phase is
154+
`True` the phase will be restricted to the range [-180, 180) (or
155+
[:math:`-\\pi`, :math:`\\pi`) radians). If `wrap_phase` is specified
156+
as a float, the phase will be offset by 360 degrees if it falls below
157+
the specified value. Default value is `False` and can be set using
158+
config.defaults['freqplot.wrap_phase'].
158159
159160
The default values for Bode plot configuration parameters can be reset
160161
using the `config.defaults` dictionary, with module name 'bode'.
@@ -573,9 +574,6 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
573574
return_contour : bool, optional
574575
If 'True', return the contour used to evaluate the Nyquist plot.
575576
576-
*args : :func:`matplotlib.pyplot.plot` positional properties, optional
577-
Additional arguments for `matplotlib` plots (color, linestyle, etc)
578-
579577
**kwargs : :func:`matplotlib.pyplot.plot` keyword properties, optional
580578
Addition 8000 al keywords (passed to `matplotlib`)
581579
@@ -586,15 +584,12 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
586584
multiple systems are given, an array of counts is returned.
587585
588586
contour : ndarray (or list of ndarray if len(syslist) > 1)), optional
589-
The contour used to create the primary Nyquist curve segment. To
590-
obtain the Nyquist curve values, evaluate system(s) along contour.
587+
The contour used to create the primary Nyquist curve segment, returned
588+
if `return_contour` is Tue. To obtain the Nyquist curve values,
589+
evaluate system(s) along contour.
591590
592591
Additional Parameters
593592
---------------------
594-
label_freq : int, optiona
595-
Label every nth frequency on the plot. If not specified, no labels
596-
are generated.
597-
598593
arrows : int or 1D/2D array of floats, optional
599594
Specify the number of arrows to plot on the Nyquist curve. If an
600595
integer is passed. that number of equally spaced arrows will be
@@ -630,6 +625,10 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
630625
imaginary axis. Portions of the Nyquist plot corresponding to indented
631626
portions of the contour are plotted using a different line style.
632627
628+
label_freq : int, optiona
629+
Label every nth frequency on the plot. If not specified, no labels
630+
are generated.
631+
633632
max_curve_magnitude : float, optional
634633
Restrict the maximum magnitude of the Nyquist plot to this value.
635634
Portions of the Nyquist plot whose magnitude is restricted are
@@ -666,6 +665,10 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
666665
warn_nyquist : bool, optional
667666
If set to 'False', turn off warnings about frequencies above Nyquist.
668667
668+
warn_encirclements : bool, optional
669+
If set to 'False', turn off warnings about number of encirclements not
670+
meeting the Nyquist criterion.
671+
669672
Notes
670673
-----
671674
1. If a discrete time model is given, the frequency response is computed
@@ -885,22 +888,22 @@ def _parse_linestyle(style_name, allow_false=False):
885888
# See if we need to indent around it
886889
if abs(s - p) < indent_radius:
887890
# Figure out how much to offset (simple trigonometry)
888-
offset = np.sqrt(indent_radius ** 2 - (s-p).imag ** 2) \
889-
-(s-p).real
891+
offset = np.sqrt(indent_radius ** 2 - (s - p).imag ** 2) \
892+
- (s - p).real
890893

891894
# Figure out which way to offset the contour point
892-
if p.real < 0 or (np.isclose(p.real, 0) \
893-
and indent_direction == 'right'):
895+
if p.real < 0 or (np.isclose(p.real, 0)
896+
and indent_direction == 'right'):
894897
# Indent to the right
895898
splane_contour[i] += offset
896899

897-
elif p.real > 0 or (np.isclose(p.real, 0) \
898-
and indent_direction == 'left'):
900+
elif p.real > 0 or (np.isclose(p.real, 0)
901+
and indent_direction == 'left'):
899902
# Indent to the left
900903
splane_contour[i] -= offset
901904

902905
else:
903-
ValueError("unknown value for indent_direction")
906+
raise ValueError("unknown value for indent_direction")
904907

905908
# change contour to z-plane if necessary
906909
if sys.isctime():
@@ -939,7 +942,8 @@ def _parse_linestyle(style_name, allow_false=False):
939942
"number of encirclements does not match Nyquist criterion;"
940943
" check frequency range and indent radius/direction",
941944
UserWarning, stacklevel=2)
942-
elif indent_direction == 'none' and any(sys.pole().real == 0):
945+
elif indent_direction == 'none' and \
946+
any(np.isclose(sys.pole().real, 0)):
943947
warnings.warn(
944948
"system has pure imaginary poles but indentation is"
945949
" turned off; results may be meaningless",
@@ -950,14 +954,14 @@ def _parse_linestyle(style_name, allow_false=False):
950954

951955
if plot:
952956
# Parse the arrows keyword
953-
if isinstance(arrows, int):
957+
if not arrows:
958+
arrow_pos = []
959+
elif isinstance(arrows, int):
954960
N = arrows
955961
# Space arrows out, starting midway along each "region"
956962
arrow_pos = np.linspace(0.5/N, 1 + 0.5/N, N, endpoint=False)
957963
elif isinstance(arrows, (list, np.ndarray)):
958964
arrow_pos = np.sort(np.atleast_1d(arrows))
959-
elif not arrows:
960-
arrow_pos = []
961965
else:
962966
raise ValueError("unknown or unsupported arrow location")
963967

@@ -1150,6 +1154,7 @@ def _add_arrows_to_line2D(
11501154
arrows.append(p)
11511155
return arrows
11521156

1157+
11531158
#
11541159
# Function to compute Nyquist curve offsets
11551160
#
@@ -1172,13 +1177,13 @@ def _compute_curve_offset(resp, mask, max_offset):
11721177
while i < resp.size and mask[i]:
11731178
i += 1 # Increment the counter
11741179
if i == resp.size:
1175-
break;
1180+
break
11761181
# Keep track of the arclength
11771182
arclen[i] = arclen[i-1] + np.abs(resp[i] - resp[i-1])
11781183

11791184
nsegs += 0.5
11801185
if i == resp.size:
1181-
break;
1186+
break
11821187

11831188
# Save the starting offset of this segment
11841189
seg_start = i
@@ -1187,13 +1192,13 @@ def _compute_curve_offset(resp, mask, max_offset):
11871192
while i < resp.size and not mask[i]:
11881193
i += 1
11891194
if i == resp.size: # See if we are done with this segment
1190-
break;
1195+
break
11911196
# Keep track of the arclength
11921197
arclen[i] = arclen[i-1] + np.abs(resp[i] - resp[i-1])
11931198

11941199
nsegs += 0.5
11951200
if i == resp.size:
1196-
break;
1201+
break
11971202

11981203
# Save the ending offset of this segment
11991204
seg_end = i
@@ -1333,7 +1338,8 @@ def singular_values_plot(syslist, omega=None,
13331338
*args, **kwargs):
13341339
"""Singular value plot for a system
13351340
1336-
Plots a Singular Value plot for the system over a (optional) frequency range.
1341+
Plots a singular value plot for the system over a (optional) frequency
1342+
range.
13371343
13381344
Parameters
13391345
----------
@@ -1347,11 +1353,11 @@ def singular_values_plot(syslist, omega=None,
13471353
Limits of the frequency vector to generate.
13481354
If Hz=True the limits are in Hz otherwise in rad/s.
13491355
omega_num : int
1350-
Number of samples to plot.
1351-
Default value (1000) set by config.defaults['freqplot.number_of_samples'].
1356+
Number of samples to plot. Default value (1000) set by
1357+
config.defaults['freqplot.number_of_samples'].
13521358
dB : bool
1353-
If True, plot result in dB.
1354-
Default value (False) set by config.defaults['freqplot.dB'].
1359+
If True, plot result in dB. Default value (False) set by
1360+
config.defaults['freqplot.dB'].
13551361
Hz : bool
13561362
If True, plot frequency in Hz (omega must be provided in rad/sec).
13571363
Default value (False) set by config.defaults['freqplot.Hz']
@@ -1373,7 +1379,8 @@ def singular_values_plot(syslist, omega=None,
13731379
--------
13741380
>>> import numpy as np
13751381
>>> den = [75, 1]
1376-
>>> sys = TransferFunction([[[87.8], [-86.4]], [[108.2], [-109.6]]], [[den, den], [den, den]])
1382+
>>> sys = TransferFunction(
1383+
[[[87.8], [-86.4]], [[108.2], [-109.6]]], [[den, den], [den, den]])
13771384
>>> omega = np.logspace(-4, 1, 1000)
13781385
>>> sigma, omega = singular_values_plot(sys, plot=True)
13791386
>>> singular_values_plot(sys, 0.0, plot=False)
@@ -1480,7 +1487,8 @@ def singular_values_plot(syslist, omega=None,
14801487
# Add a grid to the plot + labeling
14811488
if plot:
14821489
ax_sigma.grid(grid, which='both')
1483-
ax_sigma.set_ylabel("Singular Values (dB)" if dB else "Singular Values")
1490+
ax_sigma.set_ylabel(
1491+
"Singular Values (dB)" if dB else "Singular Values")
14841492
ax_sigma.set_xlabel("Frequency (Hz)" if Hz else "Frequency (rad/sec)")
14851493

14861494
if len(syslist) == 1:

control/tests/nyquist_test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ def test_nyquist_fbs_examples():
185185

186186
@pytest.mark.parametrize("arrows", [
187187
None, # default argument
188+
False, # no arrows
188189
1, 2, 3, 4, # specified number of arrows
189190
[0.1, 0.5, 0.9], # specify arc lengths
190191
])
@@ -318,12 +319,22 @@ def test_nyquist_exceptions():
318319
with pytest.warns(FutureWarning, match="use `arrow_size` instead"):
319320
ct.nyquist_plot(sys, arrow_width=8, arrow_length=6)
320321

322+
# Unknown arrow keyword
323+
with pytest.raises(ValueError, match="unsupported arrow location"):
324+
ct.nyquist_plot(sys, arrows='uniform')
325+
326+
# Bad value for indent direction
327+
sys = ct.tf([1], [1, 0, 1])
328+
with pytest.raises(ValueError, match="unknown value for indent"):
329+
ct.nyquist_plot(sys, indent_direction='up')
330+
321331
# Discrete time system sampled above Nyquist frequency
322332
sys = ct.drss(2, 1, 1)
323333
sys.dt = 0.01
324334
with pytest.warns(UserWarning, match="above Nyquist"):
325335
ct.nyquist_plot(sys, np.logspace(-2, 3))
326336

337+
327338
def test_linestyle_checks():
328339
sys = ct.rss(2, 1, 1)
329340

@@ -337,6 +348,10 @@ def test_linestyle_checks():
337348
with pytest.raises(ValueError, match="invalid 'mirror_style'"):
338349
ct.nyquist_plot(sys, mirror_style=0.2)
339350

351+
# If only one line style is given use, the default value for the other
352+
# TODO: for now, just make sure the signature works; no correct check yet
353+
ct.nyquist_plot(sys, primary_style=':', mirror_style='-.')
354+
340355
@pytest.mark.usefixtures("editsdefaults")
341356
def test_nyquist_legacy():
342357
ct.use_legacy_defaults('0.9.1')

0 commit comments

Comments
 (0)
0