/ proof-of-concept / plate-dynamics-lab-2
Sign in
proof-of-concept / plate-dynamics-lab-2
plate-dynamics-lab-2 / apps / lab / src / views / ModeTable.tsx
83 lines · 2.9 KBCodeBlameHistory
2004981Plate dynamics lab 2: a hammer on a hung plate by Rayleigh-Ritz and by Mindlin-Reissner finite elementsJeremy Magland 1import type { PlateResult } from "@plate-dyn/core";
3export interface ModeTableProps {
4 result: PlateResult;
5 selected: number | null;
6 onSelect: (k: number) => void;
7}
9/**
10 * One row per mode: frequency, quality, the shape at the strike point (what
11 * the hammer can put into it), at the hole (what the thread's dashpot takes
12 * out) and its volume participation (what radiates). Click a row to see the
13 * shape.
14 */
15export function ModeTable({ result, selected, onSelect }: ModeTableProps) {
16 const m = result.modes;
17 const hitPeak = Math.max(...Array.from(m.hit).map(Math.abs), 1e-300);
18 return (
19 <div>
20 <div className="pl-plot-title">Modes</div>
21 <div style={{ overflowX: "auto" }}>
22 <table className="modes-table">
23 <thead>
24 <tr>
25 <th>#</th>
26 <th>f [Hz]</th>
27 <th>Q</th>
28 <th>at the strike</th>
29 <th>at the hole</th>
30 <th>radiation</th>
31 <th>excited</th>
32 </tr>
33 </thead>
34 <tbody>
35 {Array.from(m.freq).map((f, k) => {
36 const rigid = !m.audible[k];
37 const rel = Math.abs(m.hit[k]) / hitPeak;
38 return (
39 <tr
40 key={k}
41 className={selected === k ? "selected" : undefined}
42 onClick={() => onSelect(k)}
43 style={{ cursor: "pointer", opacity: rigid ? 0.6 : 1 }}
44 title="Show this mode's shape"
45 >
46 <td>{k + 1}</td>
47 <td>{rigid ? `${f.toFixed(2)} (rigid)` : f.toFixed(1)}</td>
48 <td>{rigid ? "–" : m.q[k].toFixed(0)}</td>
49 <td>{fmt(m.hit[k])}</td>
50 <td>{fmt(m.support[k])}</td>
51 <td>{rigid ? "–" : fmt(m.radiation[k])}</td>
52 <td>
53 <span
54 className="bar"
55 style={{ width: `${Math.round(60 * rel)}px` }}
56 aria-label={`${(100 * rel).toFixed(0)} percent of the strongest`}
57 />
58 </td>
59 </tr>
60 );
61 })}
62 </tbody>
63 </table>
64 </div>
65 <div className="pl-small pl-muted">
66 Shapes are mass-normalized (units of 1/√kg), so "at the strike" times the impulse is the
67 modal momentum the hammer delivers; "radiation" is the integral of the shape over the plate
68 (m²/√kg), zero for antisymmetric modes, which a microphone on the normal cannot hear.
69 {result.info.n_rigid > 0
70 ? " The rigid-body modes take part in the collision and are left out of the sound."
71 : ""}
72 </div>
73 </div>
74 );
77function fmt(x: number): string {
78 if (!Number.isFinite(x)) return "–";
79 const a = Math.abs(x);
80 if (a === 0) return "0";
81 if (a < 1e-3 || a >= 1e4) return x.toExponential(2);
82 return x.toPrecision(3);
↑↓ move↵openescclose