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

Skip to content

Commit a9ac490

Browse files
committed
increase coverage; PEP8 cleanup
1 parent 2bc990c commit a9ac490

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'.
@@ -572,9 +573,6 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
572573
return_contour : bool, optional
573574
If 'True', return the contour used to evaluate the Nyquist plot.
574575
575-
*args : :func:`matplotlib.pyplot.plot` positional properties, optional
576-
Additional arguments for `matplotlib` plots (color, linestyle, etc)
577-
578576
**kwargs : :func:`matplotlib.pyplot.plot` keyword properties, optional
579577
Additional keywords (passed to `matplotlib`)
580578
@@ -585,15 +583,12 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
585583
multiple systems are given, an array of counts is returned.
586584
587585
contour : ndarray (or list of ndarray if len(syslist) > 1)), optional
588-
The contour used to create the primary Nyquist curve segment. To
589-
obtain the Nyquist curve values, evaluate system(s) along contour.
586+
The contour used to create the primary Nyquist curve segment, returned
587+
if `return_contour` is Tue. To obtain the Nyquist curve values,
588+
evaluate system(s) along contour.
590589
591590
Additional Parameters
592591
---------------------
593-
label_freq : int, optiona
594-
Label every nth frequency on the plot. If not specified, no labels
595-
are generated.
596-
597592
arrows : int or 1D/2D array of floats, optional
598593
Specify the number of arrows to plot on the Nyquist curve. If an
599594
integer is passed. that number of equally spaced arrows will be
@@ -629,6 +624,10 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
629624
imaginary axis. Portions of the Nyquist plot corresponding to indented
630625
portions of the contour are plotted using a different line style.
631626
627+
label_freq : int, optiona
628+
Label every nth frequency on the plot. If not specified, no labels
629+
are generated.
630+
632631
max_curve_magnitude : float, optional
633632
Restrict the maximum magnitude of the Nyquist plot to this value.
634633
Portions of the Nyquist plot whose magnitude is restricted are
@@ -665,6 +664,10 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
665664
warn_nyquist : bool, optional
666665
If set to 'False', turn off warnings about frequencies above Nyquist.
667666
667+
warn_encirclements : bool, optional
668+
If set to 'False', turn off warnings about number of encirclements not
669+
meeting the Nyquist criterion.
670+
668671
Notes
669672
-----
670673
1. If a discrete time model is given, the frequency response is computed
@@ -884,22 +887,22 @@ def _parse_linestyle(style_name, allow_false=False):
884887
# See if we need to indent around it
885888
if abs(s - p) < indent_radius:
886889
# Figure out how much to offset (simple trigonometry)
887-
offset = np.sqrt(indent_radius ** 2 - (s-p).imag ** 2) \
888-
-(s-p).real
890+
offset = np.sqrt(indent_radius ** 2 - (s - p).imag ** 2) \
891+
- (s - p).real
889892

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

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

901904
else:
902-
ValueError("unknown value for indent_direction")
905+
raise ValueError("unknown value for indent_direction")
903906

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

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

@@ -1149,6 +1153,7 @@ def _add_arrows_to_line2D(
11491153
arrows.append(p)
11501154
return arrows
11511155

1156+
11521157
#
11531158
# Function to compute Nyquist curve offsets
11541159
#
@@ -1171,13 +1176,13 @@ def _compute_curve_offset(resp, mask, max_offset):
11711176
while i < resp.size and mask[i]:
11721177
i += 1 # Increment the counter
11731178
if i == resp.size:
1174-
break;
1179+
break
11751180
# Keep track of the arclength
11761181
arclen[i] = arclen[i-1] + np.abs(resp[i] - resp[i-1])
11771182

11781183
nsegs += 0.5
11791184
if i == resp.size:
1180-
break;
1185+
break
11811186

11821187
# Save the starting offset of this segment
11831188
seg_start = i
@@ -1186,13 +1191,13 @@ def _compute_curve_offset(resp, mask, max_offset):
11861191
while i < resp.size and not mask[i]:
11871192
i += 1
11881193
if i == resp.size: # See if we are done with this segment
1189-
break;
1194+
break
11901195
# Keep track of the arclength
11911196
arclen[i] = arclen[i-1] + np.abs(resp[i] - resp[i-1])
11921197

11931198
nsegs += 0.5
11941199
if i == resp.size:
1195-
break;
1200+
break
11961201

11971202
# Save the ending offset of this segment
11981203
seg_end = i
@@ -1332,7 +1337,8 @@ def singular_values_plot(syslist, omega=None,
13321337
*args, **kwargs):
13331338
"""Singular value plot for a system
13341339
1335-
Plots a Singular Value plot for the system over a (optional) frequency range.
1340+
Plots a singular value plot for the system over a (optional) frequency
1341+
range.
13361342
13371343
Parameters
13381344
----------
@@ -1346,11 +1352,11 @@ def singular_values_plot(syslist, omega=None,
13461352
Limits of the frequency vector to generate.
13471353
If Hz=True the limits are in Hz otherwise in rad/s.
13481354
omega_num : int
1349-
Number of samples to plot.
1350-
Default value (1000) set by config.defaults['freqplot.number_of_samples'].
1355+
Number of samples to plot. Default value (1000) set by
1356+
config.defaults['freqplot.number_of_samples'].
13511357
dB : bool
1352-
If True, plot result in dB.
1353-
Default value (False) set by config.defaults['freqplot.dB'].
1358+
If True, plot result in dB. Default value (False) set by
1359+
config.defaults['freqplot.dB'].
13541360
Hz : bool
13551361
If True, plot frequency in Hz (omega must be provided in rad/sec).
13561362
Default value (False) set by config.defaults['freqplot.Hz']
@@ -1372,7 +1378,8 @@ def singular_values_plot(syslist, omega=None,
13721378
--------
13731379
>>> import numpy as np
13741380
>>> den = [75, 1]
1375-
>>> sys = TransferFunction([[[87.8], [-86.4]], [[108.2], [-109.6]]], [[den, den], [den, den]])
1381+
>>> sys = TransferFunction(
1382+
[[[87.8], [-86.4]], [[108.2], [-109.6]]], [[den, den], [den, den]])
13761383
>>> omega = np.logspace(-4, 1, 1000)
13771384
>>> sigma, omega = singular_values_plot(sys, plot=True)
13781385
>>> singular_values_plot(sys, 0.0, plot=False)
@@ -1479,7 +1486,8 @@ def singular_values_plot(syslist, omega=None,
14791486
# Add a grid to the plot + labeling
14801487
if plot:
14811488
ax_sigma.grid(grid, which='both')
1482-
ax_sigma.set_ylabel("Singular Values (dB)" if dB else "Singular Values")
1489+
ax_sigma.set_ylabel(
1490+
"Singular Values (dB)" if dB else "Singular Values")
14831491
ax_sigma.set_xlabel("Frequency (Hz)" if Hz else "Frequency (rad/sec)")
14841492

14851493
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