Chapter 17: Stability Margins and Classical Robustness Measures

Lesson 4: Practical Interpretation of Stability Margins

This lesson explains how gain margin, phase margin, and delay margin translate into concrete engineering judgements about robustness, allowable uncertainty, and time-domain performance. We connect the frequency-domain margins, already defined in previous lessons, to overshoot, damping, and delay sensitivity, and we illustrate their computation and use with software examples in Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica, with an emphasis on robotic motion/control loops.

1. From Loop Transfer Function to Practical Margins

In earlier chapters you have seen the standard unity-feedback configuration with plant \( P(s) \) and controller \( C(s) \). The open-loop transfer function is

\[ L(s) = C(s) P(s), \qquad T(s) = \frac{L(s)}{1 + L(s)} \]

Stability margins quantify how far the Nyquist (or Bode) curve of \( L(j\omega) \) is from the critical point \( -1 \), and therefore how much modeling error, gain variation, and extra phase lag (e.g. from delay) the closed loop can tolerate before losing stability.

Recall the standard definitions (introduced in the previous lessons of this chapter):

  • Gain margin (GM): Let \( \omega_{\mathrm{pc}} \) be the phase crossover frequency, where \( \arg L(j\omega_{\mathrm{pc}}) = -180^\circ \). The (linear) gain margin is

    \[ \mathrm{GM} = \frac{1}{\lvert L(j\omega_{\mathrm{pc}})\rvert}, \qquad \mathrm{GM}_{\mathrm{dB}} = 20 \log_{10}(\mathrm{GM}) \]

  • Phase margin (PM): Let \( \omega_{\mathrm{gc}} \) be the gain crossover frequency where \( \lvert L(j\omega_{\mathrm{gc}})\rvert = 1 \). The phase margin is

    \[ \mathrm{PM} = 180^\circ + \arg L(j\omega_{\mathrm{gc}}) \]

  • Delay margin (DM): The maximum additional delay \( \tau_{\mathrm{d}} \) that can be inserted into the loop before the closed loop becomes marginally stable.

Practically, you never choose a controller only to satisfy a mathematical stability condition. Instead, you want margins that are comfortably positive so that the closed-loop system:

  • survives parameter variations and unmodeled dynamics,
  • remains stable under modest delays (sensing, computation, communication), and
  • provides acceptable overshoot and settling time.
flowchart TD
  P["Plant model P(s)"] --> L["Open-loop L(s) = C(s) P(s)"]
  L --> FR["Frequency response |L(jw)|, angle(L(jw))"]
  FR --> M["Compute GM, PM, delay margin"]
  M --> TD["Relate to time-domain specs \n(overshoot, settling)"]
  M --> R["Relate to robustness \n(gain, delay, modeling error)"]
  TD --> D["Choose / tune controller C(s)"]
  R --> D
        

The rest of this lesson formalizes these qualitative links so that when you read statements like “this robot joint loop has PM \( \approx 55^\circ \) and GM \( \approx 9 \,\text{dB} \)”, you can immediately infer something concrete about the closed-loop behavior and robustness.

2. Gain Margin as Allowed Gain Variation

Suppose the controller has a nominal loop gain \( K_0 \) so that \( L_0(s) = K_0 L_{\mathrm{nom}}(s) \). The gain margin is defined in terms of the maximum gain factor before the Nyquist curve hits the critical point:

\[ \mathrm{GM} = \frac{K_{\max}}{K_0}, \qquad 0 < K < K_{\max} \quad \Rightarrow \quad \text{closed loop stable.} \]

Now suppose the true loop gain is \( K = K_0(1 + \delta_K) \), where \( \delta_K \) represents relative error due to actuator gain variation, friction changes, payload changes in a robot arm, and so on. Stability requires

\[ 0 < K_0(1 + \delta_K) < K_{\max} = \mathrm{GM}\,K_0 \quad \Rightarrow \quad 0 < 1 + \delta_K < \mathrm{GM}. \]

Hence the admissible range for positive gain errors is

\[ -1 < \delta_K < \mathrm{GM} - 1. \]

