@@ -714,41 +714,53 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
714
714
if np .any (omega_sys * sys .dt > np .pi ) and warn_nyquist :
715
715
warnings .warn ("evaluation above Nyquist frequency" )
716
716
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
721
719
722
720
# 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.
723
723
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 :
728
737
# add some points for quarter circle around poles at origin
729
- contour = np .concatenate (
738
+ splane_contour = np .concatenate (
730
739
(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 ):
733
742
# Find the nearest pole
734
- p = poles [(np .abs (poles - s )).argmin ()]
735
-
743
+ p = splane_poles [(np .abs (splane_poles - s )).argmin ()]
736
744
# See if we need to indent around it
737
745
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' ):
740
748
# Indent to the right
741
- contour [i ] += \
749
+ splane_contour [i ] += \
742
750
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' ):
745
753
# Indent to the left
746
- contour [i ] -= \
754
+ splane_contour [i ] -= \
747
755
np .sqrt (indent_radius ** 2 - (s - p ).imag ** 2 )
748
756
else :
749
757
ValueError ("unknown value for indent_direction" )
750
758
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 )
752
764
753
765
# Compute the primary curve
754
766
resp = sys (contour )
0 commit comments