0e92d35Pizzicato standup bass: coupled string-body modal model, numbl MATLAB reference, and interactive web appJeremy Magland 1# Standup Bass
3A physically-based simulation of a pizzicato standup bass (double bass), playing a single note or a seeded walking line, sampled as acoustic pressure at a point in space. Each note is a stiff, lossy string two-way coupled at the bridge to a modal model of the corpus; the pluck is a released initial condition, so between events nothing is integrated, and the coupled modes radiate to a listener point through the f-hole Helmholtz monopole and the top-plate dipoles.
5There is no microphone model: no directivity, no capsule response, no gain staging. The output is p(r, t) in pascals.
7## Contents
9| Path | What it is |
10|---|---|
11| `matlab/` | The algorithm in MATLAB syntax, run by [numbl](https://numbl.org) |
12| `webapp/` | Interactive browser app that executes the MATLAB code client-side |
14The MATLAB code runs from the command line with `cd matlab && numbl run bass_demo.m`, or `bass_validate.m` to run the checks. The web app is a Vite project; see `webapp/README.md`.
16## The model
18The signal chain, with each stage in its own `.m` file:
20```
21single note or seeded walking line bass_notes.m
22 -> body mode table seen at the bridge bass_body.m
23 -> string + body assembled per fingering bass_assemble.m
24 -> one coupled eigensolve per fingering bass_basis.m
25pluck -> initial condition on the coupled modes
26 -> closed-form damped exponentials, choked at
27 the next note
28 -> f-hole monopoles + top-plate dipoles bass_radiate.m
29 -> free-field pressure at the listener
30 -> anti-aliased decimation -> PCM bass_output.m
31```
33Three points are worth stating plainly, because they are where the model commits itself.
35**The string and the body are diagonalized together.** Each fingering (a string and a stop) is one symmetric generalized eigenproblem: the mass-normalized modes of the stiff pinned-pinned string, the modal body, and a bridge-ramp shape that lets the string's end move with the bridge. With that ansatz the elastic coupling integrals vanish and the whole coupling sits in the mass matrix, so the problem reduces through the Cholesky factor of M and is diagonalized by svd, which keeps near-degenerate coupled pairs orthonormal where a nonsymmetric eigensolver does not. The coupling is two-way: the body pulls the open A fundamental 14 cents flat at the defaults, and a note whose fundamental lands on a strong body resonance comes out as a split, fast-beating pair, which is the wolf-note mechanism, checked in the validation by its square-root-of-mobility splitting. The body itself is the empirical part: a table of twelve measured-plausible resonances (A0 near 60 Hz, the main wood modes from 97 Hz up) with effective bridge masses, Qs, and radiating areas, not a plate solve; above the table the dense modal region enters only as a resistive residual admittance. The bending stiffness of the wound string comes from a single inharmonicity parameter and stretches the high partials sharp, more so on stopped notes, as it should.
37**The pluck is an initial condition, not a force history.** Releasing a string pulled with force F leaves the classic triangular shape, whose projection through the coupled shapes gives every mode an initial amplitude, rolled off by a first-order finite-release filter standing in for the fingertip (the difference between a fleshy jazz pizzicato and a hard snap). From there every coupled mode is a damped exponential, so a note renders in closed form, faster than real time, unlike the sibling `recorder` repository whose oscillation must be integrated sample by sample. When the next note of a walking line lands, the previous note is choked with an extra decay standing in for the player stopping the string. What this gives up is the contact detail: there is no fingerboard collision, so the rattle of a very hard pluck is outside the model, and notes are otherwise independent, which is wrong for true legato slides. Damping is assigned in the uncoupled coordinates and projected: string internal loss, a finger termination on stopped notes (open strings ring longer, as on the instrument), the residual bridge conductance (a resistive end gives a constant decay rate, so the high partials die in under a second while the fundamental rings for ten), and the body Qs.
39**Radiation is a monopole pair plus dipoles, and one confessed shortcut.** A0 is the one body mode that moves net volume through the f-holes, and it radiates as a monopole split between the two f-hole points with their own retardations; every corpus mode displaces the top plate against the air with no net flow and radiates as a point dipole along the plate normal, near-field term kept, so walking behind the instrument flips their phase. The string itself is acoustically invisible. Above the retained body table, the bridge force acting on the resistive residual admittance moves the plate broadband, and that motion radiates as a small dipole: this is how the high partials reach the listener at all, it is the least principled term of the model, and `direct_gain` turns it off.
41## Validation
43`matlab/bass_validate.m` (also `npm run selftest` in `webapp/`) checks the decoupled solve against the closed-form stiff string (including the inharmonic stretch), the mass-orthonormality and stiffness-diagonalization identities of the coupled eigensolve, that a midpoint pluck silences the even partials end to end, that tuning a body mode onto a string fundamental splits it with the square-root-of-mobility scaling of a genuine two-way coupling, the far-field -6 dB per doubling of distance, exact reproducibility of the seeded walking line, and pinned end-to-end diagnostics.
45As in the sibling `maraca`, `triangle`, and `recorder` repositories, there is no separate Python reference implementation: the MATLAB code is the reference, and the pinned numbers were recorded from it when the model was built.
47## Defaults
49A 3/4-size bass with a 1.04 m scale, strung G2 D2 A1 E1 at 285 to 310 N (the linear densities follow from tension and pitch, about 7 g/m for the G and 42 g/m for the E). The default gesture is a single open A1 plucked with 15 N at 30% of the string from the bridge, released over 0.9 ms: 61 coupled modes (49 string, 12 body), a fundamental at 54.57 Hz that the body holds 14 cents flat of A1, a T60 of 10.7 s on that fundamental, and a peak of 0.371 Pa (85.4 dB SPL) at the 133 cm listener before normalization. Setting `note_count` to 8 walks a seeded quarter-note line in A major at 96 bpm, each note choked as the next lands.