Chapter 14: Bode Plot Construction and Interpretation

Lesson 4: Approximate Bode Plot Construction by Hand

This lesson develops systematic procedures for constructing approximate Bode magnitude and phase plots by hand for rational transfer functions. We exploit logarithmic scaling, asymptotic behavior of standard factors, and superposition in the decibel domain to obtain accurate engineering approximations without dense numerical computation. These techniques are fundamental in classical loop-shaping and are widely used in robotics, mechatronics, and servo control.

1. Objectives and Preliminaries

We assume familiarity with sinusoidal steady-state response and the frequency response \( G(j\omega) \) from the previous chapter. Our goal is:

  • To express a transfer function in a factored standard form.
  • To derive asymptotic slopes and corner-frequency rules for each factor.
  • To construct approximate magnitude and phase Bode plots by hand.
  • To validate hand sketches using simple numerical evaluations and code.

For a proper rational transfer function with real coefficients, we can write (assuming no repeated complex factors for simplicity)

\[ G(s) = K \, s^{n_0} \prod_{i=1}^{N_z} \left(1 + \frac{s}{z_i}\right)^{n_i} \prod_{k=1}^{N_p} \left(1 + \frac{s}{p_k}\right)^{-m_k}, \]

where \(K \in \mathbb{R}\) is the static gain, \( z_i, p_k > 0 \) are (positive) real corner frequencies after shifting any negative real poles/zeros onto the negative real axis, and \( n_0, n_i, m_k \in \mathbb{Z} \). For complex-conjugate pairs we use a slightly different quadratic standard form (Section 3).

The Bode magnitude plot is the graph of

\[ L(\omega) = 20 \log_{10} \bigl|G(j\omega)\bigr| \]

versus \( \log_{10} \omega \), and the phase plot is \( \angle G(j\omega) \) (in degrees) versus the same logarithmic frequency axis.

2. Decibel Addition and Basic Slope Rules

A central simplification for hand construction is that logarithms convert products into sums. For two factors \( G(s) = G_1(s) G_2(s) \) we have

\[ 20 \log_{10} |G(j\omega)| = 20 \log_{10} |G_1(j\omega)| + 20 \log_{10} |G_2(j\omega)|. \]

Thus, we can:

  1. Construct Bode plots for elementary factors.
  2. Add their magnitudes in dB (algebraic sum).
  3. Add their phases (in degrees) to obtain the total phase.

For engineering accuracy, it suffices to use straight-line asymptotes, with small corrections near corner frequencies. The key basic slope rules (per real pole or zero) are:

  • Real zero at \( \omega = \omega_z \): +20 dB/decade slope in magnitude for \( \omega > \omega_z \), phase asymptotically approaching +90°.
  • Real pole at \( \omega = \omega_p \): −20 dB/decade slope in magnitude for \( \omega > \omega_p \), phase asymptotically approaching −90°.
  • Integrator \( \frac{1}{s} \): constant −20 dB/decade slope and −90° phase over all frequencies.
  • Differentiator \( s \): constant +20 dB/decade slope and +90° phase over all frequencies.

These slopes are derived from high- and low-frequency approximations of the magnitude of standard first-order factors, as shown next.

3. Asymptotic Behavior of Standard Real Factors

3.1 Gain and power of \( s \)

For a constant gain \( K \neq 0 \),

\[ G(s) = K \quad \Rightarrow \quad |G(j\omega)| = |K|, \quad L(\omega) = 20\log_{10}|K|. \]

The magnitude is a horizontal line at \( 20\log_{10}|K| \) dB; the phase is 0° if \( K > 0 \), and 180° if \( K < 0 \).

For a pure power of \( s \),

\[ G(s) = s^n \quad \Rightarrow \quad G(j\omega) = (j\omega)^n, \quad |G(j\omega)| = \omega^n. \]

Hence

\[ L(\omega) = 20 \log_{10} \omega^n = 20n \log_{10} \omega, \]

