codexfloquet-stroboscopic-multiplier-and-rate.py
floquet-stroboscopic-multiplier-and-rate.py
"""Compare one-period multipliers with instantaneous and asymptotic rates.
Emit the PNG into the current directory. Tested with Python 3.14,
NumPy 2.3.5, and Matplotlib 3.10.7.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
plt.rcParams.update({"font.size": 11, "axes.spines.top": False,
"axes.spines.right": False, "figure.facecolor": "white"})
period = 2 * np.pi
n = np.arange(9)
t = np.linspace(0, 2 * period, 1201)
cases = [(-0.2, "#2476aa"), (0.0, "#25834d"), (0.2, "#bf5229")]
fig, (left, right) = plt.subplots(1, 2, figsize=(11, 5.4), layout="constrained")
fig.suptitle(r"$y'= (a+\cos t)y$: factor per period versus rate per unit time", fontsize=16)
for a, color in cases:
multiplier = np.exp(a * period)
left.semilogy(n, multiplier ** n, "o-", color=color, lw=2, ms=5,
label=f"a = {a:+.1f}, m = {multiplier:.4f}")
right.plot(t / period, a + np.cos(t), color=color, lw=2,
label=f"a = {a:+.1f}")
right.axhline(a, color=color, ls="--", lw=1.6)
left.set(title=r"Same phase every period: $y(nT)=m^n$", xlabel=r"Number of periods $n$",
ylabel=r"Sampled value $y(nT)$ (log scale)", xlim=(-0.15, 8.15))
left.set_xticks(n)
left.legend(loc="upper left", framealpha=0.95, fontsize=10)
left.text(0.04, 0.03, r"$\log y(nT)=n\log m=nTa$", transform=left.transAxes,
bbox={"facecolor": "white", "edgecolor": "none", "alpha": 0.9})
right.set(title="Instantaneous oscillation and long-term rate",
xlabel=r"Time $t/T$, with $T=2\pi$", ylabel="Logarithmic growth rate",
xlim=(0, 2), ylim=(-1.45, 1.45))
right.set_xticks([0, 0.5, 1, 1.5, 2])
right.legend(loc="upper right", fontsize=10)
right.text(0.03, 0.04, "Solid: instantaneous rate a + cos t\nDashed: long-term rate log(m)/T = a",
transform=right.transAxes, fontsize=10,
bbox={"facecolor": "white", "edgecolor": "none", "alpha": 0.94})
for ax in [left, right]:
ax.grid(alpha=0.18)
fig.savefig(Path(__file__).stem + ".png", dpi=100, facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()