Chapter 17: Stability Margins and Classical Robustness Measures

Lesson 2: Gain and Phase Crossover Frequencies

In this lesson we formalize the notions of gain crossover frequency and phase crossover frequency for SISO linear time-invariant feedback systems. We connect these frequencies to gain and phase margins, derive analytical formulas for standard transfer-function structures, and present numerical algorithms and software implementations in Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica. Throughout, we assume familiarity with Bode plots, Nyquist plots, and stability margins from previous lessons.

1. Conceptual Overview of Crossover Frequencies

Consider a unity-feedback SISO control loop with controller \( C(s) \) and plant \( G(s) \). The open-loop transfer function is

\[ L(s) = C(s)G(s), \quad L(j\omega) = |L(j\omega)| e^{\,j \angle L(j\omega)}. \]

The frequency response \( L(j\omega) \) is summarized by its magnitude \( |L(j\omega)| \) and phase \( \angle L(j\omega) \). In Bode plots, we usually display:

  • The magnitude in decibels: \( 20\log_{10}|L(j\omega)| \).
  • The phase in degrees: \( \angle L(j\omega) \) (deg).

Two special frequencies are crucial for classical robustness analysis:

  • The gain crossover frequency \( \omega_{gc} \): frequency where the open-loop magnitude equals unity (0 dB).
  • The phase crossover frequency \( \omega_{pc} \): frequency where the open-loop phase is \(-180^\circ\) (i.e., \(-\pi\) radians).

Intuitively, \( \omega_{gc} \) is related to the closed-loop bandwidth and speed of the response, while \( \omega_{pc} \) is related to how much gain can be increased before encircling the Nyquist critical point \(-1+j0\). The gain and phase margins defined in Lesson 1 can be expressed directly in terms of these crossover frequencies, making them central design quantities.

flowchart TD
  P["Plant G(s)"] --- C["Controller C(s)"]
  C --> L["Open-loop L(s) = C(s) G(s)"]
  L --> FREQ["Frequency response L(jw)"]
  FREQ --> MAG["Magnitude |L(jw)|"]
  FREQ --> PH["Phase angle(L(jw))"]
  MAG --> GCF["Find w_gc where |L(jw_gc)| = 1"]
  PH --> PCF["Find w_pc where angle(L(jw_pc)) = -180 deg"]
  GCF --> MARG["Compute phase margin from angle at w_gc"]
  PCF --> MARG
  MARG --> DESIGN["Stability & robustness assessment"]
        

2. Formal Definitions and Relation to Stability Margins

Let \( L(s) \) be a proper, rational transfer function with no poles on the imaginary axis. For each real frequency \( \omega > 0 \), define:

\[ M(\omega) = |L(j\omega)|, \quad \phi(\omega) = \angle L(j\omega). \]

In general, \( M(\omega) \) and \( \phi(\omega) \) are continuous functions of \( \omega \) except at isolated singularities.

2.1 Gain Crossover Frequency

A gain crossover frequency is any solution \( \omega_{gc} > 0 \) of

\[ M(\omega_{gc}) = |L(j\omega_{gc})| = 1. \]

In decibels, this is the frequency where the magnitude Bode plot crosses the 0 dB line:

\[ 20\log_{10} M(\omega_{gc}) = 0 \text{ dB}. \]

There can be multiple such frequencies; in classical design we usually refer to the lowest positive solution as \( \omega_{gc} \), because it typically corresponds to the main closed-loop bandwidth.

2.2 Phase Crossover Frequency

A phase crossover frequency is any solution \( \omega_{pc} > 0 \) of

\[ \phi(\omega_{pc}) = \angle L(j\omega_{pc}) = -(2k+1)\pi, \quad k\in\mathbb{Z}. \]

In degrees this is \(-180^\circ + 360^\circ k\). Again, there may be several such frequencies; the principal one is usually the smallest \( \omega_{pc} > 0 \) at which the phase plot crosses \(-180^\circ\).

