@@ -644,14 +644,14 @@ def nyquist_plot(
644644 Linestyles for mirror image of the Nyquist curve. The first element
645645 is used for unscaled portions of the Nyquist curve, the second element
646646 is used for portions that are scaled (using max_curve_magnitude). If
647- `False` then omit completely. Default linestyle (['--', '-. ']) is
647+ `False` then omit completely. Default linestyle (['--', ': ']) is
648648 determined by config.defaults['nyquist.mirror_style'].
649649
650650 primary_style : [str, str], optional
651651 Linestyles for primary image of the Nyquist curve. The first
652652 element is used for unscaled portions of the Nyquist curve,
653653 the second element is used for portions that are scaled (using
654- max_curve_magnitude). Default linestyle (['-', ': ']) is
654+ max_curve_magnitude). Default linestyle (['-', '-. ']) is
655655 determined by config.defaults['nyquist.mirror_style'].
656656
657657 start_marker : str, optional
@@ -750,6 +750,9 @@ def _parse_linestyle(style_name, allow_false=False):
750750 if isinstance (style , str ):
751751 # Only one style provided, use the default for the other
752752 style = [style , _nyquist_defaults ['nyquist.' + style_name ][1 ]]
753+ warnings .warn (
754+ "use of a single string for linestyle will be deprecated "
755+ " in a future release" , PendingDeprecationWarning )
753756 if (allow_false and style is False ) or \
754757 (isinstance (style , list ) and len (style ) == 2 ):
755758 return style
@@ -765,7 +768,7 @@ def _parse_linestyle(style_name, allow_false=False):
765768
766769 # Determine the range of frequencies to use, based on args/features
767770 omega , omega_range_given = _determine_omega_vector (
768- syslist , omega , omega_limits , omega_num )
771+ syslist , omega , omega_limits , omega_num , feature_periphery_decades = 2 )
769772
770773 # If omega was not specified explicitly, start at omega = 0
771774 if not omega_range_given :
@@ -790,7 +793,7 @@ def _parse_linestyle(style_name, allow_false=False):
790793
791794 # Determine the contour used to evaluate the Nyquist curve
792795 if sys .isdtime (strict = True ):
793- # Transform frequencies in for discrete-time systems
796+ # Restrict frequencies for discrete-time systems
794797 nyquistfrq = math .pi / sys .dt
795798 if not omega_range_given :
796799 # limit up to and including nyquist frequency
@@ -817,12 +820,12 @@ def _parse_linestyle(style_name, allow_false=False):
817820 # because we don't need to indent for them
818821 zplane_poles = sys .poles ()
819822 zplane_poles = zplane_poles [~ np .isclose (abs (zplane_poles ), 0. )]
820- splane_poles = np .log (zplane_poles )/ sys .dt
823+ splane_poles = np .log (zplane_poles ) / sys .dt
821824
822825 zplane_cl_poles = sys .feedback ().poles ()
823826 zplane_cl_poles = zplane_cl_poles [
824827 ~ np .isclose (abs (zplane_poles ), 0. )]
825- splane_cl_poles = np .log (zplane_cl_poles )/ sys .dt
828+ splane_cl_poles = np .log (zplane_cl_poles ) / sys .dt
826829
827830 #
828831 # Check to make sure indent radius is small enough
@@ -851,8 +854,8 @@ def _parse_linestyle(style_name, allow_false=False):
851854 # See if we should add some frequency points near imaginary poles
852855 #
853856 for p in splane_poles :
854- # See if we need to process this pole (skip any that is on
855- # the not near or on the negative omega axis + user override)
857+ # See if we need to process this pole (skip if on the negative
858+ # imaginary axis or not near imaginary axis + user override)
856859 if p .imag < 0 or abs (p .real ) > indent_radius or \
857860 omega_range_given :
858861 continue
@@ -894,13 +897,13 @@ def _parse_linestyle(style_name, allow_false=False):
894897 - (s - p ).real
895898
896899 # Figure out which way to offset the contour point
897- if p .real < 0 or (np . isclose ( p .real , 0 )
898- and indent_direction == 'right' ):
900+ if p .real < 0 or (p .real == 0 and
901+ indent_direction == 'right' ):
899902 # Indent to the right
900903 splane_contour [i ] += offset
901904
902- elif p .real > 0 or (np . isclose ( p .real , 0 )
903- and indent_direction == 'left' ):
905+ elif p .real > 0 or (p .real == 0 and
906+ indent_direction == 'left' ):
904907 # Indent to the left
905908 splane_contour [i ] -= offset
906909
@@ -937,9 +940,21 @@ def _parse_linestyle(style_name, allow_false=False):
937940 # Nyquist criterion is actually satisfied.
938941 #
939942 if isinstance (sys , (StateSpace , TransferFunction )):
940- P = (sys .poles ().real > 0 ).sum () if indent_direction == 'right' \
941- else (sys .poles ().real >= 0 ).sum ()
942- Z = (sys .feedback ().poles ().real >= 0 ).sum ()
943+ # Count the number of open/closed loop RHP poles
944+ if sys .isctime ():
945+ if indent_direction == 'right' :
946+ P = (sys .poles ().real > 0 ).sum ()
947+ else :
948+ P = (sys .poles ().real >= 0 ).sum ()
949+ Z = (sys .feedback ().poles ().real >= 0 ).sum ()
950+ else :
951+ if indent_direction == 'right' :
952+ P = (np .abs (sys .poles ()) > 1 ).sum ()
953+ else :
954+ P = (np .abs (sys .poles ()) >= 1 ).sum ()
955+ Z = (np .abs (sys .feedback ().poles ()) >= 1 ).sum ()
956+
957+ # Check to make sure the results make sense; warn if not
943958 if Z != count + P and warn_encirclements :
944959 warnings .warn (
945960 "number of encirclements does not match Nyquist criterion;"
@@ -976,7 +991,7 @@ def _parse_linestyle(style_name, allow_false=False):
976991 # Find the different portions of the curve (with scaled pts marked)
977992 reg_mask = np .logical_or (
978993 np .abs (resp ) > max_curve_magnitude ,
979- contour .real != 0 )
994+ splane_contour .real != 0 )
980995 # reg_mask = np.logical_or(
981996 # np.abs(resp.real) > max_curve_magnitude,
982997 # np.abs(resp.imag) > max_curve_magnitude)
@@ -1508,7 +1523,7 @@ def singular_values_plot(syslist, omega=None,
15081523
15091524# Determine the frequency range to be used
15101525def _determine_omega_vector (syslist , omega_in , omega_limits , omega_num ,
1511- Hz = None ):
1526+ Hz = None , feature_periphery_decades = None ):
15121527 """Determine the frequency range for a frequency-domain plot
15131528 according to a standard logic.
15141529
@@ -1554,9 +1569,9 @@ def _determine_omega_vector(syslist, omega_in, omega_limits, omega_num,
15541569 if omega_limits is None :
15551570 omega_range_given = False
15561571 # Select a default range if none is provided
1557- omega_out = _default_frequency_range (syslist ,
1558- number_of_samples = omega_num ,
1559- Hz = Hz )
1572+ omega_out = _default_frequency_range (
1573+ syslist , number_of_samples = omega_num , Hz = Hz ,
1574+ feature_periphery_decades = feature_periphery_decades )
15601575 else :
15611576 omega_limits = np .asarray (omega_limits )
15621577 if len (omega_limits ) != 2 :
@@ -1640,7 +1655,7 @@ def _default_frequency_range(syslist, Hz=None, number_of_samples=None,
16401655
16411656 features_ = np .concatenate ((sys .poles (), sys .zeros ()))
16421657 # Get rid of poles and zeros on the real axis (imag==0)
1643- # * origin and real < 0
1658+ # * origin and real < 0
16441659 # * at 1.: would result in omega=0. (logaritmic plot!)
16451660 toreplace = np .isclose (features_ .imag , 0.0 ) & (
16461661 (features_ .real <= 0. ) |
0 commit comments