@@ -222,6 +222,14 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None,
222222 ax .set_xlabel ('Real' )
223223 ax .set_ylabel ('Imaginary' )
224224
225+ # Set up the limits for the plot
226+ # Note: need to do this before computing grid lines
227+ if xlim :
228+ ax .set_xlim (xlim )
229+ if ylim :
230+ ax .set_ylim (ylim )
231+
232+ # Draw the grid
225233 if grid and sisotool :
226234 if isdtime (sys , strict = True ):
227235 zgrid (ax = ax )
@@ -236,14 +244,9 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None,
236244 ax .axhline (0. , linestyle = ':' , color = 'k' , zorder = - 20 )
237245 ax .axvline (0. , linestyle = ':' , color = 'k' , zorder = - 20 )
238246 if isdtime (sys , strict = True ):
239- ax .add_patch (plt .Circle ((0 ,0 ), radius = 1.0 ,
240- linestyle = ':' , edgecolor = 'k' , linewidth = 1.5 ,
241- fill = False , zorder = - 20 ))
242-
243- if xlim :
244- ax .set_xlim (xlim )
245- if ylim :
246- ax .set_ylim (ylim )
247+ ax .add_patch (plt .Circle (
248+ (0 , 0 ), radius = 1.0 , linestyle = ':' , edgecolor = 'k' ,
249+ linewidth = 1.5 , fill = False , zorder = - 20 ))
247250
248251 return mymat , kvect
249252
@@ -642,16 +645,21 @@ def _sgrid_func(fig=None, zeta=None, wn=None):
642645 ax = fig .gca ()
643646 else :
644647 ax = fig .axes [1 ]
648+
649+ # Get locator function for x-axis tick marks
645650 xlocator = ax .get_xaxis ().get_major_locator ()
646651
652+ # Decide on the location for the labels (?)
647653 ylim = ax .get_ylim ()
648654 ytext_pos_lim = ylim [1 ] - (ylim [1 ] - ylim [0 ]) * 0.03
649655 xlim = ax .get_xlim ()
650656 xtext_pos_lim = xlim [0 ] + (xlim [1 ] - xlim [0 ]) * 0.0
651657
658+ # Create a list of damping ratios, if needed
652659 if zeta is None :
653660 zeta = _default_zetas (xlim , ylim )
654661
662+ # Figure out the angles for the different damping ratios
655663 angles = []
656664 for z in zeta :
657665 if (z >= 1e-4 ) and (z <= 1 ):
@@ -661,11 +669,8 @@ def _sgrid_func(fig=None, zeta=None, wn=None):
661669 y_over_x = np .tan (angles )
662670
663671 # zeta-constant lines
664-
665- index = 0
666-
667- for yp in y_over_x :
668- ax .plot ([0 , xlocator ()[0 ]], [0 , yp * xlocator ()[0 ]], color = 'gray' ,
672+ for index , yp in enumerate (y_over_x ):
673+ ax .plot ([0 , xlocator ()[0 ]], [0 , yp * xlocator ()[0 ]], color = 'gray' ,
669674 linestyle = 'dashed' , linewidth = 0.5 )
670675 ax .plot ([0 , xlocator ()[0 ]], [0 , - yp * xlocator ()[0 ]], color = 'gray' ,
671676 linestyle = 'dashed' , linewidth = 0.5 )
@@ -679,45 +684,96 @@ def _sgrid_func(fig=None, zeta=None, wn=None):
679684 ytext_pos = ytext_pos_lim
680685 ax .annotate (an , textcoords = 'data' , xy = [xtext_pos , ytext_pos ],
681686 fontsize = 8 )
682- index += 1
683687 ax .plot ([0 , 0 ], [ylim [0 ], ylim [1 ]],
684688 color = 'gray' , linestyle = '
9E81
;dashed' , linewidth = 0.5 )
685689
686- angles = np .linspace (- 90 , 90 , 20 )* np .pi / 180
690+ # omega-constant lines
691+ angles = np .linspace (- 90 , 90 , 20 ) * np .pi / 180
687692 if wn is None :
688693 wn = _default_wn (xlocator (), ylim )
689694
690695 for om in wn :
691696 if om < 0 :
692- yp = np .sin (angles )* np .abs (om )
693- xp = - np .cos (angles )* np .abs (om )
694- ax .plot (xp , yp , color = 'gray' ,
695- linestyle = 'dashed' , linewidth = 0.5 )
696- an = "%.2f" % - om
697- ax .annotate (an , textcoords = 'data' , xy = [om , 0 ], fontsize = 8 )
697+ # Generate the lines for natural frequency curves
698+ yp = np .sin (angles ) * np .abs (om )
699+ xp = - np .cos (angles ) * np .abs (om )
700+
701+ # Plot the natural frequency contours
702+ ax .plot (xp , yp , color = 'gray' , linestyle = 'dashed' , linewidth = 0.5 )
703+
704+ # Annotate the natural frequencies by listing on x-axis
705+ # Note: need to filter values for proper plotting in Jupyter
706+ if (om > xlim [0 ]):
707+ an = "%.2f" % - om
708+ ax .annotate (an , textcoords = 'data' , xy = [om , 0 ], fontsize = 8 )
698709
699710
700711def _default_zetas (xlim , ylim ):
701- """Return default list of damping coefficients"""
702- sep1 = - xlim [0 ]/ 4
712+ """Return default list of damping coefficients
713+
714+ This function computes a list of damping coefficients based on the limits
715+ of the graph. A set of 4 damping coefficients are computed for the x-axis
716+ and a set of three damping coefficients are computed for the y-axis
717+ (corresponding to the normal 4:3 plot aspect ratio in `matplotlib`?).
718+
719+ Parameters
720+ ----------
721+ xlim : array_like
722+ List of x-axis limits [min, max]
723+ ylim : array_like
724+ List of y-axis limits [min, max]
725+
726+ Returns
727+ -------
728+ zeta : list
729+ List of default damping coefficients for the plot
730+
731+ """
732+ # Damping coefficient lines that intersect the x-axis
733+ sep1 = - xlim [0 ] / 4
703734 ang1 = [np .arctan ((sep1 * i )/ ylim [1 ]) for i in np .arange (1 , 4 , 1 )]
735+
736+ # Damping coefficient lines that intersection the y-axis
704737 sep2 = ylim [1 ] / 3
705738 ang2 = [np .arctan (- xlim [0 ]/ (ylim [1 ]- sep2 * i )) for i in np .arange (1 , 3 , 1 )]
706739
740+ # Put the lines together and add one at -pi/2 (negative real axis)
707741 angles = np .concatenate ((ang1 , ang2 ))
708742 angles = np .insert (angles , len (angles ), np .pi / 2 )
743+
744+ # Return the damping coefficients corresponding to these angles
709745 zeta = np .sin (angles )
710746 return zeta .tolist ()
711747
712748
713749def _default_wn (xloc , ylim ):
714- """Return default wn for root locus plot"""
750+ """Return default wn for root locus plot
751+
752+ This function computes a list of natural frequencies based on the grid
753+ parameters of the graph.
754+
755+ Parameters
756+ ----------
757+ xloc : array_like
758+ List of x-axis tick values
759+ ylim : array_like
760+ List of y-axis limits [min, max]
761+
762+ Returns
763+ -------
764+ wn : list
765+ List of default natural frequencies for the plot
766+
767+ """
768+
769+ wn = xloc # one frequency per x-axis tick mark
770+ sep = xloc [1 ]- xloc [0 ] # separation between ticks
715771
716- wn = xloc
717- sep = xloc [1 ]- xloc [0 ]
772+ # Insert additional frequencies to span the y-axis
718773 while np .abs (wn [0 ]) < ylim [1 ]:
719774 wn = np .insert (wn , 0 , wn [0 ]- sep )
720775
776+ # If there are too many values, cut them in half
721777 while len (wn ) > 7 :
722778 wn = wn [0 :- 1 :2 ]
723779
0 commit comments