5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 1// Predefined design scripts, selectable from the interface. Each is a
2// MATLAB-syntax script that fills in the `design` struct; see design.ts for
3// the fields. A script is self-contained: the shape functions it uses are
4// ordinary MATLAB functions written at the bottom of the script itself.
6export interface Preset {
7 id: string;
8 label: string;
9 source: string;
10}
2481a63Remove the standJeremy Magland 12const flatRectangle = `% A flat rectangular sheet of stainless steel, hanging freely.
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 13% The script is an ordinary MATLAB program that fills in a struct named
14% design. Lengths are meters; the constants at the top are the only units.
15% A field can be a number or a function handle @(x, y, r, theta) of the
16% point, measured from the center of the bounding box; the handles are
17% applied to whole grid matrices, so use elementwise operators (.*, ./, .^)
18% inside them. Anything else a script needs it defines itself, as MATLAB
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 19% functions at the bottom; the other presets show how. The decay of the
20% sound is not prescribed: it follows from the loss factor of the metal, its
21% thermal constants (thermoelastic damping), the radiation of each mode into
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 23inch = 0.0254; % m
24mm = 1e-3; % m
26design.name = 'Flat steel rectangle';
27design.material.E = 170e9; % Young's modulus [Pa]
28design.material.nu = 0.29; % Poisson ratio
29design.material.rho = 7900; % density [kg/m^3]
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 30design.material.lossFactor = 3e-4; % internal friction of the metal (typical published value)
31design.material.alpha = 17e-6; % thermal expansion [1/K] } for the thermoelastic damping
32design.material.cp = 500; % specific heat [J/(kg K)] }
33design.material.k = 16; % conductivity [W/(m K)] }
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 34design.bounds.width = 12*inch; % bounding box [m]
35design.bounds.height = 18*inch;
36design.thickness = 0.79*mm;
37`;
7c1c648Remove the center holes from the presetsJeremy Magland 39const aluminumSquare = `% A flat 12 inch square of 6061-T6 aluminum, 1.02 mm thick.
40% Aluminum is a third the density of steel and a third as stiff, so
76b7843Slice size follows the bandwidth (about bw/3.5); aluminum square presetJeremy Magland 41% the bending frequencies land near those of a steel plate of the same size
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 42% and thickness. Its high thermal expansion and conductivity give it the
43% strongest thermoelastic damping of the three metals here.
76b7843Slice size follows the bandwidth (about bw/3.5); aluminum square presetJeremy Magland 44inch = 0.0254; mm = 1e-3;
47design.name = 'Aluminum 6061-T6 square';
48design.material.E = 68.9e9; % Young's modulus [Pa]
49design.material.nu = 0.33; % Poisson ratio
50design.material.rho = 2700; % density [kg/m^3]
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 51design.material.lossFactor = 1e-4; % internal friction of the metal (typical published value)
52design.material.alpha = 23.6e-6; % thermal expansion [1/K] } for the thermoelastic damping
53design.material.cp = 896; % specific heat [J/(kg K)] }
54design.material.k = 167; % conductivity [W/(m K)] }
76b7843Slice size follows the bandwidth (about bw/3.5); aluminum square presetJeremy Magland 55design.bounds.width = W;
56design.bounds.height = W;
57design.thickness = 1.02*mm;
58`;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 60const bowedRectangle = `% The same steel sheet with a 3 mm parabolic bow across its width, the
61% kind of bow that rolling and handling leave in real sheet metal. The bow
62% makes the sheet a shallow shell: the linear modes couple bending to
63% stretching, and the full simulation oil-cans and wobbles when struck.
64inch = 0.0254; mm = 1e-3;
65W = 12*inch; H = 18*inch;
67design.name = 'Bowed steel rectangle';
68design.material.E = 170e9;
69design.material.nu = 0.29;
70design.material.rho = 7900;
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 71design.material.lossFactor = 3e-4; % internal friction of the metal (typical published value)
72design.material.alpha = 17e-6; % thermal expansion [1/K] } for the thermoelastic damping
73design.material.cp = 500; % specific heat [J/(kg K)] }
74design.material.k = 16; % conductivity [W/(m K)] }
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 75design.bounds.width = W;
76design.bounds.height = H;
77design.thickness = 0.79*mm;
78design.profile = @(x, y, r, theta) bow(x, W, 3*mm, 0.3); % stress-free height [m]
80function v = bow(s, span, sag, offset)
81% A parabola of the given sag across a span centered on 0; s runs along the
82% span, and the offset in -1..1 moves the crest toward one end.
83t = 2*s/span;
84v = sag * (1 - t.^2) .* (1 + offset*t);
85end
86`;
7c1c648Remove the center holes from the presetsJeremy Magland 88const flatDisc = `% A flat 16 inch bronze disc, hanging freely.
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 89inch = 0.0254; mm = 1e-3;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 91
92design.name = 'Flat bronze disc';
93design.material.E = 110e9; % bronze
94design.material.nu = 0.34;
95design.material.rho = 8800;
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 96design.material.lossFactor = 2e-4; % internal friction of the metal (typical published value)
97design.material.alpha = 18e-6; % thermal expansion [1/K] } for the thermoelastic damping
98design.material.cp = 370; % specific heat [J/(kg K)] }
99design.material.k = 40; % conductivity [W/(m K)] }
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 100design.bounds.width = D;
101design.bounds.height = D;
7c1c648Remove the center holes from the presetsJeremy Magland 102design.inside = @(x, y, r, theta) r <= D/2;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 103design.thickness = 1.0*mm;
104`;
106const crash16 = `% A 16 inch flat crash: bronze, lathed to a taper from 1.2 mm at the
7c1c648Remove the center holes from the presetsJeremy Magland 107% center to 0.7 mm at the edge. Flat, so the linear modes are pure bending
108% modes; the tapered profile is what makes it a crash rather than a ride.
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 109inch = 0.0254; mm = 1e-3;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 111tCenter = 1.2*mm; tEdge = 0.7*mm;
113design.name = '16 inch flat crash';
114design.material.E = 110e9;
115design.material.nu = 0.34;
116design.material.rho = 8800;
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 117design.material.lossFactor = 2e-4; % internal friction of the metal (typical published value)
118design.material.alpha = 18e-6; % thermal expansion [1/K] } for the thermoelastic damping
119design.material.cp = 370; % specific heat [J/(kg K)] }
120design.material.k = 40; % conductivity [W/(m K)] }
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 121design.bounds.width = D;
122design.bounds.height = D;
7c1c648Remove the center holes from the presetsJeremy Magland 123design.inside = @(x, y, r, theta) r <= R;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 124design.thickness = @(x, y, r, theta) tCenter + (tEdge - tCenter) * ramp(40*mm, R, r);
126function v = ramp(a, b, x)
127% 0 at x = a, 1 at x = b, clamped to that range outside.
128v = min(max((x - a) ./ (b - a), 0), 1);
129end
130`;
132const ride20 = `% A 20 inch flat ride: thicker bronze, 2.2 mm at the center to 1.4 mm at
7c1c648Remove the center holes from the presetsJeremy Magland 133% the edge. The thickness raises every frequency in proportion, and the
134% ride has a clearer ping and a longer decay than the crash.
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 135inch = 0.0254; mm = 1e-3;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 137
138design.name = '20 inch flat ride';
139design.material.E = 110e9;
140design.material.nu = 0.34;
141design.material.rho = 8800;
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 142design.material.lossFactor = 2e-4; % internal friction of the metal (typical published value)
143design.material.alpha = 18e-6; % thermal expansion [1/K] } for the thermoelastic damping
144design.material.cp = 370; % specific heat [J/(kg K)] }
145design.material.k = 40; % conductivity [W/(m K)] }
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 146design.bounds.width = D;
147design.bounds.height = D;
7c1c648Remove the center holes from the presetsJeremy Magland 148design.inside = @(x, y, r, theta) r <= R;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 149design.thickness = @(x, y, r, theta) 2.2*mm + (1.4*mm - 2.2*mm) * ramp(50*mm, R, r);
151function v = ramp(a, b, x)
152v = min(max((x - a) ./ (b - a), 0), 1);
153end
154`;
029a0a3The stand is a parameter group, not part of the design scriptJeremy Magland 156const crashBell16 = `% A 16 inch crash with a shallow bow and a cosine bell. The
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 157% profile makes the cymbal a shallow shell: the linear model couples the
158% bending to the stretching (a larger eigenproblem, so the modes take
159% longer), and the full simulation shows the asymmetric nonlinearity of a
160% curved plate. The slopes are kept small; the interface reports the
161% largest one.
162inch = 0.0254; mm = 1e-3;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 164bellR = 55*mm; bellH = 8*mm; bowH = 10*mm;
165tCenter = 1.2*mm; tEdge = 0.7*mm;
167design.name = '16 inch crash with bell';
168design.material.E = 110e9;
169design.material.nu = 0.34;
170design.material.rho = 8800;
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 171design.material.lossFactor = 2e-4; % internal friction of the metal (typical published value)
172design.material.alpha = 18e-6; % thermal expansion [1/K] } for the thermoelastic damping
173design.material.cp = 370; % specific heat [J/(kg K)] }
174design.material.k = 40; % conductivity [W/(m K)] }
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 175design.bounds.width = D;
176design.bounds.height = D;
7c1c648Remove the center holes from the presetsJeremy Magland 177design.inside = @(x, y, r, theta) r <= R;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 178design.thickness = @(x, y, r, theta) tCenter + (tEdge - tCenter) * ramp(bellR, R, r);
179design.profile = @(x, y, r, theta) bowH * (1 - (r/R).^2) + dome(r, bellR, bellH);
181function v = ramp(a, b, x)
182v = min(max((x - a) ./ (b - a), 0), 1);
183end
185function v = dome(d, radius, height)
186% A cosine dome of the given height and base radius, with zero slope both at
187% its rim and at its apex; d is the distance from its center.
188v = 0.5 * height * (1 + cos(pi * d / radius)) .* (d < radius);
189end
190`;
0b50660Add a hammered crash presetJeremy Magland 192const crashHammered16 = `% The 16 inch crash with bell, hammered: 160 shallow dents of 0.4 mm on
149833cHammered crash: an option to scatter the dents at randomJeremy Magland 193% the bow, laid out on a sunflower spiral so that no two align, or, with
194% randomDents set to 1, scattered at random over the bow (dentSeed picks the
195% pattern, and the same seed gives the same cymbal). A hammered cymbal is
196% no longer axisymmetric, so its degenerate mode pairs split and its modes
197% mix, which is part of what makes a cymbal sound like one. The dents here
198% are what a script can express, a change of the rest shape; the residual
199% stresses of real hammering are not modeled.
201D = 16*inch; R = D/2;
202bellR = 55*mm; bellH = 8*mm; bowH = 10*mm;
203tCenter = 1.2*mm; tEdge = 0.7*mm;
204nDents = 160; dentR = 12*mm; dentDepth = 0.4*mm;
dcd0c16update presetJeremy Magland 205randomDents = 1; % 0: the spiral; 1: random places, overlapping as hammer marks do
149833cHammered crash: an option to scatter the dents at randomJeremy Magland 206dentSeed = 1; % any positive integer; changes the random pattern
208design.name = '16 inch hammered crash';
209design.material.E = 110e9;
210design.material.nu = 0.34;
211design.material.rho = 8800;
212design.material.lossFactor = 2e-4; % internal friction of the metal (typical published value)
213design.material.alpha = 18e-6; % thermal expansion [1/K] } for the thermoelastic damping
214design.material.cp = 370; % specific heat [J/(kg K)] }
215design.material.k = 40; % conductivity [W/(m K)] }
216design.bounds.width = D;
217design.bounds.height = D;
218design.inside = @(x, y, r, theta) r <= R;
219design.thickness = @(x, y, r, theta) tCenter + (tEdge - tCenter) * ramp(bellR, R, r);
149833cHammered crash: an option to scatter the dents at randomJeremy Magland 220design.profile = @(x, y, r, theta) bowH * (1 - (r/R).^2) + dome(r, bellR, bellH) + dents(x, y, bellR + dentR, R - dentR, nDents, dentR, dentDepth, randomDents, dentSeed);
222function v = ramp(a, b, x)
223v = min(max((x - a) ./ (b - a), 0), 1);
224end
226function v = dome(d, radius, height)
227% A cosine dome of the given height and base radius, with zero slope both at
228% its rim and at its apex; d is the distance from its center.
229v = 0.5 * height * (1 + cos(pi * d / radius)) .* (d < radius);
230end
149833cHammered crash: an option to scatter the dents at randomJeremy Magland 232function v = dents(x, y, r0, r1, n, rd, depth, random, seed)
0b50660Add a hammered crash presetJeremy Magland 233% n hammer marks between the radii r0 and r1: Gaussian dents of 1/e radius
234% rd, placed on a sunflower spiral (equal area per mark, golden-angle
149833cHammered crash: an option to scatter the dents at randomJeremy Magland 235% spacing) so that the pattern has no symmetry, or at random with uniform
236% density over the annulus, from a small congruential generator so that a
237% seed always gives the same pattern.
239ga = pi * (3 - sqrt(5));
243 s = mod(s * 1664525 + 1013904223, 4294967296); u = s / 4294967296;
244 s = mod(s * 1664525 + 1013904223, 4294967296); w = s / 4294967296;
245 rk = sqrt(r0^2 + (r1^2 - r0^2) * u);
246 tk = 2 * pi * w;
247 else
248 rk = sqrt(r0^2 + (r1^2 - r0^2) * (k - 0.5) / n);
249 tk = k * ga;
250 end
252 v = v - depth * exp(-(dx.^2 + dy.^2) / rd^2);
253end
254end
255`;
029a0a3The stand is a parameter group, not part of the design scriptJeremy Magland 257const ellipse = `% An elliptical steel plate. The outline is any test on the point;
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 258% an ellipse inscribed in the bounding box here. The degenerate mode pairs
259% of a disc split on an ellipse, which the mode browser shows.
260inch = 0.0254; mm = 1e-3;
261A = 14*inch; B = 10*inch;
263design.name = 'Steel ellipse';
264design.material.E = 170e9;
265design.material.nu = 0.29;
266design.material.rho = 7900;
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 267design.material.lossFactor = 3e-4; % internal friction of the metal (typical published value)
268design.material.alpha = 17e-6; % thermal expansion [1/K] } for the thermoelastic damping
269design.material.cp = 500; % specific heat [J/(kg K)] }
270design.material.k = 16; % conductivity [W/(m K)] }
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 271design.bounds.width = A;
272design.bounds.height = B;
273design.inside = @(x, y, r, theta) (x/(A/2)).^2 + (y/(B/2)).^2 <= 1;
274design.thickness = 1.0*mm;
275`;
2481a63Remove the standJeremy Magland 277const thunderSheet = `% A thunder sheet: a large thin steel sheet, hung from a corner in reality.
278% Its modes are dense and low, and the full simulation turns a hard hit into
279% a roar.
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 280% Long at the default spacing; a coarser grid keeps it interactive.
281inch = 0.0254; mm = 1e-3;
283design.name = 'Thunder sheet';
284design.material.E = 200e9;
285design.material.nu = 0.3;
286design.material.rho = 7850;
2a1a6daDerive the losses from physical constants instead of a prescribed decay curveJeremy Magland 287design.material.lossFactor = 3e-4; % internal friction of the metal (typical published value)
288design.material.alpha = 12e-6; % thermal expansion [1/K] } for the thermoelastic damping
289design.material.cp = 460; % specific heat [J/(kg K)] }
290design.material.k = 50; % conductivity [W/(m K)] }
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 291design.bounds.width = 24*inch;
292design.bounds.height = 36*inch;
293design.thickness = 0.5*mm;
294`;
296export const PRESETS: Preset[] = [
297 { id: "flat-rectangle", label: "Flat steel rectangle", source: flatRectangle },
029a0a3The stand is a parameter group, not part of the design scriptJeremy Magland 298 { id: "aluminum-square", label: "Aluminum 6061-T6 square", source: aluminumSquare },
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 299 { id: "bowed-rectangle", label: "Bowed steel rectangle", source: bowedRectangle },
029a0a3The stand is a parameter group, not part of the design scriptJeremy Magland 300 { id: "flat-disc", label: "Flat bronze disc", source: flatDisc },
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 301 { id: "crash-16", label: "16 inch flat crash", source: crash16 },
302 { id: "ride-20", label: "20 inch flat ride", source: ride20 },
303 { id: "crash-bell-16", label: "16 inch crash with bell", source: crashBell16 },
0b50660Add a hammered crash presetJeremy Magland 304 { id: "crash-hammered-16", label: "16 inch hammered crash", source: crashHammered16 },
5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 305 { id: "ellipse", label: "Steel ellipse", source: ellipse },
306 { id: "thunder-sheet", label: "Thunder sheet", source: thunderSheet },
307];
309export const DEFAULT_PRESET = "crash-16";
311export function presetById(id: string): Preset | undefined {
312 return PRESETS.find((p) => p.id === id);
313}