so the slope is \( 20n \) dB/decade everywhere. The phase is constant \( n \cdot 90^\circ \) because \( \angle(j\omega)^n = n\cdot90^\circ \).

3.2 First-order zero

Consider a first-order zero at \( -\omega_z \):

\[ G(s) = 1 + \frac{s}{\omega_z} \quad \Rightarrow \quad G(j\omega) = 1 + j\frac{\omega}{\omega_z}. \]

The magnitude is

\[ |G(j\omega)| = \sqrt{1 + \left(\frac{\omega}{\omega_z}\right)^2}. \]

For \( \omega \ll \omega_z \), \( |G(j\omega)| \approx 1 \), so \( L(\omega) \approx 0 \) dB (horizontal asymptote). For \( \omega \gg \omega_z \) we have \( |G(j\omega)| \approx \frac{\omega}{\omega_z} \) and

\[ L(\omega) \approx 20 \log_{10} \frac{\omega}{\omega_z} = 20\log_{10}\omega - 20\log_{10}\omega_z, \]

which is a straight line with slope +20 dB/decade. The phase is

\[ \angle G(j\omega) = \arctan\left(\frac{\omega}{\omega_z}\right), \]

increasing from 0° to 90°. The standard piecewise linear phase approximation is:

  • for \( \omega \leq \omega_z / 10 \).
  • Linear from 0° to 90° between \( \omega_z/10 \) and \( 10\omega_z \).
  • 90° for \( \omega \geq 10\omega_z \).

3.3 First-order pole

For a first-order pole at \( -\omega_p \):

\[ G(s) = \frac{1}{1 + \frac{s}{\omega_p}} \quad \Rightarrow \quad G(j\omega) = \frac{1}{1 + j\frac{\omega}{\omega_p}}. \]

Then

\[ |G(j\omega)| = \frac{1}{\sqrt{1 + \left(\frac{\omega}{\omega_p}\right)^2}}, \quad \angle G(j\omega) = -\arctan\left(\frac{\omega}{\omega_p}\right). \]

Asymptotically:

  • For \( \omega \ll \omega_p \): \( |G(j\omega)| \approx 1 \) (0 dB), phase ≈ 0°.
  • For \( \omega \gg \omega_p \): \( |G(j\omega)| \approx \frac{\omega_p}{\omega} \Rightarrow L(\omega) \approx -20\log_{10}\omega + 20\log_{10}\omega_p \), slope −20 dB/decade, phase ≈ −90°.

The piecewise linear phase approximation mirrors the zero, but with opposite sign.

4. Second-Order Factors and Damping

A standard underdamped second-order denominator is

\[ G(s) = \frac{\omega_n^2}{s^2 + 2 \zeta \omega_n s + \omega_n^2}, \]

where \( \omega_n \) is the natural frequency and \( \zeta \) the damping ratio. Evaluated at \( s = j\omega \):

\[ G(j\omega) = \frac{\omega_n^2}{-\omega^2 + j 2 \zeta \omega_n \omega + \omega_n^2}. \]

The magnitude and phase are

\[ |G(j\omega)| = \frac{\omega_n^2} {\sqrt{\left(\omega_n^2 - \omega^2\right)^2 + \left(2 \zeta \omega_n \omega\right)^2}}, \]

\[ \angle G(j\omega) = - \arctan\left( \frac{2 \zeta \omega_n \omega} {\omega_n^2 - \omega^2} \right). \]

Asymptotically:

  • For \( \omega \ll \omega_n \): \( |G(j\omega)| \approx 1 \) (0 dB), phase ≈ 0°.
  • For \( \omega \gg \omega_n \): \( |G(j\omega)| \approx \omega_n^2 / \omega^2 \) (−40 dB/decade) and phase ≈ −180°.

Thus a second-order pole contributes −40 dB/decade beyond \( \omega_n \) and a phase drop from 0° to −180°. As with first-order factors, a practical piecewise linear approximation uses:

  • 0° phase for \( \omega \leq \omega_n / 10 \).
  • Linear drop to −180° between \( \omega_n/10 \) and \( 10\omega_n \).
  • −180° for \( \omega \geq 10\omega_n \).