In other words, the gain margin directly quantifies how much multiplicative gain uncertainty you can tolerate.

In decibels, if \( \mathrm{GM}_{\mathrm{dB}} = 20\log_{10}(\mathrm{GM}) \), then \( \mathrm{GM} = 10^{\mathrm{GM}_{\mathrm{dB}} / 20} \), and the maximum relative gain increase is \( \delta_K^{\max} = 10^{\mathrm{GM}_{\mathrm{dB}} / 20} - 1 \). Typical numbers:

  • \( \mathrm{GM}_{\mathrm{dB}} \approx 6\,\text{dB} \Rightarrow \mathrm{GM} \approx 2 \): you can roughly double the loop gain.
  • \( \mathrm{GM}_{\mathrm{dB}} \approx 12\,\text{dB} \Rightarrow \mathrm{GM} \approx 4 \): you can roughly quadruple the loop gain.

For robotic manipulators, changing payload can dramatically alter effective inertia and friction. A gain margin of, say, \( 6\text{--}10 \,\text{dB} \) is often used as a conservative guideline so that the closed loop remains stable even when the arm is loaded with tools or objects heavier than those used during tuning.

3. Phase Margin, Damping, and Time Response

Phase margin is strongly correlated with the damping of the dominant closed-loop poles and therefore with overshoot and settling time. For a closed-loop transfer function whose dominant dynamics can be approximated by a standard second-order model,

\[ T(s) \approx \frac{\omega_n^2}{s^2 + 2\zeta \omega_n s + \omega_n^2}, \]

the unit-step overshoot is

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

In many “well-shaped” loops (single dominant resonant peak), empirical relationships between phase margin and damping ratio are observed. A frequently used qualitative mapping is:

Phase margin (PM) Approx. damping \( \zeta \) Approx. overshoot \( M_p \) Qualitative behavior
\( 20^\circ \text{--} 30^\circ \) \( \zeta \approx 0.2 \text{--} 0.3 \) \( 35\% \text{--} 50\% \) Fast but oscillatory, borderline comfort
\( 40^\circ \text{--} 50^\circ \) \( \zeta \approx 0.4 \text{--} 0.5 \) \( 15\% \text{--} 25\% \) Good compromise of speed and damping
\( 55^\circ \text{--} 65^\circ \) \( \zeta \approx 0.6 \text{--} 0.7 \) \( < 10\% \) Well damped but somewhat slower

These are rules of thumb, not exact equalities. They are nonetheless very useful: robot joint position loops with PM around \( 45^\circ\text{--}60^\circ \) tend to show a visually well-behaved step response: quick convergence to the target with limited overshoot and without prolonged ringing.

flowchart TD
  S["Measured margins"] --> A["GM <~ 3 dB or \nPM <~ 20 deg"]
  S --> B["GM ~ 6-12 dB and \nPM ~ 45-60 deg"]
  S --> C["GM >~ 12 dB and \nPM >~ 60 deg"]
  A --> A1["Very aggressive: \nfast but oscillatory"]
  B --> B1["Balanced: \nspeed vs robustness"]
  C --> C1["Conservative: robust but slower, \nnarrow bandwidth"]
        

When you tune a loop on real hardware (for example, a DC-motor-driven robot joint), you typically increase loop gain until oscillations appear, then back off to obtain a comfortable phase margin (often confirmed by a Bode analysis of \( L(j\omega) \)). Understanding the qualitative meaning of margins lets you interpret those Bode plots without having to simulating every possible step response.

4. Phase Margin and Delay Margin

A pure time delay \( \tau \) in the loop (from sensing, ADC/DAC, computation, or communication) multiplies the loop transfer function by \( \mathrm{e}^{-s \tau} \). At frequency \( \omega \) this contributes an additional phase lag \( -\omega \tau \) (radians), without changing the magnitude.

Consider the gain crossover frequency \( \omega_{\mathrm{gc}} \), where \( \lvert L(j\omega_{\mathrm{gc}})\rvert = 1 \). By definition,

\[ \arg L(j\omega_{\mathrm{gc}}) = -180^\circ + \mathrm{PM}. \]

