/ proof-of-concept / toy-instruments
Sign in
proof-of-concept / toy-instruments
Cymbal defaults to bow and bell with a 1 m/s stick; Run button at the top of the panel
Jeremy Magland <jmagland@flatironinstitute.org> committed commit a9ca16b1ac47 parent a78afe0 Browse files
5 changed files+15−11
README.mdmodified+1−1View file
@@ -36,7 +36,7 @@ String tests (`test/string.test.ts`): modes vs the discrete-string formula; smal
3636
3737 ## Cymbal
3838
39-- Thin bronze plate (E = 100 GPa, 8600 kg/m^3, 0.8 mm by default), round, free rim, centre hole; flat by default, optional bow (dome, y = h (1 - (r/R)^2)) and bell (raised cosine). Beads on a triangular lattice lifted to the profile; the mesh is scaled so its area equals the disk's.
39+- Thin bronze plate (E = 100 GPa, 8600 kg/m^3, 0.8 mm by default), round, free rim, centre hole; flat, or with a bow (dome, y = h (1 - (r/R)^2)) and a bell (raised cosine); the default preset has a 12 mm bow and bell and a stick at 1 m/s. Beads on a triangular lattice lifted to the profile; the mesh is scaled so its area equals the disk's.
4040 - In-plane: springs with k = sqrt(3)/2 E t / softening (an edge with one triangle gets half). Softening (default 30x in the fast preset) speeds the run; bending is unaffected.
4141 - Bending: dihedral angles across interior edges (`src/sim/hinge.ts`, Bridson et al. 2003), sign-normalized so a positive change folds toward the upward normal. Each triangle builds a shape operator S = sum_e phi_e l_e / (2A) m_e m_e^T and stores the plate energy A D/2 [(tr S)^2 - 2 (1 - nu) det S] (nu = 1/3) as a 3x3 matrix in its hinge angles, condensed over free edges so they carry no moment. Plain hinge springs get the twisting term wrong on a regular mesh (effective nu = -1/3), which matters for a free rim. Damping uses the same matrices (Rayleigh, sigma1 omega^2).
4242 - Support: none. The plate is free; its rigid-body motion (translation and rotation, mass-weighted about the current centre of mass) is removed from the accelerations at every force evaluation and from the velocities after every step (`BeadSystem.freeRigid`). The elastic modes are mass-orthogonal to the rigid ones, so they are unchanged; nothing stiffens or damps them. Pinning only the centre bead was tried: an off-centre hit sets the plate tumbling (tilts past 89 degrees within a second).
src/instruments/bead-cymbal/presets.tsmodified+8−7View file
@@ -22,7 +22,7 @@ const toy: CymbalParams = {
2222 hitAngle: 0,
2323 excWidth: 0.015, // wider than a stick tip: one light bead alone makes the stick chatter
2424 stickMass: 0.03,
25- stickSpeed: 4,
25+ stickSpeed: 1,
2626 stickK: 5e8,
2727 malletMass: 0.03,
2828 malletSpeed: 2,
@@ -48,10 +48,16 @@ export interface CymbalPreset {
4848 }
4949
5050 export const CYMBAL_PRESETS: CymbalPreset[] = [
51+ {
52+ name: 'Bow and bell, stick',
53+ description:
54+ '8" bronze cymbal, 0.8 mm, with a 12 mm bow (dome) and a 7 cm bell, 12 mm high; ~370 beads, free (nothing holds it; its rigid motion is removed). In-plane stiffness softened 30× for speed; curvature couples bending to in-plane stretching, so softening matters more here than on a flat plate. Stick at 1 m/s near the edge, spread over a 15 mm patch (a single bead would make the stick chatter). Bending is resolved to about 1.3 kHz.',
55+ params: { ...toy, bowHeight: 0.012, bellHeight: 0.012 },
56+ },
5157 {
5258 name: 'Flat 8" toy, stick (fast)',
5359 description:
54- 'Flat 0.8 mm bronze plate, 20 cm, ~370 beads, free (nothing holds it; its rigid motion is removed). In-plane stiffness softened 30× for speed (bending is real). Stick hit near the edge, spread over a 15 mm patch (a single bead would make the stick chatter). Bending is resolved to about 1.3 kHz.',
60+ 'Flat 0.8 mm bronze plate, 20 cm, ~370 beads, free. In-plane stiffness softened 30× for speed (a flat plate bends the same at small amplitude). Stick at 1 m/s near the edge, spread over a 15 mm patch.',
5561 params: toy,
5662 },
5763 {
@@ -59,11 +65,6 @@ export const CYMBAL_PRESETS: CymbalPreset[] = [
5965 description: 'Same plate with real in-plane stiffness: about 5× more time steps.',
6066 params: { ...toy, soften: 1 },
6167 },
62- {
63- name: 'Bow and bell',
64- description: '12 mm bow (dome) and a 7 cm bell, 12 mm high. Curvature couples bending to in-plane stretching, so softening matters more here.',
65- params: { ...toy, bowHeight: 0.012, bellHeight: 0.012 },
66- },
6768 {
6869 name: 'Glancing crash stroke',
6970 description: 'Stick at 6 m/s, 60° from the normal toward the rim, with friction: pushes the plate sideways as well as down.',
src/style.cssmodified+1−0View file
@@ -116,6 +116,7 @@ input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1
116116 .btn:disabled { opacity: 0.5; cursor: default; }
117117 .btn-small { background: transparent; color: var(--text-primary); border: 1px solid var(--border); padding: 4px 10px; font-size: 13px; }
118118 .run-row { display: flex; gap: 8px; align-items: center; margin-top: 14px; }
119+.run-row.top { margin-top: 4px; }
119120 .gpu-toggle { margin-left: auto; }
120121 progress { width: 100%; margin-top: 8px; accent-color: var(--accent); }
121122
src/ui/instrumentPage.tsmodified+2−2View file
@@ -64,14 +64,14 @@ export function mountInstrumentPage<P extends SimParams>(root: HTMLElement, cfg:
6464 <h1>${cfg.title}</h1>
6565 <label class="ctl preset"><span class="ctl-name">Preset</span><select data-r="preset"></select></label>
6666 <p class="sub" data-r="preset-desc"></p>
67- <div data-r="controls"></div>
68- <div class="run-row">
67+ <div class="run-row top">
6968 <button class="btn" data-r="run">Run simulation</button>
7069 <button class="btn-small" data-r="cancel" hidden>Cancel</button>
7170 <label class="inline gpu-toggle" data-r="gpu-label"><input type="checkbox" data-r="gpu"> WebGPU</label>
7271 </div>
7372 <progress data-r="progress" max="1" value="0" hidden></progress>
7473 <p class="error" data-r="error" hidden></p>
74+ <div data-r="controls"></div>
7575 </aside>
7676 <main class="results">
7777 <section class="card"><h2>Model</h2><div data-r="scene"></div></section>
test/cymbal.test.tsmodified+3−1View file
@@ -4,7 +4,9 @@ import { CYMBAL_PRESETS } from '../src/instruments/bead-cymbal/presets';
44 import { bendingEnergy, simulate } from '../src/sim/solver';
55 import { spectrum } from '../src/ui/fft';
66
7-const base = (over: Partial<CymbalParams> = {}): CymbalParams => ({ ...CYMBAL_PRESETS[0].params, ...over });
7+// the flat plate (the tests compare with flat-plate theory)
8+const flat = CYMBAL_PRESETS.find((p) => p.name.startsWith('Flat 8" toy, stick'))!.params;
9+const base = (over: Partial<CymbalParams> = {}): CymbalParams => ({ ...flat, ...over });
810
911 describe('cymbal lattice', () => {
1012 it('bending energy matches the plate (nu = 1/3) for bending, doming and twisting', () => {
↑↓ move↵openescclose