For small damping \( \zeta < 1/\sqrt{2} \), there is a resonant peak near \( \omega \approx \omega_n \sqrt{1 - 2\zeta^2} \). The straight-line approximation neglects this peak but is sufficiently accurate for many design tasks.

5. Algorithmic Procedure for Approximate Bode Plot

We now summarize the step-by-step algorithm to sketch the Bode plot by hand for a given transfer function \( G(s) \).

flowchart TD
  A["Start: G(s) given"] --> B["Factor G(s) into K, s^n, first-order and second-order terms"]
  B --> C["Compute corner frequencies: omega_c = 1/tau, omega_n etc."]
  C --> D["Sketch magnitude: sum asymptotic lines (slopes +-20, +-40 dB/dec)"]
  D --> E["Add corner frequency 'kinks' at each pole/zero"]
  E --> F["Sketch phase: piecewise linear approx for each factor"]
  F --> G["Superimpose all factors: add magnitudes and phases"]
  G --> H["Optionally refine near corners (e.g., +-3 dB corrections)"]
        

More explicitly:

  1. Normalize factors. Express each real pole/zero as \( 1 + s/\omega_c \) or \( 1 + s / (2 \zeta \omega_n) + \dots \) so that corner frequencies are explicit.
  2. DC gain. Evaluate \( G(0) \) (if defined) to locate the starting magnitude at low frequencies.
  3. Identify corner frequencies. Compute each \( \omega_c \) from \( 1 + s/\omega_c \) and each \( \omega_n \) from second-order factors; mark them on the log-frequency axis.
  4. Magnitude asymptotes. From very low \( \omega \), use the slope implied by integrators/differentiators and any low-frequency poles/zeros; then change slope by ±20 dB/decade at each real pole/zero and by ±40 dB/decade at each second-order pole/zero.
  5. Phase asymptotes. For each factor, use the piecewise approximation over two decades around its corner, then sum the individual phase contributions.
  6. Refinement. If higher accuracy is needed, evaluate \( |G(j\omega)| \) numerically at a few key frequencies (e.g., corners and mid-decade) and adjust the straight lines slightly.

6. Worked Example in Detail

Consider the transfer function

\[ G(s) = 100 \frac{s + 10}{s(s + 1)(s + 100)}. \]

This structure is typical for servo loops in robotics and motion control (e.g., position control of a motor axis). We convert it to normalized factors:

\[ G(s) = 100 \cdot \frac{1 + \frac{s}{10}}{s \left(1 + s\right)\left(1 + \frac{s}{100}\right)}. \]

The elementary factors are:

  • Gain: \( K = 100 \).
  • Integrator: \( 1/s \).
  • Real pole at 1 rad/s: \( 1/(1 + s) \Rightarrow \omega_p = 1 \).
  • Real pole at 100 rad/s: \( 1/(1 + s/100) \Rightarrow \omega_p = 100 \).
  • Real zero at 10 rad/s: \( 1 + s/10 \Rightarrow \omega_z = 10 \).

6.1 Magnitude asymptotic construction

Step 1: Starting point. For very low frequency \( \omega \rightarrow 0 \), the zero and finite poles behave as constants, but the integrator dominates:

\[ |G(j\omega)| \approx 100 \cdot \frac{1}{\omega} \Rightarrow L(\omega) \approx 20\log_{10}(100) - 20\log_{10}\omega. \]

Since \( 20\log_{10}(100) = 40 \) dB, the low-frequency magnitude is a straight line with slope −20 dB/decade.

Step 2: Corner frequencies and slope changes. The corner frequencies in ascending order are:

  • \( \omega = 1 \) (pole),
  • \( \omega = 10 \) (zero),
  • \( \omega = 100 \) (pole).