Adding delay multiplies the loop transfer function by \( \mathrm{e}^{-j\omega \tau} \), so at \( \omega_{\mathrm{gc}} \) the new phase is

\[ \arg L(j\omega_{\mathrm{gc}}) - \omega_{\mathrm{gc}} \tau. \]

The closed loop becomes marginally stable when the phase margin is driven to zero:

\[ -180^\circ + \mathrm{PM} - \omega_{\mathrm{gc}} \tau_{\mathrm{d}} = -180^\circ \quad \Rightarrow \quad \omega_{\mathrm{gc}} \tau_{\mathrm{d}} = \mathrm{PM}_{\mathrm{rad}}, \]

where \( \mathrm{PM}_{\mathrm{rad}} \) is the phase margin in radians. Hence the delay margin is approximately

\[ \tau_{\mathrm{d}} \approx \frac{\mathrm{PM}_{\mathrm{rad}}}{\omega_{\mathrm{gc}}} = \frac{\mathrm{PM}_{\mathrm{deg}} \,\pi / 180}{\omega_{\mathrm{gc}}}. \]

This simple formula is extremely useful in practice. For example, if \( \mathrm{PM}_{\mathrm{deg}} = 45^\circ \) and \( \omega_{\mathrm{gc}} = 20 \,\text{rad/s} \), then

\[ \tau_{\mathrm{d}} \approx \frac{45 \cdot \pi / 180}{20} = \frac{\pi/4}{20} \approx 0.039 \,\text{s}. \]

The loop can tolerate approximately \( 40 \,\text{ms} \) of additional delay before becoming marginally stable. In robot control, this delay budget must cover sensor filtering, communication (e.g. field bus, Ethernet), and computation of the control law.

A larger phase margin at a fixed bandwidth (fixed \( \omega_{\mathrm{gc}} \)) therefore directly translates into a larger delay margin, i.e., more tolerance to delays and model phase errors. Conversely, pushing bandwidth too high for a fixed PM shrinks the delay margin and makes the loop fragile to even small computational or communication delays.

5. Example: Robot Joint with P Controller

Consider a simplified single-joint model of a rigid robot arm around a fixed configuration. Let \( \theta(t) \) be the joint angle and \( v(t) \) the motor voltage. A standard linearized model is

\[ P(s) = \frac{\Theta(s)}{V(s)} = \frac{K}{J s^2 + B s}, \]

where \( J > 0 \) is the equivalent inertia, \( B > 0 \) the viscous friction, and \( K > 0 \) a gain constant. Use a proportional controller \( C(s) = K_p \) and unity feedback. Then

\[ L(s) = C(s) P(s) = \frac{K_p K}{J s^2 + B s}. \]

We can compute its Bode plot and stability margins, and then inspect the closed-loop step response \( \theta(t) \) to see how GM and PM manifest as overshoot and damping. The software examples below do exactly this for typical parameter values (e.g. \( J = 0.01 \), \( B = 0.1 \), \( K = 1 \)).

In a more realistic robot controller one would add integral and derivative action, and possibly nested current/velocity loops. However, the basic interpretation of margins carries over: they still measure how close the Nyquist curve of the full loop transfer function is to the critical point.

6. Python Implementation – Margins for a Robot Joint Loop

In Python, the python-control library provides convenient functions margin and bode_plot. Robotics-oriented toolboxes such as roboticstoolbox can provide more detailed robot models, which you can then connect to python-control for loop analysis.


import numpy as np
import matplotlib.pyplot as plt

# Core control library
import control  # pip install control

# (Optional) robotics toolbox for realistic robot models
# import roboticstoolbox as rtb

# Robot joint parameters (simplified)
J = 0.01   # inertia
B = 0.1    # viscous friction
K = 1.0    # gain from voltage to torque*gear etc.

Kp = 20.0  # proportional gain to be tuned

# Continuous-time transfer functions
s = control.TransferFunction.s
P = K / (J * s**2 + B * s)  # plant
C = Kp                     # P controller
L = C * P                  # open loop
T = control.feedback(L, 1) # closed loop (unity feedback)

