Skip to content

Commit affe4d3

Browse files
Merge pull request #668 from sawyerbfuller/nyquist-discrete-indent
modify discrete-time contour for nyquist plots to indent around poles
2 parents e9c224c + a948186 commit affe4d3

File tree

1 file changed

+32
-20
lines changed

1 file changed

+32
-20
lines changed

control/freqplot.py

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -714,41 +714,53 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
714714
if np.any(omega_sys * sys.dt > np.pi) and warn_nyquist:
715715
warnings.warn("evaluation above Nyquist frequency")
716716

717-
# Transform frequencies to continuous domain
718-
contour = np.exp(1j * omega * sys.dt)
719-
else:
720-
contour = 1j * omega_sys
717+
# do indentations in s-plane where it is more convenient
718+
splane_contour = 1j * omega_sys
721719

722720
# Bend the contour around any poles on/near the imaginary axis
721+
# TODO: smarter indent radius that depends on dcgain of system
722+
# and timebase of discrete system.
723723
if isinstance(sys, (StateSpace, TransferFunction)) \
724-
and sys.isctime() and indent_direction != 'none':
725-
poles = sys.pole()
726-
if contour[1].imag > indent_radius \
727-
and 0. in poles and not omega_range_given:
724+
and indent_direction != 'none':
725+
if sys.isctime():
726+
splane_poles = sys.pole()
727+
else:
728+
# map z-plane poles to s-plane, ignoring any at the origin
729+
# because we don't need to indent for them
730+
zplane_poles = sys.pole()
731+
zplane_poles = zplane_poles[~np.isclose(abs(zplane_poles), 0.)]
732+
splane_poles = np.log(zplane_poles)/sys.dt
733+
734+
if splane_contour[1].imag > indent_radius \
735+
and np.any(np.isclose(abs(splane_poles), 0)) \
736+
and not omega_range_given:
728737
# add some points for quarter circle around poles at origin
729-
contour = np.concatenate(
738+
splane_contour = np.concatenate(
730739
(1j * np.linspace(0., indent_radius, 50),
731-
contour[1:]))
732-
for i, s in enumerate(contour):
740+
splane_contour[1:]))
741+
for i, s in enumerate(splane_contour):
733742
# Find the nearest pole
734-
p = poles[(np.abs(poles - s)).argmin()]
735-
743+
p = splane_poles[(np.abs(splane_poles - s)).argmin()]
736744
# See if we need to indent around it
737745
if abs(s - p) < indent_radius:
738-
if p.real < 0 or \
739-
(p.real == 0 and indent_direction == 'right'):
746+
if p.real < 0 or (np.isclose(p.real, 0) \
747+
and indent_direction == 'right'):
740748
# Indent to the right
741-
contour[i] += \
749+
splane_contour[i] += \
742750
np.sqrt(indent_radius ** 2 - (s-p).imag ** 2)
743-
elif p.real > 0 or \
744-
(p.real == 0 and indent_direction == 'left'):
751+
elif p.real > 0 or (np.isclose(p.real, 0) \
752+
and indent_direction == 'left'):
745753
# Indent to the left
746-
contour[i] -= \
754+
splane_contour[i] -= \
747755
np.sqrt(indent_radius ** 2 - (s-p).imag ** 2)
748756
else:
749757
ValueError("unknown value for indent_direction")
750758

751-
# TODO: add code to indent around discrete poles on unit circle
759+
# change contour to z-plane if necessary
760+
if sys.isctime():
761+
contour = splane_contour
762+
else:
763+
contour = np.exp(splane_contour * sys.dt)
752764

753765
# Compute the primary curve
754766
resp = sys(contour)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy