@@ -1060,7 +1060,9 @@ def gen_zero_centered_series(val_min, val_max, period):
10601060 'nyquist.max_curve_magnitude' : 20 , # clip large values
10611061 'nyquist.max_curve_offset' : 0.02 , # offset of primary/mirror
10621062 'nyquist.start_marker' : 'o' , # marker at start of curve
1063- 'nyquist.start_marker_size' : 4 , # size of the maker
1063+ 'nyquist.start_marker_size' : 4 , # size of the marker
1064+ 'nyquist.circle_style' : # style for unit circles
1065+ {'color' : 'black' , 'linestyle' : 'dashed' , 'linewidth' : 1 }
10641066}
10651067
10661068
@@ -1477,8 +1479,8 @@ def nyquist_response(
14771479
14781480def nyquist_plot (
14791481 data , omega = None , plot = None , label_freq = 0 , color = None , label = None ,
1480- return_contour = None , title = None , legend_loc = 'upper right' ,
1481- ax = None , ** kwargs ):
1482+ return_contour = None , title = None , legend_loc = 'upper right' , ax = None ,
1483+ unit_circle = False , mt_circles = None , ms_circles = None , ** kwargs ):
14821484 """Nyquist plot for a system.
14831485
14841486 Generates a Nyquist plot for the system over a (optional) frequency
@@ -1501,7 +1503,13 @@ def nyquist_plot(
15011503 ``omega_limits``.
15021504 color : string, optional
15031505 Used to specify the color of the line and arrowhead.
1504-
1506+ unit_circle : bool, optional
1507+ If ``True``, display the unit circle, to read gain crossover frequency.
1508+ mt_circles : array_like, optional
1509+ Draw circles corresponding to the given magnitudes of sensitivity.
1510+ ms_circles : array_like, optional
1511+ Draw circles corresponding to the given magnitudes of complementary
1512+ sensitivity.
15051513 **kwargs : :func:`matplotlib.pyplot.plot` keyword properties, optional
15061514 Additional keywords (passed to `matplotlib`)
15071515
@@ -1856,7 +1864,48 @@ def _parse_linestyle(style_name, allow_false=False):
18561864 # Mark the -1 point
18571865 plt .plot ([- 1 ], [0 ], 'r+' )
18581866
1859- # Label the frequencies of the points
1867+ #
1868+ # Draw circles for gain crossover and sensitivity functions
1869+ #
1870+ theta = np .linspace (0 , 2 * np .pi , 100 )
1871+ cos = np .cos (theta )
1872+ sin = np .sin (theta )
1873+ label_pos = 15
1874+
1875+ # Display the unit circle, to read gain crossover frequency
1876+ if unit_circle :
1877+ plt .plot (cos , sin , ** config .defaults ['nyquist.circle_style' ])
1878+
1879+ # Draw circles for given magnitudes of sensitivity
1880+ if ms_circles is not None :
1881+ for ms in ms_circles :
1882+ pos_x = - 1 + (1 / ms )* cos
1883+ pos_y = (1 / ms )* sin
1884+ plt .plot (
1885+ pos_x , pos_y , ** config .defaults ['nyquist.circle_style' ])
1886+ plt .text (pos_x [label_pos ], pos_y [label_pos ], ms )
1887+
1888+ # Draw circles for given magnitudes of complementary sensitivity
1889+ if mt_circles is not None :
1890+ for mt in mt_circles :
1891+ if mt != 1 :
1892+ ct = - mt ** 2 / (mt ** 2 - 1 ) # Mt center
1893+ rt = mt / (mt ** 2 - 1 ) # Mt radius
1894+ pos_x = ct + rt * cos
1895+ pos_y = rt * sin
1896+ plt .plot (
1897+ pos_x , pos_y ,
1898+ ** config .defaults ['nyquist.circle_style' ])
1899+ plt .text (pos_x [label_pos ], pos_y [label_pos ], mt )
1900+ else :
1901+ _ , _ , ymin , ymax = plt .axis ()
1902+ pos_y = np .linspace (ymin , ymax , 100 )
1903+ plt .vlines (
1904+ - 0.5 , ymin = ymin , ymax = ymax ,
1905+ ** config .defaults ['nyquist.circle_style' ])
1906+ plt .text (- 0.5 , pos_y [label_pos ], 1 )
1907+
1908+ # Label the frequencies of the points on the Nyquist curve
18601909 if label_freq :
18611910 ind = slice (None , None , label_freq )
18621911 omega_sys = np .imag (splane_contour [np .real (splane_contour ) == 0 ])
0 commit comments