# Compute stability margins
gm, pm, w_pc, w_gc = control.margin(L)
gm_db = 20 * np.log10(gm)

print(f"Gain margin (linear): {gm:.2f}")
print(f"Gain margin (dB):    {gm_db:.2f}")
print(f"Phase margin (deg):  {pm:.2f}")
print(f"Phase crossover w_pc (rad/s): {w_pc:.2f}")
print(f"Gain crossover w_gc  (rad/s): {w_gc:.2f}")

# Approximate delay margin from phase margin
pm_rad = pm * np.pi / 180.0
tau_d = pm_rad / w_gc
print(f"Approximate delay margin tau_d ~ {tau_d:.4f} s")

# Bode plot with margins overlaid
mag, phase, w = control.bode_plot(
    L,
    dB=True,
    Hz=False,
    omega_limits=(0.1, 1e3),
    margins=True,   # draws lines for GM/PM
    grid=True
)

# Closed-loop step response
t, y = control.step_response(T)
plt.figure()
plt.plot(t, y)
plt.xlabel("t [s]")
plt.ylabel("theta(t) [rad]")
plt.title("Closed-loop step response of robot joint (P control)")
plt.grid(True)

plt.show()
      

By changing Kp you can observe how GM, PM, and the step response change. For a practical robot joint controller, you would tune Kp (and possibly I and D gains) to achieve, for example, PM around \( 55^\circ \) and GM around \( 8\text{--}10 \,\text{dB} \), corresponding to well-damped but responsive motion.

7. C++ Implementation – Numerical Margins with Eigen and Robotics Libraries

In C++, robotics projects often rely on Eigen for linear algebra and specialized libraries such as the Robotics Library (RL) or the Control Toolbox (CT) for modeling and control of complex robots. Here we implement a minimal numerical Bode and margin computation for the same robot joint model, using only the C++ standard library. The same function L(s) could later be replaced by a more sophisticated model coming from RL or CT.


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

// Robot joint parameters
const double J = 0.01;
const double B = 0.1;
const double K = 1.0;
double Kp = 20.0;

// Open-loop transfer L(s) = (Kp*K) / (J s^2 + B s)
std::complex<double> L_of_jw(double w) {
    std::complex<double> s(0.0, w);
    std::complex<double> num(Kp * K, 0.0);
    std::complex<double> den = J * s * s + B * s;
    return num / den;
}

int main() {
    // Log-spaced frequency grid
    const int N = 2000;
    const double w_min = 0.1;
    const double w_max = 1000.0;

    double gm = std::numeric_limits<double>::infinity();
    double pm = -1e9;
    double w_pc = 0.0, w_gc = 0.0;

    bool found_pc = false, found_gc = false;

    double w_prev = w_min;
    std::complex<double> L_prev = L_of_jw(w_prev);
    double mag_prev = std::abs(L_prev);
    double phase_prev = std::arg(L_prev); // radians

    for (int i = 1; i < N; ++i) {
        double alpha = static_cast<double>(i) / (N - 1);
        double w = w_min * std::pow(w_max / w_min, alpha);

        std::complex<double> Lw = L_of_jw(w);
        double mag = std::abs(Lw);
        double phase = std::arg(Lw); // radians

        // Gain crossover: |L(jw)| crosses 1
        if (!found_gc && (mag_prev - 1.0) * (mag - 1.0) <= 0.0) {
            w_gc = w;
            found_gc = true;
            double pm_rad = M_PI + phase; // PM = 180 deg + phase
            pm = pm_rad * 180.0 / M_PI;
        }

        // Phase crossover: phase crosses -pi
        if (!found_pc && (phase_prev + M_PI) * (phase + M_PI) <= 0.0) {
            w_pc = w;
            found_pc = true;
            gm = 1.0 / mag;
        }

        w_prev = w;
        mag_prev = mag;
        phase_prev = phase;
    }

    double gm_db = 20.0 * std::log10(gm);

    std::cout << "Approximate gain margin (linear): " << gm << "\n";
    std::cout << "Approximate gain margin (dB):    " << gm_db << "\n";
    std::cout << "Approximate phase margin (deg):  " << pm << "\n";
    std::cout << "w_pc (phase crossover):          " << w_pc << " rad/s\n";
    std::cout << "w_gc (gain crossover):           " << w_gc << " rad/s\n";

    if (w_gc > 0.0) {
        double pm_rad = pm * M_PI / 180.0;
        double tau_d = pm_rad / w_gc;
        std::cout << "Approximate delay margin tau_d ~ "
                  << tau_d << " s\n";
    }

    // In a robotics project, the same code structure can be reused
    // with P(s) coming from RL or CT models, while margin computation
    // remains identical.

    return 0;
}
      

