Articles in this series
- Phased array antenna — an introduction
- Electronic scanning arrays
- Grating lobes in electronic scanning (this article)
- Array pattern multiplication
Introduction
A uniform array samples the aperture field at equal intervals. Sample too coarsely and the far-field pattern aliases—the same idea as undersampling a time signal. The aliases show up as grating lobes: extra peaks that look like main beams, steal power, and create false directions.
Motive
How far apart may the elements be, and how far may you scan, before a grating lobe enters visible space? We want one clear rule and a few plots that check it.
Technical development
Peaks of the array factor repeat when
\[u_m = u_0 + m\,\frac{\lambda}{d}, \quad m=0,\pm 1,\pm 2,\ldots\]Only those \(u_m\) with \(|u|\le 1\) appear as real angles. Asking the first aliases to stay outside the visible region gives
\[|u_0|_{\max} = \frac{\lambda}{d} – 1\](when that quantity is positive). At \(d=\lambda/2\) you may scan the whole visible region; larger spacing shrinks the safe scan cone.



How this achieves the motive
Figure 1 shows aliases appearing as soon as \(d\ge\lambda\) at broadside. Figure 2 shows how scanning moves those aliases. Figure 3 summarises the design inequality. Together they answer the spacing-and-scan question.
Sample simulation
import numpy as np
import matplotlib.pyplot as plt
def array_factor(u, N, d_over_lambda, u0=0.0, weights=None):
"""Normalized |AF(u)|^2, u=sin(theta)."""
if weights is None:
weights = np.ones(N)
weights = np.asarray(weights, dtype=float)
weights = weights / np.max(np.abs(weights))
kdl = 2 * np.pi * d_over_lambda
af = np.zeros_like(u, dtype=complex)
for n in range(N):
af += weights[n] * np.exp(1j * n * kdl * (u - u0))
g = np.abs(af) ** 2
return g / np.max(g)
def db(g, floor=-60.0):
return 10 * np.log10(np.maximum(g, 10 ** (floor / 10)))
u = np.linspace(-1, 1, 4001)
N = 24
plt.figure(figsize=(8, 4.8))
for d, lab in ((0.5, "d=lambda/2"), (1.0, "d=lambda"), (1.5, "d=1.5 lambda")):
plt.plot(u, db(array_factor(u, N, d, u0=0.0)), label=lab)
plt.xlabel("u"); plt.ylabel("dB"); plt.ylim(-45, 2); plt.grid(True); plt.legend(); plt.show()
d_over = np.linspace(0.35, 1.6, 400)
u_max = np.maximum(0.0, 1.0/d_over - 1.0)
plt.plot(d_over, u_max); plt.fill_between(d_over, 0, u_max, alpha=0.12)
plt.axvline(0.5, linestyle="--"); plt.xlabel("d/lambda"); plt.ylabel("|u0|_max"); plt.grid(True); plt.show()
Sample results
The first plot should match Figure 1: one beam for \(d=\lambda/2\), edge lobes for \(d=\lambda\), interior lobes for \(d=1.5\lambda\). The budget plot should match Figure 3, touching \(|u_0|=1\) at \(d=\lambda/2\).
Next topic
Real elements are not isotropic. Next we multiply the array factor by an element pattern and see how amplitude tapering trades sidelobes for beamwidth.
References
[1] Balanis. [2] Mailloux, grating-lobe chapters.