8. Asymptotic Bode diagrams

One of the big advantages of Bode diagrams is that they are very easy to sketch out by hand (or, equivalently, to visualise mentally).

[1]:
import numpy
import matplotlib.pyplot as plt
%matplotlib inline
[2]:
omega = numpy.logspace(-2, 2, 1000)
s = 1j*omega

9. Systems with real poles

Let’s study the bode diagrams of systems of the form

\[\frac{K}{(\tau s + 1)^n}\]
[3]:
def annotated_bode(ax_gain, ax_phase, G, K, tau, order):
    high_freq_asymptote = K/(tau*omega)**order

    # Gain part
    ax_gain.loglog(omega, numpy.abs(G))
    ax_gain.axhline(K, color='grey')  # Rule 1
    ax_gain.loglog(omega, high_freq_asymptote, color='grey') # Rule 2
    ax_gain.axvline(1/tau, color='grey')  # Rule 2
    ax_gain.set_ylim([1e-2, 1e+1])
    ax_gain.set_ylabel('|G|')

    # Phase part
    ax_phase.axhline(0, color='grey')  # Rule 3
    ax_phase.semilogx(omega, numpy.unwrap(numpy.angle(G)))
    ax_phase.axhline(-numpy.pi/2*order, color='grey')  # Rule 4
    ax_phase.axvline(1/tau, color='grey')  # Rule 5
    ax_phase.set_ylim([-3*numpy.pi/2, 2*numpy.pi/2])
    ax_phase.set_ylabel(r'$\angle G$')
[4]:
def plotresponse(order=1, tau=1, K=1):
    G = K/(tau*s + 1)**order

    fig, [ax_gain, ax_phase] = plt.subplots(2, 1)
    annotated_bode(ax_gain, ax_phase, G, K, tau, order)
[5]:
from ipywidgets import interact
[6]:
interact(plotresponse, order=(-2, 3), tau=(0.1, 10), K=(-1., 2));

We see that we can construct a reasonable approximation by knowing a couple of things

  1. The gain (\(K\)) of the system defines the low frequency asymptote of the gain graph

  2. The high frequency asymptote of the gain is \(\frac{K}{(\omega\tau)^n}\). Effectively, on a loglog scale, this means we have -n/decade slope above frequencies of around \(1/\tau\)

  3. The low frequency phase asymptote is 0

  4. The high frequency phase asymptote is \(-n\pi/2\)

  5. The phase curve has an inflection at \(1/\tau\)

10. Systems with complex poles

Systems with complex poles show uniique frequency response behaviour. We will focus on the second order system shown below:

\[G = \frac{K}{\tau^2 s^2 + 2\tau\zeta s + 1}\]
[7]:
def plotresponse(K=1, tau=1, zeta=1):
    plt.figure(figsize=(15, 5))
    order = 2
    G = K/(tau**2*s**2 + 2*tau*zeta*s + 1)

    ax_gain = plt.subplot2grid((2, 2), (0, 0))
    ax_phase = plt.subplot2grid((2, 2), (1, 0))
    ax_complex = plt.subplot2grid((2, 2), (0, 1), rowspan=2)

    annotated_bode(ax_gain, ax_phase, G, K, tau, order)

    # poles
    poles = numpy.roots([tau**2, 2*tau*zeta, 1])
    ax_complex.scatter(poles.real, poles.imag)
    ax_complex.axhline(0)
    ax_complex.axvline(0)
    ax_complex.axis([-2, 2, -2, 2])
[8]:
interact(plotresponse, K=(0.1, 2), tau=(0.1, 2), zeta=(0., 1.1))
[8]:
<function __main__.plotresponse(K=1, tau=1, zeta=1)>

We see that the rules from before still hold, except that we start seeing the so-called “harmonic nose” emerge when \(\zeta<\sqrt{2}/2\approx{0.7}\). The maximum of the nose occurs at the resonant frequency of

\[\omega_r = \frac{\sqrt{1 - 2\zeta^2}}{\tau}\]

11. Dead time

The effect of dead time is to increase the phase lag indefinitely as a function of frequency. Delay has no effect on the gain of a system.

[9]:
D = 1
G = numpy.exp(-D*s)
[10]:
plt.semilogx(omega, numpy.unwrap(numpy.angle(G)))
[10]:
[<matplotlib.lines.Line2D at 0x117a944e0>]
../../_images/1_Dynamics_8_Frequency_domain_Asymptotic_Bode_diagrams_15_1.png