As we cross each:

  • At \( \omega = 1 \): a pole contributes an extra −20 dB/decade, so the slope changes from −20 to −40 dB/decade.
  • At \( \omega = 10 \): a zero contributes +20 dB/decade, so the slope changes from −40 to −20 dB/decade.
  • At \( \omega = 100 \): a pole contributes another −20 dB/decade, so the slope changes from −20 to −40 dB/decade.
flowchart TD
  S["Initial slope = -20 dB/dec (integrator)"] --> C1["Cross pole at 1 rad/s: slope -40 dB/dec"]
  C1 --> C2["Cross zero at 10 rad/s: slope -20 dB/dec"]
  C2 --> C3["Cross pole at 100 rad/s: slope -40 dB/dec"]
        

6.2 Phase asymptotic construction

We list phase contributions for each factor:

  • Gain \( 100 \): 0°.
  • Integrator \( 1/s \): −90° at all frequencies.
  • Pole at 1: from 0° to −90° between 0.1 and 10 rad/s.
  • Zero at 10: from 0° to +90° between 1 and 100 rad/s.
  • Pole at 100: from 0° to −90° between 10 and 1000 rad/s.

At very low frequency (say \( \omega = 0.01 \)), the total asymptotic phase is dominated by the integrator, ≈ −90°. At very high frequency (say \( \omega = 1000 \)), the poles at 1 and 100 each contribute about −90°, the zero at 10 contributes about +90°, and the integrator −90°, yielding roughly −180° total.

A precise hand sketch overlays these piecewise linear contributions on a common log-frequency axis and adds them algebraically.

7. Python Implementation (Robotics-Oriented)

In robotics, Python is frequently used for rapid prototyping of control loops (often alongside frameworks such as ROS). For frequency response analysis, packages like python-control are common, but here we implement the asymptotic approximation directly to mirror the hand-sketch procedure.


import numpy as np

def bode_asymptotic_real(omega, K, zeros, poles, n_int=0, n_diff=0):
    """
    Approximate Bode magnitude (dB) and phase (deg) for
    G(s) = K * s**n_diff / s**n_int
           * prod(1 + s/z_i) / prod(1 + s/p_k),
    where zeros, poles are lists of real corner frequencies (rad/s).
    """
    omega = np.asarray(omega, dtype=float)
    logw = np.log10(omega)

    # Magnitude in dB: start with gain contribution
    mag_db = 20.0 * np.log10(abs(K)) * np.ones_like(omega)

    # Integrator / differentiator contributions
    # 1/s raises -20 dB/decade, s raises +20 dB/decade
    mag_db += 20.0 * (n_diff - n_int) * logw

    # Phase in degrees
    phase_deg = np.zeros_like(omega)
    if K < 0:
        phase_deg += 180.0
    phase_deg += 90.0 * (n_diff - n_int)

    def phase_piecewise_first_order(omega, wc, sign):
        """
        sign = +1 for zero, -1 for pole.
        Piecewise linear phase approximation:
        0 deg for w <= wc/10,
        +/-90 deg for w >= 10*wc,
        linear in between.
        """
        ph = np.zeros_like(omega)
        w1 = wc / 10.0
        w2 = 10.0 * wc

        # region w <= w1: 0 deg
        # region w >= w2: +/-90 deg
        ph[omega >= w2] = sign * 90.0

        # linear region
        mask = (omega > w1) & (omega < w2)
        # fraction in [0, 1]
        frac = (np.log10(omega[mask]) - np.log10(w1)) / (np.log10(w2) - np.log10(w1))
        ph[mask] = sign * 90.0 * frac
        return ph

    # Real zeros
    for wz in zeros:
        # magnitude: +20 dB/decade beyond wz
        mag_db += 20.0 * np.maximum(0.0, np.log10(omega / wz))
        # phase
        phase_deg += phase_piecewise_first_order(omega, wz, +1.0)

    # Real poles
    for wp in poles:
        # magnitude: -20 dB/decade beyond wp
        mag_db -= 20.0 * np.maximum(0.0, np.log10(omega / wp))
        # phase
        phase_deg += phase_piecewise_first_order(omega, wp, -1.0)

    return mag_db, phase_deg

