codexmach-angle-versus-speed-ratio.py
mach-angle-versus-speed-ratio.py
"""Original Mach-angle curve; Python 3.14, NumPy 2.3.5, Matplotlib 3.10.7.
Run from _media; writes mach-angle-versus-speed-ratio.png to the CWD.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
plt.rcParams.update({"font.size": 12, "axes.spines.top": False,
"axes.spines.right": False})
fig, ax = plt.subplots(figsize=(8, 5.5), dpi=120, facecolor="white")
ax.set_facecolor("white")
mach = np.linspace(1, 6, 1200)
angle = np.degrees(np.arcsin(1 / mach))
ax.plot(mach, angle, color="#285b89", lw=2.6)
ax.plot(1, 90, "o", ms=7, mfc="white", mec="#285b89", mew=1.8)
ax.text(1.12, 84, r"$90^\circ$ limit as $M\to1^+$", fontsize=11)
ax.plot([2, 2], [0, 30], "--", color="#c64632", lw=1.3)
ax.plot([1, 2], [30, 30], "--", color="#c64632", lw=1.3)
ax.plot(2, 30, "o", color="#c64632", ms=8)
ax.annotate(r"$M=2\quad\Rightarrow\quad\mu=30^\circ$",
(2, 30), (3.1, 52), color="#a63223",
arrowprops={"arrowstyle": "->", "color": "#a63223"})
ax.text(3.0, 71,
r"$U=680\ \mathrm{m\,s^{-1}}$" + "\n" +
r"$c=340\ \mathrm{m\,s^{-1}}$" + "\n" +
"Chosen uniform-gas example",
fontsize=11, bbox={"boxstyle": "round,pad=0.5",
"facecolor": "#f3f6f9", "edgecolor": "#c8d1db"})
ax.set_xlim(0.95, 6.05)
ax.set_ylim(0, 96)
ax.set_xticks([1, 2, 3, 4, 5, 6])
ax.set_yticks([0, 15, 30, 45, 60, 75, 90])
ax.set_xlabel(r"Mach number $M=U/c$ (gas-relative speed)")
ax.set_ylabel(r"Mach half-angle $\mu$ (degrees)")
ax.grid(alpha=0.22)
ax.set_title(r"A faster source makes a narrower sound cone: "
r"$\mu=\arcsin(1/M)$", fontsize=14, pad=14)
fig.text(0.5, 0.075,
"Weak linear waves, steady source, uniform isotropic 3D medium; M > 1.",
ha="center", fontsize=10)
fig.text(0.5, 0.029,
"Model prediction; not a finite-deflection shock angle or measured boom strength.",
ha="center", fontsize=10, color="#525b65")
fig.subplots_adjust(left=0.12, right=0.975, top=0.875, bottom=0.23)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"),
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()