10000 turn off encirclement warnings for describing function plot · python-control/python-control@5dd6a70 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5dd6a70

Browse files
committed
turn off encirclement warnings for describing function plot
1 parent 9a5759f commit 5dd6a70

File tree

3 files changed

+37
-23
lines changed

3 files changed

+37
-23
lines changed

control/descfcn.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ def describing_function(
199199

200200

201201
def describing_function_plot(
202-
H, F, A, omega=None, refine=True, label="%5.2g @ %-5.2g", **kwargs):
202+
H, F, A, omega=None, refine=True, label="%5.2g @ %-5.2g",
203+
warn=None, **kwargs):
203204
"""Plot a Nyquist plot with a describing function for a nonlinear system.
204205
205206
This function generates a Nyquist plot for a closed loop system consisting
@@ -220,6 +221,10 @@ def describing_function_plot(
220221
label : str, optional
221222
Formatting string used to label intersection points on the Nyquist
222223
plot. Defaults to "%5.2g @ %-5.2g". Set to `None` to omit labels.
224+
warn : bool, optional
225+
Set to True to turn on warnings generated by `nyquist_plot` or False
226+
to turn off warnings. If not set (or set to None), warnings are
227+
turned off if omega is specified, otherwise they are turned on.
223228
224229
Returns
225230
-------
@@ -240,9 +245,15 @@ def describing_function_plot(
240245
[(3.344008947853124, 1.414213099755523)]
241246
242247
"""
248+
# Decide whether to turn on warnings or not
249+
if warn is None:
250+
# Turn warnings on unless omega was specified
251+
warn = omega is None
252+
243253
# Start by drawing a Nyquist curve
244254
count, contour = nyquist_plot(
245-
H, omega, plot=True, return_contour=True, **kwargs)
255+
H, omega, plot=True, return_contour=True,
256+
warn_encirclements=warn, warn_nyquist=warn, **kwargs)
246257
H_omega, H_vals = contour.imag, H(contour)
247258

248259
# Compute the describing function
Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -535,9 +535,10 @@ def gen_zero_centered_series(val_min, val_max, period):
535535
}
536536

537537