if __name__ == "__main__":
    # Example: G(s) = 100 (s + 10) / (s (s + 1) (s + 100))
    K = 100.0
    zeros = [10.0]
    poles = [1.0, 100.0]
    n_int = 1    # one integrator
    n_diff = 0

    w = np.logspace(-2, 3, 200)
    mag_db, phase_deg = bode_asymptotic_real(w, K, zeros, poles, n_int, n_diff)

    import matplotlib.pyplot as plt

    plt.figure()
    plt.semilogx(w, mag_db)
    plt.xlabel("omega [rad/s]")
    plt.ylabel("Magnitude [dB]")
    plt.grid(True, which="both")

    plt.figure()
    plt.semilogx(w, phase_deg)
    plt.xlabel("omega [rad/s]")
    plt.ylabel("Phase [deg]")
    plt.grid(True, which="both")

    plt.show()
      

This function mirrors precisely the hand-sketch algorithm, making it easy to embed approximate Bode reasoning into Python-based robotics control pipelines.

8. C++ Implementation (Using std::complex)

In embedded robotics controllers, C++ is widely used. Below is a minimal implementation that evaluates the exact frequency response and computes its Bode magnitude/phase, which can then be compared with the hand-crafted asymptotes.


#include <iostream>
#include <vector>
#include <complex>
#include <cmath>

struct RealFactorBode {
    double K;
    int n_int;                    // integrators (1/s)
    int n_diff;                   // differentiators (s)
    std::vector<double> zeros;   // w_z
    std::vector<double> poles;   // w_p

    std::complex<double> G(std::complex<double> s) const {
        std::complex<double> val = K;
        // differentiators
        for (int i = 0; i < n_diff; ++i)
            val *= s;
        // integrators
        for (int i = 0; i < n_int; ++i)
            val /= s;
        // real zeros
        for (double wz : zeros)
            val *= (1.0 + s / wz);
        // real poles
        for (double wp : poles)
            val /= (1.0 + s / wp);
        return val;
    }
};

int main() {
    RealFactorBode sys;
    sys.K = 100.0;
    sys.n_int = 1;
    sys.n_diff = 0;
    sys.zeros = {10.0};
    sys.poles = {1.0, 100.0};

    std::vector<double> omega;
    for (int k = -2; k <= 3; ++k) {
        // 10 points per decade
        for (int j = 0; j < 10; ++j) {
            double exp10 = k + j / 10.0;
            omega.push_back(std::pow(10.0, exp10));
        }
    }

    for (double w : omega) {
        std::complex<double> s(0.0, w);
        std::complex<double> Gjw = sys.G(s);
        double mag = std::abs(Gjw);
        double mag_db = 20.0 * std::log10(mag);
        double phase = std::arg(Gjw) * 180.0 / M_PI;
        std::cout << w << " " << mag_db << " " << phase << "\n";
    }
    return 0;
}
      

The RealFactorBode struct can be extended with second-order factors and used in robotics control stacks that run on microcontrollers or real-time PCs.

9. Java Implementation

Java is sometimes used for high-level simulation or teaching tools. The following class evaluates the same transfer function on a grid of frequencies.


public class BodeExample {

    public static class Complex {
        public double re;
        public double im;

        public Complex(double re, double im) {
            this.re = re;
            this.im = im;
        }

        public Complex add(Complex other) {
            return new Complex(this.re + other.re, this.im + other.im);
        }

        public Complex mul(Complex other) {
            return new Complex(
                this.re * other.re - this.im * other.im,
                this.re * other.im + this.im * other.re
            );
        }

        public Complex div(Complex other) {
            double den = other.re * other.re + other.im * other.im;
            return new Complex(
                (this.re * other.re + this.im * other.im) / den,
                (this.im * other.re - this.re * other.im) / den
            );
        }

        public double abs() {
            return Math.hypot(re, im);
        }