2.3 Gain and Phase Margins via Crossover Frequencies

For a unity-feedback loop with open-loop \( L(s) \) and closed-loop transfer function \( T(s) = \dfrac{L(s)}{1+L(s)} \), assume the open-loop is stable and the Nyquist contour does not pass directly through the critical point \(-1+j0\). The gain margin (GM) and phase margin (PM) can be expressed in terms of crossover frequencies:

\[ \mathrm{GM} = \frac{1}{|L(j\omega_{pc})|}, \quad \mathrm{PM} = \pi + \phi(\omega_{gc}) \quad \text{(radians)}. \]

In degrees:

\[ \mathrm{PM}(^\circ) = 180^\circ + \angle L(j\omega_{gc}) \text{ (deg)}. \]

The Nyquist criterion shows that, when the open-loop is stable, positive gain and phase margins are sufficient to guarantee closed-loop stability. Thus computing \( \omega_{gc} \) and \( \omega_{pc} \) accurately is essential.

3. Analytical Examples of Crossover Frequencies

For some simple transfer functions, the crossover frequencies can be obtained analytically. These examples build intuition that will guide numerical algorithms for more complicated plants.

3.1 First-Order System with Static Gain

Consider \( L(s) = \dfrac{K}{Ts + 1} \) with \( K > 0, T > 0 \). The frequency response is

\[ L(j\omega) = \frac{K}{1 + j\omega T}, \quad M(\omega) = |L(j\omega)| = \frac{K}{\sqrt{1 + (\omega T)^2}}, \quad \phi(\omega) = -\arctan(\omega T). \]

Gain crossover frequency

Solve \( M(\omega_{gc}) = 1 \):

\[ \frac{K}{\sqrt{1 + (\omega_{gc} T)^2}} = 1 \quad \Rightarrow \quad K^2 = 1 + (\omega_{gc} T)^2 \quad \Rightarrow \quad \omega_{gc} = \frac{\sqrt{K^2 - 1}}{T}. \]

This solution exists only if \( K > 1 \), which is intuitive: if the low-frequency magnitude is less than 0 dB, the magnitude Bode plot never crosses 0 dB.

Phase crossover frequency

The phase is strictly in \( (-\pi/2, 0) \) for all \( \omega > 0 \); thus, there is no phase crossover at \(-\pi\) for a first-order system. In other words, a pure first-order lag cannot produce a \(-180^\circ\) phase shift by itself.

3.2 Second-Order System with Extra Pole (Type-1)

Consider a typical open-loop form encountered in servo and robotic joint control:

\[ L(s) = \frac{K}{s(Ts + 1)}. \]

The frequency response is

\[ L(j\omega) = \frac{K}{j\omega (1 + j\omega T)}. \]

The magnitude and phase are:

\[ M(\omega) = |L(j\omega)| = \frac{K}{\omega \sqrt{1 + (\omega T)^2}}, \quad \phi(\omega) = -\frac{\pi}{2} - \arctan(\omega T). \]

Gain crossover frequency

Setting \( M(\omega_{gc}) = 1 \) gives

\[ \frac{K}{\omega_{gc} \sqrt{1 + (\omega_{gc} T)^2}} = 1 \quad \Rightarrow \quad K^2 = \omega_{gc}^2 \left(1 + (\omega_{gc} T)^2\right). \]

Letting \( x = \omega_{gc}^2 \), we obtain a quadratic equation

\[ x + T^2 x^2 - K^2 = 0. \]

The positive solution is

\[ x = \frac{-1 + \sqrt{1 + 4K^2 T^2}}{2T^2}, \quad \omega_{gc} = \sqrt{x} = \sqrt{\frac{-1 + \sqrt{1 + 4K^2 T^2}}{2T^2}}. \]

This closed-form expression shows that increasing \( K \) increases \( \omega_{gc} \), pushing the loop bandwidth to higher frequencies (faster response) but also moving the operating point into a region of larger phase lag, which reduces phase margin.