538-
def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
539-
omega_num=None, label_freq=0, color=None,
540-
return_contour=False, warn_nyquist=True, *args, **kwargs):
538+
def nyquist_plot(
539+
syslist, omega=None, plot=True, omega_limits=None, omega_num=None,
540+
label_freq=0, color=None, return_contour=False,
541+
warn_encirclements=True, warn_nyquist=True, **kwargs):
541542
"""Nyquist plot for a system
542543
543544
Plots a Nyquist plot for the system over a (optional) frequency range.
@@ -647,11 +648,11 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
647648
determined by config.defaults['nyquist.mirror_style'].
648649
649650
primary_style : [str, str], optional
650-
Linestyles for primary image of the Nyquist curve. The first element
651-
is used for unscaled portions of the Nyquist curve, the second
652-
element is used for scaled portions that are scaled (using
653-
max_curve_magnitude). Default linestyle (['-', ':']) is determined by
654-
config.defaults['nyquist.mirror_style'].
651+
Linestyles for primary image of the Nyquist curve. The first
652+
element is used for unscaled portions of the Nyquist curve,
653+
the second element is used for portions that are scaled (using
654+
max_curve_magnitude). Default linestyle (['-', ':']) is
655+
determined by config.defaults['nyquist.mirror_style'].
655656
656657
start_marker : str, optional
657658
Matplotlib marker to use to mark the starting point of the Nyquist
@@ -839,7 +840,8 @@ def _parse_linestyle(style_name, allow_false=False):
839840
p_ol = splane_poles[
840841
(np.abs(splane_poles - p_cl)).argmin()]
841842

842-
if abs(p_ol - p_cl) <= indent_radius:
843+
if abs(p_ol - p_cl) <= indent_radius and \
844+
warn_encirclements:
843845
warnings.warn(
844846
"indented contour may miss closed loop pole; "
845847
"consider reducing indent_radius to be less than "
@@ -920,7 +922,8 @@ def _parse_linestyle(style_name, allow_false=False):
920922
count = int(np.round(encirclements, 0))
921923

922924
# Let the user know if the count might not make sense
923-
if abs(encirclements - count) > encirclement_threshold:
925+
if abs(encirclements - count) > encirclement_threshold and \
926+
warn_encirclements:
924927
warnings.warn(
925928
"number of encirclements was a non-integer value; this can"
926929
" happen is contour is not closed, possibly based on a"
@@ -937,13 +940,13 @@ def _parse_linestyle(style_name, allow_false=False):
937940
P = (sys.pole().real > 0).sum() if indent_direction == 'right' \
938941
else (sys.pole().real >= 0).sum()
939942
Z = (sys.feedback().pole().real >= 0).sum()
940-
if Z != count + P:
943+
if Z != count + P and warn_encirclements:
941944
warnings.warn(
942945
"number of encirclements does not match Nyquist criterion;"
943946
" check frequency range and indent radius/direction",
944947
UserWarning, stacklevel=2)
945-
elif indent_direction == 'none' and \
946-
any(np.isclose(sys.pole().real, 0)):
948+
elif indent_direction == 'none' and any(sys.pole().real == 0) and \
949+
warn_encirclements:
947950
warnings.warn(
948951
"system has pure imaginary poles but indentation is"
949952
" turned off; results may be meaningless",
@@ -991,7 +994,7 @@ def _parse_linestyle(style_name, allow_false=False):
991994
x_reg = np.ma.masked_where(reg_mask, resp.real)
992995
y_reg = np.ma.masked_where(reg_mask, resp.imag)
993996
p = plt.plot(
994-
x_reg, y_reg, primary_style[0], color=color, *args, **kwargs)
997+
x_reg, y_reg, primary_style[0], color=color, **kwargs)
995998
c = p[0].get_color()
996999

9971000
# Figure out how much to offset the curve: the offset goes from
@@ -1005,13 +1008,13 @@ def _parse_linestyle(style_name, allow_false=False):
10051008
y_scl = np.ma.masked_where(scale_mask, resp.imag)
10061009
plt.plot(
10071010
x_scl * (1 + curve_offset), y_scl * (1 + curve_offset),
1008-
primary_style[1], color=c, *args, **kwargs)
1011+
primary_style[1], color=c, **kwargs)
10091012

10101013
# Plot the primary curve (invisible) for setting arrows
10111014
x, y = resp.real.copy(), resp.imag.copy()
10121015
x[reg_mask] *= (1 + curve_offset[reg_mask])
10131016
y[reg_mask] *= (1 + curve_offset[reg_mask])
1014-
p = plt.plot(x, y, linestyle='None', color=c, *args, **kwargs)
1017+
p = plt.plot(x, y, linestyle='None', color=c, **kwargs)
10151018

10161019
# Add arrows
10171020
ax = plt.gca()
@@ -1022,17 +1025,17 @@ def _parse_linestyle(style_name, allow_false=False):
10221025
if mirror_style is not False:
10231026
# Plot the regular and scaled segments
10241027
plt.plot(
1025-
x_reg, -y_reg, mirror_style[0], color=c, *args, **kwargs)
1028+
x_reg, -y_reg, mirror_style[0], color=c, **kwargs)
10261029
plt.plot(
10271030
x_scl * (1 - curve_offset),
10281031
-y_scl * (1 - curve_offset),
1029-
mirror_style[1], color=c, *args, **kwargs)
1032+
mirror_style[1], color=c, **kwargs)
10301033

10311034
# Add the arrows (on top of an invisible contour)
10321035
x, y = resp.real.copy(), resp.imag.copy()
10331036
x[reg_mask] *= (1 - curve_offset[reg_mask])
10341037
y[reg_mask] *= (1 - curve_offset[reg_mask])
1035-
p = plt.plot(x, -y, linestyle='None', color=c, *args, **kwargs)
1038+
p = plt.plot(x, -y, linestyle='None', color=c, **kwargs)
10361039
_add_arrows_to_line2D(
10371040
ax, p[0], arrow_pos, arrowstyle=arrow_style, dir=-1)
10381041

control/tests/descfcn_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def test_describing_function(fcn, amin, amax):
140140
def test_describing_function_plot():
141141
# Simple linear system with at most 1 intersection
142142
H_simple = ct.tf([1], [1, 2, 2, 1])
143-
omega = np.logspace(-2, 2, 100)
143+
omega = np.logspace(-1, 2, 100)
144144

145145
# Saturation nonlinearity
146146
F_saturation = ct.descfcn.saturation_nonlinearity(1)
@@ -160,7 +160,7 @@ def test_describing_function_plot():
160160

161161
# Multiple intersections
162162
H_multiple = H_simple * ct.tf(*ct.pade(5, 4)) * 4
163-
omega = np.logspace(-2, 3, 50)
163+
omega = np.logspace(-1, 3, 50)
164164
F_backlash = ct.descfcn.friction_backlash_nonlinearity(1)
165165
amp = np.linspace(0.6, 5, 50)
166166
xsects = ct.describing_function_plot(H_multiple, F_backlash, amp, omega)

0 commit comments

Comments
 (0)
0