        public double arg() {
            return Math.atan2(im, re);
        }
    }

    public static Complex G(Complex s) {
        // G(s) = 100 (s + 10) / (s (s + 1) (s + 100))
        Complex K = new Complex(100.0, 0.0);
        Complex num = s.add(new Complex(10.0, 0.0));
        Complex den = s.mul(s.add(new Complex(1.0, 0.0)))
                      .mul(s.add(new Complex(100.0, 0.0)));
        return K.mul(num).div(den);
    }

    public static void main(String[] args) {
        for (int k = -2; k <= 3; ++k) {
            for (int j = 0; j < 10; ++j) {
                double exp10 = k + j / 10.0;
                double w = Math.pow(10.0, exp10);
                Complex s = new Complex(0.0, w);
                Complex Gjw = G(s);

                double mag = Gjw.abs();
                double magDb = 20.0 * Math.log10(mag);
                double phase = Gjw.arg() * 180.0 / Math.PI;

                System.out.printf("%.4f %.3f %.3f%n", w, magDb, phase);
            }
        }
    }
}
      

Once the basic complex arithmetic is implemented, alternative transfer functions can be used to test approximate hand sketches for teaching or controller design exercises.

10. MATLAB/Simulink and Wolfram Mathematica

10.1 MATLAB/Simulink

MATLAB and Simulink are standard tools in control and robotics. For the same example, MATLAB can both produce exact Bode plots and overlay the hand-derived asymptotes.


% Define transfer function
s = tf('s');
G = 100 * (s + 10) / (s * (s + 1) * (s + 100));

% Exact Bode plot
w = logspace(-2, 3, 200);
[mag, phase] = bode(G, w);
mag = squeeze(mag);
phase = squeeze(phase);

% Approximate magnitude using slope rules
mag_db_approx = 20*log10(100) - 20*log10(w);  % integrator + gain

% Adjust slopes at corners:
% Pole at 1 rad/s
idx = w >= 1;
mag_db_approx(idx) = mag_db_approx(idx) - 20*log10(w(idx) / 1);

% Zero at 10 rad/s
idx = w >= 10;
mag_db_approx(idx) = mag_db_approx(idx) + 20*log10(w(idx) / 10);

% Pole at 100 rad/s
idx = w >= 100;
mag_db_approx(idx) = mag_db_approx(idx) - 20*log10(w(idx) / 100);

figure;
semilogx(w, 20*log10(mag), 'LineWidth', 1.5); hold on;
semilogx(w, mag_db_approx, '--', 'LineWidth', 1.5);
grid on;
xlabel('omega [rad/s]');
ylabel('Magnitude [dB]');
legend('Exact', 'Approximate');

% Phase (exact from bode)
figure;
semilogx(w, phase, 'LineWidth', 1.5);
grid on;
xlabel('omega [rad/s]');
ylabel('Phase [deg]');
title('Phase of G(s)');
      

In Simulink, one can implement the transfer function via blocks (Gain, Integrator, Transfer Fcn) and use the Bode Plot tool in the Linear Analysis toolbox to verify the hand approximation.

10.2 Wolfram Mathematica

Mathematica enables symbolic manipulation of frequency response and plotting:


(* Define transfer function G(s) *)
Clear[s, w];
G[s_] := 100 (s + 10)/(s (s + 1) (s + 100));

(* Frequency response G(j w) *)
Gj[w_] := G[I w];

mag[w_] := Abs[Gj[w]];
phase[w_] := Arg[Gj[w]] * 180/Pi;

wgrid = LogSpace[-2, 3, 200]; (* define a helper for log grid *)
LogSpace[a_, b_, n_] := 10^Subdivide[a, b, n - 1];

ListLogLinearPlot[
  {Transpose[{wgrid, 20 Log10[mag /@ wgrid]}]},
  Frame -> True,
  FrameLabel -> {"omega [rad/s]", "Magnitude [dB]"},
  PlotLegends -> {"Exact"},
  GridLines -> Automatic
]

