"""Paraxial biprism rays and ideal equal-amplitude interference (Python 3.14). Run in the mirrored media directory; writes fresnel-biprism-virtual-sources.png. """ from pathlib import Path import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib.patches import Rectangle A = np.deg2rad(1.0) n, a, b, wavelength = 1.5, 0.10, 0.90, 600e-9 bend = (n - 1) * A separation = 2 * a * bend spacing = wavelength * (a + b) / separation fig, (rays, fringes) = plt.subplots(1, 2, figsize=(10.4, 4.2), dpi=120, gridspec_kw={'width_ratios': [2.15, 1]}, layout='constrained') fig.patch.set_facecolor('white') for ax in (rays, fringes): ax.set_facecolor('white') ax.spines[['top', 'right']].set_visible(False) rays.axhline(0, color='0.8', lw=0.8) for sign, color in [(1, '#2457a6'), (-1, '#ba4d22')]: virtual_height = sign * a * bend for height in sign * np.array([0.0004, 0.0008, 0.0012]): screen_height = height + b * (height / a - sign * bend) rays.plot([-100*a, 0], [0, 1000*height], color=color, lw=1.2) rays.plot([0, 100*b], [1000*height, 1000*screen_height], color=color, lw=1.2) rays.plot([-100*a, 0], [1000*virtual_height, 1000*height], '--', color=color, lw=0.8, alpha=0.65) rays.scatter([-100*a], [1000*virtual_height], facecolors='white', edgecolors=color, zorder=6, s=35) rays.annotate(f'Virtual source S{sign:+d}', (-100*a, 1000*virtual_height), xytext=(-9, sign*5.6), color=color, fontsize=9, arrowprops={'arrowstyle': '-', 'color': color}) rays.scatter([-100*a], [0], color='black', s=22, zorder=7) rays.annotate('Slit S', (-100*a, 0), xytext=(-15, 2.7), fontsize=9, arrowprops={'arrowstyle': '-', 'color': 'black'}) rays.add_patch(Rectangle((-0.45, -3), 0.9, 6, color='#5bbac4', alpha=0.5, zorder=5)) rays.text(2, 6.8, 'Thin biprism\n(schematic)', fontsize=9) rays.plot([100*b]*2, [-7.5, 7.5], color='black', lw=2) rays.text(100*b-3, 7.9, 'Screen', ha='center', fontsize=10) rays.set(xlim=(-17, 97), ylim=(-8.5, 8.7), xlabel='Axial position (cm)', ylabel='Transverse position (mm)', title='Two virtual sources from one slit') rays.text(30, -7.8, 'Dashed lines: backward extensions', fontsize=9, color='0.35') screen_position = np.linspace(-1e-3, 1e-3, 1800) intensity = 0.5 * (1 + np.cos(2*np.pi * screen_position / spacing)) fringes.plot(intensity, screen_position*1000, color='#57498b', lw=1.7) fringes.set(xlim=(0, 1.1), ylim=(-1, 1), xlabel='Normalized intensity', ylabel='Screen position (mm)', title='Central interference fringes') fringes.grid(alpha=0.18) fringes.text(0.03, 0.02, f'Fringe spacing = {spacing*1e3:.3f} mm', transform=fringes.transAxes, fontsize=9, bbox={'facecolor': 'white', 'edgecolor': 'none', 'alpha': 0.9}) fig.suptitle('Chosen thin-prism model: n = 1.50, A = 1°, a = 0.10 m, b = 0.90 m, λ = 600 nm', fontsize=11) fig.savefig(Path('fresnel-biprism-virtual-sources.png'), facecolor='white', transparent=False) plt.close(fig)