This example demonstrates the logic behind margin computation, which can be reused even when the plant is described by a high-dimensional state-space model derived from a robotics library.

8. Java Implementation – Margin Estimation in a Robotics Context

Java is widely used in educational robotics (e.g. FIRST Robotics Competition via WPILib). WPILib focuses on state-space and time-domain control, but you can still approximate Bode and stability margins numerically by sampling \( L(j\omega) \). Below is a minimal, self-contained Java example with a tiny Complex helper class.


public class RobotJointMargins {

    // Simple complex number class for frequency response
    static class Complex {
        final double re;
        final double im;
        Complex(double re, double im) { this.re = re; this.im = im; }

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

        Complex sub(Complex other) {
            return new Complex(this.re - other.re, this.im - other.im);
        }

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

        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
            );
        }

        double abs() { return Math.hypot(re, im); }
        double arg() { return Math.atan2(im, re); } // radians
    }

    // Robot joint parameters
    static final double J = 0.01;
    static final double B = 0.1;
    static final double K = 1.0;
    static double Kp = 20.0;

    // L(s) = (Kp*K) / (J s^2 + B s)
    static Complex L_of_jw(double w) {
        Complex s = new Complex(0.0, w);
        Complex num = new Complex(Kp * K, 0.0);
        Complex den = new Complex(J * ( -w * w ), B * w); // J*(j w)^2 + B*(j w)
        return num.div(den);
    }

    public static void main(String[] args) {
        int N = 2000;
        double wMin = 0.1;
        double wMax = 1000.0;

        double gm = Double.POSITIVE_INFINITY;
        double pm = Double.NEGATIVE_INFINITY;
        double wPc = 0.0, wGc = 0.0;

        boolean foundPc = false, foundGc = false;

        double wPrev = wMin;
        Complex Lprev = L_of_jw(wPrev);
        double magPrev = Lprev.abs();
        double phasePrev = Lprev.arg();

        for (int i = 1; i < N; ++i) {
            double alpha = (double) i / (N - 1);
            double w = wMin * Math.pow(wMax / wMin, alpha);

            Complex Lw = L_of_jw(w);
            double mag = Lw.abs();
            double phase = Lw.arg();

            if (!foundGc && (magPrev - 1.0) * (mag - 1.0) <= 0.0) {
                wGc = w;
                foundGc = true;
                double pmRad = Math.PI + phase;
                pm = pmRad * 180.0 / Math.PI;
            }

            if (!foundPc && (phasePrev + Math.PI) * (phase + Math.PI) <= 0.0) {
                wPc = w;
                foundPc = true;
                gm = 1.0 / mag;
            }

            wPrev = w;
            magPrev = mag;
            phasePrev = phase;
        }

        double gmDb = 20.0 * Math.log10(gm);

        System.out.println("Approximate GM (linear): " + gm);
        System.out.println("Approximate GM (dB):    " + gmDb);
        System.out.println("Approximate PM (deg):   " + pm);
        System.out.println("w_pc (rad/s):           " + wPc);
        System.out.println("w_gc (rad/s):           " + wGc);

        if (wGc > 0.0) {
            double pmRad = pm * Math.PI / 180.0;
            double tauD = pmRad / wGc;
            System.out.println("Approximate delay margin tau_d ~ " + tauD + " s");
        }

        // In an FRC robot, the same logic can be combined with WPILib's
        // identified plant models to reason about margins for drivetrain
        // or arm joints.
    }
}
      

