/ proof-of-concept / steelsim21
Sign in
proof-of-concept / steelsim21
steelsim21 / src / params.ts
142 lines · 4.8 KBBlameHistoryRaw
1// Physical and numerical parameters of the simulation, plus derived quantities.
3export interface PhysParams {
4 Lx: number; // plate width along x [m]
5 Ly: number; // plate height along y [m]
6 h: number; // thickness [m]
7 E: number; // Young's modulus [Pa]
8 nu: number; // Poisson ratio
9 rho: number; // density [kg/m^3]
10 sigma0: number; // frequency-independent loss [1/s]
11 sigma1: number; // frequency-dependent loss [m^2/s]
12 sigmaIn: number; // additional loss of the in-plane motion [1/s]
13 holeInset: number; // distance of the thread hole from the two edges of the top-left corner [m]
14 pushAmount: number; // corner displacement [m]
15 fingerRadius: number; // radius of the pushed patch [m]
16 rampTime: number; // duration of the push ramp [s]
17 holdMax: number; // maximum settle time before release [s]
18 releaseTime: number; // time over which the finger force falls to zero [s]
19 settleSigma0: number; // artificial damping during push and settle [1/s]
20 settleKE: number; // kinetic energy threshold that counts as settled [J]
21 spacing: number; // requested grid spacing [m]
22 fs: number; // audio sample rate [Hz]
23 fps: number; // movie frame rate (also the batch rate) [Hz]
24 duration: number; // recorded duration after release [s]
25 listenerDist: number; // [m]
26 listenerAzimuth: number; // [deg], rotation about the plate's vertical axis (0 = on the normal)
27 listenerElevation: number; // [deg]
28 radiation: "rayleigh" | "dipole";
29 bowShape: BowShape; // stress-free initial shape of the sheet
30 bowAmplitude: number; // sag of the initial shape, center relative to the edges [m]
33export type BowShape = "none" | "width" | "height" | "dish";
35export const defaultParams: PhysParams = {
36 Lx: 18 * 0.0254,
37 Ly: 12 * 0.0254,
38 h: 0.79e-3,
39 E: 193e9,
40 nu: 0.29,
41 rho: 7900,
42 sigma0: 1.15,
43 sigma1: 5e-4,
44 sigmaIn: 20,
45 holeInset: 0.012,
46 pushAmount: 0.01,
47 fingerRadius: 0.01,
48 rampTime: 0.1,
49 holdMax: 0.5,
50 releaseTime: 0.02,
51 settleSigma0: 300,
52 settleKE: 1e-8,
53 spacing: 0.004,
54 fs: 48000,
55 fps: 120,
56 duration: 4,
57 listenerDist: 1.0,
58 listenerAzimuth: 0,
59 listenerElevation: 0,
60 radiation: "rayleigh",
61 bowShape: "width",
62 bowAmplitude: 3e-3,
63};
65/** Stress-free initial shape w0 at every node. */
66export function initialShape(p: PhysParams, g: Grid): Float32Array<ArrayBuffer> {
67 const w0 = new Float32Array(g.n);
68 if (p.bowShape === "none" || p.bowAmplitude === 0) return w0;
69 for (let j = 0; j < g.ny; j++) {
70 for (let i = 0; i < g.nx; i++) {
71 const X = (2 * nodeX(g, i)) / p.Lx; // -1..1
72 const Y = (2 * nodeY(g, j)) / p.Ly;
73 let f = 0;
74 if (p.bowShape === "width") f = 1 - X * X;
75 else if (p.bowShape === "height") f = 1 - Y * Y;
76 else f = 1 - 0.5 * (X * X + Y * Y);
77 w0[j * g.nx + i] = p.bowAmplitude * f;
78 }
79 }
80 return w0;
83export const SPEED_OF_SOUND = 343; // [m/s]
84export const RHO_AIR = 1.2; // [kg/m^3]
85export const HIST_LEN = 256; // ring buffer length for the retarded-time audio sum [samples]
86export const RB_INTERVAL = 32; // steps between rigid-body projections while ringing
87export const RB_INTERVAL_HELD = 4; // while the finger constraint is active
89export interface Grid {
90 nx: number;
91 ny: number;
92 hx: number;
93 hy: number;
94 n: number;
97export interface Material {
98 D: number; // bending stiffness [N m]
99 C: number; // membrane stiffness E h / (1 - nu^2) [N/m]
100 G: number; // membrane shear stiffness E h / (2 (1 + nu)) [N/m]
101 nu: number;
102 rhoh: number; // mass per unit area [kg/m^2]
105export function makeGrid(p: PhysParams): Grid {
106 const nx = Math.max(6, Math.round(p.Lx / p.spacing) + 1);
107 const ny = Math.max(6, Math.round(p.Ly / p.spacing) + 1);
108 return { nx, ny, hx: p.Lx / (nx - 1), hy: p.Ly / (ny - 1), n: nx * ny };
111export function makeMaterial(p: PhysParams): Material {
112 return {
113 D: (p.E * p.h ** 3) / (12 * (1 - p.nu * p.nu)),
114 C: (p.E * p.h) / (1 - p.nu * p.nu),
115 G: (p.E * p.h) / (2 * (1 + p.nu)),
116 nu: p.nu,
117 rhoh: p.rho * p.h,
118 };
121/** Node coordinates relative to the plate center. */
122export function nodeX(g: Grid, i: number): number {
123 return (i - (g.nx - 1) / 2) * g.hx;
125export function nodeY(g: Grid, j: number): number {
126 return (j - (g.ny - 1) / 2) * g.hy;
129/** Trapezoidal weight of a node: 1 in the interior, 1/2 on an edge, 1/4 at a corner. */
130export function trapWeight(g: Grid, i: number, j: number): number {
131 const tx = i === 0 || i === g.nx - 1 ? 0.5 : 1;
132 const ty = j === 0 || j === g.ny - 1 ? 0.5 : 1;
133 return tx * ty;
136/** Decay time T60 [s] of a mode with angular frequency omega under the two-parameter loss model. */
137export function t60(m: Material, p: PhysParams, omega: number): number {
138 const kappa = Math.sqrt(m.D / m.rhoh);
139 const k2 = omega / kappa;
140 const sigma = p.sigma0 + p.sigma1 * k2;
141 return (3 * Math.LN10) / sigma; // amplitude factor 1000 = 60 dB
↑↓ move↵openescclose