4. Relationship to Closed-Loop Bandwidth and Time-Domain Behavior

For many well-designed loops dominated by a pair of complex closed-loop poles, there is an approximate relationship between the gain crossover frequency and the closed-loop bandwidth \( \omega_b \). For typical phase margins in the range \( 30^\circ \) to \( 70^\circ \), one often finds

\[ \omega_b \approx \omega_{gc}, \]

meaning that \( \omega_{gc} \) is a good proxy for how quickly the system responds to step inputs.

For a standard second-order closed-loop transfer function \( T(s) \) with natural frequency \( \omega_n \) and damping ratio \( \zeta \), we know from earlier chapters that the percentage overshoot \( M_p \) is

\[ M_p = 100 \exp\!\left(\frac{-\pi \zeta}{\sqrt{1 - \zeta^2}}\right)\% \quad \text{for } 0 < \zeta < 1. \]

Meanwhile, for a broad class of loop shapes, the phase margin \( \mathrm{PM} \) is approximately a monotone decreasing function of the closed-loop overshoot. Roughly speaking,

  • Large phase margin \( \mathrm{PM} \gtrsim 60^\circ \) implies small overshoot.
  • Moderate phase margin \( \mathrm{PM} \approx 40^\circ \) implies moderate overshoot.
  • Very low phase margin \( \mathrm{PM} \lesssim 20^\circ \) often leads to oscillatory or nearly unstable behavior.

Thus, by controlling the crossover frequencies (through the controller design), we indirectly shape the bandwidth and time-domain performance while preserving sufficient stability margin.

5. Numerical Algorithms for Crossover Frequencies

For general rational transfer functions with multiple poles and zeros, analytic formulas for \( \omega_{gc} \) and \( \omega_{pc} \) are rarely available. Instead, we compute them numerically from sampled frequency-response data.

5.1 Discrete Frequency Grid and Search

Suppose we have a vector of logarithmically spaced frequencies \( \omega_i \), \( i = 0,\dots,N \), and corresponding samples \( L(j\omega_i) = M_i e^{j\phi_i} \). Define

\[ g_i = M_i - 1, \quad h_i = \phi_i + \pi. \]

Then \( g_i = 0 \) corresponds to the gain crossover, and \( h_i = 0 \) corresponds to the phase crossover (in radians).

A simple algorithm:

  1. Compute \( L(j\omega_i) \) on a dense logarithmic grid.
  2. Find indices \( i \) such that \( g_i \) and \( g_{i+1} \) have opposite signs. Use linear interpolation to approximate the root between \( \omega_i \) and \( \omega_{i+1} \). This gives candidates for \( \omega_{gc} \).
  3. Repeat with \( h_i \) to obtain candidates for \( \omega_{pc} \).
  4. Select the smallest positive roots as the primary gain and phase crossover frequencies.
flowchart TD
  A["Choose log-spaced frequency grid w_i"] --> B["Evaluate L(j w_i) for all i"]
  B --> C["Compute magnitude M_i and phase phi_i"]
  C --> D["Form g_i = M_i - 1, h_i = phi_i + 180deg"]
  D --> E["Locate sign changes of g_i and h_i"]
  E --> F["Linearly interpolate zero crossings to get w_gc, w_pc"]
  F --> G["Compute gain and phase margins from L(j w_gc), L(j w_pc)"]
        

This approach is standard in numerical control libraries and aligns with what Bode-plot routines internally perform when reporting gain and phase margins.

6. Python Implementation (Control and Robotics Context)

In Python, the python-control library provides utilities for transfer functions and frequency-response analysis. In robotics, such LTI models arise from linearization of rigid-body dynamics (e.g., single-joint servo loops), and python-control or roboticstoolbox-python are commonly used.

The following example computes \( \omega_{gc} \) and \( \omega_{pc} \) for \( L(s) = \dfrac{K}{s(Ts + 1)} \), which can model a position-controlled DC motor with PI-like behavior.