In a full robotics project you would obtain a plant model (e.g. via system identification) and then use this numerical margin routine as part of a tuning tool, while the actual real-time control uses WPILib's PID or state-space controllers.

9. MATLAB / Simulink – Built-in Margin Analysis

MATLAB has native support for Bode plots and stability margins. The Robotics System Toolbox and classical Robotics Toolbox (e.g. Peter Corke's) can provide robot models; here we focus on the same simple joint model and use MATLAB's margin function. In Simulink, you can attach a Bode viewer to a linear analysis point to obtain the same data graphically.


% Robot joint parameters
J = 0.01;
B = 0.1;
K = 1.0;
Kp = 20.0;

s = tf('s');
P = K / (J*s^2 + B*s);
C = Kp;           % P controller
L = C * P;        % open loop
T = feedback(L, 1);  % closed loop

% Bode plot with margins
figure;
margin(L); grid on;
title('Bode plot with gain/phase margins for robot joint loop');

% Numeric margins
[gm, pm, w_pc, w_gc] = margin(L);
gm_db = 20*log10(gm);
fprintf('GM (linear) = %.2f, GM (dB) = %.2f\n', gm, gm_db);
fprintf('PM = %.2f deg\n', pm);
fprintf('w_pc = %.2f rad/s, w_gc = %.2f rad/s\n', w_pc, w_gc);

% Approximate delay margin
pm_rad = pm*pi/180;
tau_d = pm_rad / w_gc;
fprintf('Approximate delay margin tau_d ~ %.4f s\n', tau_d);

% Closed-loop step response
figure;
step(T);
grid on;
title('Closed-loop step response of robot joint');

% In a robotics workflow, P could be replaced by a linearized
% joint model from Robotics System Toolbox, while the margin
% analysis commands remain the same.
      

In Simulink, a standard approach is to model the plant and controller blocks, designate an open-loop linearization point, and use the Linear Analysis tool to automatically compute Bode plots, margins, and time responses as you adjust controller parameters.

10. Wolfram Mathematica – BodePlot with StabilityMargins

Wolfram Mathematica's control functionality allows you to define a transfer function model symbolically and then use BodePlot with the StabilityMargins option, or to call GainPhaseMargins explicitly for numerical values.


J = 0.01;
B = 0.1;
K = 1.0;
Kp = 20.0;

(* Continuous-time transfer function model *)
tf = TransferFunctionModel[
  Kp*K / (J*s^2 + B*s),
  s
];

(* Bode plot with stability margins marked *)
BodePlot[
  tf,
  {10^-1, 10^3},
  StabilityMargins -> True,
  GridLines -> Automatic,
  PlotTheme -> "Detailed",
  FrameLabel -> { {"Magnitude (dB)", "Phase (deg)"}, {"Frequency (rad/s)", "Bode plot with margins"} }
];

(* Numeric gain and phase margins *)
gmData = GainPhaseMargins[tf];
Print["Gain margin (linear): ", gmData[[1]]];
Print["Phase margin (deg):   ", gmData[[2]]];
Print["w_pc (rad/s):         ", gmData[[3]]];
Print["w_gc (rad/s):         ", gmData[[4]]];

(* Approximate delay margin *)
pmDeg = gmData[[2]];
wgc   = gmData[[4]];
pmRad = pmDeg*Pi/180;
tauD  = pmRad / wgc;
Print["Approximate delay margin tau_d ~ ", tauD, " s"];
      

Symbolic capabilities allow you to explore how margins change as functions of controller parameters (e.g. \( K_p \), zero locations) by treating them as symbolic variables and using parameter sweeps or Manipulate.

11. Problems and Solutions

Problem 1 (Gain Margin and Gain Uncertainty): A loop has gain margin \( \mathrm{GM}_{\mathrm{dB}} = 8 \,\text{dB} \). Assuming the nominal loop gain is \( K_0 \), what is the maximum positive relative gain error \( \delta_K^{\max} \) such that the closed loop is still guaranteed stable?

Solution: Convert the gain margin to linear units:

\[ \mathrm{GM} = 10^{\mathrm{GM}_{\mathrm{dB}} / 20} = 10^{8/20} = 10^{0.4} \approx 2.51. \]

From Section 2, stability is guaranteed as long as \( 0 < K < \mathrm{GM} K_0 \), with \( K = K_0(1 + \delta_K) \), hence

\[ 0 < 1 + \delta_K < \mathrm{GM} \quad \Rightarrow \quad \delta_K^{\max} = \mathrm{GM} - 1 \approx 1.51. \]

Thus the loop can tolerate roughly a \( 151\% \) increase in effective loop gain relative to the nominal value before reaching the stability boundary. (In practice, you would keep some additional safety margin and not operate exactly at this limit.)

Problem 2 (Deriving Delay Margin from Phase Margin): Show that for a loop with phase margin \( \mathrm{PM}_{\mathrm{rad}} \) at gain crossover frequency \( \omega_{\mathrm{gc}} \), the delay margin satisfies \( \tau_{\mathrm{d}} \approx \mathrm{PM}_{\mathrm{rad}} / \omega_{\mathrm{gc}} \).

Solution: At gain crossover, by definition,

\[ \lvert L(j\omega_{\mathrm{gc}})\rvert = 1, \qquad \arg L(j\omega_{\mathrm{gc}}) = -180^\circ + \mathrm{PM}. \]

Adding a pure delay \( \tau \) multiplies the loop transfer function by \( \mathrm{e}^{-s \tau} \), contributing phase \( -\omega \tau \) at frequency \( \omega \). At \( \omega_{\mathrm{gc}} \), the new phase is

\[ \arg L(j\omega_{\mathrm{gc}}) - \omega_{\mathrm{gc}} \tau = -180^\circ + \mathrm{PM} - \omega_{\mathrm{gc}} \tau. \]

The delay margin is the value \( \tau = \tau_{\mathrm{d}} \) that drives the phase margin to zero, i.e. makes the Nyquist curve cross the critical point:

\[ -180^\circ + \mathrm{PM} - \omega_{\mathrm{gc}} \tau_{\mathrm{d}} = -180^\circ \quad \Rightarrow \quad \omega_{\mathrm{gc}} \tau_{\mathrm{d}} = \mathrm{PM}_{\mathrm{rad}}. \]

Hence

\[ \tau_{\mathrm{d}} \approx \frac{\mathrm{PM}_{\mathrm{rad}}}{\omega_{\mathrm{gc}}}, \]

as claimed.

Problem 3 (Phase Margin and Overshoot): A joint-position loop in a robot arm is tuned such that its closed-loop response is well approximated by a second-order system with damping ratio \( \zeta \approx 0.45 \). Estimate the overshoot and infer a typical range of phase margin that would be consistent with such behavior.

Solution: For a second-order model,

\[ M_p = \exp\!\left( -\frac{\pi \zeta}{\sqrt{1 - \zeta^2}} \right). \]

Substituting \( \zeta = 0.45 \) gives

\[ M_p \approx \exp\!\left( -\frac{\pi \cdot 0.45}{\sqrt{1 - 0.45^2}} \right) \approx 0.2, \]

i.e. about \( 20\% \) overshoot. From the qualitative mapping table in Section 3, an overshoot in the range \( 15\%\text{--}25\% \) corresponds to phase margins roughly between \( 40^\circ \) and \( 50^\circ \). Thus a reasonable consistency check is that the loop should exhibit \( \mathrm{PM} \approx 45^\circ \) when analyzed in the frequency domain.

Problem 4 (Delay Constraint from Desired Delay Margin): A control engineer demands that a robot joint loop tolerate at least \( 25 \,\text{ms} \) of additional delay beyond sensor and actuation hardware. If the designed loop has gain crossover at \( \omega_{\mathrm{gc}} = 40 \,\text{rad/s} \), what minimum phase margin is required?

Solution: From the approximate relation \( \tau_{\mathrm{d}} \approx \mathrm{PM}_{\mathrm{rad}} / \omega_{\mathrm{gc}} \), we require

\[ \mathrm{PM}_{\mathrm{rad}} \approx \omega_{\mathrm{gc}} \tau_{\mathrm{d}} = 40 \cdot 0.025 = 1.0 \,\text{rad}. \]

Converting to degrees:

\[ \mathrm{PM}_{\mathrm{deg}} = \frac{180}{\pi} \mathrm{PM}_{\mathrm{rad}} \approx \frac{180}{\pi} \cdot 1.0 \approx 57^\circ. \]

So the loop should be designed with at least about \( 57^\circ \) of phase margin at \( 40 \,\text{rad/s} \) to satisfy the required delay robustness.

Problem 5 (Choosing a Margin Target): Two candidate controllers for the same plant yield the following margins:

  • Controller A: \( \mathrm{GM} = 20 \,\text{dB} \), \( \mathrm{PM} = 70^\circ \).
  • Controller B: \( \mathrm{GM} = 8 \,\text{dB} \), \( \mathrm{PM} = 50^\circ \).

Which controller would you expect to give a better trade-off between robustness and bandwidth for a robot joint servo, and why?

Solution: Controller A has very large margins: GM \( = 20 \,\text{dB} \) and PM \( = 70^\circ \). While this indicates strong robustness to gain variations and delay, it also suggests that the Nyquist curve is far from the critical point, which typically implies a relatively conservative (slow) loop with limited bandwidth.

Controller B, with GM \( = 8 \,\text{dB} \) and PM \( = 50^\circ \), still has comfortable margins (roughly allowing gain changes by a factor of about \( 2.5 \) and corresponding to \( 15\text{--}25\% \) overshoot in a second-order-like response). It is therefore likely to provide faster tracking and higher bandwidth while remaining adequately robust for a mechanical system such as a robot joint. Hence, Controller B is typically preferred for a servo application.

12. Summary

In this lesson, we moved beyond the formal definitions of gain, phase, and delay margins to interpret them as concrete measures of robustness and performance:

  • Gain margin quantifies allowable multiplicative gain error before instability, directly linked to parameter variations and changing payloads in robotic systems.
  • Phase margin correlates strongly with damping, overshoot, and the “feel” of the closed-loop response, with \( 45^\circ\text{--}60^\circ \) often providing a good balance between speed and robustness.
  • Delay margin is approximately \( \tau_{\mathrm{d}} \approx \mathrm{PM}_{\mathrm{rad}} / \omega_{\mathrm{gc}} \), providing a simple rule for acceptable sensing, computation, and communication delays.
  • Software tools in Python, C++, Java (robotics libraries), MATLAB/Simulink, and Wolfram Mathematica all support the same conceptual workflow: model \( L(s) \), compute margins, and connect them to time-domain and implementation constraints.

In the next lesson we will apply these interpretations in design examples, selecting controllers to meet specific margin requirements under realistic constraints.

13. References

  1. Nyquist, H. (1932). Regeneration theory. Bell System Technical Journal, 11(1), 126–147.
  2. Bode, H. W. (1940). Relations between attenuation and phase in feedback amplifier design. Bell System Technical Journal, 19(3), 421–454.
  3. MacColl, L. A. (1945). Fundamental theory of servomechanisms. Bell System Technical Journal, 24(1), 1–34.
  4. Horowitz, I. M. (1963). On the theory of the optimum corrective feedback system. Transactions of the American Society of Mechanical Engineers, 85, 76–88.
  5. Safonov, M. G., & Athans, M. (1977). Gain and phase margin for multiloop LQG regulators. IEEE Transactions on Automatic Control, 22(2), 173–179.
  6. Doyle, J. C. (1978). Guaranteed margins for LQG regulators. IEEE Transactions on Automatic Control, 23(4), 756–757.
  7. 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.
  8. Skogestad, S., & Postlethwaite, I. (1992). Integrating disturbance rejection and robustness for SISO feedback systems. International Journal of Control, 55(6), 1379–1393.
  9. Åström, K. J., & Hägglund, T. (1995). The future of PID control. Control Engineering Practice, 9(11), 1163–1175.
  10. Middleton, R. H., & Goodwin, G. C. (1990). Digital control and estimation: A unified approach. IEEE Control Systems Magazine, various articles on robustness margins in sampled-data systems.