Skip to content

Commit d95ecf0

Browse files
committed
added margin display to the bode plots
1 parent 601b581 commit d95ecf0

File tree

1 file changed

+48
-3
lines changed

1 file changed

+48
-3
lines changed

control/freqplot.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import math
4848
from .ctrlutil import unwrap
4949
from .bdalg import feedback
50+
from .margins import stability_margins
5051

5152
__all__ = ['bode_plot', 'nyquist_plot', 'gangof4_plot',
5253
'bode', 'nyquist', 'gangof4']
@@ -60,7 +61,7 @@
6061

6162
# Bode plot
6263
def 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

Comments
 (0)