@@ -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 ()]
@@ -1185,7 +1189,8 @@ def singular_values_plot(syslist, omega=None,
11851189
11861190
11871191# Determine the frequency range to be used
1188- def _determine_omega_vector (syslist , omega_in , omega_limits , omega_num ):
1192+ def _determine_omega_vector (syslist , omega_in , omega_limits , omega_num ,
1193+ replace_origin = False ):
11891194 """Determine the frequency range for a frequency-domain plot
11901195 according to a standard logic.
11911196
@@ -1221,7 +1226,6 @@ def _determine_omega_vector(syslist, omega_in, omega_limits, omega_num):
12211226 omega_in or through omega_limits. False if both omega_in
12221227 and omega_limits are None.
12231228 """
1224-
12251229 omega_range_given = True
12261230
12271231 if omega_in is None :
@@ -1244,12 +1248,14 @@ def _determine_omega_vector(syslist, omega_in, omega_limits, omega_num):
12441248
12451249# Compute reasonable defaults for axes
12461250def _default_frequency_range (syslist , Hz = None , number_of_samples = None ,
1247- feature_periphery_decades = None ):
1248- """Compute a reasonable default frequency range for frequency
1249- domain plots.
1251+ feature_periphery_decades = None ,
1252+ replace_origin = False ):
1253+ """Compute a default frequency range for frequency domain plots.
12501254
1251- Finds a reasonable default frequency range by examining the features
1252- (poles and zeros) of the systems in syslist.
1255+ This code looks at the poles and zeros of all of the systems that
1256+ we are plotting and sets the frequency range to be one decade above
1257+ and below the min and max feature frequencies, rounded to the nearest
1258+ integer. If no features are found, it returns logspace(-1, 1)
12531259
12541260 Parameters
12551261 ----------
@@ -1280,12 +1286,6 @@ def _default_frequency_range(syslist, Hz=None, number_of_samples=None,
12801286 >>> omega = _default_frequency_range(sys)
12811287
12821288 """
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-
12891289 # Set default values for options
12901290 number_of_samples = config ._get_param (
12911291 'freqplot' , 'number_of_samples' , number_of_samples )
@@ -1307,30 +1307,31 @@ def _default_frequency_range(syslist, Hz=None, number_of_samples=None,
13071307 features_ = np .concatenate ((np .abs (sys .pole ()),
13081308 np .abs (sys .zero ())))
13091309 # Get rid of poles and zeros at the origin
1310- features_ = features_ [features_ != 0.0 ]
1311- features = np .concatenate ((features , features_ ))
1310+ toreplace = features_ == 0.0
1311+ if np .any (toreplace ):
1312+ features_ = features_ [~ toreplace ]
13121313 elif sys .isdtime (strict = True ):
13131314 fn = math .pi * 1. / sys .dt
13141315 # TODO: What distance to the Nyquist frequency is appropriate?
13151316 freq_interesting .append (fn * 0.9 )
13161317
13171318 features_ = np .concatenate ((sys .pole (),
13181319 sys .zero ()))
1319- # Get rid of poles and zeros
1320- # * at the origin and real <= 0 & imag==0: log!
1320+ # Get rid of poles and zeros on the real axis (imag==0)
1321+ # * origin and real < 0
13211322 # * 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 )) ]
1323+ toreplace = ( features_ . imag == 0.0 ) & (
1324+ (features_ .real <= 0. ) |
1325+ ( np . abs ( features_ . real - 1.0 ) < 1.e-10 ))
1326+ if np .any ( toreplace ):
1327+ features_ = features_ [ ~ toreplace ]
13271328 # TODO: improve
1328- features__ = np .abs (np .log (features_ ) / (1.j * sys .dt ))
1329- features = np .concatenate ((features , features__ ))
1329+ features_ = np .abs (np .log (features_ ) / (1.j * sys .dt ))
13301330 else :
13311331 # TODO
13321332 raise NotImplementedError (
13331333 "type of system in not implemented now" )
1334+ features = np .concatenate ((features , features_ ))
13341335 except NotImplementedError :
13351336 pass
13361337
0 commit comments