/ proof-of-concept / fput-chain
Sign in
proof-of-concept / fput-chain
fput-chain / README.md
5.9 KBPreviewCodeBlameHistoryRaw

fput-chain#

(See also ../gong-wire, which adds bending stiffness and a dome to this chain to get a gong-like cascade to high frequencies.)

A struck Fermi-Pasta-Ulam-Tsingou chain: the many-mode companion of the two-oscillator toy in ../chaos-toy-examples, and a simple stand-in for the struck plate of cymbal-elastodynamics/flat-plate-2.

The model#

NN unit masses on a line between two fixed walls, joined by springs with force law f(Δ)=Δ+βΔ3f(\Delta) = \Delta + \beta \Delta^3 (β=1\beta = 1), and optionally held by on-site springs of stiffness μ2\mu^2. The normal modes are sin⁡(jkπ/(N+1))\sin(jk\pi/(N+1)) with ωk2=μ2+4sin⁡2(kπ/(2(N+1)))\omega_k^2 = \mu^2 + 4\sin^2(k\pi/(2(N+1))): for μ=0\mu = 0 the low modes are nearly harmonic (like a string), and μ>0\mu > 0 detunes them (like a plate). The stiffness of a stretched spring is 1+3βΔ21 + 3\beta\Delta^2, so stretching couples the modes, as stretching the midplane does in a plate. Damping is friction c0c_0 on every mass plus dashpots c1c_1 between neighbours; mode kk decays (in amplitude) at (c0+c1(ωk2−μ2))/2(c_0 + c_1(\omega_k^2 - \mu^2))/2, the chain's version of the plate's σ0+σ1k2\sigma_0 + \sigma_1 k^2 damping. The strike gives a few masses near one end a smooth velocity profile with kinetic energy EE.

model.py integrates ensembles of strikes with a fourth-order symplectic scheme (Yoshida) and the exact propagator of the damping, integrates the tangent dynamics for the largest Lyapunov exponent, and computes mode energies and the effective fraction of modes eS/Ne^S/N (SS the entropy of the mode shares; 1 for equal shares, about 0.7 for random equipartition, 1/N1/N for a single mode).

Results (2026-10-05; N=32N = 32, strike on mass 8, width 2 masses)#

Equipartition and chaos vs strike energy, undamped (results/scan.png, 4000 time units, 6 strikes per energy):

E 0.5 0.8 2 5 13 32 50
μ=0\mu = 0: Lyapunov exponent 0.0007 0.0015 0.006 0.021 0.050 0.10 0.13
μ=0\mu = 0: fraction of modes sharing the energy 0.18 0.50 0.67 0.67 0.64 0.64 0.67
μ=1\mu = 1: Lyapunov exponent 0 0 0.0001 0.0002 0.0009 0.013 0.037
μ=1\mu = 1: fraction of modes sharing the energy 0.17 0.17 0.18 0.18 0.18 0.25 0.43

Below E≈0.5E \approx 0.5 the harmonic chain keeps the strike's energy in the modes it started in, the classic FPUT observation. From E≈1E \approx 1 to 2 it spreads to equipartition, and the Lyapunov exponent grows roughly in proportion to EE. The detuned chain (μ=1\mu = 1) holds the energy in its initial modes up to E≈30E \approx 30, some twenty times more: detuning removes the near-resonances through which the modes exchange energy (results/cascade.png shows the mode energies over time). The same effect, much weaker, separated the equal and detuned pairs of the two-oscillator toy, and the plate's spectrum is strongly inharmonic.

Damped strikes and the frozen spectrum (results/damped_mu0.png, results/damped_mu1.png; lowest mode decaying at 4e-4, highest at 3e-3 per time unit; 16 strikes whose strengths differ by 10−1010^{-10} times the member index):

So an energy cascade is not the same as an audible fingerprint. Whether a tiny difference between strikes grows to a visible one depends on the amplification accumulated over the chaotic phase, exp⁡(∫λ dt)\exp(\int \lambda\, dt), against the size of the difference; a strike can share its energy among all modes and still be perfectly repeatable. The damping enters directly: the web app shows that with the highest mode damped twice as fast (ring time 0.15 s instead of 0.3 s at 110 Hz), the strong strike at E0=30E_0 = 30 no longer separates at all.

Web application#

web/index.html (single page, no build step; published as a private artifact at https://claude.ai/artifact/C6oaNiG2zCRX9VR7Wn4Wfx) simulates 8 strikes in the browser and plays strikes A and B. Controls: strike energy, number of masses, on-site springs, strike position and width, the A/B difference, ring times of the lowest and highest modes, the pitch of the lowest mode, and length. Panels: the chain with displacements drawn sideways and springs drawn by stiffness (with slow motion), the energy of strike A per mode over time, the effective fraction of modes for all 8 strikes, their final spectra, the local Lyapunov exponent with the energy, and a spectrogram of any of the 8 strikes (a selector above it, or the arrow keys, flips between strikes on a shared color scale, highlights the chosen strike in the two plots above, and plays it). Presets: Gentle (E=0.5E = 0.5), Cascade only (E=5E = 5), Strong (E=30E = 30), Strong, detuned (μ=1\mu = 1, E=30E = 30). Locally: cd web && python -m http.server.

Time in the app is scaled so the lowest mode sounds at the chosen pitch, so a ring time in seconds means different damping in the chain's own time units for different μ\mu: with μ=1\mu = 1 the lowest mode is at ω≈1\omega \approx 1 instead of 0.095, and one second of sound is about ten times fewer time units.

Running#

Experiments run on the office workstation (~/work/fput-chain, Python 3.9 with numpy and scipy), plots locally:

WORKERS=32 python experiments.py all     # results/*.npz
python plots.py                          # results/*.png
↑↓ move↵openescclose