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

Skip to content

Commit f3dfe04

Browse files
committed
turn off encirclement warnings for describing function plot
1 parent a9ac490 commit f3dfe04

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

control/freqplot.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -534,9 +534,10 @@ def gen_zero_centered_series(val_min, val_max, period):
534534
}
535535

536536

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

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

921923
# Let the user know if the count might not make sense
922-
if abs(encirclements - count) > encirclement_threshold:
924+
if abs(encirclements - count) > encirclement_threshold and \
925+
warn_encirclements:
923926
warnings.warn(
924927
"number of encirclements was a non-integer value; this can"
925928
" happen is contour is not closed, possibly based on a"
@@ -936,13 +939,13 @@ def _parse_linestyle(style_name, allow_false=False):
936939
P = (sys.pole().real > 0).sum() if indent_direction == 'right' \
937940
else (sys.pole().real >= 0).sum()
938941
Z = (sys.feedback().pole().real >= 0).sum()
939-
if Z != count + P:
942+
if Z != count + P and warn_encirclements:
940943
warnings.warn(
941944
"number of encirclements does not match Nyquist criterion;"
942945
" check frequency range and indent radius/direction",
943946
UserWarning, stacklevel=2)
944-
elif indent_direction == 'none' and \
945-
any(np.isclose(sys.pole().real, 0)):
947+
elif indent_direction == 'none' and any(sys.pole().real == 0) and \
948+
warn_encirclements:
946949
warnings.warn(
947950
"system has pure imaginary poles but indentation is"
948951
" turned off; results may be meaningless",
@@ -990,7 +993,7 @@ def _parse_linestyle(style_name, allow_false=False):
990993
x_reg = np.ma.masked_where(reg_mask, resp.real)
991994
y_reg = np.ma.masked_where(reg_mask, resp.imag)
992995
p = plt.plot(
993-
x_reg, y_reg, primary_style[0], color=color, *args, **kwargs)
996+
x_reg, y_reg, primary_style[0], color=color, **kwargs)
994997
c = p[0].get_color()
995998

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

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

10151018
# Add arrows
10161019
ax = plt.gca()
@@ -1021,17 +1024,17 @@ def _parse_linestyle(style_name, allow_false=False):
10211024
if mirror_style is not False:
10221025
# Plot the regular and scaled segments
10231026
plt.plot(
1024-
x_reg, -y_reg, mirror_style[0], color=c, *args, **kwargs)
1027+
x_reg, -y_reg, mirror_style[0], color=c, **kwargs)
10251028
plt.plot(
10261029
x_scl * (1 - curve_offset),
10271030
-y_scl * (1 - curve_offset),
1028-
mirror_style[1], color=c, *args, **kwargs)
1031+
mirror_style[1], color=c, **kwargs)
10291032

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

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