/ proof-of-concept / bead-percussion
Sign in
proof-of-concept / bead-percussion
bead-percussion / src / sim / types.ts
100 lines · 3.8 KBCodeBlameHistory
fc06d37Bead-and-spring percussion simulator: numbl-scripted setup, Verlet/Yoshida solver with exact damping, linear modes, browser appJeremy Magland 1// The bead system as the solver sees it. Indices are 0-based here; the
2// script uses 1-based indices and parse.ts converts them.
4export type Method = "verlet" | "yoshida4";
7export interface Hit {
8 t: number; // start time (s)
9 beads: Int32Array;
10 // Impulse: velocity added to each bead at time t (m/s). Used when duration == 0.
11 velocity: [number, number, number];
12 // Force pulse: raised-cosine force on each bead, peak `force` (N), lasting `duration` (s).
13 force: [number, number, number];
14 duration: number;
17export interface BeadSystem {
18 n: number;
19 pos0: Float64Array; // 3n, interleaved x,y,z (m)
20 mass: Float64Array; // n (kg)
21 pinned: Uint8Array; // n, 1 = held fixed
22 // Springs: f = k e + k3 e^3, e = L - L0
23 si: Int32Array;
24 sj: Int32Array;
25 sk: Float64Array;
26 sL0: Float64Array;
27 sk3: Float64Array;
29 // with damping force -cb (v_i - 2 v_j + v_k) (1, -2, 1) on (i, j, k)
30 bi: Int32Array;
31 bj: Int32Array;
32 bk: Int32Array;
33 bkb: Float64Array;
34 bcb: Float64Array;
36 // energy kh/2 (theta - theta0)^2, theta the angle between the triangles,
37 // theta0 its value at the rest positions; damping force -ch (dtheta/dt) grad theta
38 hi: Int32Array;
39 hj: Int32Array;
40 hk: Int32Array;
41 hl: Int32Array;
42 hkh: Float64Array;
43 hch: Float64Array;
44 hth0: Float64Array;
46 di: Int32Array;
47 dj: Int32Array;
48 dc: Float64Array;
50 // direction d from bead i to bead j
51 dca: Float64Array;
53 hits: Hit[];
54 listenBeads: Int32Array;
55 listenDir: [number, number, number]; // unit vector
58 sampleRate: number; // Hz, audio output
59 dt: number; // s; 0 = automatic
60 safety: number; // fraction of the stability limit used when dt is automatic
61 method: Method;
62 frameRate: number; // Hz, snapshots for animation and mode energies
917e5cdWebGPU toggle: single-precision GPU integration (displacement-based, multi-dispatch phases, frames read back), linear modes behind a toggle (off by default), shared prepare()Jeremy Magland 63 modes: boolean | null; // compute linear modes and track their energies; null: as the page's toggle says
66export interface SimProgress {
67 t: number;
68 duration: number;
71export interface Modes {
72 freqs: Float64Array; // Hz, ascending
74 // freedom in dof, column-major (dof.length x nModes)
77 kind: "transverse" | "full"; // z motion of a flat net only, or all motion
80export interface SimResult {
81 audio: Float32Array; // listener displacement at sampleRate (m)
82 sampleRate: number;
83 dt: number;
84 substeps: number; // solver steps per audio sample
85 omegaMax: number; // rad/s, highest linearized frequency
86 frameTimes: Float64Array; // times of the energy records (s)
87 energy: Float64Array; // mechanical energy above the rest state at each frame (J)
88 animTimes: Float64Array; // times of the stored displacement snapshots (s)
89 animFrames: Float32Array[]; // displacement (3n) at each snapshot (m)
90 dissipated: Float64Array; // cumulative energy removed by damping (J)
91 // mode energies (nModes per frame, frame-major), present when modes were computed
92 modeEnergy: Float32Array | null;
93 residualForce: number; // max |F| on free beads at rest (N)
94 maxTension: number; // max spring force at rest (N)
95 energyDrift: number; // max relative change in E + dissipated after the last excitation
96 freqErrors: { hz: number; cents: number }[]; // integrator frequency error at a few frequencies
97 elapsedMs: number;
98 aborted: string | null; // reason if the run stopped early
99 warnings: string[];
↑↓ move↵openescclose