codex/crash-pulse-equal-velocity-change.py

crash-pulse-equal-velocity-change.py
"""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)