Skip to main content

Bode Plots and Frequency Response

Frequency response studies the steady-state output of a stable linear system driven by sinusoidal inputs. Nise introduces Bode plots as a practical way to approximate and interpret magnitude and phase over many decades of frequency. The same transfer function used for time response is evaluated on the imaginary axis, s=jωs=j\omega.

The value of frequency response is design visibility. Low-frequency gain relates to steady-state tracking. Crossover frequency relates to speed and bandwidth. Phase lag near crossover relates to overshoot and stability margin. Bode plots show these trade-offs in a form engineers can sketch, measure, and tune.

An asymptotic Bode plot shows magnitude and phase changing across logarithmic frequency.

Figure: Asymptotic Bode plot for frequency-response analysis. Image: Wikimedia Commons, Mintz l, public domain.

Definitions

For a transfer function G(s)G(s), the frequency response is

G(jω).G(j\omega).

The magnitude is often expressed in decibels:

G(jω)dB=20log10G(jω).|G(j\omega)|_{\text{dB}}=20\log_{10}|G(j\omega)|.

The phase is

G(jω)\angle G(j\omega)

in degrees or radians.

A Bode magnitude plot graphs 20log10G(jω)20\log_{10}\vert G(j\omega)\vert versus log10ω\log_{10}\omega. A Bode phase plot graphs phase versus log10ω\log_{10}\omega.

The break frequency or corner frequency of a factor (1+s/ωb)(1+s/\omega_b) is ωb\omega_b. First-order factors change magnitude slope by 2020 dB/decade and phase by up to 9090^\circ. A pole contributes negative slope and phase; a zero contributes positive slope and phase.

For a sinusoidal input

r(t)=Asin(ωt),r(t)=A\sin(\omega t),

a stable LTI system produces steady-state output

css(t)=AG(jω)sin(ωt+G(jω)).c_{ss}(t)=A|G(j\omega)|\sin(\omega t+\angle G(j\omega)).

Key results

Basic Bode factors:

FactorMagnitude asymptotePhase trend
constant KK20log10K20\log_{10}\vert K\vert 00^\circ if K>0K\gt 0, 180180^\circ if K<0K\lt 0
pole at origin 1/s1/s20-20 dB/dec90-90^\circ
zero at origin ss+20+20 dB/dec+90+90^\circ
real pole 1/(1+s/ωp)1/(1+s/\omega_p)slope changes by 20-20 dB/dec00^\circ to 90-90^\circ
real zero (1+s/ωz)(1+s/\omega_z)slope changes by +20+20 dB/dec00^\circ to +90+90^\circ
second-order polespossible resonant peakup to 180-180^\circ

For a product of transfer-function factors, magnitudes in dB add and phases add. This is why Bode plots are convenient:

20log10G1G2=20log10G1+20log10G2.20\log_{10}|G_1G_2|=20\log_{10}|G_1|+20\log_{10}|G_2|.

The low-frequency magnitude of the open-loop transfer function indicates static error constants. A Type 1 system has a 20-20 dB/dec low-frequency slope because of one pole at the origin; a Type 2 system has 40-40 dB/dec.

Bandwidth is loosely associated with how fast a closed-loop system responds. Higher crossover or bandwidth often means faster response, but high bandwidth also passes more noise and may reduce robustness if phase lag is large.

Bode plots are asymptotic design tools as well as exact computational plots. Hand sketching begins with low-frequency gain and slope, then changes slope at each break frequency. The exact curve is smooth: a first-order pole is already contributing phase a decade before its break frequency and continues a decade after. The magnitude is 33 dB away from the asymptote at the break frequency. Knowing the asymptotes helps the designer understand the exact plot rather than merely display it.

Minimum-phase systems have a close relationship between magnitude slope and phase. A downward magnitude slope near crossover usually corresponds to phase lag. Nonminimum-phase zeros and time delays break the most comforting versions of this intuition: a right-half-plane zero may increase magnitude like a left-half-plane zero but contributes negative phase, and a pure delay contributes phase lag without magnitude change. These effects limit achievable bandwidth.

Frequency response can be measured directly. Apply sinusoids at different frequencies, wait for transients to decay, then record output amplitude ratio and phase shift. This experimental method is valuable when physical parameters are uncertain. The resulting Bode plot may be used for design even if no exact differential-equation model is available, though noise, nonlinearities, and actuator limits must be managed during testing.

Open-loop and closed-loop frequency responses answer different questions. Open-loop loop transfer L(jω)L(j\omega) is used for gain crossover, phase margin, Nyquist plots, and loop shaping. Closed-loop transfer T(jω)T(j\omega) shows how commands pass to outputs. Sensitivity S(jω)=1/(1+L(jω))S(j\omega)=1/(1+L(j\omega)) shows disturbance rejection and robustness. Complementary sensitivity T(jω)=L(jω)/(1+L(jω))T(j\omega)=L(j\omega)/(1+L(j\omega)) shows command following and noise transmission for unity feedback.

A good loop shape is usually high at low frequency, crosses over with adequate phase margin, and rolls off at high frequency. High low-frequency gain reduces tracking error and load disturbances. Moderate crossover gives speed. High-frequency rolloff avoids amplifying sensor noise and unmodeled plant dynamics. Most frequency-response design is a disciplined negotiation among those three regions.

Second-order factors add another layer of interpretation. A lightly damped pair of poles can create a resonant peak in the magnitude plot and a rapid phase transition. The peak corresponds to the same low damping that creates overshoot in step response. Increasing damping flattens the resonance and spreads the phase change over a broader frequency range. This is one reason frequency response and time response are not separate subjects; they are two views of the same poles.