import numpy as np
import control as ct  # python-control library

# Example open-loop: L(s) = K / (s (T s + 1))
K = 10.0
T = 0.1
num = [K]
den = [T, 1.0, 0.0]  # s (T s + 1) = T s^2 + s

L = ct.TransferFunction(num, den)

# Frequency grid (logarithmic)
w = np.logspace(-1, 3, 2000)  # 0.1 rad/s to 1000 rad/s

# Frequency response
mag, phase, w = ct.freqresp(L, w)
mag = mag.flatten()
phase = phase.flatten()   # radians

# Helpers to approximate zero crossings of a sampled function
def zero_crossings(x):
    """Return indices i where x[i] and x[i+1] have opposite sign."""
    s = np.sign(x)
    return np.where(np.diff(s) != 0)[0]

def interp_root(w, x, i):
    """Linear interpolation of root between w[i], w[i+1]."""
    w1, w2 = w[i], w[i+1]
    x1, x2 = x[i], x[i+1]
    return w1 - x1 * (w2 - w1) / (x2 - x1)

# Gain crossover: |L(jw)| = 1
g = mag - 1.0
idx_gc = zero_crossings(g)
w_gc = None
if idx_gc.size > 0:
    i = idx_gc[0]
    w_gc = interp_root(w, g, i)

# Phase crossover: angle(L(jw)) = -pi (mod 2 pi)
# Wrap phase to (-pi, pi] and shift by +pi so zero crossings correspond to -pi
phase_wrapped = (phase + np.pi) % (2 * np.pi) - np.pi
h = phase_wrapped + np.pi    # h = 0 when phase_wrapped = -pi

idx_pc = zero_crossings(h)
w_pc = None
if idx_pc.size > 0:
    i = idx_pc[0]
    w_pc = interp_root(w, h, i)

print("Approximate gain crossover w_gc:", w_gc)
print("Approximate phase crossover w_pc:", w_pc)

# Gain and phase margins
if w_gc is not None:
    L_gc = ct.evalfr(L, 1j * w_gc)
    pm_rad = np.pi + np.angle(L_gc)
    print("Phase margin (deg) ~", pm_rad * 180.0 / np.pi)

if w_pc is not None:
    L_pc = ct.evalfr(L, 1j * w_pc)
    gm = 1.0 / abs(L_pc)
    print("Gain margin ~", gm, " (", 20 * np.log10(gm), " dB )")
      

In a robotic joint controller, L would typically be formed from the motor dynamics, gear train, and controller transfer function. The same procedure applies, provided the dynamics are approximately linear around the operating point.

7. C++ Implementation with Eigen (Robotics-Oriented)

C++ is widely used in robotics (e.g., within ROS and real-time control loops). Here we show a simple stand-alone implementation that evaluates \( L(j\omega) \) for a given transfer function \( L(s) = \dfrac{b_0 + b_1 s + \cdots + b_m s^m}{a_0 + a_1 s + \cdots + a_n s^n} \) and searches for crossover frequencies. Libraries such as Eigen facilitate complex arithmetic and linear algebra.


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

using std::complex;
using std::vector;
using std::cout;
using std::endl;

using dcomplex = complex<double>;

// Evaluate polynomial p(s) = c[0] + c[1] s + ... + c[N] s^N at s
dcomplex poly_eval(const vector<double>& c, dcomplex s) {
    dcomplex val(0.0, 0.0);
    dcomplex p(1.0, 0.0);
    for (double coeff : c) {
        val += coeff * p;
        p *= s;
    }
    return val;
}

