fput-plate#
The fourth chaos toy: the FPUT chain made two-dimensional, as a toy cymbal or gong. It follows ../gong-wire, which added bending stiffness and a dome to the FPUT chain but sounded thin. The reason is the mode count: a one-dimensional wire with plate-like dispersion has fewer and fewer modes per octave as the pitch rises, so its high band holds only a handful of widely spaced partials. A two-dimensional plate has roughly a constant number of modes per unit frequency, so each octave up holds about twice as many as the one below, and that dense top is what a cymbal's wash is made of.
The model (plate.py)#
unit beads on a square grid move up and down, ; the boundary ring is pinned and the bending simply supported. The sheet may be built as a shallow dome . The energy is
with the height difference across a link to one of the four neighbours, its rest slope, and the 5-point Laplacian. The links are the FPUT- springs in two directions (a height difference stretches a link by about ), standing in for a plate's midplane stretching; bending gives plate-like dispersion; the dome adds stiffness and the three-wave coupling of curved shells. Without a dome the modes are products of sines with , , and mode energies are computed in this basis (approximately, when there is a dome). Damping is friction plus dashpots between neighbours, applied explicitly each step; time stepping is leapfrog. Checks: the force equals minus the energy gradient to 2e-11, the sine products are exact modes of the flat sheet to 4e-16, and energy is conserved to 1e-5 to 1e-4.
One simplification to keep in mind: the links pull only vertically, while a real plate's midplane can also slide sideways and partly relax the stretching. The sheet's nonlinearity is therefore stiffer than a plate's; FPUT makes the same simplification.
Results (2026-10-05)#
With 24 x 24 beads there are 576 modes. With bending stiffness 25 and the lowest mode at 100 Hz they reach 16.8 kHz; with bending 4 they reach only 8.6 kHz, but even then the count per octave rises steadily: 2, 7, 18, 36, 104 and 300 modes in the octaves from 100 Hz up to 6.4 kHz.
Exploration, undamped (experiments.py, results/explore.png; strike centered on bead (8, 10), radius 2). Share of the energy above 4 kHz at 10, 50 and 300 ms, dome 10:
| bending | top mode | E = 3000 | E = 10000 | E = 30000 |
|---|---|---|---|---|
| 8 | 11.4 kHz | 5%, 25%, 60% | 30%, 59%, 69% | 50%, 70%, 74% |
| 25 | 16.8 kHz | 0.2%, 1%, 13% | 3%, 13%, 49% | 21%, 54%, 74% |
The sheet needs much harder strikes than the wire or the chain (around rather than 10 to 50), because the bending stiffness dominates the linear forces and the stretching only competes at larger amplitudes. At bending 25 and the energy climbs into the band above 4 kHz over 300 ms, a gradual bloom; at it climbs within tens of milliseconds. A dome of height 10 adds a few percent; without one the picture is the same.
Bloom without chaos, unless damping is light. In the web app (lowest mode ringing 4 s, highest 0.8 s) the Gong preset () puts 22% of the energy above 4 kHz at 145 ms, and the Crash preset () 47% at 152 ms. With the highest mode ringing only 0.25 s, even the Crash strike was essentially regular: a perturbation grew by about in all, and strikes differing by ended identical. Strikes differing by still drifted apart, through amplitude-dependent pitch shifts rather than exponential separation. Undamped, the same strike is chaotic (growth about in 0.6 s). So in this toy, as in the gong wire, the high-frequency bloom is robust and reproducible, while chaos needs both a hard strike and light damping of the high modes.
Where the chaos is (chaos_scan.py). Pairs of strikes differing by in strength, 1.5 s of sound, lowest mode at 100 Hz ringing 6 s, strike at bead (9, 10) with radius 1.6. Reported: RMS difference of the final energy share per band, in dB, for the highest mode ringing 0.8 / 2 / 5 s. Values below about 0.1 dB mean the strikes ended the same; above 1 dB they sound different.
| bending, dome | E = 10^4 | E = 3 x 10^4 | E = 10^5 |
|---|---|---|---|
| 8, flat | 0.00 / 0.05 / 0.30 | 1.5 / 2.3 / 3.2 | 2.9 / 2.8 / 4.0 |
| 8, dome 10 | 0.05 / 0.63 / 1.8 | 2.2 / 4.7 / 2.3 | 3.1 / 5.5 / 2.7 |
| 25, flat | 0.03 / 0.02 / 0.04 | 0.02 / 0.04 / 0.04 | 0.11 / 2.5 / 2.5 |
| 25, dome 10 | 0.01 / 0.01 / 0.02 | 0.03 / 0.35 / 0.24 | 1.6 / 3.6 / 4.2 |
Softer bending makes chaos far easier to reach: at bending 8 every strike of or more is chaotic, while bending 25 needs about and a high-mode ring of 2 s or more. Presumably this is because the stretching competes with a weaker linear restoring force, so the same strike is relatively more nonlinear. A dome helps in most cases, and so does lighter damping of the high modes, with some exceptions (bending 8, dome 10, differs less at 5 s than at 2 s; with only one pair per setting these numbers carry noise). The app's original presets (bending 25, , high ring 0.8 s) all sit in the regular corner, which is why hits there sounded identical.
Time step. The app steps at about 0.6 of leapfrog's linear stability limit. Waveforms differ from runs with 4 times smaller steps (the top modes accumulate phase error over hundreds of periods), but the share of energy above 4 kHz over time and the final spectrum by band agree within a few percent, which is what the sound depends on.
Web application#
web/index.html (published as a private artifact at https://claude.ai/artifact/UeCkZbQqcbzpk3e4kvCmr5) runs 8 strikes and a separate Lyapunov run in parallel Web Workers. Controls: strike energy, bending stiffness, dome height, beads per side, strike position (sliders, or click the sheet) and radius, listener position (sliders, or shift-click) or the whole sheet summed, the difference between strikes, ring times, pitch of the lowest mode (held so the top stays under 20 kHz), and length. Panels: the sheet from above with heights as color (with slow motion), strike A's energy per frequency band over time, the share above 1 and 4 kHz for all strikes, their final spectra by band, the local Lyapunov exponent with the energy, and a spectrogram of any strike. Presets: Soft (), Gong (), Crash (), Flat (no dome), all regular; and two chosen from the scan to be chaotic: Chaotic gong (bending 8, , high ring 2 s, lowest mode 150 Hz; final spectra differ by 1.5 dB in the browser) and Chaotic crash (bending 25, , high ring 2 s; 1.1 dB). Computing a preset takes about 5 to 10 s on a 12-core laptop; the Lyapunov run, which also integrates the tangent dynamics, takes about three times as long as a strike and sets the wait. The step code works on zero-padded arrays with the substeps fused into three passes; it gives bit-for-bit the same output as the plain version and runs about 1.5 times faster. Locally: cd web && python -m http.server.
Running#
Experiments run on the office workstation (~/work/fput-plate, Python 3.9 with numpy), plots locally:
WORKERS=12 python experiments.py # results/explore.npz (weaker strikes)
TAG=explore2 WORKERS=12 python experiments.py # results/explore2.npz (harder strikes)
python plots.py # results/explore.png