import type { Damping, Material, PlateGeometry, ProblemSpec, ThreadMaterial } from "./types"; /** * Material presets. Values are room-temperature handbook figures for the named * alloy (ASM Handbook, MatWeb, Copper Development Association) and are typical * rather than certified: real stock varies by a few percent in E and rho. * The damping values are illustrative starting points in the two-parameter * loss model, not measurements; damping in a real plate depends heavily on the * mounting, which is part of what this lab is about. */ export interface MaterialPreset { id: string; material: Material; damping: Damping; /** Where the numbers come from and what they do not capture */ source: string; } export const MATERIAL_PRESETS: MaterialPreset[] = [ { id: "a36-steel", material: { name: "A36 structural steel", E: 200e9, nu: 0.26, rho: 7850 }, damping: { sigma0: 1.0, sigma1: 0.005 }, source: "ASTM A36 hot-rolled plate; E and nu typical of low-carbon steel.", }, { id: "304-stainless", material: { name: "304 stainless steel", E: 193e9, nu: 0.29, rho: 8000 }, damping: { sigma0: 1.0, sigma1: 0.005 }, source: "Annealed 304 sheet, typical values.", }, { id: "6061-t6", material: { name: "6061-T6 aluminium", E: 68.9e9, nu: 0.33, rho: 2700 }, damping: { sigma0: 1.2, sigma1: 0.006 }, source: "6061-T6 sheet and plate, typical values.", }, { id: "c260-brass", material: { name: "C260 cartridge brass", E: 110e9, nu: 0.375, rho: 8530 }, damping: { sigma0: 1.0, sigma1: 0.006 }, source: "70/30 brass, half-hard sheet, typical values.", }, { id: "ti-6al-4v", material: { name: "Ti-6Al-4V titanium", E: 113.8e9, nu: 0.342, rho: 4430 }, damping: { sigma0: 0.8, sigma1: 0.004 }, source: "Annealed Grade 5 titanium sheet, typical values.", }, { id: "b20-bronze", material: { name: "B20 bell bronze (CuSn20)", E: 105e9, nu: 0.34, rho: 8800 }, damping: { sigma0: 0.4, sigma1: 0.002 }, source: "Bell and cymbal bronze with about 20% tin; E ranges 100 to 110 GPa depending on the casting and working. Low damping is what makes it ring.", }, { id: "b8-bronze", material: { name: "B8 bronze (CuSn8)", E: 110e9, nu: 0.34, rho: 8800 }, damping: { sigma0: 0.5, sigma1: 0.0025 }, source: "8% tin bronze used for cymbals and as phosphor bronze sheet; typical values.", }, { id: "1095-spring-steel", material: { name: "1095 spring steel (bar stock)", E: 205e9, nu: 0.29, rho: 7850 }, damping: { sigma0: 0.5, sigma1: 0.003 }, source: "High-carbon steel used for glockenspiel and chime bars; E and rho typical of carbon steel.", }, ]; export interface PlatePreset { id: string; name: string; plate: PlateGeometry; /** Notes on what this stands in for */ note: string; } const inch = 0.0254; export const PLATE_PRESETS: PlatePreset[] = [ { id: "sheet-300x200x2", name: "300 x 200 x 2 mm sheet", plate: { shape: "rectangle", Lx: 0.3, Ly: 0.2, h: 0.002 }, note: "A common cut-to-size sheet; the default problem.", }, { id: "sheet-12x12x1-8in", name: "12 x 12 x 1/8 in plate", plate: { shape: "rectangle", Lx: 12 * inch, Ly: 12 * inch, h: inch / 8 }, note: "Square stock in imperial sizes.", }, { id: "sheet-500x300x1", name: "500 x 300 x 1 mm sheet", plate: { shape: "rectangle", Lx: 0.5, Ly: 0.3, h: 0.001 }, note: "Thin and large: many modes below 20 kHz, expensive for finite differences, and the one where the self-weight tension shifts the lowest modes most.", }, { id: "disk-300x2", name: "Disk, 300 mm diameter x 2 mm", plate: { shape: "ellipse", Lx: 0.3, Ly: 0.3, h: 0.002 }, note: "A round blank; hung from a hole near the rim it is a small gong.", }, { id: "disk-250x1", name: "Disk, 250 mm diameter x 1 mm", plate: { shape: "ellipse", Lx: 0.25, Ly: 0.25, h: 0.001 }, note: "Thin enough to hold between two fingers and strike.", }, { id: "ellipse-300x200x2", name: "Elliptical plate, 300 x 200 x 2 mm", plate: { shape: "ellipse", Lx: 0.3, Ly: 0.2, h: 0.002 }, note: "The default sheet cut to an ellipse: same box, same strike, less plate.", }, { id: "cymbal-flat-400x1p2", name: "Flat cymbal stand-in, 400 mm diameter x 1.2 mm", plate: { shape: "ellipse", Lx: 0.4, Ly: 0.4, h: 0.0012 }, note: "A cymbal is a disk, free at the rim and held at the centre between felts. What this flat disk leaves out is the curvature (a real cymbal is a shallow cone with a raised bell), the taper in thickness and the hole.", }, { id: "glockenspiel-bar", name: "Glockenspiel bar, 200 x 32 x 6 mm", plate: { shape: "rectangle", Lx: 0.2, Ly: 0.032, h: 0.006 }, note: "Real bars rest on two pads under the nodes of the first mode, which is the pads mount here. Thickness is a fifth of the width, at the edge of thin-plate validity.", }, { id: "ruler-300x50x3", name: "Steel strip, 300 x 50 x 3 mm", plate: { shape: "rectangle", Lx: 0.3, Ly: 0.05, h: 0.003 }, note: "A ruler-sized strip; clamp one end in a vise and it is the classic cantilever.", }, ]; export interface ThreadPreset { id: string; thread: ThreadMaterial; note: string; } /** * Threads. The shear modulus is what sets the torsional stiffness G J / L, * which for any of these is so small that a plate on one thread spins with a * period of minutes; it is here so that the spin has a frequency at all. */ export const THREAD_PRESETS: ThreadPreset[] = [ { id: "nylon-0p5", thread: { name: "nylon monofilament, 0.5 mm", diameter: 0.5e-3, G: 1.0e9 }, note: "Fishing line or sewing nylon; G about 1 GPa.", }, { id: "cotton-1", thread: { name: "cotton string, 1 mm", diameter: 1e-3, G: 0.3e9 }, note: "A twisted string; its effective shear modulus is low and uncertain.", }, { id: "steel-wire-0p3", thread: { name: "steel wire, 0.3 mm", diameter: 0.3e-3, G: 80e9 }, note: "Music wire; still a weak torsion spring at this diameter.", }, ]; export interface PadPreset { id: string; name: string; /** Stiffness [N/m^3] and damping [N s/m^3] per unit area */ k: number; c: number; note: string; } /** * Support materials as a stiffness and damping per unit area, E / t for a * layer of modulus E and thickness t with a loss factor of a few tenths at * some hundred hertz. Every one of these is an order-of-magnitude figure. */ export const PAD_PRESETS: PadPreset[] = [ { id: "foam-20", name: "soft foam, 20 mm", k: 2.5e6, c: 1.2e3, note: "Polyurethane packing foam, E about 50 kPa.", }, { id: "felt-5", name: "felt, 5 mm", k: 2e8, c: 6e4, note: "Dense wool felt, E about 1 MPa: the washers of a cymbal stand, the pads of a glockenspiel.", }, { id: "rubber-5", name: "rubber, 5 mm", k: 6e8, c: 1e5, note: "A rubber sheet, E about 3 MPa.", }, { id: "cork-5", name: "cork, 5 mm", k: 4e9, c: 3e5, note: "Cork, E about 20 MPa.", }, { id: "hard-edge", name: "hard edge (wood or metal)", k: 1e10, c: 1e5, note: "A knife edge or a bare bench: the stiffness is a penalty, not a measurement, and it shortens the time step a little.", }, ]; export interface ScenarioPreset { id: string; name: string; /** What is on the bench and what to look for */ note: string; spec: ProblemSpec; } const mat = (id: string) => MATERIAL_PRESETS.find((m) => m.id === id)!; const plate = (id: string) => ({ ...PLATE_PRESETS.find((p) => p.id === id)!.plate }); const thread = (id: string) => ({ ...THREAD_PRESETS.find((t) => t.id === id)!.thread }); const pad = (id: string) => PAD_PRESETS.find((p) => p.id === id)!; const felt = pad("felt-5"); const foam = pad("foam-20"); const AIR = { c: 343, rho_air: 1.2 }; /** * Whole problems: plate, material, mount, orientation, excitation, probe and * listener set together. Each is something you could build and strike; the * note says what the run should show. */ export const SCENARIO_PRESETS: ScenarioPreset[] = [ { id: "sheet-on-thread", name: "Steel sheet on a thread", note: "A 300 x 200 mm sheet hung from a hole near the top edge and struck off-centre. It swings on the thread at about 0.8 Hz, rocks about the hole at about 3 Hz, spins slowly about the thread, and rings; the unbaffled listener loses the low end.", spec: { plate: plate("sheet-300x200x2"), material: { ...mat("a36-steel").material }, gravity: { g: 9.81 }, mount: { type: "thread", x: 0.15, y: 0.19, length: 0.3, thread: thread("nylon-0p5") }, damping: { ...mat("a36-steel").damping }, excitation: { type: "impulse", x: 0.1, y: 0.08, force: 50, duration: 1e-3, radius: 0.012 }, probe: { x: 0.2, y: 0.12 }, listener: { x: 0.15, y: 0.1, z: 1.0, ...AIR, model: "unbaffled" }, output: { fs: 44100, nframes: 90 }, fd: { nx: 41, ny: 27, cfl: 0.9, duration: 3.0 }, }, }, { id: "gong-on-cords", name: "Gong on two cords", note: "A bronze disk hung from two holes near the rim, struck at the centre. Two cords stop the spin and the yaw; the swing and sway remain, and the low damping of bell bronze lets it ring for the whole run.", spec: { plate: plate("disk-300x2"), material: { ...mat("b20-bronze").material }, gravity: { g: 9.81 }, mount: { type: "threads", x1: 0.091, y1: 0.277, x2: 0.209, y2: 0.277, length: 0.4 }, damping: { ...mat("b20-bronze").damping }, excitation: { type: "impulse", x: 0.15, y: 0.15, force: 100, duration: 2e-3, radius: 0.02 }, probe: { x: 0.15, y: 0.08 }, listener: { x: 0.15, y: 0.15, z: 1.0, ...AIR, model: "unbaffled" }, output: { fs: 44100, nframes: 90 }, fd: { nx: 41, ny: 41, cfl: 0.9, duration: 3.0 }, }, }, { id: "glockenspiel-bar", name: "Glockenspiel bar on nodal pads", note: "A spring-steel bar on two felt strips placed under the nodes of its first free-free mode, 22.4 percent in from each end, struck in the middle. The pads barely disturb that mode; the bar bounces on them a little after the strike.", spec: { plate: plate("glockenspiel-bar"), material: { ...mat("1095-spring-steel").material }, gravity: { g: 9.81 }, mount: { type: "pads", pads: [ { x: 0.0448, y: 0.016, rx: 0.004, ry: 0.02 }, { x: 0.1552, y: 0.016, rx: 0.004, ry: 0.02 }, ], k: felt.k, c: felt.c, }, damping: { ...mat("1095-spring-steel").damping }, excitation: { type: "impulse", x: 0.1, y: 0.016, force: 20, duration: 0.3e-3, radius: 0.006 }, probe: { x: 0.05, y: 0.016 }, listener: { x: 0.1, y: 0.016, z: 0.5, ...AIR, model: "baffled" }, output: { fs: 44100, nframes: 90 }, fd: { nx: 61, ny: 11, cfl: 0.9, duration: 0.5 }, }, }, { id: "sheet-on-foam", name: "Sheet on four foam blocks", note: "The steel sheet lying on foam pads under its corners, struck hard in the middle. The strike lifts it off the pads for a moment; watch the pad forces go to zero and the plate land again.", spec: { plate: plate("sheet-300x200x2"), material: { ...mat("a36-steel").material }, gravity: { g: 9.81 }, mount: { type: "pads", pads: [ { x: 0.03, y: 0.03, rx: 0.02, ry: 0.02 }, { x: 0.27, y: 0.03, rx: 0.02, ry: 0.02 }, { x: 0.03, y: 0.17, rx: 0.02, ry: 0.02 }, { x: 0.27, y: 0.17, rx: 0.02, ry: 0.02 }, ], k: foam.k, c: foam.c, }, damping: { ...mat("a36-steel").damping }, excitation: { type: "impulse", x: 0.15, y: 0.1, force: 300, duration: 1e-3, radius: 0.012 }, probe: { x: 0.2, y: 0.12 }, listener: { x: 0.15, y: 0.1, z: 1.0, ...AIR, model: "baffled" }, output: { fs: 44100, nframes: 90 }, fd: { nx: 41, ny: 27, cfl: 0.9, duration: 2.0 }, }, }, { id: "cymbal-on-stand", name: "Cymbal on a stand", note: "A flat bronze disk between the felts of a stand, struck near the edge. The felts hold the centre with a preload; a hard enough strike separates one of them for an instant. What is missing is the cymbal's bow and bell.", spec: { plate: plate("cymbal-flat-400x1p2"), material: { ...mat("b20-bronze").material }, gravity: { g: 9.81 }, mount: { type: "cymbal", r_rod: 0.006, r_felt: 0.02, k: felt.k, c: felt.c, preload: 0.5e-3 }, damping: { ...mat("b20-bronze").damping }, excitation: { type: "impulse", x: 0.36, y: 0.2, force: 30, duration: 1e-3, radius: 0.015 }, probe: { x: 0.2, y: 0.33 }, listener: { x: 0.2, y: 0.2, z: 1.0, ...AIR, model: "unbaffled" }, output: { fs: 44100, nframes: 90 }, fd: { nx: 41, ny: 41, cfl: 0.9, duration: 2.0 }, }, }, { id: "cantilever-in-vise", name: "Cantilever in a vise", note: "A steel strip gripped at one end in a vise, held horizontal, its free end pulled down 10 mm and let go. It sags under its own weight first (the static field), then rings at its cantilever frequency; tilt the vise to hang it or stand it up.", spec: { plate: plate("ruler-300x50x3"), material: { ...mat("a36-steel").material }, gravity: { g: 9.81 }, mount: { type: "vise", edge: "x0", depth: 0.015, tilt: 90 }, damping: { ...mat("a36-steel").damping }, excitation: { type: "release", x: 0.29, y: 0.025, displacement: 0.01, radius: 0.008 }, probe: { x: 0.25, y: 0.025 }, listener: { x: 0.15, y: 0.025, z: 0.5, ...AIR, model: "baffled" }, output: { fs: 44100, nframes: 90 }, fd: { nx: 61, ny: 11, cfl: 0.9, duration: 2.0 }, }, }, { id: "disk-in-hand", name: "Disk pinched in the hand", note: "A thin stainless disk held between finger and thumb near its rim, hanging, and struck. The fingers are a soft, lossy spring: the disk swings from them and its vibration dies faster than on a thread.", spec: { plate: plate("disk-250x1"), material: { ...mat("304-stainless").material }, gravity: { g: 9.81 }, mount: { type: "pinched", x: 0.125, y: 0.235, radius: 0.008, k: 2000, c: 20, tilt: 0 }, damping: { ...mat("304-stainless").damping }, excitation: { type: "impulse", x: 0.125, y: 0.1, force: 30, duration: 1e-3, radius: 0.012 }, probe: { x: 0.18, y: 0.125 }, listener: { x: 0.125, y: 0.125, z: 1.0, ...AIR, model: "unbaffled" }, output: { fs: 44100, nframes: 90 }, fd: { nx: 41, ny: 41, cfl: 0.9, duration: 2.0 }, }, }, ]; export function scenarioPreset(id: string): ScenarioPreset { const s = SCENARIO_PRESETS.find((x) => x.id === id); if (!s) throw new Error(`unknown scenario ${id}`); return s; }