int main() {
    // Example: L(s) = K / (s (T s + 1)) = K / (T s^2 + s)
    double K = 10.0;
    double T = 0.1;

    vector<double> num{K};           // b0
    vector<double> den{0.0, 1.0, T}; // a0 + a1 s + a2 s^2 = T s^2 + s

    // Logarithmic frequency grid
    int N = 2000;
    double w_min = 0.1;
    double w_max = 1000.0;
    vector<double> w(N);
    for (int i = 0; i < N; ++i) {
        double alpha = static_cast<double>(i) / (N - 1);
        w[i] = w_min * std::pow(w_max / w_min, alpha);
    }

    auto sign = [](double x) {
        if (x > 0.0) return 1;
        if (x < 0.0) return -1;
        return 0;
    };

    double w_gc = -1.0;
    double w_pc = -1.0;

    double prev_g = 0.0;
    double prev_h = 0.0;
    int prev_g_sign = 0;
    int prev_h_sign = 0;
    bool first = true;

    for (int i = 0; i < N; ++i) {
        dcomplex s(0.0, w[i]);
        dcomplex L = poly_eval(num, s) / poly_eval(den, s);
        double mag = std::abs(L);
        double phase = std::arg(L); // radians, in (-pi, pi]

        double g = mag - 1.0;
        double phase_wrapped = std::atan2(std::sin(phase), std::cos(phase));
        double h = phase_wrapped + M_PI; // zero at -pi

        int sg = sign(g);
        int sh = sign(h);

        if (!first) {
            if (w_gc < 0.0 && sg != 0 && sg != prev_g_sign && prev_g_sign != 0) {
                double t = prev_g / (prev_g - g);
                w_gc = w[i - 1] + t * (w[i] - w[i - 1]);
            }
            if (w_pc < 0.0 && sh != 0 && sh != prev_h_sign && prev_h_sign != 0) {
                double t = prev_h / (prev_h - h);
                w_pc = w[i - 1] + t * (w[i] - w[i - 1]);
            }
        } else {
            first = false;
        }

        prev_g = g;
        prev_h = h;
        prev_g_sign = sg;
        prev_h_sign = sh;
    }

    cout << "Approx gain crossover w_gc = " << w_gc << " rad/s" << endl;
    cout << "Approx phase crossover w_pc = " << w_pc << " rad/s" << endl;

    return 0;
}
      

In a ROS-based robotic controller (e.g., for a manipulator joint), the same logic can be wrapped in a diagnostic tool to report gain and phase margins for the current controller gains, enhancing safety and robustness analysis.

8. Java Implementation (Using Basic Arrays or Commons Math)

Java is sometimes used in robotics (e.g., FIRST Robotics). The following code sketches a simple frequency-response computation using complex arithmetic (no external libraries required, though libraries such as Apache Commons Math provide more robust complex-number support).


public class CrossoverFrequencies {

    public static class Complex {
        public final double re;
        public final 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 denom = other.re * other.re + other.im * other.im;
            return new Complex(
                (this.re * other.re + this.im * other.im) / denom,
                (this.im * other.re - this.re * other.im) / denom
            );
        }
        public double abs() {
            return Math.hypot(re, im);
        }
        public double arg() {
            return Math.atan2(im, re);
        }
    }

    // Evaluate polynomial c[0] + c[1] s + ... at s
    public static Complex polyEval(double[] c, Complex s) {
        Complex val = new Complex(0.0, 0.0);
        Complex p = new Complex(1.0, 0.0);
        for (double coeff : c) {
            val = new Complex(val.re + coeff * p.re, val.im + coeff * p.im);
            p = p.mul(s);
        }
        return val;
    }

    public static void main(String[] args) {
        double K = 10.0;
        double T = 0.1;
        double[] num = {K};
        double[] den = {0.0, 1.0, T}; // T s^2 + s

        int N = 2000;
        double wMin = 0.1;
        double wMax = 1000.0;
        double[] w = new double[N];
        for (int i = 0; i < N; ++i) {
            double alpha = (double) i / (double) (N - 1);
            w[i] = wMin * Math.pow(wMax / wMin, alpha);
        }

        double wGc = -1.0;
        double wPc = -1.0;

        double prevG = 0.0;
        double prevH = 0.0;
        int prevGSign = 0;
        int prevHSign = 0;
        boolean first = true;

        for (int i = 0; i < N; ++i) {
            Complex s = new Complex(0.0, w[i]);
            Complex L = polyEval(num, s).div(polyEval(den, s));
            double mag = L.abs();
            double phase = L.arg();

            double g = mag - 1.0;

            double phaseWrapped = Math.atan2(Math.sin(phase), Math.cos(phase));
            double h = phaseWrapped + Math.PI;

            int sg = (g > 0) ? 1 : (g < 0 ? -1 : 0);
            int sh = (h > 0) ? 1 : (h < 0 ? -1 : 0);

            if (!first) {
                if (wGc < 0.0 && sg != 0 && sg != prevGSign && prevGSign != 0) {
                    double t = prevG / (prevG - g);
                    wGc = w[i - 1] + t * (w[i] - w[i - 1]);
                }
                if (wPc < 0.0 && sh != 0 && sh != prevHSign && prevHSign != 0) {
                    double t = prevH / (prevH - h);
                    wPc = w[i - 1] + t * (w[i] - w[i - 1]);
                }
            } else {
                first = false;
            }

            prevG = g;
            prevH = h;
            prevGSign = sg;
            prevHSign = sh;
        }

        System.out.println("Approx gain crossover w_gc = " + wGc + " rad/s");
        System.out.println("Approx phase crossover w_pc = " + wPc + " rad/s");
    }
}
      

