/ proof-of-concept / cymbalsim
Sign in
proof-of-concept / cymbalsim
cymbalsim / src / presets.ts
262 lines · 10.2 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 aluminumSquare = `% A flat 12 inch square of 6061-T6 aluminum, 1.02 mm thick, with a center
35% hole on a cymbal stand: felt pads below and above the plate around the
36% rod. Aluminum is a third the density of steel and a third as stiff, so
37% the bending frequencies land near those of a steel plate of the same size
38% and thickness; the material damping is low, hence the long decay.
39inch = 0.0254; mm = 1e-3;
40W = 12*inch; hole = 13*mm;
42design.name = 'Aluminum 6061-T6 square';
43design.material.E = 68.9e9; % Young's modulus [Pa]
44design.material.nu = 0.33; % Poisson ratio
45design.material.rho = 2700; % density [kg/m^3]
46design.bounds.width = W;
47design.bounds.height = W;
48design.inside = @(x, y, r, theta) r >= hole/2;
49design.thickness = 1.02*mm;
50design.stand.pad.innerRadius = 7*mm; % the felt sits on the plastic sleeve of the rod
51design.stand.pad.outerRadius = 20*mm;
52design.stand.pad.thickness = 12*mm;
53design.stand.pad.E = 0.5e6; % Pa, felt in compression
54design.stand.pad.lossFactor = 0.3;
55design.stand.topPad = true;
56design.stand.preload = 1*mm; % compression of the top pad by the wing nut
57design.loss.T60 = @(f) 4 ./ (1 + f/2000);
58`;
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;
71design.bounds.width = W;
72design.bounds.height = H;
73design.thickness = 0.79*mm;
74design.profile = @(x, y, r, theta) bow(x, W, 3*mm, 0.3); % stress-free height [m]
75design.stand = [];
76design.loss.T60 = @(f) 3 ./ (1 + f/1500);
78function v = bow(s, span, sag, offset)
79% A parabola of the given sag across a span centered on 0; s runs along the
80% span, and the offset in -1..1 moves the crest toward one end.
81t = 2*s/span;
82v = sag * (1 - t.^2) .* (1 + offset*t);
83end
84`;
86const flatDisc = `% A flat 16 inch bronze disc with a center hole on a cymbal stand. The
87% stand is a rod through the hole with a felt pad below the plate and
88% another above it under the wing nut; each pad is an annulus of felt of
89% the given radii and thickness, and its stiffness per unit area is E over
90% the thickness. The pads hold the disc level and let it bounce and rock.
91inch = 0.0254; mm = 1e-3;
92D = 16*inch; hole = 13*mm;
94design.name = 'Flat bronze disc';
95design.material.E = 110e9; % bronze
96design.material.nu = 0.34;
97design.material.rho = 8800;
98design.bounds.width = D;
99design.bounds.height = D;
100design.inside = @(x, y, r, theta) (r <= D/2) & (r >= hole/2);
101design.thickness = 1.0*mm;
102design.stand.pad.innerRadius = 7*mm; % the felt sits on the plastic sleeve of the rod
103design.stand.pad.outerRadius = 20*mm;
104design.stand.pad.thickness = 12*mm;
105design.stand.pad.E = 0.5e6; % Pa, felt in compression
106design.stand.pad.lossFactor = 0.3;
107design.stand.topPad = true;
108design.stand.preload = 1*mm; % compression of the top pad by the wing nut
109design.loss.T60 = @(f) 4 ./ (1 + f/2000);
110`;
112const crash16 = `% A 16 inch flat crash: bronze, lathed to a taper from 1.2 mm at the
113% center to 0.7 mm at the edge, on a stand. Flat, so the linear modes are
114% pure bending modes; the tapered profile is what makes it a crash rather
115% than a ride.
116inch = 0.0254; mm = 1e-3;
117D = 16*inch; R = D/2; hole = 13*mm;
118tCenter = 1.2*mm; tEdge = 0.7*mm;
120design.name = '16 inch flat crash';
121design.material.E = 110e9;
122design.material.nu = 0.34;
123design.material.rho = 8800;
124design.bounds.width = D;
125design.bounds.height = D;
126design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
127design.thickness = @(x, y, r, theta) tCenter + (tEdge - tCenter) * ramp(40*mm, R, r);
128design.stand.pad.innerRadius = 7*mm;
129design.stand.pad.outerRadius = 20*mm;
130design.stand.pad.thickness = 12*mm;
131design.stand.pad.E = 0.5e6;
132design.stand.pad.lossFactor = 0.3;
133design.stand.topPad = true;
134design.stand.preload = 1*mm;
135design.loss.T60 = [100 5; 1000 3.5; 5000 1.2; 15000 0.4]; % table of [Hz seconds], interpolated
137function v = ramp(a, b, x)
138% 0 at x = a, 1 at x = b, clamped to that range outside.
139v = min(max((x - a) ./ (b - a), 0), 1);
140end
141`;
143const ride20 = `% A 20 inch flat ride: thicker bronze, 2.2 mm at the center to 1.4 mm at
144% the edge, on a stand with a loose wing nut (a small preload). The
145% thickness raises every frequency in proportion, and the ride has a
146% clearer ping and a longer decay than the crash.
147inch = 0.0254; mm = 1e-3;
148D = 20*inch; R = D/2; hole = 13*mm;
150design.name = '20 inch flat ride';
151design.material.E = 110e9;
152design.material.nu = 0.34;
153design.material.rho = 8800;
154design.bounds.width = D;
155design.bounds.height = D;
156design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
157design.thickness = @(x, y, r, theta) 2.2*mm + (1.4*mm - 2.2*mm) * ramp(50*mm, R, r);
158design.stand.pad.innerRadius = 7*mm;
159design.stand.pad.outerRadius = 22*mm;
160design.stand.pad.thickness = 12*mm;
161design.stand.pad.E = 0.5e6;
162design.stand.pad.lossFactor = 0.3;
163design.stand.topPad = true;
164design.stand.preload = 0.3*mm;
165design.loss.T60 = @(f) 8 ./ (1 + f/2500);
167function v = ramp(a, b, x)
168v = min(max((x - a) ./ (b - a), 0), 1);
169end
170`;
172const crashBell16 = `% A 16 inch crash with a shallow bow and a cosine bell, on a stand. The
173% profile makes the cymbal a shallow shell: the linear model couples the
174% bending to the stretching (a larger eigenproblem, so the modes take
175% longer), and the full simulation shows the asymmetric nonlinearity of a
176% curved plate. The slopes are kept small; the interface reports the
177% largest one.
178inch = 0.0254; mm = 1e-3;
179D = 16*inch; R = D/2; hole = 13*mm;
180bellR = 55*mm; bellH = 8*mm; bowH = 10*mm;
181tCenter = 1.2*mm; tEdge = 0.7*mm;
183design.name = '16 inch crash with bell';
184design.material.E = 110e9;
185design.material.nu = 0.34;
186design.material.rho = 8800;
187design.bounds.width = D;
188design.bounds.height = D;
189design.inside = @(x, y, r, theta) (r <= R) & (r >= hole/2);
190design.thickness = @(x, y, r, theta) tCenter + (tEdge - tCenter) * ramp(bellR, R, r);
191design.profile = @(x, y, r, theta) bowH * (1 - (r/R).^2) + dome(r, bellR, bellH);
192design.stand.pad.innerRadius = 7*mm;
193design.stand.pad.outerRadius = 20*mm;
194design.stand.pad.thickness = 12*mm;
195design.stand.pad.E = 0.5e6;
196design.stand.pad.lossFactor = 0.3;
197design.stand.topPad = true;
198design.stand.preload = 1*mm;
199design.loss.T60 = [100 5; 1000 3.5; 5000 1.2; 15000 0.4];
201function v = ramp(a, b, x)
202v = min(max((x - a) ./ (b - a), 0), 1);
203end
205function v = dome(d, radius, height)
206% A cosine dome of the given height and base radius, with zero slope both at
207% its rim and at its apex; d is the distance from its center.
208v = 0.5 * height * (1 + cos(pi * d / radius)) .* (d < radius);
209end
210`;
212const ellipse = `% A free elliptical steel plate. The outline is any test on the point;
213% an ellipse inscribed in the bounding box here. The degenerate mode pairs
214% of a disc split on an ellipse, which the mode browser shows.
215inch = 0.0254; mm = 1e-3;
216A = 14*inch; B = 10*inch;
218design.name = 'Steel ellipse';
219design.material.E = 170e9;
220design.material.nu = 0.29;
221design.material.rho = 7900;
222design.bounds.width = A;
223design.bounds.height = B;
224design.inside = @(x, y, r, theta) (x/(A/2)).^2 + (y/(B/2)).^2 <= 1;
225design.thickness = 1.0*mm;
226design.stand = [];
227design.loss.T60 = @(f) 3 ./ (1 + f/1500);
228`;
230const thunderSheet = `% A thunder sheet: a large thin steel sheet hung from one corner. Its modes
231% are dense and low, and the full simulation turns a hard hit into a roar.
232% Long at the default spacing; a coarser grid keeps it interactive.
233inch = 0.0254; mm = 1e-3;
235design.name = 'Thunder sheet';
236design.material.E = 200e9;
237design.material.nu = 0.3;
238design.material.rho = 7850;
239design.bounds.width = 24*inch;
240design.bounds.height = 36*inch;
241design.thickness = 0.5*mm;
242design.stand = [];
243design.loss.T60 = @(f) 2.5 ./ (1 + f/1000);
244`;
246export const PRESETS: Preset[] = [
247 { id: "flat-rectangle", label: "Flat steel rectangle", source: flatRectangle },
248 { id: "aluminum-square", label: "Aluminum 6061-T6 square on a stand", source: aluminumSquare },
249 { id: "bowed-rectangle", label: "Bowed steel rectangle", source: bowedRectangle },
250 { id: "flat-disc", label: "Flat bronze disc on a stand", source: flatDisc },
251 { id: "crash-16", label: "16 inch flat crash", source: crash16 },
252 { id: "ride-20", label: "20 inch flat ride", source: ride20 },
253 { id: "crash-bell-16", label: "16 inch crash with bell", source: crashBell16 },
254 { id: "ellipse", label: "Steel ellipse", source: ellipse },
255 { id: "thunder-sheet", label: "Thunder sheet", source: thunderSheet },
256];
258export const DEFAULT_PRESET = "crash-16";
260export function presetById(id: string): Preset | undefined {
261 return PRESETS.find((p) => p.id === id);
↑↓ move↵openescclose