>
section 6 of 102 min read

6. Computing It: Python for VSWR, Smith Chart, and Quarter-Wave Matching

A short illustration of the kinds of plots and quick calculations every RF engineer writes a hundred times.

python
import numpy as np
import matplotlib.pyplot as plt
 
# Reflection coefficient and VSWR vs. frequency for a quarter-wave matcher
Z0 = 50.0       # source impedance
ZL = 200.0      # load impedance
ZT = np.sqrt(Z0 * ZL)         # transformer impedance
f0 = 1e9        # design frequency 1 GHz
v = 1.4e8       # phase velocity on FR-4
lam0 = v / f0
length = lam0 / 4              # quarter wavelength at f0
 
freqs = np.linspace(0.5e9, 1.5e9, 401)
betas = 2 * np.pi * freqs / v
# Input impedance of transformer terminated in ZL
Zin = ZT * (ZL + 1j*ZT*np.tan(betas*length)) / (ZT + 1j*ZL*np.tan(betas*length))
gamma = (Zin - Z0) / (Zin + Z0)
vswr = (1 + np.abs(gamma)) / (1 - np.abs(gamma))
return_loss_dB = -20 * np.log10(np.abs(gamma) + 1e-12)
 
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))
ax1.plot(freqs/1e9, vswr)
ax1.axhline(2.0, ls=":", color="gray")
ax1.set(xlabel="Frequency (GHz)", ylabel="VSWR",
        title="Quarter-wave matcher: VSWR vs frequency")
 
ax2.plot(freqs/1e9, return_loss_dB)
ax2.axhline(10, ls=":", color="gray")
ax2.set(xlabel="Frequency (GHz)", ylabel="Return loss (dB)",
        title="Return loss vs frequency")
 
plt.tight_layout()
plt.show()

This shows the narrow-band character of a single quarter-wave matcher: VSWR is exactly 1 at the design frequency, but degrades as you move away. Real systems use multi-section transformers to flatten the response.

A second, deeper example: compute the input impedance looking into a lossy line, sweeping frequency:

python
def line_input_impedance(Z0, ZL, R, L, G, C, length, freq):
    omega = 2 * np.pi * freq
    Zser = R + 1j*omega*L
    Ysh  = G + 1j*omega*C
    gamma = np.sqrt(Zser * Ysh)
    Zc    = np.sqrt(Zser / Ysh)
    return Zc * (ZL + Zc*np.tanh(gamma*length)) / (Zc + ZL*np.tanh(gamma*length))
 
# RG-58 50 Ω coax, 10 m long, terminated in 100 Ω
freqs = np.logspace(6, 10, 401)
Zin   = np.array([line_input_impedance(50, 100, 0.05, 240e-9, 1e-6, 100e-12, 10.0, f)
                  for f in freqs])

The result lets you trace how a real coax line transforms a load impedance versus frequency, including resistive loss. Plotting Γ|\Gamma| versus frequency reveals the resonant peaks and valleys characteristic of mismatched lines.