In Java-based robotics frameworks, one can embed similar routines in tuning utilities or monitoring dashboards for safety checks on controller parameters.

9. MATLAB / Simulink Implementation

MATLAB is a standard tool in control and robotics. The Control System Toolbox functions bode and margin directly provide crossover frequencies and stability margins. The following script computes \( \omega_{gc} \), \( \omega_{pc} \), GM, and PM:


% Parameters for L(s) = K / (s (T s + 1))
K = 10;
T = 0.1;
num = K;
den = [T 1 0];   % T s^2 + s

L = tf(num, den);

% Use margin to get gain and phase crossover frequencies
[GM, PM, w_pc, w_gc] = margin(L);

fprintf('Gain crossover w_gc = %.3f rad/s\n', w_gc);
fprintf('Phase crossover w_pc = %.3f rad/s\n', w_pc);
fprintf('Gain margin = %.3f (%.2f dB)\n', GM, 20*log10(GM));
fprintf('Phase margin = %.2f deg\n', PM);

% Bode plot with margins
figure;
margin(L);
grid on;
title('Open-loop Bode plot with gain/phase margins');

% Simulink hint:
% In a Simulink model of a robotic joint (plant + controller),
% 1) Linearize the model around an operating point using "linearize".
% 2) Use "bode" or "margin" on the resulting LTI system.
      

In robotics applications (e.g., with the Robotics System Toolbox), one typically derives the manipulator dynamics, linearizes the joint around a fixed configuration, and then computes margins to ensure robust performance under inertia and friction variations.

10. Wolfram Mathematica Implementation

Wolfram Mathematica supports symbolic and numerical frequency-response calculations. Below we demonstrate both:


(* Define transfer function L(s) = K / (s (T s + 1)) *)
K = 10.0;
T = 0.1;

L[s_] := K/(s (T s + 1));

(* Frequency response L(j w) *)
Lw[w_] := L[I w];

(* Magnitude and phase as functions of w *)
mag[w_] := Abs[Lw[w]];
phase[w_] := Arg[Lw[w]];  (* radians *)

(* Numerical search for gain crossover: mag(w_gc) == 1 *)
wgcSol = FindRoot[mag[w] == 1, {w, 10.0}];  (* initial guess 10 rad/s *)
wgc = w /. wgcSol;

(* Numerical search for phase crossover: phase(w_pc) == -Pi *)
wpcSol = FindRoot[phase[w] == -Pi, {w, 10.0}];
wpc = w /. wpcSol;

Print["Gain crossover w_gc = ", wgc];
Print["Phase crossover w_pc = ", wpc];

