Skip to content

Commit 31cd4d0

Browse files
committed
add some omegas for quarter circle around origin poles in nyquist contour
1 parent 0a82909 commit 31cd4d0

File tree

1 file changed

+30
-31
lines changed

1 file changed

+30
-31
lines changed

control/freqplot.py

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
620620
621621
2. If a continuous-time system contains poles on or near the imaginary
622622
axis, a small indentation will be used to avoid the pole. The radius
623-
of the indentation is given by `indent_radius` and it is taken the the
623+
of the indentation is given by `indent_radius` and it is taken to the
624624
right of stable poles and the left of unstable poles. If a pole is
625625
exactly on the imaginary axis, the `indent_direction` parameter can be
626626
used to set the direction of indentation. Setting `indent_direction`
@@ -675,13 +675,11 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
675675
if not hasattr(syslist, '__iter__'):
676676
syslist = (syslist,)
677677

678-
omega, omega_range_given = _determine_omega_vector(syslist,
679-
omega,
680-
omega_limits,
681-
omega_num)
678+
omega, omega_range_given = _determine_omega_vector(
679+
syslist, omega, omega_limits, omega_num)
682680
if not omega_range_given:
683-
# Replace first point with the origin
684-
omega[0] = 0
681+
# Start contour at zero frequency
682+
omega[0] = 0.
685683

686684
# Go through each system and keep track of the results
687685
counts, contours = [], []
@@ -713,9 +711,15 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
713711
contour = 1j * omega_sys
714712

715713
# Bend the contour around any poles on/near the imaginary axis
716-
if isinstance(sys, (StateSpace, TransferFunction)) and \
717-
sys.isctime() and indent_direction != 'none':
714+
if isinstance(sys, (StateSpace, TransferFunction)) \
715+
and sys.isctime() and indent_direction != 'none':
718716
poles = sys.pole()
717+
if contour[1].imag > indent_radius \
718+
and 0. in poles and not omega_range_given:
719+
# add some points for quarter circle around poles at origin
720+
contour = np.concatenate(
721+
(1j * np.linspace(0., indent_radius, 50),
722+
contour[1:]))
719723
for i, s in enumerate(contour):
720724
# Find the nearest pole
721725
p = poles[(np.abs(poles - s)).argmin()]
@@ -1221,7 +1225,6 @@ def _determine_omega_vector(syslist, omega_in, omega_limits, omega_num):
12211225
omega_in or through omega_limits. False if both omega_in
12221226
and omega_limits are None.
12231227
"""
1224-
12251228
omega_range_given = True
12261229

12271230
if omega_in is None:
@@ -1245,11 +1248,12 @@ def _determine_omega_vector(syslist, omega_in, omega_limits, omega_num):
12451248
# Compute reasonable defaults for axes
12461249
def _default_frequency_range(syslist, Hz=None, number_of_samples=None,
12471250
feature_periphery_decades=None):
1248-
"""Compute a reasonable default frequency range for frequency
1249-
domain plots.
1251+
"""Compute a default frequency range for frequency domain plots.
12501252
1251-
Finds a reasonable default frequency range by examining the features
1252-
(poles and zeros) of the systems in syslist.
1253+
This code looks at the poles and zeros of all of the systems that
1254+
we are plotting and sets the frequency range to be one decade above
1255+
and below the min and max feature frequencies, rounded to the nearest
1256+
integer. If no features are found, it returns logspace(-1, 1)
12531257
12541258
Parameters
12551259
----------
@@ -1280,12 +1284,6 @@ def _default_frequency_range(syslist, Hz=None, number_of_samples=None,
12801284
>>> omega = _default_frequency_range(sys)
12811285
12821286
"""
1283-
# This code looks at the poles and zeros of all of the systems that
1284-
# we are plotting and sets the frequency range to be one decade above
1285-
# and below the min and max feature frequencies, rounded to the nearest
1286-
# integer. It excludes poles and zeros at the origin. If no features
1287-
# are found, it turns logspace(-1, 1)
1288-
12891287
# Set default values for options
12901288
number_of_samples = config._get_param(
12911289
'freqplot', 'number_of_samples', number_of_samples)
@@ -1307,30 +1305,31 @@ def _default_frequency_range(syslist, Hz=None, number_of_samples=None,
13071305
features_ = np.concatenate((np.abs(sys.pole()),
13081306
np.abs(sys.zero())))
13091307
# Get rid of poles and zeros at the origin
1310-
features_ = features_[features_ != 0.0]
1311-
features = np.concatenate((features, features_))
1308+
toreplace = features_ == 0.0
1309+
if np.any(toreplace):
1310+
features_ = features_[~toreplace]
13121311
elif sys.isdtime(strict=True):
13131312
fn = math.pi * 1. / sys.dt
13141313
# TODO: What distance to the Nyquist frequency is appropriate?
13151314
freq_interesting.append(fn * 0.9)
13161315

13171316
features_ = np.concatenate((sys.pole(),
13181317
sys.zero()))
1319-
# Get rid of poles and zeros
1320-
# * at the origin and real <= 0 & imag==0: log!
1318+
# Get rid of poles and zeros on the real axis (imag==0)
1319+
# * origin and real < 0
13211320
# * at 1.: would result in omega=0. (logaritmic plot!)
1322-
features_ = features_[
1323-
(features_.imag != 0.0) | (features_.real > 0.)]
1324-
features_ = features_[
1325-
np.bitwise_not((features_.imag == 0.0) &
1326-
(np.abs(features_.real - 1.0) < 1.e-10))]
1321+
toreplace = (features_.imag == 0.0) & (
1322+
(features_.real <= 0.) |
1323+
(np.abs(features_.real - 1.0) < 1.e-10))
1324+
if np.any(toreplace):
1325+
features_ = features_[~toreplace]
13271326
# TODO: improve
1328-
features__ = np.abs(np.log(features_) / (1.j * sys.dt))
1329-
features = np.concatenate((features, features__))
1327+
features_ = np.abs(np.log(features_) / (1.j * sys.dt))
13301328
else:
13311329
# TODO
13321330
raise NotImplementedError(
13331331
"type of system in not implemented now")
1332+
features = np.concatenate((features, features_))
13341333
except NotImplementedError:
13351334
pass
13361335

0 commit comments

Comments
 (0)