4747import math
4848from .ctrlutil import unwrap
4949from .bdalg import feedback
50+ from .margins import stability_margins
5051
5152__all__ = ['bode_plot' , 'nyquist_plot' , 'gangof4_plot' ,
5253 'bode' , 'nyquist' , 'gangof4' ]
6061
6162# Bode plot
6263def bode_plot (syslist , omega = None , dB = None , Hz = None , deg = None ,
63- Plot = True , omega_limits = None , omega_num = None , * args , ** kwargs ):
64+ Plot = True , omega_limits = None , omega_num = None ,margins = None , * args , ** kwargs ):
6465 """Bode plot for a system
6566
6667 Plots a Bode plot for the system over a (optional) frequency range.
@@ -208,7 +209,7 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
208209 color = pltline [0 ].get_color ())
209210
210211 # Add a grid to the plot + labeling
211- ax_mag .grid (True , which = 'both' )
212+ ax_mag .grid (False if margins else True , which = 'both' )
212213 ax_mag .set_ylabel ("Magnitude (dB)" if dB else "Magnitude" )
213214
214215 # Phase plot
@@ -218,6 +219,50 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
218219 phase_plot = phase
219220 ax_phase .semilogx (omega_plot , phase_plot , * args , ** kwargs )
220221
222+ #show the phase and gain margins in the plot
223+ if margins :
224+ margin = stability_margins (sys )
225+ gm , pm , Wcg , Wcp = margin [0 ], margin [1 ], margin [3 ], margin [4 ]
226+ if pm >= 0. :
227+ phase_limit = - 180.
228+ else :
229+ phase_limit = 180.
230+
231+ ax_mag .axhline (y = 0 if dB else 1 , color = 'k' , linestyle = ':' )
232+ ax_phase .axhline (y = phase_limit if deg else math .radians (phase_limit ), color = 'k' , linestyle = ':' )
233+ mag_ylim = ax_mag .get_ylim ()
234+ phase_ylim = ax_phase .get_ylim ()
235+
236+ if pm != float ('inf' ) and Wcp != float ('nan' ):
237+ if dB :
238+ ax_mag .semilogx ([Wcp , Wcp ], [0 , - (10 ** 5. )], color = 'k' , linestyle = ':' )
239+ else :
240+ ax_mag .loglog ([Wcp ,Wcp ], [1 ,10. ** - 20. ],color = 'k' ,linestyle = ':' )
241+
242+ if deg :
243+ ax_phase .semilogx ([Wcp , Wcp ], [(10 ** 5. ) if phase_limit > 0. else 10. ** - 20. , phase_limit + pm ], color = 'k' , linestyle = ':' )
244+ ax_phase .semilogx ([Wcp , Wcp ], [phase_limit + pm , phase_limit ], color = 'k' , linestyle = '-' )
245+ else :
246+ ax_phase .semilogx ([Wcp , Wcp ], [10. ** - 20. , - math .pi + math .radians (pm )], color = 'k' , linestyle = ':' )
247+ ax_phase .semilogx ([Wcp , Wcp ], [- math .pi + math .radians (pm ), - math .pi ], color = 'k' , linestyle = '-' )
248+
249+ if gm != float ('inf' ) and Wcg != float ('nan' ):
250+ if dB :
251+ ax_mag .semilogx ([Wcg , Wcg ], [- 20. * np .log10 (gm ), - (10 ** 5. )], color = 'k' , linestyle = ':' )
252+ ax_mag .semilogx ([Wcg , Wcg ], [0 ,- 20 * np .log10 (gm )], color = 'k' , linestyle = '-' )
253+ else :
254+ ax_mag .semilogx ([Wcg , Wcg ], [1. / gm , 10. ** - 20. ], color = 'k' , linestyle = ':' )
255+ ax_mag .semilogx ([Wcg , Wcg ], [1. , 1. / gm ], color = 'k' , linestyle = '-' )
256+
257+ if deg :
258+ ax_phase .semilogx ([Wcg , Wcg ], [10. ** - 20. , phase_limit ], color = 'k' , linestyle = ':' )
259+ else :
260+ ax_phase .semilogx ([Wcg , Wcg ], [10. ** - 20. , - math .pi ], color = 'k' , linestyle = ':' )
261+
262+ ax_mag .set_ylim (mag_ylim )
263+ ax_phase .set_ylim (phase_ylim )
264+ plt .suptitle ('Gm = %.2f %s(at %.2f rad/s), Pm = %.2f %s (at %.2f rad/s)' % (20 * np .log10 (gm ) if dB else gm ,'dB' if dB else '\b ' ,Wcg ,pm if deg else math .degrees (pm ),'deg' if deg else 'rad' ,Wcp ))
265+
221266 if nyquistfrq_plot :
222267 ax_phase .axvline (nyquistfrq_plot , color = pltline [0 ].get_color ())
223268
@@ -236,7 +281,7 @@ def genZeroCenteredSeries(val_min, val_max, period):
236281 ylim = ax_phase .get_ylim ()
237282 ax_phase .set_yticks (genZeroCenteredSeries (ylim [0 ], ylim [1 ], math .pi / 4. ))
238283 ax_phase .set_yticks (genZeroCenteredSeries (ylim [0 ], ylim [1 ], math .pi / 12. ), minor = True )
239- ax_phase .grid (True , which = 'both' )
284+ ax_phase .grid (False if margins else True , which = 'both' )
240285 # ax_mag.grid(which='minor', alpha=0.3)
241286 # ax_mag.grid(which='major', alpha=0.9)
242287 # ax_phase.grid(which='minor', alpha=0.3)
0 commit comments