5959
6060# Main function: compute a root locus diagram
6161def root_locus (sys , kvect = None , xlim = None , ylim = None , plotstr = '-' , Plot = True ,
62- PrintGain = True ):
62+ PrintGain = True , grid = False ):
6363 """Root locus plot
6464
6565 Calculate the root locus by finding the roots of 1+k*TF(s)
@@ -99,9 +99,17 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None, plotstr='-', Plot=True,
9999 mymat = _RLFindRoots (nump , denp , kvect )
100100 mymat = _RLSortRoots (mymat )
101101
102- # Create the plot
103- if (Plot ):
104- f = pylab .figure ()
102+ # Create the Plot
103+ if Plot :
104+ figure_number = pylab .get_fignums ()
105+ figure_title = [pylab .figure (numb ).canvas .get_window_title () for numb in figure_number ]
106+ new_figure_name = "Root Locus"
107+ rloc_num = 1
108+ while new_figure_name in figure_title :
109+ new_figure_name = "Root Locus " + str (rloc_num )
110+ rloc_num += 1
111+ f = pylab .figure (new_figure_name )
112+
105113 if PrintGain :
106114 f .canvas .mpl_connect (
107115 'button_release_event' , partial (_RLFeedbackClicks , sys = sys ))
@@ -127,6 +135,8 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None, plotstr='-', Plot=True,
127135 ax .set_ylim (ylim )
128136 ax .set_xlabel ('Real' )
129137 ax .set_ylabel ('Imaginary' )
138+ if grid :
139+ sgrid_func (f )
130140
131141 return mymat , kvect
132142
@@ -305,6 +315,63 @@ def _RLFeedbackClicks(event, sys):
305315 K = - 1. / sys .horner (s )
306316 if abs (K .real ) > 1e-8 and abs (K .imag / K .real ) < 0.04 :
307317 print ("Clicked at %10.4g%+10.4gj gain %10.4g damp %10.4g" %
308- (s .real , s .imag , K .real , - 1 * s .real / abs (s )))
318+ (s .real , s .imag , K .real , - 1 * s .real / abs (s )))
319+
320+
321+ def sgrid_func (fig ):
322+ ax = fig .gca ()
323+ ylocator = ax .get_yaxis ().get_major_locator ()
324+ xlocator = ax .get_yaxis ().get_major_locator ()
325+
326+ long_xaxis = xlocator ()[- 1 ] - xlocator ()[0 ]
327+ long_yaxis = ylocator ()[- 1 ] - ylocator ()[0 ]
328+
329+ angules = np .arange (- 90 , 80 , 15 )* np .pi / 180
330+
331+ # radial lines
332+ y_over_x = np .tan (angules [1 ::])* ylocator ()[- 1 ]/ xlocator ()[- 1 ]
333+
334+ ylim = ax .get_ylim ()
335+ ytext_pos_lim = ylim [1 ]- (ylim [1 ]- ylim [0 ])* 0.03
336+
337+ xlim = ax .get_xlim ()
338+ xtext_pos_lim = xlim [0 ]+ (xlim [1 ]- xlim [0 ])* 0.0
339+
340+ index = 0
341+ zeta = np .sin (np .pi / 2 - angules [1 ::])
342+
343+ for yp in y_over_x :
344+ ax .plot ([0 , xlocator ()[0 ]], [0 , yp * xlocator ()[0 ]], color = 'gray' ,
345+ linestyle = 'dashed' , linewidth = 0.5 )
346+ an = "%.2f" % zeta [index ]
347+ if yp > 0 :
348+ xtext_pos = - 1 / yp * ylim [1 ]
349+ ytext_pos = - yp * xtext_pos_lim
350+ if np .abs (xtext_pos ) > np .abs (xtext_pos_lim ):
351+ xtext_pos = xtext_pos_lim
352+ else :
353+ ytext_pos = ytext_pos_lim
354+ ax .annotate (an , textcoords = 'data' , xy = [xtext_pos , ytext_pos ], fontsize = 8 )
355+ elif yp < 0 :
356+ xtext_pos = - 1 / yp * ylim [1 ]
357+ ytext_pos = yp * xtext_pos_lim
358+ if np .abs (xtext_pos ) > np .abs (xtext_pos_lim ):
359+ xtext_pos = xtext_pos_lim
360+ ytext_pos = - ytext_pos
361+ else :
362+ ytext_pos = ylim [0 ]
363+ xtext_pos = - xtext_pos
364+ ax .annotate (an , textcoords = 'data' , xy = [xtext_pos , ytext_pos ], fontsize = 8 )
365+ index += 1
366+
367+ angules = np .linspace (- 90 , 90 , 20 )* np .pi / 180
368+ for xt in xlocator ():
369+ if xt < 0 :
370+ yp = np .sin (angules )* np .abs (xt )
371+ xp = - np .cos (angules )* np .abs (xt )
372+ ax .plot (xp , yp , color = 'gray' ,
373+ linestyle = 'dashed' , linewidth = 0.5 )
374+ an = "%.2f" % - xt
375+ ax .annotate (an , textcoords = 'data' , xy = [xt , 0 ], fontsize = 8 )
309376
310377rlocus = root_locus
0 commit comments