/ proof-of-concept / cymbalsim
Sign in
proof-of-concept / cymbalsim
cymbalsim / src / presets.ts
235 lines · 8.9 KBBlameHistoryRaw
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;
12const flatRectangle = `% A flat rectangular sheet of stainless steel, hanging freely (no stand).
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
19% functions at the bottom; the other presets show how.
20inch = 0.0254; % m
21mm = 1e-3; % m
23design.name = 'Flat steel rectangle';
24design.material.E = 170e9; % Young's modulus [Pa]
25design.material.nu = 0.29; % Poisson ratio
26design.material.rho = 7900; % density [kg/m^3]
27design.bounds.width = 12*inch; % bounding box [m]
28design.bounds.height = 18*inch;
29design.thickness = 0.79*mm;
30design.stand = []; % free plate
31design.loss.T60 = @(f) 3 ./ (1 + f/1500); % decay time [s] as a function of frequency [Hz]
32`;
34const bowedRectangle = `% The same steel sheet with a 3 mm parabolic bow across its width, the
35% kind of bow that rolling and handling leave in real sheet metal. The bow
36% makes the sheet a shallow shell: the linear modes couple bending to
37% stretching, and the full simulation oil-cans and wobbles when struck.
38inch = 0.0254; mm = 1e-3;
39W = 12*inch; H = 18*inch;
41design.name = 'Bowed steel rectangle';
42design.material.E = 170e9;
43design.material.nu = 0.29;
44design.material.rho = 7900;
45design.bounds.width = W;
46design.bounds.height = H;
47design.thickness = 0.79*mm;
48design.profile = @(x, y, r, theta) bow(x, W, 3*mm, 0.3); % stress-free height [m]
49design.stand = [];
50design.loss.T60 = @(f) 3 ./ (1 + f/1500);
52function v = bow(s, span, sag, offset)
53% A parabola of the given sag across a span centered on 0; s runs along the
54% span, and the offset in -1..1 moves the crest toward one end.
55t = 2*s/span;
56v = sag * (1 - t.^2) .* (1 + offset*t);
57end
58`;
60const flatDisc = `% A flat 16 inch bronze disc with a center hole on a cymbal stand. The
61% stand is a rod through the hole with a felt pad below the plate and
62% another above it under the wing nut; each pad is an annulus of felt of
63% the given radii and thickness, and its stiffness per unit area is E over
64% the thickness. The pads hold the disc level and let it bounce and rock.
65inch = 0.0254; mm = 1e-3;
66D = 16*inch; hole = 13*mm;
68design.name = 'Flat bronze disc';
69design.material.E = 110e9; % bronze
70design.material.nu = 0.34;
71design.material.rho = 8800;
72design.bounds.width = D;
73design.bounds.height = D;
74design.inside = @(x, y, r, theta) (r <= D/2) & (r >= hole/2);
75design.thickness = 1.0*mm;
76design.stand.pad.innerRadius = 7*mm; % the felt sits on the plastic sleeve of the rod
77design.stand.pad.outerRadius = 20*mm;
78design.stand.pad.thickness = 12*mm;
79design.stand.pad.E = 0.5e6; % Pa, felt in compression
80design.stand.pad.lossFactor = 0.3;
81design.stand.topPad = true;
82design.stand.preload = 1*mm; % compression of the top pad by the wing nut
83design.loss.T60 = @(f) 4 ./ (1 + f/2000);
84`;
86const crash16 = `% A 16 inch flat crash: bronze, lathed to a taper from 1.2 mm at the
87% center to 0.7 mm at the edge, on a stand. Flat, so the linear modes are
88% pure bending modes; the tapered profile is what makes it a crash rather
89% than a ride.
90inch = 0.0254; mm = 1e-3;
91D = 16*inch; R = D/2; hole = 13*mm;
92tCenter = 1.2*mm; tEdge = 0.7*mm;
94design.name = '16 inch flat crash';
95design.material.E = 110e9;
96design.material.nu = 0.34;
97design.material.rho = 8800;
98design.bounds.width = D;
99design.bounds.height = D;
100design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
101design.thickness = @(x, y, r, theta) tCenter + (tEdge - tCenter) * ramp(40*mm, R, r);
102design.stand.pad.innerRadius = 7*mm;
103design.stand.pad.outerRadius = 20*mm;
104design.stand.pad.thickness = 12*mm;
105design.stand.pad.E = 0.5e6;
106design.stand.pad.lossFactor = 0.3;
107design.stand.topPad = true;
108design.stand.preload = 1*mm;
109design.loss.T60 = [100 5; 1000 3.5; 5000 1.2; 15000 0.4]; % table of [Hz seconds], interpolated
111function v = ramp(a, b, x)
112% 0 at x = a, 1 at x = b, clamped to that range outside.
113v = min(max((x - a) ./ (b - a), 0), 1);
114end
115`;
117const ride20 = `% A 20 inch flat ride: thicker bronze, 2.2 mm at the center to 1.4 mm at
118% the edge, on a stand with a loose wing nut (a small preload). The
119% thickness raises every frequency in proportion, and the ride has a
120% clearer ping and a longer decay than the crash.
121inch = 0.0254; mm = 1e-3;
122D = 20*inch; R = D/2; hole = 13*mm;
124design.name = '20 inch flat ride';
125design.material.E = 110e9;
126design.material.nu = 0.34;
127design.material.rho = 8800;
128design.bounds.width = D;
129design.bounds.height = D;
130design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
131design.thickness = @(x, y, r, theta) 2.2*mm + (1.4*mm - 2.2*mm) * ramp(50*mm, R, r);
132design.stand.pad.innerRadius = 7*mm;
133design.stand.pad.outerRadius = 22*mm;
134design.stand.pad.thickness = 12*mm;
135design.stand.pad.E = 0.5e6;
136design.stand.pad.lossFactor = 0.3;
137design.stand.topPad = true;
138design.stand.preload = 0.3*mm;
139design.loss.T60 = @(f) 8 ./ (1 + f/2500);
141function v = ramp(a, b, x)
142v = min(max((x - a) ./ (b - a), 0), 1);
143end
144`;
146const crashBell16 = `% A 16 inch crash with a shallow bow and a cosine bell, on a stand. The
147% profile makes the cymbal a shallow shell: the linear model couples the
148% bending to the stretching (a larger eigenproblem, so the modes take
149% longer), and the full simulation shows the asymmetric nonlinearity of a
150% curved plate. The slopes are kept small; the interface reports the
151% largest one.
152inch = 0.0254; mm = 1e-3;
153D = 16*inch; R = D/2; hole = 13*mm;
154bellR = 55*mm; bellH = 8*mm; bowH = 10*mm;
155tCenter = 1.2*mm; tEdge = 0.7*mm;
157design.name = '16 inch crash with bell';
158design.material.E = 110e9;
159design.material.nu = 0.34;
160design.material.rho = 8800;
161design.bounds.width = D;
162design.bounds.height = D;
163design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
164design.thickness = @(x, y, r, theta) tCenter + (tEdge - tCenter) * ramp(bellR, R, r);
165design.profile = @(x, y, r, theta) bowH * (1 - (r/R).^2) + dome(r, bellR, bellH);
166design.stand.pad.innerRadius = 7*mm;
167design.stand.pad.outerRadius = 20*mm;
168design.stand.pad.thickness = 12*mm;
169design.stand.pad.E = 0.5e6;
170design.stand.pad.lossFactor = 0.3;
171design.stand.topPad = true;
172design.stand.preload = 1*mm;
173design.loss.T60 = [100 5; 1000 3.5; 5000 1.2; 15000 0.4];
175function v = ramp(a, b, x)
176v = min(max((x - a) ./ (b - a), 0), 1);
177end
179function v = dome(d, radius, height)
180% A cosine dome of the given height and base radius, with zero slope both at
181% its rim and at its apex; d is the distance from its center.
182v = 0.5 * height * (1 + cos(pi * d / radius)) .* (d < radius);
183end
184`;
186const ellipse = `% A free elliptical steel plate. The outline is any test on the point;
187% an ellipse inscribed in the bounding box here. The degenerate mode pairs
188% of a disc split on an ellipse, which the mode browser shows.
189inch = 0.0254; mm = 1e-3;
190A = 14*inch; B = 10*inch;
192design.name = 'Steel ellipse';
193design.material.E = 170e9;
194design.material.nu = 0.29;
195design.material.rho = 7900;
196design.bounds.width = A;
197design.bounds.height = B;
198design.inside = @(x, y, r, theta) (x/(A/2)).^2 + (y/(B/2)).^2 <= 1;
199design.thickness = 1.0*mm;
200design.stand = [];
201design.loss.T60 = @(f) 3 ./ (1 + f/1500);
202`;
204const thunderSheet = `% A thunder sheet: a large thin steel sheet hung from one corner. Its modes
205% are dense and low, and the full simulation turns a hard hit into a roar.
206% Long at the default spacing; a coarser grid keeps it interactive.
207inch = 0.0254; mm = 1e-3;
209design.name = 'Thunder sheet';
210design.material.E = 200e9;
211design.material.nu = 0.3;
212design.material.rho = 7850;
213design.bounds.width = 24*inch;
214design.bounds.height = 36*inch;
215design.thickness = 0.5*mm;
216design.stand = [];
217design.loss.T60 = @(f) 2.5 ./ (1 + f/1000);
218`;
220export const PRESETS: Preset[] = [
221 { id: "flat-rectangle", label: "Flat steel rectangle", source: flatRectangle },
222 { id: "bowed-rectangle", label: "Bowed steel rectangle", source: bowedRectangle },
223 { id: "flat-disc", label: "Flat bronze disc on a stand", source: flatDisc },
224 { id: "crash-16", label: "16 inch flat crash", source: crash16 },
225 { id: "ride-20", label: "20 inch flat ride", source: ride20 },
226 { id: "crash-bell-16", label: "16 inch crash with bell", source: crashBell16 },
227 { id: "ellipse", label: "Steel ellipse", source: ellipse },
228 { id: "thunder-sheet", label: "Thunder sheet", source: thunderSheet },
229];
231export const DEFAULT_PRESET = "crash-16";
233export function presetById(id: string): Preset | undefined {
234 return PRESETS.find((p) => p.id === id);
↑↓ move↵openescclose