Introduction

Every thermostat, cruise control and drone autopilot is a feedback loop: measure the error, push back against it, measure again. Push back too gently and the system drifts. Push back too hard, or too late, and it starts to oscillate — sometimes settling into a wobble, sometimes shaking itself apart.

The unsettling part is that a loop can look perfectly reasonable at a glance and still be one small change away from disaster: a slightly heavier load, a longer cable, a firmware update that adds a few milliseconds of delay. How do engineers know, before switching it on, whether a design has room to spare or is teetering on the edge?

The answer is a pair of numbers you can read straight off a frequency response plot: the gain margin and the phase margin. They turn "will this system blow up?" into a question you can answer by inspecting a graph.

Slide the Gain, Watch the Margins

Below is a simple third-order feedback loop. Slide the loop gain KK and watch two things at once: the Bode magnitude/phase plot, and the step response on the right.

<p class="hint">{{hint_para}}</p>
<div class="controls">
  <label for="gain">{{gain_label}} <span id="gainVal">3.0</span></label>
  <input type="range" id="gain" min="1" max="12" step="0.1" value="3">
</div>
<div class="readouts">
  <div class="ro"><span class="ro-label">{{gm_label}}</span><span id="gmVal" class="ro-val">--</span></div>
  <div class="ro"><span class="ro-label">{{pm_label}}</span><span id="pmVal" class="ro-val">--</span></div>
  <div class="ro" id="verdictRow"><span class="ro-label">{{verdict_label}}</span><span id="verdictVal" class="ro-val">--</span></div>
</div>
<div class="plots">
  <div class="plot-col">
    <div class="plot-title">{{bode_title}}</div>
    <svg id="bodeSvg" viewBox="0 0 320 220" class="plot"></svg>
  </div>
  <div class="plot-col">
    <div class="plot-title">{{step_title}}</div>
    <svg id="stepSvg" viewBox="0 0 320 220" class="plot"></svg>
  </div>
</div>
<div class="status" id="status">{{status_idle}}</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.controls { display: flex; align-items: center; gap: .6rem; margin-bottom: .6rem; flex-wrap: wrap; }
.controls label { font-size: .9rem; font-weight: 600; color: #1d3557; display: flex; align-items: center; gap: .4rem; }
.controls input[type="range"] { width: 220px; }
.readouts { display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: .6rem; }
.ro { background: #eef2f6; border: 1px solid #cdd9e3; border-radius: 8px; padding: .35rem .7rem; font-size: .88rem; display: flex; gap: .4rem; }
.ro-label { color: #444; font-weight: 600; }
.ro-val { color: #1d3557; font-weight: 700; font-variant-numeric: tabular-nums; }
.ro.warn .ro-val { color: #c92f3c; }
.plots { display: flex; gap: .8rem; flex-wrap: wrap; }
.plot-col { flex: 1 1 260px; min-width: 240px; }
.plot-title { font-size: .82rem; font-weight: 600; color: #444; margin-bottom: .2rem; }
.plot { width: 100%; height: auto; background: #fbfcfd; border: 1px solid #dbe2e8; border-radius: 8px; }
.axis { stroke: #b6c0c9; stroke-width: 1; }
.gridline { stroke: #e5eaef; stroke-width: 1; }
.curve-mag { stroke: #1d3557; stroke-width: 2; fill: none; }
.curve-phase { stroke: #7a5cc9; stroke-width: 2; fill: none; }
.curve-step { stroke: #0a7d33; stroke-width: 2; fill: none; }
.marker { fill: #c92f3c; }
.refline { stroke: #c92f3c; stroke-width: 1; stroke-dasharray: 3 2; }
.plot-label { font-size: 7px; fill: #667; font-family: system-ui, sans-serif; }
.status { font-size: .95rem; font-weight: 600; margin: .6rem 0 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.warn { color: #b8860b; }
.status.bad { color: #c92f3c; }
// Code not found

Push KK up and the gain margin (how much extra gain would push the loop to instability) and the phase margin (how much extra phase lag it can tolerate at the frequency where gain crosses 0 dB) both shrink. Watch the step response grow ringier as the margins approach zero — and start to grow without bound once they cross it.

The Real Complexity

Why should a plot of gain and phase against frequency say anything about stability at all?

  • The hard way is to find the roots of the closed-loop characteristic equation and check that every one has negative real part. For high-order systems, or systems with time delay, that polynomial can be nasty or not even finite-dimensional.
  • Nyquist's insight (1932): plot the open-loop response L(jω)L(j\omega) as ω\omega sweeps from -\infty to \infty in the complex plane. Count how many times that curve encircles the point 1-1. The Nyquist stability criterion says the number of unstable closed-loop poles equals the number of unstable open-loop poles plus the number of clockwise encirclements of 1-1 — no root-finding required.
  • Gain and phase margins are a shortcut. At the frequency ωpc\omega_{pc} where the phase of L(jω)L(j\omega) crosses 180°-180°, the gain margin is how far L(jωpc)|L(j\omega_{pc})| sits below 11 (in dB, GM=20log10L(jωpc)\text{GM} = -20\log_{10}|L(j\omega_{pc})|). At the frequency ωgc\omega_{gc} where L(jωgc)=1|L(j\omega_{gc})| = 1 (0 dB), the phase margin is PM=180°+L(jωgc)\text{PM} = 180° + \angle L(j\omega_{gc}). Both measure the same thing as Nyquist's encirclement count: how far the curve sits from wrapping around 1-1.
  • Small margins mean fragility. A phase margin near 0° means a tiny extra delay — a sensor lag, a slower processor — flips the sign of every encirclement and the system rings or diverges. That is why control engineers routinely demand PM45°\text{PM} \gtrsim 45° and GM6-10 dB\text{GM} \gtrsim 6\text{-}10\ \text{dB} as a safety buffer, not because the nominal design is unstable, but because real systems are never exactly the model.

The elegance is topological: instead of computing where the poles are, Nyquist counts how many times a curve loops around a single point — turning an algebra problem into a geometry problem you can read off a plot.

Where It Matters

Any system built out of "measure, compare, correct" lives or dies by its margins:

  • Aerospace and drones: flight-control loops are certified partly by showing adequate gain and phase margin across the flight envelope, since airframe dynamics change with speed and altitude.
  • Process control: chemical plants and power grids rely on margin checks to stay stable even as loads, temperatures and delays drift over months of operation.
  • Controller tuning: methods that tune a PID controller explicitly target a phase margin (often 45-60°) as the design goal, trading responsiveness for safety.
  • Robust control: modern designs generalize margins into structured-uncertainty bounds, but the underlying question is identical — how much can the model be wrong before the real loop goes unstable?

Whenever a system pushes back against its own error, someone had to check its margins first — the same question sits underneath controllability and observability: can we even steer and see the system well enough to keep it safe?

Conclusion

Gain and phase margins compress a hard algebraic question — where exactly do the closed-loop poles sit? — into two numbers you can read off a frequency-response plot. Nyquist's encirclement count is the rigorous version; the margins are its everyday, practical shadow.

So the next time a control system behaves a little too perfectly, remember: somewhere behind it is a Bode plot showing just how much gain or phase it could still absorb before the feedback that keeps it steady turns into the feedback that shakes it apart.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/bode-nyquist-stability/Content licensed under CC BY-NC 4.0.