(* Gain and phase margins *)
Lgc = Lw[wgc];
Lpc = Lw[wpc];

gm = 1/Abs[Lpc];
pm = Pi + Arg[Lgc];  (* radians *)

Print["Gain margin GM = ", gm, "  (", 20 Log[10, gm], " dB)"];
Print["Phase margin PM (deg) = ", pm*180/Pi];
      

Mathematica is especially effective when exploring symbolic relationships between controller parameters (such as \( K \) and \( T \)) and crossover frequencies, providing insight before moving to numerical tuning.

11. Problems and Solutions

Problem 1 (Gain crossover for a type-1 loop): Consider the open-loop transfer function \( L(s) = \dfrac{K}{s(Ts + 1)} \) with \( K > 0 \) and \( T > 0 \). Derive the expression for the gain crossover frequency \( \omega_{gc} \) and the phase \( \phi(\omega_{gc}) \).

Solution:

We already computed in Section 3:

\[ M(\omega) = \frac{K}{\omega \sqrt{1 + (\omega T)^2}}, \quad \phi(\omega) = -\frac{\pi}{2} - \arctan(\omega T). \]

Setting \( M(\omega_{gc}) = 1 \) gives

\[ \frac{K}{\omega_{gc} \sqrt{1 + (\omega_{gc} T)^2}} = 1 \quad \Rightarrow \quad K^2 = \omega_{gc}^2 \left(1 + (\omega_{gc} T)^2\right). \]

Let \( x = \omega_{gc}^2 \). Then

\[ T^2 x^2 + x - K^2 = 0, \]

whose positive solution is

\[ x = \frac{-1 + \sqrt{1 + 4K^2 T^2}}{2T^2}, \quad \omega_{gc} = \sqrt{x} = \sqrt{\frac{-1 + \sqrt{1 + 4K^2 T^2}}{2T^2}}. \]

Substituting into the phase expression:

\[ \phi(\omega_{gc}) = -\frac{\pi}{2} - \arctan(\omega_{gc} T), \]

which is strictly less than \(-\pi/2\). As \( K \) increases, \( \omega_{gc} \) increases, and \( \phi(\omega_{gc}) \) becomes more negative, reducing the phase margin.


Problem 2 (Effect of loop gain on crossover frequency): Let \( L(s) = K L_0(s) \) with \( L_0(s) \) fixed and stable. Suppose \( M_0(\omega) = |L_0(j\omega)| \) is strictly decreasing in \( \omega \). Show that the gain crossover frequency \( \omega_{gc}(K) \) is a strictly increasing function of \( K \).

Solution:

The gain crossover condition is

\[ |K L_0(j\omega_{gc})| = 1 \quad \Leftrightarrow \quad K M_0(\omega_{gc}) = 1. \]

This can be written as

\[ M_0(\omega_{gc}) = \frac{1}{K}. \]

Since \( M_0(\omega) \) is strictly decreasing in \( \omega \), it is invertible. Let \( M_0^{-1} \) denote the inverse. Then

\[ \omega_{gc}(K) = M_0^{-1}\!\left(\frac{1}{K}\right). \]

As \( K \) increases, \( 1/K \) decreases. Because \( M_0^{-1} \) is strictly decreasing (inverse of a strictly decreasing function), it follows that \( \omega_{gc}(K) \) increases with \( K \). Thus higher loop gain shifts the gain crossover frequency to higher values.


Problem 3 (Gain margin from phase crossover): Let \( L(s) \) be stable, and suppose there is a unique phase crossover frequency \( \omega_{pc} > 0 \) such that \( \angle L(j\omega_{pc}) = -\pi \). Prove that increasing the loop gain \( K \) beyond the gain margin \( \mathrm{GM} = 1/|L(j\omega_{pc})| \) leads to closed-loop instability.

Solution:

Consider the scaled open-loop \( K L(s) \). At the phase crossover frequency \( \omega_{pc} \), the Nyquist point is

