@@ -139,7 +139,6 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None, plotstr='-', Plot=True,
139
139
ax .set_ylabel ('Imaginary' )
140
140
if grid :
141
141
sgrid_func (f )
142
-
143
142
return mymat , kvect
144
143
145
144
@@ -162,7 +161,7 @@ def _default_gains(num, den, xlim, ylim):
162
161
mymat_xl = mymat
163
162
singular_points = np .concatenate ((num .roots , den .roots ), axis = 0 )
164
163
important_points = np .concatenate ((singular_points , real_break ), axis = 0 )
165
- important_points = np .concatenate ((singular_points , np .zeros (2 )), axis = 0 )
164
+ important_points = np .concatenate ((important_points , np .zeros (2 )), axis = 0 )
166
165
mymat_xl = np .append (mymat_xl , important_points )
167
166
168
167
if xlim is None :
@@ -267,6 +266,7 @@ def _systopoly1d(sys):
267
266
# Check to see if num, den are already polynomials; otherwise convert
268
267
if (not isinstance (nump , poly1d )):
269
268
nump = poly1d (nump )
269
+
270
270
if (not isinstance (denp , poly1d )):
271
271
denp = poly1d (denp )
272
272
@@ -321,55 +321,72 @@ def _RLFeedbackClicks(event, sys):
321
321
(s .real , s .imag , K .real , - 1 * s .real / abs (s )))
322
322
323
323
324
- def sgrid_func (fig ):
324
+ def sgrid_func (fig , zeta = None , wn = None ):
325
325
ax = fig .gca ()
326
326
ylocator = ax .get_yaxis ().get_major_locator ()
327
- xlocator = ax .get_yaxis ().get_major_locator ()
327
+ xlocator = ax .get_xaxis ().get_major_locator ()
328
328
329
- angules = np .arange (- 90 , 80 , 15 )* np .pi / 180
329
+ if zeta is None :
330
+ zeta = _default_zetas (xlocator (), ylocator ())
331
+
332
+ angules = []
333
+ for z in zeta :
334
+ if (z >= 1e-4 ) & (z < 1 ):
335
+ angules .append (np .pi / 2 + np .arcsin (z ))
336
+ else :
337
+ zeta .remove (z )
338
+ y_over_x = np .tan (angules )
330
339
331
340
# zeta-constant lines
332
- y_over_x = np .tan (angules [1 ::])* ylocator ()[- 1 ]/ xlocator ()[- 1 ]
333
341
ylim = ax .get_ylim ()
334
342
ytext_pos_lim = ylim [1 ]- (ylim [1 ]- ylim [0 ])* 0.03
335
343
xlim = ax .get_xlim ()
336
344
xtext_pos_lim = xlim [0 ]+ (xlim [1 ]- xlim [0 ])* 0.0
337
345
index = 0
338
- zeta = np .sin (np .pi / 2 - angules [1 ::])
339
346
340
347
for yp in y_over_x :
341
348
ax .plot ([0 , xlocator ()[0 ]], [0 , yp * xlocator ()[0 ]], color = 'gray' ,
342
349
linestyle = 'dashed' , linewidth = 0.5 )
350
+ ax .plot ([0 , xlocator ()[0 ]], [0 , - yp * xlocator ()[0 ]], color = 'gray' ,
351
+ linestyle = 'dashed' , linewidth = 0.5 )
343
352
an = "%.2f" % zeta [index ]
344
- if yp > 0 :
345
- xtext_pos = - 1 / yp * ylim [1 ]
346
- ytext_pos = - yp * xtext_pos_lim
347
- if np .abs (xtext_pos ) > np .abs (xtext_pos_lim ):
348
- xtext_pos = xtext_pos_lim
349
- else :
350
- ytext_pos = ytext_pos_lim
351
- ax .annotate (an , textcoords = 'data' , xy = [xtext_pos , ytext_pos ], fontsize = 8 )
352
- elif yp < 0 :
353
- xtext_pos = - 1 / yp * ylim [1 ]
353
+ if yp < 0 :
354
+ xtext_pos = 1 / yp * ylim [1 ]
354
355
ytext_pos = yp * xtext_pos_lim
355
356
if np .abs (xtext_pos ) > np .abs (xtext_pos_lim ):
356
357
xtext_pos = xtext_pos_lim
357
- ytext_pos = - ytext_pos
358
358
else :
359
- ytext_pos = ylim [0 ]
360
- xtext_pos = - xtext_pos
359
+ ytext_pos = ytext_pos_lim
361
360
ax .annotate (an , textcoords = 'data' , xy = [xtext_pos , ytext_pos ], fontsize = 8 )
362
361
index += 1
363
362
ax .plot ([0 , 0 ], [ylim [0 ], ylim [1 ]], color = 'gray' , linestyle = 'dashed' , linewidth = 0.5 )
364
363
365
364
angules = np .linspace (- 90 , 90 , 20 )* np .pi / 180
366
- for xt in xlocator ():
367
- if xt < 0 :
368
- yp = np .sin (angules )* np .abs (xt )
369
- xp = - np .cos (angules )* np .abs (xt )
365
+ if wn is None :
366
+ wn = _default_wn (xlocator (), ylocator ())
367
+
368
+ for om in wn :
369
+ if om < 0 :
370
+ yp = np .sin (angules )* np .abs (om )
371
+ xp = - np .cos (angules )* np .abs (om )
370
372
ax .plot (xp , yp , color = 'gray' ,
371
373
linestyle = 'dashed' , linewidth = 0.5 )
372
- an = "%.2f" % - xt
373
- ax .annotate (an , textcoords = 'data' , xy = [xt , 0 ], fontsize = 8 )
374
+ an = "%.2f" % - om
375
+ ax .annotate (an , textcoords = 'data' , xy = [om , 0 ], fontsize = 8 )
376
+
377
+
378
+ def _default_zetas (xloc , yloc ):
379
+ """Return default list of dumps coefficients"""
380
+ # TODO: smart selection on zetas to draw in root locus plot
381
+ angules = np .arange (0 , 80 , 15 ) * np .pi / 180
382
+ zeta = np .sin (np .pi / 2 - angules [1 ::])
383
+ return zeta .tolist ()
384
+
385
+
386
+ def _default_wn (xloc , yloc ):
387
+ """Return default wn for root locus plot"""
388
+ # TODO: better selection of wn (up to maximum ylim with same separation in xloc)
389
+ wn = xloc
390
+ return wn
374
391
375
392
rlocus = root_locus
0 commit comments