ListLogLinearPlot[
  {Transpose[{wgrid, phase /@ wgrid}]},
  Frame -> True,
  FrameLabel -> {"omega [rad/s]", "Phase [deg]"},
  PlotLegends -> {"Exact"},
  GridLines -> Automatic
]
      

Symbolic capabilities can also be used to factor transfer functions and automatically derive corner frequencies, which supports teaching and analysis of Bode approximations.

11. Problems and Solutions

Problem 1 (Simple first-order system): Consider \( G(s) = \dfrac{10}{1 + s} \). Construct the approximate Bode magnitude plot by hand and compute the asymptotic magnitude at \( \omega = 0.1, 1, 10 \) rad/s.

Solution:

Normalize: \( G(s) = 10 / (1 + s) \). The elements are gain \( K = 10 \) and a real pole at \( \omega_p = 1 \).

  • Gain: 20 log10(10) = 20 dB (horizontal).
  • Low-frequency asymptote: 20 dB (since the pole is not active yet).
  • At \( \omega = 1 \): slope changes from 0 to −20 dB/decade.

Approximate values:

  • \( \omega = 0.1 < \omega_p \): magnitude ≈ 20 dB.
  • \( \omega = 1 \): still ≈ 20 dB on the asymptote (true value is about 3 dB lower).
  • \( \omega = 10 \): one decade above the pole, so magnitude is approximately \( 20 - 20 \times 1 = 0 \) dB.

Exact magnitudes can be checked: \( |G(j0.1)| = \tfrac{10}{\sqrt{1 + 0.1^2}} \approx 9.95 \) (≈ 20 dB), \( |G(j1)| \approx \tfrac{10}{\sqrt{2}} \approx 7.07 \) (≈ 16.99 dB), \( |G(j10)| \approx \tfrac{10}{\sqrt{101}} \approx 0.995 \) (≈ 0 dB).

Problem 2 (Effects of multiple real poles): For \( G(s) = \dfrac{100}{(1 + s)(1 + s/10)} \), determine:

  1. The low-frequency magnitude and slope.
  2. The slopes in each frequency region \( (0, 1), (1, 10), (10, \infty) \).

Solution:

Normalize: \( G(s) = 100 / \bigl((1 + s)(1 + s/10)\bigr) \).

  • Gain: \( K = 100 \Rightarrow 40 \) dB.
  • Poles at \( \omega_{p1} = 1 \) and \( \omega_{p2} = 10 \).

Low-frequency region \( \omega \ll 1 \): both poles behave as constants, so \( |G(j\omega)| \approx 100 \), magnitude 40 dB, slope 0 dB/decade.

Region \( 1 \leq \omega < 10 \): the pole at 1 is active, giving −20 dB/decade; the pole at 10 is still inactive. So slope is −20 dB/decade.

Region \( \omega \geq 10 \): both poles are active, so slope is −40 dB/decade.

Thus, the approximate magnitude plot is a horizontal line at 40 dB up to \( \omega = 1 \), then −20 dB/decade down to \( \omega = 10 \), then −40 dB/decade thereafter.

Problem 3 (Zero and integrator): Consider \( G(s) = \dfrac{s + 5}{s} \). Sketch the approximate Bode magnitude slope and phase at low and high frequencies.

Solution:

Normalize: \( G(s) = (1 + s/5)/s \). Elements:

  • Zero at \( \omega_z = 5 \).
  • Integrator \( 1/s \).

Magnitude slopes:

  • Integrator gives −20 dB/decade everywhere.
  • Zero at 5 adds +20 dB/decade for \( \omega > 5 \).

Therefore:

  • \( \omega \ll 5 \): slope = −20 dB/decade.
  • \( \omega \gg 5 \): zero compensates integrator slope, net slope ≈ 0 dB/decade.

Phase: integrator contributes −90°; zero contributes from 0° to +90° around \( \omega_z \). At very low frequency, total phase ≈ −90°. At very high frequency, the zero contributes ≈ +90°, so total phase ≈ 0°.

