@@ -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
12461249def _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