Skip to content

Commit 5e9b179

Browse files
committed
rename keyword to plot_maximum_magintude and option to turn it off by setting it to zero; docstring improvement; old indentation method still available if omega is explicitly specified
1 parent 23b3e8c commit 5e9b179

File tree

2 files changed

+50
-28
lines changed

2 files changed

+50
-28
lines changed

control/freqplot.py

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -523,22 +523,22 @@ def gen_zero_centered_series(val_min, val_max, period):
523523
'nyquist.arrows': 2,
524524
'nyquist.arrow_size': 8,
525525
'nyquist.indent_radius': 1e-6,
526-
'nyquist.maximum_magnitude': 5,
526+
'nyquist.plot_maximum_magnitude': 5,
527527
'nyquist.indent_direction': 'right',
528528
}
529529

530530

531531
def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
532532
omega_num=None, label_freq=0, color=None,
533-
return_contour=False, warn_nyquist=True,
533+
return_contour=False, warn_nyquist=True,
534534
*args, **kwargs):
535535
"""Nyquist plot for a system
536536
537537
Plots a Nyquist plot for the system over a (optional) frequency range.
538538
The curve is computed by evaluating the Nyqist segment along the positive
539539
imaginary axis, with a mirror image generated to reflect the negative
540540
imaginary axis. Poles on or near the imaginary axis are avoided using a
541-
small indentation. The portion of the Nyquist contour at infinity is not
541+
small indentation. If portions of the Nyquist plot The portion of the Nyquist contour at infinity is not
542542
explicitly computed (since it maps to a constant value for any system with
543543
a proper transfer function).
544544
@@ -596,9 +596,10 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
596596
arrow_style : matplotlib.patches.ArrowStyle
597597
Define style used for Nyquist curve arrows (overrides `arrow_size`).
598598
599-
maximum_magnitude : float
600-
Magnitude/radius at which to draw contours whose magnitude exceeds
601-
this value.
599+
plot_maximum_magnitude : float
600+
If this value is not 0, an additional curve showing the path of
601+
the Nyquist plot when it leaves the plot window is drawn at a radius
602+
equal to this value.
602603
603604
indent_radius : float
604605
Amount to indent the Nyquist contour around poles that are at or near
@@ -687,13 +688,14 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
687688
'nyquist', 'indent_radius', kwargs, _nyquist_defaults, pop=True)
688689
indent_direction = config._get_param(
689690
'nyquist', 'indent_direction', kwargs, _nyquist_defaults, pop=True)
690-
maximum_magnitude = config._get_param(
691-
'nyquist', 'maximum_magnitude', kwargs, _nyquist_defaults, pop=True)
691+
plot_maximum_magnitude = config._get_param(
692+
'nyquist', 'plot_maximum_magnitude', kwargs, _nyquist_defaults, pop=True)
692693

693694
# If argument was a singleton, turn it into a list
694695
if not hasattr(syslist, '__iter__'):
695696
syslist = (syslist,)
696697

698+
omega_given = True if omega is not None else False
697699
omega, omega_range_given = _determine_omega_vector(
698700
syslist, omega, omega_limits, omega_num)
699701
if not omega_range_given:
@@ -740,7 +742,7 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
740742
zplane_poles = zplane_poles[~np.isclose(abs(zplane_poles), 0.)]
741743
splane_poles = np.log(zplane_poles)/sys.dt
742744

743-
if omega_range_given:
745+
if omega_given:
744746
# indent given contour
745747
for i, s in enumerate(splane_contour):
746748
# Find the nearest pole
@@ -793,13 +795,14 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
793795
# Compute the primary curve
794796
resp = sys(contour)
795797

796-
# compute large radius contour where it exceeds
797-
# fill with nans that don't plot
798-
large_mag_contour = np.full_like(contour, np.nan + 1j * np.nan)
799-
# where too big, use angle of resp but specifified mag
800-
too_big = abs(resp) > maximum_magnitude
801-
large_mag_contour[too_big] = \
802-
maximum_magnitude *(1+isys/20) * np.exp(1j * np.angle(resp[too_big]))
798+
if plot_maximum_magnitude != 0:
799+
# compute large radius contour where it exceeds
800+
# fill with nans that don't plot
801+
large_mag_contour = np.full_like(contour, np.nan + 1j * np.nan)
802+
# where too big, use angle of resp but specifified mag
803+
too_big = abs(resp) > plot_maximum_magnitude
804+
large_mag_contour[too_big] = plot_maximum_magnitude *\
805+
(1+isys/20) * np.exp(1j * np.angle(resp[too_big]))
803806

804807
# Compute CW encirclements of -1 by integrating the (unwrapped) angle
805808
phase = -unwrap(np.angle(resp + 1))
@@ -828,28 +831,31 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
828831

829832
# Save the components of the response
830833
x, y = resp.real, resp.imag
831-
x_lg, y_lg = large_mag_contour.real, large_mag_contour.imag
834+
if plot_maximum_magnitude != 0:
835+
x_lg, y_lg = large_mag_contour.real, large_mag_contour.imag
832836

833837
# Plot the primary curve
834838
p = plt.plot(x, y, '-', color=color, *args, **kwargs)
835839
c = p[0].get_color()
836840
ax = plt.gca()
837841
_add_arrows_to_line2D(
838842
ax, p[0], arrow_pos, arrowstyle=arrow_style, dir=1)
839-
# plot large magnitude contour
840-
p = plt.plot(x_lg, y_lg, color='red', *args, **kwargs)
841-
_add_arrows_to_line2D(
842-
ax, p[0], arrow_pos, arrowstyle=arrow_style, dir=1)
843+
if plot_maximum_magnitude != 0:
844+
# plot large magnitude contour
845+
p = plt.plot(x_lg, y_lg, color='red', *args, **kwargs)
846+
_add_arrows_to_line2D(
847+
ax, p[0], arrow_pos, arrowstyle=arrow_style, dir=1)
843848

844849
# Plot the mirror image
845850
if mirror_style is not False:
846851
p = plt.plot(x, -y, mirror_style, color=c, *args, **kwargs)
847852
_add_arrows_to_line2D(
848853
ax, p[0], arrow_pos, arrowstyle=arrow_style, dir=-1)
849-
p = plt.plot(x_lg, -y_lg, mirror_style,
850-
color='red', *args, **kwargs)
851-
_add_arrows_to_line2D(
852-
ax, p[0], arrow_pos, arrowstyle=arrow_style, dir=-1)
854+
if plot_maximum_magnitude != 0:
855+
p = plt.plot(x_lg, -y_lg, mirror_style,
856+
color='red', *args, **kwargs)
857+
_add_arrows_to_line2D(
858+
ax, p[0], arrow_pos, arrowstyle=arrow_style, dir=-1)
853859

854860
# Mark the -1 point
855861
plt.plot([-1], [0], 'r+')
@@ -883,8 +889,9 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
883889
ax.set_xlabel("Real axis")
884890
ax.set_ylabel("Imaginary axis")
885891
ax.grid(color="lightgray")
886-
ax.set_xlim(-maximum_magnitude*1.1, maximum_magnitude*1.1)
887-
ax.set_ylim(-maximum_magnitude*1.1, maximum_magnitude*1.1)
892+
if plot_maximum_magnitude != 0:
893+
ax.set_xlim(-plot_maximum_magnitude*1.1,plot_maximum_magnitude*1.1)
894+
ax.set_ylim(-plot_maximum_magnitude*1.1,plot_maximum_magnitude*1.1)
888895

889896
# "Squeeze" the results
890897
if len(syslist) == 1:

control/tests/nyquist_test.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,23 @@ def test_nyquist_fbs_examples():
141141
count = ct.nyquist_plot(sys)
142142
assert _Z(sys) == count + _P(sys)
143143

144+
# when omega is specified, no points are added at indentations, leading
145+
# to incorrect encirclement count
146+
plt.figure()
147+
plt.title("Figure 10.10: L(s) = 3 (s+6)^2 / (s (s+1)^2) [zoom]")
148+
count = ct.nyquist_plot(sys, omega=np.linspace(1.5, 1e3, 1000))
149+
# assert _Z(sys) == count + _P(sys)
150+
assert count == -1
151+
152+
# when only the range of the frequency is provided, this permits
153+
# extra points to be added at indentations, leading to correct count
144154
plt.figure()
145155
plt.title("Figure 10.10: L(s) = 3 (s+6)^2 / (s (s+1)^2) [zoom]")
146156
count = ct.nyquist_plot(sys, omega_limits=[1.5, 1e3])
147157
# Frequency limits for zoom give incorrect encirclement count
148158
# assert _Z(sys) == count + _P(sys)
149-
assert count == -1
159+
assert count == 0
160+
150161

151162

152163
@pytest.mark.parametrize("arrows", [
@@ -227,6 +238,10 @@ def test_nyquist_indent():
227238
plt.title("Imaginary poles; encirclements = %d" % count)
228239
assert _Z(sys) == count + _P(sys)
229240

241+
# confirm we can turn off maximum_magitude plot
242+
plt.figure();
243+
count = ct.nyquist_plot(sys, plot_maximum_magnitude=0)
244+
230245
# Imaginary poles with indentation to the left
231246
plt.figure();
232247
count = ct.nyquist_plot(sys, indent_direction='left', label_freq=300)

0 commit comments

Comments
 (0)