Problem 4 (Second-order factor): For \( G(s) = \dfrac{\omega_n^2}{s^2 + 2 \zeta \omega_n s + \omega_n^2} \) with \( \zeta = 0.3 \), determine the asymptotic low- and high-frequency slopes and phase, and discuss how the true magnitude differs from the straight line near \( \omega \approx \omega_n \).

Solution:

As shown earlier, the asymptotic behavior does not depend on \( \zeta \) (for \( \zeta > 0 \)):

  • \( \omega \ll \omega_n \): magnitude ≈ 0 dB, slope 0 dB/decade, phase ≈ 0°.
  • \( \omega \gg \omega_n \): magnitude ≈ −40 dB/decade, phase ≈ −180°.

For \( \zeta = 0.3 \), there is a resonant peak near \( \omega \approx \omega_n \sqrt{1 - 2\zeta^2} \). The straight-line approximation ignores this peak; in reality, the magnitude may briefly rise above 0 dB before decaying with −40 dB/decade. The phase also transitions more sharply around resonance than the straight piecewise line suggests.

Problem 5 (Factoring and slope table): Factor \( G(s) = \dfrac{50 (s + 2)}{(s + 0.5)(s + 20)} \) into normalized form and construct a table of magnitude slopes versus frequency regions.

Solution:

Normalize:

\[ G(s) = 50 \frac{1 + \frac{s}{2}}{\left(1 + 2s\right)\left(1 + \frac{s}{20}\right)}. \]

Corner frequencies:

  • Zero at \( \omega_z = 2 \).
  • Poles at \( \omega_{p1} = 0.5 \) (because \( 1 + 2s = 1 + s/0.5 \)) and \( \omega_{p2} = 20 \).

Regions and slopes (starting from low frequency, where slope = 0):

  • \( \omega < 0.5 \): slope = 0 dB/decade.
  • \( 0.5 \leq \omega < 2 \): one pole active → slope = −20 dB/decade.
  • \( 2 \leq \omega < 20 \): one pole and one zero active → net slope = 0 dB/decade.
  • \( \omega \geq 20 \): two poles, one zero active → net slope = −20 dB/decade.

This slope table is the backbone of the approximate magnitude Bode plot for this system.

12. Summary

In this lesson we developed a systematic procedure for constructing approximate Bode magnitude and phase plots by hand. By factoring transfer functions into standard gains, powers of \( s \), and first- and second-order factors, we obtained straight-line asymptotes whose slopes change in multiples of 20 dB/decade at corner frequencies. Phase plots were approximated using piecewise linear transitions over frequency decades around each corner.

We connected these analytical rules to numerical implementations in Python, C++, Java, MATLAB/Simulink, and Mathematica, emphasizing how approximate Bode ideas remain practically useful in modern robotics and mechatronic control design. These hand-construction skills will be used extensively in later lessons on Bode-based design, stability margins, and loop shaping.

13. References

  1. Bode, H.W. (1945). Network Analysis and Feedback Amplifier Design. Van Nostrand, New York.
  2. Evans, W.R. (1948). Graphical analysis of control systems. Transactions of the American Institute of Electrical Engineers, 67(1), 547–551.
  3. Black, H.S. (1934). Stabilized feedback amplifiers. Bell System Technical Journal, 13(1), 1–18.
  4. Nyquist, H. (1932). Regeneration theory. Bell System Technical Journal, 11(1), 126–147.
  5. Nichols, N.B. (1947). Stability and damping criteria for automatic control systems. Transactions of the American Institute of Electrical Engineers, 66(4), 280–286.
  6. MacColl, L.A. (1945). Fundamental theory of servomechanisms. Bell System Technical Journal, 24(1), 1–34.
  7. Zames, G. (1966). On the input-output stability of time-varying nonlinear feedback systems. Part I: Conditions derived using concepts of loop gain, conicity, and positivity. IEEE Transactions on Automatic Control, 11(2), 228–238.