/ proof-of-concept / steelsim41
Sign in
proof-of-concept / steelsim41
steelsim41 / src / presets.ts
189 lines · 7.9 KBBlameHistoryRaw
1// Predefined design scripts, selectable from the interface. Each is a plain
2// JavaScript script body that returns the design object; see design.ts for
3// the fields and the helpers in scope.
5export interface Preset {
6 id: string;
7 label: string;
8 source: string;
9}
11const flatRectangle = `// A flat rectangular sheet of stainless steel, hanging freely (no mount).
12// Lengths are meters; inch and mm are conversion constants.
13// Every field can be a number or a function (x, y, r, theta) of the point,
14// measured from the center of the bounding box.
15return {
16 name: "Flat steel rectangle",
17 material: { E: 170e9, nu: 0.29, rho: 7900 },
18 bounds: { width: 12 * inch, height: 18 * inch },
19 thickness: 0.79 * mm,
20 profile: 0,
21 mount: null,
22 loss: { sigma0: 1.15, sigma1: 5e-4, sigmaIn: 20 },
23};
24`;
26const bowedRectangle = `// The same steel sheet with a 3 mm parabolic bow across its width, the
27// kind of bow that rolling and handling leave in real sheet metal. The bow
28// makes the sheet a shallow shell, which oil-cans and wobbles when struck.
29const W = 12 * inch, H = 18 * inch;
30return {
31 name: "Bowed steel rectangle",
32 material: { E: 170e9, nu: 0.29, rho: 7900 },
33 bounds: { width: W, height: H },
34 thickness: 0.79 * mm,
35 // bow(s, span, sag, offset): parabola of the given sag across the span; the
36 // offset in -1..1 moves the crest toward one edge.
37 profile: (x, y) => bow(x, W, 3 * mm, 0.3),
38 mount: null,
39 loss: { sigma0: 1.15, sigma1: 5e-4, sigmaIn: 20 },
40};
41`;
43const flatDisc = `// A flat 16 inch steel disc with a center hole, sitting on a stand: the
44// nodes within the mount radius are tied to the ground by a spring (the felt)
45// and a dashpot, spread over the mount area.
46const D = 16 * inch;
47return {
48 name: "Flat steel disc",
49 material: { E: 170e9, nu: 0.29, rho: 7900 },
50 bounds: { width: D, height: D },
51 inside: circle(D, 12 * mm), // diameter, hole diameter
52 thickness: 1.0 * mm,
53 profile: 0,
54 mount: { radius: 20 * mm, stiffness: 2e4, damping: 5 },
55 loss: { sigma0: 1.15, sigma1: 5e-4, sigmaIn: 20 },
56};
57`;
59const crash16 = `// A 16 inch crash: B20 bronze, tapered from the bell to the edge, with a
60// shallow bow and a cosine bell. The shallow-shell model behind the
61// simulation is strained where the slope of the profile exceeds about 0.1
62// to 0.2, so the bow and the bell are a little flatter than on a real crash.
63const D = 16 * inch, R = D / 2;
64const bellR = 60 * mm, bellH = 12 * mm; // base radius and height of the bell
65const bowH = 16 * mm; // rise from the edge to the foot of the bell
66return {
67 name: "16 inch crash",
68 material: { E: 110e9, nu: 0.34, rho: 8800 },
69 bounds: { width: D, height: D },
70 inside: circle(D, 12 * mm),
71 // Taper: 1.4 mm at the bell, 0.8 mm at the edge.
72 thickness: (x, y, r) => lerp(1.4 * mm, 0.8 * mm, clamp((r - bellR) / (R - bellR), 0, 1)),
73 // A paraboloidal bow plus the bell; dome(d, radius, height) has zero slope at its rim.
74 profile: (x, y, r) => bowH * (1 - (r / R) ** 2) + dome(r, bellR, bellH),
75 mount: { radius: 20 * mm, stiffness: 2e4, damping: 5 },
76 loss: { sigma0: 0.6, sigma1: 2.5e-4, sigmaIn: 20 },
77};
78`;
80const crashDented = `// A 16 inch crash that has been through a lot: the same bronze, taper,
81// bow, and bell as the clean crash, plus a dozen dents scattered over the
82// bow and a faint hammering texture. The dents are Gaussian bumps of a few
83// centimeters (broad compared with the 8 mm grid) and a millimeter or two
84// in height, up or down; change the seed for a different set. Dents break
85// the symmetry of the disc, split the degenerate mode pairs, and give the
86// cymbal a less pure, more trashy tone.
87const D = 16 * inch, R = D / 2;
88const bellR = 60 * mm, bellH = 12 * mm, bowH = 16 * mm;
89// A small seeded generator, so the dents are the same every time.
90let seed = 7;
91const rnd = () => { seed = (seed * 1664525 + 1013904223) % 4294967296; return seed / 4294967296; };
92const dents = [];
93for (let k = 0; k < 12; k++) {
94 const rr = bellR + 25 * mm + (R - bellR - 45 * mm) * rnd(); // on the bow, clear of the bell and the edge
95 const th = 2 * Math.PI * rnd();
96 dents.push({
97 x: rr * Math.cos(th), y: rr * Math.sin(th),
98 radius: (18 + 14 * rnd()) * mm,
99 height: (rnd() < 0.5 ? -1 : 1) * (0.8 + 1.4 * rnd()) * mm,
100 });
102const hammer = noise2d(3, 40 * mm); // unit RMS, correlation length 40 mm
103return {
104 name: "16 inch crash, dented",
105 material: { E: 110e9, nu: 0.34, rho: 8800 },
106 bounds: { width: D, height: D },
107 inside: circle(D, 12 * mm),
108 thickness: (x, y, r) => lerp(1.4 * mm, 0.8 * mm, clamp((r - bellR) / (R - bellR), 0, 1)),
109 profile: (x, y, r) => {
110 let z = bowH * (1 - (r / R) ** 2) + dome(r, bellR, bellH);
111 for (const d of dents) z += bump(Math.hypot(x - d.x, y - d.y), d.radius, d.height);
112 z += 0.3 * mm * hammer(x, y) * smoothstep(bellR, bellR + 30 * mm, r); // no hammering on the bell
113 return z;
114 },
115 mount: { radius: 20 * mm, stiffness: 2e4, damping: 5 },
116 loss: { sigma0: 0.6, sigma1: 2.5e-4, sigmaIn: 20 },
117};
118`;
120const ride20 = `// A 20 inch ride: heavier bronze, a larger bell, a flatter bow. The taper
121// is stronger than on the crash, and the mount is a little stiffer.
122const D = 20 * inch, R = D / 2;
123const bellR = 70 * mm, bellH = 14 * mm;
124const bowH = 15 * mm;
125return {
126 name: "20 inch ride",
127 material: { E: 110e9, nu: 0.34, rho: 8800 },
128 bounds: { width: D, height: D },
129 inside: circle(D, 12 * mm),
130 thickness: (x, y, r) => lerp(2.0 * mm, 1.1 * mm, smoothstep(bellR, R, r)),
131 profile: (x, y, r) => bowH * (1 - (r / R) ** 2) + dome(r, bellR, bellH),
132 mount: { radius: 22 * mm, stiffness: 3e4, damping: 8 },
133 loss: { sigma0: 0.5, sigma1: 2e-4, sigmaIn: 20 },
134};
135`;
137const ellipseTwist = `// A steel ellipse with a saddle (twist) and a bow, hanging freely. The
138// twist raises two opposite quadrants and lowers the other two, which
139// breaks the symmetry of the disc modes.
140const W = 14 * inch, H = 20 * inch;
141return {
142 name: "Steel ellipse with a twist",
143 material: { E: 170e9, nu: 0.29, rho: 7900 },
144 bounds: { width: W, height: H },
145 inside: ellipse(W, H),
146 thickness: 0.79 * mm,
147 profile: (x, y) => {
148 const X = (2 * x) / W, Y = (2 * y) / H; // -1..1 over the bounding box
149 return 2 * mm * X * Y + bow(y, H, 2 * mm);
150 },
151 mount: null,
152 loss: { sigma0: 1.15, sigma1: 5e-4, sigmaIn: 20 },
153};
154`;
156const china18 = `// An 18 inch china: a conical bow that falls from the bell toward a flange,
157// and an upturned edge that rises again over the outer 45 mm. The bell is
158// square-topped (a plateau with rounded shoulders). The edge slope is well
159// beyond the shallow-shell range, so this preset is the least trustworthy.
160const D = 18 * inch, R = D / 2;
161const bellR = 65 * mm, bellH = 14 * mm;
162const flangeR = R - 45 * mm, bowH = 14 * mm, edgeH = 12 * mm;
163return {
164 name: "18 inch china",
165 material: { E: 110e9, nu: 0.34, rho: 8800 },
166 bounds: { width: D, height: D },
167 inside: circle(D, 12 * mm),
168 thickness: (x, y, r) => lerp(1.6 * mm, 0.9 * mm, smoothstep(bellR, flangeR, r)),
169 profile: (x, y, r) =>
170 bowH * Math.max(0, 1 - r / flangeR) // cone down to the flange
171 + edgeH * smoothstep(flangeR, R, r) // upturned edge
172 + bellH * (1 - smoothstep(bellR - 20 * mm, bellR, r)), // flat-topped bell
173 mount: { radius: 20 * mm, stiffness: 2e4, damping: 5 },
174 loss: { sigma0: 0.7, sigma1: 3e-4, sigmaIn: 20 },
175};
176`;
178export const PRESETS: Preset[] = [
179 { id: "flat-rectangle", label: "Flat steel rectangle", source: flatRectangle },
180 { id: "bowed-rectangle", label: "Bowed steel rectangle", source: bowedRectangle },
181 { id: "flat-disc", label: "Flat steel disc on a stand", source: flatDisc },
182 { id: "crash-16", label: "16 inch crash", source: crash16 },
183 { id: "crash-16-dented", label: "16 inch crash, dented", source: crashDented },
184 { id: "ride-20", label: "20 inch ride", source: ride20 },
185 { id: "ellipse-twist", label: "Steel ellipse with a twist", source: ellipseTwist },
186 { id: "china-18", label: "18 inch china", source: china18 },
187];
189export const DEFAULT_PRESET = PRESETS[0];
↑↓ move↵openescclose