\[ K L(j\omega_{pc}) = K |L(j\omega_{pc})| e^{-j\pi} = -K |L(j\omega_{pc})|. \]

The Nyquist critical point is \( -1 + j0 \). The scaled open-loop passes through this point if

\[ -K |L(j\omega_{pc})| = -1 \quad \Leftrightarrow \quad K = \frac{1}{|L(j\omega_{pc})|} = \mathrm{GM}. \]

By the Nyquist stability criterion (with stable open-loop and no crossings of the real axis at the origin), increasing \( K \) beyond this value causes the Nyquist plot to encircle the point \(-1\), introducing at least one closed-loop pole in the right half-plane. Therefore, the closed-loop becomes unstable for \( K > \mathrm{GM} \).


Problem 4 (Numerical estimation of crossover frequencies): Suppose you have a table of frequency-response samples \( (\omega_i, M_i, \phi_i) \) with sufficiently dense sampling. Describe a linear interpolation method to approximate \( \omega_{gc} \) when the magnitude crosses unity between two points, and discuss the effect of grid density on the accuracy.

Solution:

Suppose \( M_i > 1 \) and \( M_{i+1} < 1 \). Assuming \( M(\omega) \) varies approximately linearly between \( \omega_i \) and \( \omega_{i+1} \), we approximate

\[ M(\omega) \approx M_i + \frac{M_{i+1} - M_i}{\omega_{i+1} - \omega_i}(\omega - \omega_i). \]

Setting \( M(\omega_{gc}) = 1 \) and solving for \( \omega_{gc} \):

\[ 1 = M_i + \frac{M_{i+1} - M_i}{\omega_{i+1} - \omega_i} (\omega_{gc} - \omega_i) \quad \Rightarrow \quad \omega_{gc} = \omega_i + (\omega_{i+1} - \omega_i)\frac{1 - M_i}{M_{i+1} - M_i}. \]

The accuracy of this approximation depends on:

  • The smoothness of \( M(\omega) \) near the crossing.
  • The spacing \( \omega_{i+1} - \omega_i \).

Increasing grid density (more closely spaced frequencies) reduces the interpolation error, but at the cost of more computations. Logarithmic spacing concentrates samples where dynamics change rapidly, giving good accuracy with moderate computational effort.

12. Summary

In this lesson, we rigorously defined the gain crossover frequency \( \omega_{gc} \) and phase crossover frequency \( \omega_{pc} \) for SISO LTI systems, and related them to the gain and phase margins introduced in Lesson 1 via the open-loop frequency response \( L(j\omega) \). Using analytic examples, we observed how increasing loop gain shifts \( \omega_{gc} \) to higher frequencies, trading robustness for faster response. We then developed numerical algorithms based on sampling and interpolation to compute crossover frequencies from Bode data, and implemented these algorithms in Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica. These tools form the basis for systematic robustness analysis and loop-shaping design in subsequent lessons.

13. References

  1. Bode, H. W. (1945). Network Analysis and Feedback Amplifier Design. Van Nostrand.
  2. Nyquist, H. (1932). Regeneration theory. Bell System Technical Journal, 11(1), 126–147.
  3. MacColl, L. A. (1945). Fundamental theory of servomechanisms. Bell System Technical Journal, 24(4), 555–618.
  4. 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.
  5. Freudenberg, J. S., & Looze, D. P. (1985). Right half plane poles and zeros and design tradeoffs in feedback systems. IEEE Transactions on Automatic Control, 30(6), 555–565.
  6. Astrom, K. J., & Hagglund, T. (1984). Automatic tuning of simple regulators with specifications on phase and amplitude margins. Automatica, 20(5), 645–651.
  7. Desoer, C. A., & Vidyasagar, M. (1975). Feedback Systems: Input-Output Properties. Academic Press.
  8. Middleton, R. H., & Goodwin, G. C. (1988). Improved finite word length characteristics in digital control using delta operators. IEEE Transactions on Automatic Control, 33(10), 947–958.