8db04e0Design scripts in MATLAB syntax, run by numblJeremy 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
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 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, so
5// that reading the script tells the whole story of the design and editing it
6// cannot go wrong for want of a hidden helper.
8export interface Preset {
9 id: string;
10 label: string;
11 source: string;
12}
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 14const flatRectangle = `% A flat rectangular sheet of stainless steel, hanging freely (no mount).
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 15% The script is an ordinary MATLAB program that fills in a struct named
16% design. Lengths are meters; the constants at the top are the only units.
17% A field can be a number or a function handle @(x, y, r, theta) of the
18% point, measured from the center of the bounding box; the handles are
19% applied to whole grid matrices, so use elementwise operators (.*, ./, .^)
20% inside them. Anything else a script needs it defines itself, as MATLAB
21% functions at the bottom; the other presets show how.
22inch = 0.0254; % m
23mm = 1e-3; % m
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 25design.name = 'Flat steel rectangle';
26design.material.E = 170e9; % Young's modulus [Pa]
27design.material.nu = 0.29; % Poisson ratio
28design.material.rho = 7900; % density [kg/m^3]
29design.bounds.width = 12*inch; % bounding box [m]
30design.bounds.height = 18*inch;
31design.thickness = 0.79*mm;
32design.profile = 0; % stress-free height [m]: flat
33design.mount = []; % free plate
34design.loss.sigma0 = 1.15; % frequency-independent loss [1/s]
35design.loss.sigma1 = 5e-4; % loss proportional to k^2 [m^2/s]
36design.loss.sigmaIn = 20; % extra loss of the in-plane motion [1/s]
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 39const bowedRectangle = `% The same steel sheet with a 3 mm parabolic bow across its width, the
40% kind of bow that rolling and handling leave in real sheet metal. The bow
41% makes the sheet a shallow shell, which oil-cans and wobbles when struck.
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 42inch = 0.0254; mm = 1e-3;
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 45design.name = 'Bowed steel rectangle';
46design.material.E = 170e9;
47design.material.nu = 0.29;
48design.material.rho = 7900;
49design.bounds.width = W;
50design.bounds.height = H;
51design.thickness = 0.79*mm;
52design.profile = @(x, y, r, theta) bow(x, W, 3*mm, 0.3);
53design.mount = [];
54design.loss.sigma0 = 1.15;
55design.loss.sigma1 = 5e-4;
56design.loss.sigmaIn = 20;
58function v = bow(s, span, sag, offset)
59% A parabola of the given sag across a span centered on 0; s runs along the
60% span, and the offset in -1..1 moves the crest toward one end.
61t = 2*s/span;
62v = sag * (1 - t.^2) .* (1 + offset*t);
63end
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 66const flatDisc = `% A flat 16 inch steel disc with a center hole, sitting on a stand: the
67% nodes within the mount radius are tied to the ground by a spring (the felt)
68% and a dashpot, spread over the mount area.
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 69inch = 0.0254; mm = 1e-3;
70D = 16*inch; hole = 12*mm;
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 72design.name = 'Flat steel disc';
73design.material.E = 170e9;
74design.material.nu = 0.29;
75design.material.rho = 7900;
76design.bounds.width = D;
77design.bounds.height = D;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 78design.inside = @(x, y, r, theta) (r <= D/2) & (r >= hole/2);
80design.profile = 0;
81design.mount.radius = 20*mm; % felt radius
82design.mount.stiffness = 2e4; % [N/m]
83design.mount.damping = 5; % [N s/m]
84design.loss.sigma0 = 1.15;
85design.loss.sigma1 = 5e-4;
86design.loss.sigmaIn = 20;
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 89const crash16 = `% A 16 inch crash: B20 bronze, tapered from the bell to the edge, with a
90% shallow bow and a cosine bell. The shallow-shell model behind the
91% simulation is strained where the slope of the profile exceeds about 0.1
92% to 0.2, so the bow and the bell are a little flatter than on a real crash.
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 93inch = 0.0254; mm = 1e-3;
94D = 16*inch; R = D/2; hole = 12*mm;
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 95bellR = 60*mm; bellH = 12*mm; % base radius and height of the bell
96bowH = 16*mm; % rise from the edge to the foot of the bell
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 97tBell = 1.4*mm; tEdge = 0.8*mm; % thickness at the bell and at the edge
100design.material.E = 110e9;
101design.material.nu = 0.34;
102design.material.rho = 8800;
103design.bounds.width = D;
104design.bounds.height = D;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 105design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
106% Linear taper from the foot of the bell to the edge.
107design.thickness = @(x, y, r, theta) tBell + (tEdge - tBell) * ramp(bellR, R, r);
108% A paraboloidal bow plus the bell; dome has zero slope at its rim.
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 109design.profile = @(x, y, r, theta) bowH * (1 - (r/R).^2) + dome(r, bellR, bellH);
110design.mount.radius = 20*mm;
111design.mount.stiffness = 2e4;
112design.mount.damping = 5;
113design.loss.sigma0 = 0.6;
114design.loss.sigma1 = 2.5e-4;
115design.loss.sigmaIn = 20;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 116
117function v = ramp(a, b, x)
118% 0 at x = a, 1 at x = b, clamped to that range outside.
119v = min(max((x - a) ./ (b - a), 0), 1);
120end
122function v = dome(d, radius, height)
123% A cosine dome of the given height and base radius, with zero slope both at
124% its rim and at its apex; d is the distance from its center.
125v = 0.5 * height * (1 + cos(pi * d / radius)) .* (d < radius);
126end
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 129const crashDented = `% A 16 inch crash that has been through a lot: the same bronze, taper,
130% bow, and bell as the clean crash, plus a dozen dents scattered over the
131% bow and a faint hammering texture. The dents are Gaussian bumps of a few
132% centimeters (broad compared with the 8 mm grid) and a millimeter or two
133% in height, up or down; change the seed for a different set. Dents break
134% the symmetry of the disc, split the degenerate mode pairs, and give the
135% cymbal a less pure, more trashy tone.
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 136inch = 0.0254; mm = 1e-3;
137D = 16*inch; R = D/2; hole = 12*mm;
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 138bellR = 60*mm; bellH = 12*mm; bowH = 16*mm;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 139tBell = 1.4*mm; tEdge = 0.8*mm;
141% Twelve dents from the seeded generator at the bottom (the same on every run).
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 143u = reshape(seededrand(7, 4*nd), 4, nd); % rows: radius, angle, size, height
144rr = bellR + 25*mm + (R - bellR - 45*mm) * u(1,:); % on the bow, clear of the bell and the edge
146cx = rr .* cos(th); cy = rr .* sin(th);
147rad = (18 + 14*u(3,:)) * mm;
148hgt = sign(u(4,:) - 0.5) .* (0.8 + 1.4*u(4,:)) * mm;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 149hammer = noise2d(3, 40*mm); % unit RMS, correlation length 40 mm
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 151design.name = '16 inch crash, dented';
152design.material.E = 110e9;
153design.material.nu = 0.34;
154design.material.rho = 8800;
155design.bounds.width = D;
156design.bounds.height = D;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 157design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
158design.thickness = @(x, y, r, theta) tBell + (tEdge - tBell) * ramp(bellR, R, r);
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 159design.profile = @(x, y, r, theta) bowH * (1 - (r/R).^2) + dome(r, bellR, bellH) ...
160 + dents(x, y, cx, cy, rad, hgt) ...
161 + 0.3*mm * hammer(x, y) .* smoothstep(bellR, bellR + 30*mm, r); % no hammering on the bell
162design.mount.radius = 20*mm;
163design.mount.stiffness = 2e4;
164design.mount.damping = 5;
165design.loss.sigma0 = 0.6;
166design.loss.sigma1 = 2.5e-4;
167design.loss.sigmaIn = 20;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 168
169function v = ramp(a, b, x)
170% 0 at x = a, 1 at x = b, clamped to that range outside.
171v = min(max((x - a) ./ (b - a), 0), 1);
172end
174function v = smoothstep(e0, e1, x)
175% 0 below e0, 1 above e1, a smooth cubic between, with zero slope at both.
176t = ramp(e0, e1, x);
177v = t.^2 .* (3 - 2*t);
178end
180function v = dome(d, radius, height)
181% A cosine dome of the given height and base radius, with zero slope both at
182% its rim and at its apex; d is the distance from its center.
183v = 0.5 * height * (1 + cos(pi * d / radius)) .* (d < radius);
184end
186function v = dents(x, y, cx, cy, radius, height)
187% The sum of Gaussian bumps centered at (cx(k), cy(k)), each of the given
188% height and falling to 1/e of it at the given radius.
189v = zeros(size(x));
190for k = 1:numel(cx)
191 d2 = (x - cx(k)).^2 + (y - cy(k)).^2;
192 v = v + height(k) * exp(-d2 / radius(k)^2);
193end
194end
196function u = seededrand(seed, n)
197% n uniform numbers in [0, 1) from a small seeded generator, the same on
198% every run and every machine.
199s = floor(seed);
200u = zeros(1, n);
201for k = 1:n
202 s = mod(s * 1664525 + 1013904223, 4294967296);
203 u(k) = s / 4294967296;
204end
205end
207function f = noise2d(seed, len)
208% A smooth random field f(x, y) of unit RMS with the covariance
209% exp(-d^2 / len^2), the same for a given seed on any grid: a sum of plane
210% waves whose wavevectors are drawn from the matching Gaussian spectrum.
211n = 64;
212u = reshape(seededrand(seed, 5*n), 5, n);
213kx = sqrt(-2*log(1 - u(1,:))) .* cos(2*pi*u(2,:)) * sqrt(2) / len;
214ky = sqrt(-2*log(1 - u(3,:))) .* cos(2*pi*u(4,:)) * sqrt(2) / len;
215ph = 2*pi*u(5,:);
216f = @(x, y) noisesum(kx, ky, ph, x, y);
217end
219function v = noisesum(kx, ky, ph, x, y)
220v = zeros(size(x));
221for k = 1:numel(kx)
222 v = v + cos(kx(k) * x + ky(k) * y + ph(k));
223end
224v = v / sqrt(numel(kx) / 2);
225end
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 228const ride20 = `% A 20 inch ride: heavier bronze, a larger bell, a flatter bow. The taper
229% is stronger than on the crash, and the mount is a little stiffer.
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 230inch = 0.0254; mm = 1e-3;
231D = 20*inch; R = D/2; hole = 12*mm;
233bowH = 15*mm;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 234tBell = 2.0*mm; tEdge = 1.1*mm;
237design.material.E = 110e9;
238design.material.nu = 0.34;
239design.material.rho = 8800;
240design.bounds.width = D;
241design.bounds.height = D;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 242design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
243design.thickness = @(x, y, r, theta) tBell + (tEdge - tBell) * smoothstep(bellR, R, r);
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 244design.profile = @(x, y, r, theta) bowH * (1 - (r/R).^2) + dome(r, bellR, bellH);
245design.mount.radius = 22*mm;
246design.mount.stiffness = 3e4;
247design.mount.damping = 8;
248design.loss.sigma0 = 0.5;
249design.loss.sigma1 = 2e-4;
250design.loss.sigmaIn = 20;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 251
252function v = smoothstep(e0, e1, x)
253% 0 below e0, 1 above e1, a smooth cubic between, with zero slope at both.
254t = min(max((x - e0) ./ (e1 - e0), 0), 1);
255v = t.^2 .* (3 - 2*t);
256end
258function v = dome(d, radius, height)
259% A cosine dome of the given height and base radius, with zero slope both at
260% its rim and at its apex; d is the distance from its center.
261v = 0.5 * height * (1 + cos(pi * d / radius)) .* (d < radius);
262end
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 265const ellipseTwist = `% A steel ellipse with a saddle (twist) and a bow, hanging freely. The
266% twist raises two opposite quadrants and lowers the other two, which
267% breaks the symmetry of the disc modes.
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 268inch = 0.0254; mm = 1e-3;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 270
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 271design.name = 'Steel ellipse with a twist';
272design.material.E = 170e9;
273design.material.nu = 0.29;
274design.material.rho = 7900;
275design.bounds.width = W;
276design.bounds.height = H;
277% 2x/W and 2y/H run from -1 to 1 over the bounding box.
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 278design.inside = @(x, y, r, theta) (2*x/W).^2 + (2*y/H).^2 <= 1;
279design.thickness = 0.79*mm;
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 280design.profile = @(x, y, r, theta) 2*mm * (2*x/W) .* (2*y/H) + bow(y, H, 2*mm);
281design.mount = [];
282design.loss.sigma0 = 1.15;
283design.loss.sigma1 = 5e-4;
284design.loss.sigmaIn = 20;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 285
286function v = bow(s, span, sag)
287% A parabola of the given sag across a span centered on 0.
288v = sag * (1 - (2*s/span).^2);
289end
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 292const china18 = `% An 18 inch china: a conical bow that falls from the bell toward a flange,
293% and an upturned edge that rises again over the outer 45 mm. The bell is
294% square-topped (a plateau with rounded shoulders). The edge slope is well
295% beyond the shallow-shell range, so this preset is the least trustworthy.
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 296inch = 0.0254; mm = 1e-3;
297D = 18*inch; R = D/2; hole = 12*mm;
299flangeR = R - 45*mm; bowH = 14*mm; edgeH = 12*mm;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 300tBell = 1.6*mm; tEdge = 0.9*mm;
8db04e0Design scripts in MATLAB syntax, run by numblJeremy Magland 302design.name = '18 inch china';
303design.material.E = 110e9;
304design.material.nu = 0.34;
305design.material.rho = 8800;
306design.bounds.width = D;
307design.bounds.height = D;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 308design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
309design.thickness = @(x, y, r, theta) tBell + (tEdge - tBell) * smoothstep(bellR, flangeR, r);
310design.profile = @(x, y, r, theta) bowH * max(0, 1 - r/flangeR) ... % cone down to the flange
311 + edgeH * smoothstep(flangeR, R, r) ... % upturned edge
312 + bellH * (1 - smoothstep(bellR - 20*mm, bellR, r)); % flat-topped bell
314design.mount.stiffness = 2e4;
315design.mount.damping = 5;
316design.loss.sigma0 = 0.7;
317design.loss.sigma1 = 3e-4;
318design.loss.sigmaIn = 20;
7710254Self-contained design scripts; 3D by default; resizable, less verbose panelJeremy Magland 319
320function v = smoothstep(e0, e1, x)
321% 0 below e0, 1 above e1, a smooth cubic between, with zero slope at both.
322t = min(max((x - e0) ./ (e1 - e0), 0), 1);
323v = t.^2 .* (3 - 2*t);
324end
327export const PRESETS: Preset[] = [
328 { id: "flat-rectangle", label: "Flat steel rectangle", source: flatRectangle },
329 { id: "bowed-rectangle", label: "Bowed steel rectangle", source: bowedRectangle },
330 { id: "flat-disc", label: "Flat steel disc on a stand", source: flatDisc },
331 { id: "crash-16", label: "16 inch crash", source: crash16 },
6edbaa3Add a dented 16 inch crash presetJeremy Magland 332 { id: "crash-16-dented", label: "16 inch crash, dented", source: crashDented },
1ee087eCymbal designer: scripted design, thickness field, mount, single strikeJeremy Magland 333 { id: "ride-20", label: "20 inch ride", source: ride20 },
334 { id: "ellipse-twist", label: "Steel ellipse with a twist", source: ellipseTwist },
335 { id: "china-18", label: "18 inch china", source: china18 },
336];
338export const DEFAULT_PRESET = PRESETS[0];