// Generic bead-spring system in 3D. Instruments build one of these; the solver // integrates it. SI units throughout. export interface Anchor { pos: [number, number, number]; // -1: fixed point. Otherwise a massless ring on a rod: x fixed, y and z // follow this bead, so the spring to it stays parallel to x (no transverse force). slideBead: number; } export interface BeadSystem { n: number; // number of beads rest: Float64Array; // 3n equilibrium positions mass: Float64Array; // n pinned: Uint8Array; // n, 1 = held fixed at rest position anchors: Anchor[]; // node index n + a // springs: endpoints are node indices (bead < n, anchor >= n) si: Int32Array; sj: Int32Array; sk: Float64Array; // stiffness (N/m) sL0: Float64Array; // rest length (m) sc: Float64Array; // dashpot on relative velocity, all 3 components (N s/m) sigma0: number; // mass-proportional damping: force -2 sigma0 m v } export interface Excitation { u0: Float64Array; // 3n initial displacement from rest v0: Float64Array; // 3n initial velocity // External force F(t) = shape * F0 * 0.5 (1 - cos(2 pi t / tau)), 0 <= t <= tau force?: { shape: Float64Array; F0: number; tau: number }; } export interface SimOptions { duration: number; // s fs: number; // audio sample rate (Hz) cfl: number; // fraction of the leapfrog stability limit 2/omega_max frameRate: number; // displacement frames per second pickup: Float64Array; // 3n weights; audio = sum w . acceleration } export interface SimResult { audio: Float32Array; // pickup acceleration (m/s^2) at fs fs: number; frames: Float32Array; // nFrames x 3n displacement from rest frameTimes: Float64Array; energy: Float64Array; // mechanical energy above equilibrium at frame times (J) balance: Float64Array; // E + dissipated - work_in - E0 at frame times (J) dt: number; stepsPerSample: number; omegaMax: number; wallSeconds: number; maxStretch: number; // largest |l - L0| / L0 seen, at frame times }