"""Own idealized stopping pulses; write the PNG to the current directory. Tested with Python 3.14.4, NumPy 2.3.5 and Matplotlib 3.10.7. The pulses are synthetic examples, not reconstructions of crash-test data. """ from pathlib import Path import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt import numpy as np duration = 0.100 # seconds time = np.linspace(0.0, duration, 1001) constant = np.full_like(time, 80.0) triangular = 160.0 * (1.0 - np.abs(2.0 * time / duration - 1.0)) assert np.isclose(np.trapezoid(constant, time), 8.0) assert np.isclose(np.trapezoid(triangular, time), 8.0) assert np.isclose(constant.max(), 80.0) assert np.isclose(triangular.max(), 160.0) plt.rcParams.update({"font.size": 11, "figure.facecolor": "white"}) fig, axes = plt.subplots(1, 2, figsize=(8.5, 4.2), dpi=100, sharey=True) fig.subplots_adjust(left=0.085, right=0.985, bottom=0.19, top=0.77, wspace=0.18) fig.suptitle("Same velocity change, different peak deceleration", y=0.96, fontsize=14) for ax, values, title, peak, color in [ (axes[0], constant, "Constant pulse", 80, "#1766a0"), (axes[1], triangular, "Triangular pulse", 160, "#b04d13"), ]: ax.fill_between(time * 1000, values, color=color, alpha=0.18) ax.plot(time * 1000, values, color=color, linewidth=2.5) ax.vlines([0, 100], [0, 0], [values[0], values[-1]], color=color, linewidth=2.5) ax.set_title(title, fontsize=12) ax.text(0.04, 0.91, f"Peak = {peak} m/s²", transform=ax.transAxes, fontsize=10) ax.text(0.5, 0.10, "Area = 8 m/s", ha="center", transform=ax.transAxes) ax.set(xlim=(-2, 102), ylim=(0, 180), xlabel="Time (ms)") ax.set_xticks([0, 25, 50, 75, 100]) ax.set_yticks([0, 40, 80, 120, 160]) ax.grid(alpha=0.18) ax.spines[["top", "right"]].set_visible(False) axes[0].set_ylabel("Deceleration magnitude (m/s²)") fig.text(0.5, 0.045, "Synthetic 100 ms stopping pulses; shaded area is speed lost.", ha="center", fontsize=10) fig.savefig(Path("crash-pulse-equal-velocity-change.png"), facecolor="white") plt.close(fig)