Stability, Phase Margin & Frequency Compensation

Keeping feedback loops from oscillating. Learn the Barkhausen condition and why negative feedback becomes positive at high frequency, loop-gain Bode plots, gain and phase margin, their link to overshoot and ringing, the rate-of-closure rule, dominant-pole and Miller (pole-splitting) compensation, lead/lag compensation, noise-gain shaping, capacitive-load instability and its cures (isolation resistor, in-loop compensation, snubbers), stability of regulators and TIAs, and measuring stability with step response and loop-gain injection — with Python computing phase margins for different feedback factors and with a capacitive load.

Every amplifier has multiple poles. Each adds phase lag; if the total lag around the loop reaches 180° while the loop gain is still ≥ 1, negative feedback turns into positive feedback and the circuit oscillates.

Compensation deliberately shapes the loop gain so it falls below unity before the phase gets dangerous — the difference between a precise amplifier and an expensive oscillator.

An analogy

A shower with a long pipe: you turn the tap, but the temperature change arrives late. React too strongly (high gain) to the delayed feedback and you swing between scalding and freezing — oscillation. Phase margin is how much delay you can tolerate before that happens.

Reading loop-gain Bode plots

Plot |T| and ∠T. Crossover f_c is where |T| = 0 dB. Phase margin is how far ∠T(f_c) is above −180°. Gain margin is how far |T| is below 0 dB where the phase hits −180°. A useful rule: if |T| crosses 0 dB with a −20 dB/decade slope (single pole dominant), the loop is well behaved; crossing at −40 dB/decade means little phase margin.

Compensation techniques

Ways to restore phase margin:

Common instability sources

Capacitive loads (cables, MOSFET gates, ADC inputs) on op-amps; stray capacitance at the inverting input with large feedback resistors (TIAs); LDOs with the wrong output capacitor ESR; long supply leads without bypassing; unity-gain buffers built from decompensated op-amps; and parasitic oscillation of emitter followers driving capacitive loads at hundreds of MHz (fix: base stopper resistors, ferrite beads).

Verifying stability

In simulation: AC loop-gain analysis with a Middlebrook/Tian probe, plus transient step response with corner cases (temperature, load, supply, component tolerance). On the bench: small-signal step response (overshoot and ringing reveal PM), and for power supplies, injection with a network analyser (Bode 100 style) to measure T directly. Aim for ≥ 45° across all corners — ≥ 60° for well-damped responses — and ≥ 10 dB gain margin.

Formulas

Worked example: Phase margin from second pole

Given: Dominant pole, second pole at 2 × f_c

Find: PM.

Answer: ≈ 63°

Worked example: Capacitive-load pole

Given: R_o 50 Ω, C_L 1 nF

Find: f_pL.

Answer: 3.18 MHz

Worked example: Expected overshoot

Given: PM 45°

Find: Step overshoot.

Answer: ≈ 23%

Capacitive-load isolation

             ┌───────────────┐   (feedback from op-amp output: simple, loses DC accuracy
  vin ──┤+     │               │    at the load by I·R_iso)
        │  ▷───┴── R_iso 20–100 Ω ──┬── load
     ┌──┤−                         C_L (cable, MOSFET gate, ADC input)
     └──────────────────────────────┘ GND
  R_iso separates C_L from the op-amp's output resistance → removes the extra pole from the loop

The op-amp's open-loop output resistance and a capacitive load form an extra pole inside the loop. A small series resistor isolates the load so the feedback point sees a resistive output. For DC accuracy, take DC feedback from the load side and AC feedback from the op-amp side (dual-loop compensation).

Phase margin vs feedback factor and capacitive load

import math, cmath
# Loop stability: phase margin of an op-amp loop with 3 poles, and the effect of capacitive load
A0, p1, p2, p3 = 1e5, 10.0, 2e6, 20e6            # DC gain, pole frequencies (Hz)
def A(f, extra=None):
    s = 1j * f
    a = A0 / ((1 + s/p1) * (1 + s/p2) * (1 + s/p3))
    if extra: a /= (1 + s/extra)
    return a
def margins(beta, extra=None):
    lo, hi = 1.0, 1e9                            # bisection for |A*beta| = 1
    for _ in range(200):
        mid = math.sqrt(lo * hi)
        if abs(A(mid, extra) * beta) > 1: lo = mid
        else: hi = mid
    pm = 180 + math.degrees(cmath.phase(A(lo, extra) * beta))
    return lo, pm
for beta in (1.0, 0.1, 0.01):
    fc, pm = margins(beta)
    print(f"beta = {beta:<5}: crossover {fc/1e6:6.3f} MHz, phase margin {pm:5.1f} deg")
Ro, CL = 50.0, 1e-9
fpl = 1 / (2 * math.pi * Ro * CL)
fc, pm = margins(1.0, fpl)
print(f"unity-gain buffer driving 1 nF (Ro 50 ohm, extra pole {fpl/1e6:.2f} MHz): phase margin {pm:.1f} deg")
print(f"overshoot rule of thumb: PM 45 deg ~ 23% overshoot, PM 60 deg ~ 9%")
# beta = 1.0  : crossover  0.909 MHz, phase margin  62.9 deg
# beta = 0.1  : crossover  0.100 MHz, phase margin  86.9 deg
# beta = 0.01 : crossover  0.010 MHz, phase margin  89.7 deg
# unity-gain buffer driving 1 nF (Ro 50 ohm, extra pole 3.18 MHz): phase margin 48.2 deg
# overshoot rule of thumb: PM 45 deg ~ 23% overshoot, PM 60 deg ~ 9%

An op-amp compensated for unity gain has 63° phase margin at β = 1, and even more at higher closed-loop gains because crossover moves down, away from the higher poles. Adding a 1 nF load to its 50 Ω output inserts a pole at 3.2 MHz, cutting phase margin to 48° — visible as ringing; larger loads push it toward oscillation.

Common mistakes

Applications

Key takeaways

Going further