The decibel scale is useful because it turns multiplication into addition, but it can hide ordinary ratios. A 2020 dB gain is a factor of 1010 in amplitude; a 4040 dB gain is a factor of 100100; a 20-20 dB attenuation is a factor of 0.10.1. When checking actuator effort or sensor noise, convert back to ordinary magnitude so the physical size of signals remains clear.

For design documentation, a Bode plot should be accompanied by the transfer function, units, operating point, and whether the plotted system is open loop, closed loop, sensitivity, or complementary sensitivity. Many wrong conclusions come from looking at the correct curve for the wrong transfer function.

Phase should be unwrapped or interpreted consistently. A plot that jumps from 179-179^\circ to +179+179^\circ may represent a smooth continuation, not a sudden physical phase lead. Margin calculations depend on the continuous phase trend near crossover, so plotting conventions must be checked.

Always label wrapped phase plots clearly.

Units matter.

Visual

Magnitude asymptote for 10/(1+s/5)

dB
20 |---------
| \
| \
0 | \ slope -20 dB/dec
+----+-------+--------> log omega
5
QuantityHow read from Bode plotDesign meaning
dc gainlow-frequency magnitudestep tracking and disturbance rejection
crossover frequencywhere magnitude crosses 0 dBapproximate speed and margin location
phase at crossoverphase plot at gain crossoverphase margin
high-frequency rollofffinal magnitude slopenoise attenuation and unmodeled dynamics
resonant peakmagnitude bumplow damping and overshoot tendency

Worked example 1: magnitude and phase at one frequency

Problem: For

G(s)=10s+2,G(s)=\frac{10}{s+2},

find magnitude in dB and phase at ω=2\omega=2 rad/s.

Method:

  1. Substitute s=jω=j2s=j\omega=j2:
G(j2)=102+j2.G(j2)=\frac{10}{2+j2}.
  1. Denominator magnitude:
2+j2=22+22=8=2.828.|2+j2|=\sqrt{2^2+2^2}=\sqrt8=2.828.
  1. Magnitude:
G(j2)=102.828=3.536.|G(j2)|=\frac{10}{2.828}=3.536.
  1. Convert to dB:
20log10(3.536)=10.97 dB.20\log_{10}(3.536)=10.97\ \text{dB}.
  1. Denominator angle:
(2+j2)=tan1(2/2)=45.\angle(2+j2)=\tan^{-1}(2/2)=45^\circ.
  1. Numerator is positive real, so phase is
G(j2)=045=45.\angle G(j2)=0^\circ-45^\circ=-45^\circ.

Checked answer: magnitude is about 11.011.0 dB and phase is 45-45^\circ.

Worked example 2: asymptotic Bode sketch

Problem: Sketch the asymptotic magnitude slopes for

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

Method:

  1. Put factors in Bode form:
s+1=1(1+s/1),s+1=1(1+s/1), s+10=10(1+s/10).s+10=10(1+s/10).

Thus

G(s)=100(1+s)s10(1+s/10)=10(1+s/1)s(1+s/10).G(s)=\frac{100(1+s)}{s\cdot10(1+s/10)} =\frac{10(1+s/1)}{s(1+s/10)}.
  1. Constant magnitude contribution:
20log10(10)=20 dB.20\log_{10}(10)=20\ \text{dB}.
  1. Pole at origin contributes slope 20-20 dB/dec from the start.

  2. Zero at ω=1\omega=1 contributes +20+20 dB/dec after ω=1\omega=1, changing slope from 20-20 to 00 dB/dec.

  3. Pole at ω=10\omega=10 contributes 20-20 dB/dec after ω=10\omega=10, changing slope from 00 to 20-20 dB/dec.

  4. Magnitude at ω=1\omega=1 from the initial asymptote:

Since 2020 dB at ω=1\omega=1 after the origin pole expression 2020log10ω20-20\log_{10}\omega, at ω=1\omega=1 it is 2020 dB.

  1. From ω=1\omega=1 to 1010, slope is 00, so magnitude remains 2020 dB. After 1010, it falls at 20-20 dB/dec.

Checked answer: slopes are 20-20 dB/dec for ω<1\omega\lt 1, 00 dB/dec for 1<ω<101\lt \omega\lt 10, and 20-20 dB/dec for ω>10\omega\gt 10.

Code

import numpy as np
from scipy import signal

num = [100, 100] # 100(s + 1)
den = [1, 10, 0] # s(s + 10)
sys = signal.TransferFunction(num, den)

w = np.logspace(-2, 3, 500)
w, mag, phase = signal.bode(sys, w=w)

idx = np.argmin(np.abs(w - 2.0))
print("magnitude at 2 rad/s:", mag[idx], "dB")
print("phase at 2 rad/s:", phase[idx], "deg")
print("approx gain crossover rad/s:", w[np.argmin(np.abs(mag))])

Common pitfalls

  • Using 10log1010\log_{10} for voltage-like transfer-function magnitude instead of 20log1020\log_{10}.
  • Forgetting that phases add algebraically, with poles contributing negative phase and zeros positive phase.
  • Treating asymptotes as exact near break frequencies. First-order factors differ by about 33 dB at the corner.
  • Evaluating frequency response at s=ωs=\omega instead of s=jωs=j\omega.
  • Ignoring units of ω\omega. Bode formulas use rad/s unless explicitly converted.
  • Assuming higher bandwidth is always better. Noise, actuator limits, and unmodeled dynamics constrain useful bandwidth.

Connections