The Airy disk and the diffraction limit#

George Biddell Airy worked out the exact Fraunhofer diffraction pattern of a circular aperture, finding a bright central disk surrounded by faint concentric rings rather than the sharp geometric image predicted by ray optics. Lord Rayleigh turned Airy’s pattern into a practical resolving-power criterion: two point sources are just resolvable when the central peak of one Airy pattern falls on the first dark ring of the other, giving the diffraction limit \(\theta_{\min} \approx 1.22\,\lambda/D\) that bounds every microscope, telescope, and camera lens. circular_aperture() and fraunhofer_diffraction() reproduce the Airy pattern directly from a numerical Fourier transform – no closed-form Bessel function is needed – and its first dark ring lands exactly at the Rayleigh angle computed independently.

import matplotlib.pyplot as plt
import numpy as np

from physicskit.optics.wave import circular_aperture, fraunhofer_diffraction, intensity

A circular aperture, propagated to its far-field diffraction pattern#

wavelength = 0.5e-3  # mm
D = 0.2  # aperture diameter, mm
dx = 0.002
N = 512
z = 1000.0  # mm

aperture = circular_aperture((N, N), dx=dx, radius=D / 2.0)
U = fraunhofer_diffraction(aperture, wavelength=wavelength, z=z, dx=dx)
I = intensity(U)
I /= I.max()

x = (np.arange(N) - N // 2) * (wavelength * z / (N * dx))
x_first_zero = 1.22 * wavelength / D * z  # Rayleigh criterion, mapped to the screen

The central disk’s radius, found directly from the computed pattern (its first minimum), against the Rayleigh angle computed independently from \(D\) and \(\lambda\) alone.

profile = I[N // 2]
right_half = profile[N // 2 :]
first_min_index = np.argmin(right_half[: np.argmax(right_half[1:] > right_half[:-1]) + 2])
x_measured = x[N // 2 :][first_min_index]

fig, ax = plt.subplots(figsize=(7, 3))
ax.plot(x, profile)
ax.axvline(x_first_zero, color="r", ls="--", label=r"$1.22\,\lambda z/D$")
ax.axvline(-x_first_zero, color="r", ls="--")
ax.set_xlabel("screen position x (mm)")
ax.set_ylabel("normalized intensity")
ax.legend()
ax.set_title("Airy pattern: central disk + first dark ring (Rayleigh criterion)")
fig.tight_layout()

print(f"aperture diameter D = {D} mm, wavelength = {wavelength} mm")
print(f"Rayleigh angular limit: 1.22 lambda/D = {1.22 * wavelength / D:.6f} rad")
print(f"predicted first dark ring at x = {x_first_zero:.4f} mm")
print(f"first minimum found directly in the computed pattern at x = {x_measured:.4f} mm")
Airy pattern: central disk + first dark ring (Rayleigh criterion)
aperture diameter D = 0.2 mm, wavelength = 0.0005 mm
Rayleigh angular limit: 1.22 lambda/D = 0.003050 rad
predicted first dark ring at x = 3.0500 mm
first minimum found directly in the computed pattern at x = 2.9297 mm

The full 2D Airy pattern: central disk and concentric diffraction rings#

The 1D cross-section above only cuts through the pattern’s center; the actual diffraction-limited image of a point source is the full 2D Airy disk, with concentric bright rings surrounding the central maximum – exactly what limits the angular (not just linear) resolution of a real telescope or microscope aperture. Plotted on a log scale, both the bright central disk and the faint outer rings (each roughly 1.75 magnitudes fainter than the last) are visible together.

theta = np.linspace(0, 2 * np.pi, 200)
fig2, ax2 = plt.subplots(figsize=(5, 4.5))
im = ax2.imshow(
    np.log10(I + 1e-8),
    extent=(x[0], x[-1], x[0], x[-1]),
    origin="lower",
    cmap="inferno",
    vmin=-6,
    vmax=0,
)
fig2.colorbar(im, ax=ax2, label="log10 normalized intensity")
ax2.plot(x_first_zero * np.cos(theta), x_first_zero * np.sin(theta), "c--", lw=1, label="first dark ring (Rayleigh)")
ax2.set_xlabel("x (mm)")
ax2.set_ylabel("y (mm)")
ax2.legend(fontsize=8, loc="upper right")
ax2.set_title("Full 2D Airy pattern: central disk + concentric rings")
fig2.tight_layout()
Full 2D Airy pattern: central disk + concentric rings

Total running time of the script: (0 minutes 0.100 seconds)

Gallery generated by Sphinx-Gallery