-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathiso.js
More file actions
135 lines (124 loc) · 8.44 KB
/
Copy pathiso.js
File metadata and controls
135 lines (124 loc) · 8.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* iso.js — ISO 10816/20816 velocity assessment for the motors, in standard
condition-monitoring format: per-axis velocity RMS (2–1000 Hz) and top-3
spectral peaks (mm/s @ Hz), split Up / Down. */
(() => {
'use strict';
const DATA = window.LIFT_DATA;
const SVGNS = 'http://www.w3.org/2000/svg';
const $ = id => document.getElementById(id);
const AXES = ['X', 'Y', 'Z'];
const LIMIT = 4.5; // mm/s RMS — configurable reference limit
const PEAK_LIMIT = 5;
const MOTORS = DATA.order.map(k => ({ key: k, ...DATA.datasets[k] })).filter(d => d.kind === 'vibration' && d.iso);
// ---- ISO 10816/20816 zone-boundary tables (velocity RMS, mm/s, 10–1000 Hz) ----
const CLASSES = [
{ id: 'c1', label: 'ISO 10816-1 Kl. I — små maskiner (< 15 kW)', A: 0.71, B: 1.8, C: 4.5 },
{ id: 'c2', label: 'ISO 10816-1 Kl. II (15–75 kW)', A: 1.12, B: 2.8, C: 7.1 },
{ id: 'g2r', label: 'ISO 20816-3 Gruppe 2, stiv fundament (15–300 kW)', A: 1.4, B: 2.8, C: 4.5 },
{ id: 'g2f', label: 'ISO 20816-3 Gruppe 2, fleksibel fundament', A: 2.3, B: 4.5, C: 7.1 },
{ id: 'g1r', label: 'ISO 20816-3 Gruppe 1, stiv fundament (store maskiner)', A: 2.3, B: 4.5, C: 7.1 },
{ id: 'g1f', label: 'ISO 20816-3 Gruppe 1, fleksibel fundament', A: 3.5, B: 7.1, C: 11.0 },
];
const ZONES = { A: { label: 'Good', col: '#36d399' }, B: { label: 'Acceptable', col: '#b5cc3f' }, C: { label: 'Unsatisfactory', col: '#f7b955' }, D: { label: 'Unacceptable', col: '#ff5c5c' } };
const zoneOf = (v, c) => v <= c.A ? 'A' : v <= c.B ? 'B' : v <= c.C ? 'C' : 'D';
let cls = CLASSES[0];
const sel = $('classSel');
CLASSES.forEach(c => { const o = document.createElement('option'); o.value = c.id; o.textContent = c.label; sel.appendChild(o); });
sel.value = cls.id;
sel.onchange = () => { cls = CLASSES.find(c => c.id === sel.value); renderScale(); };
// ======================================================= ISO zone scale (10–1000 Hz)
const el = (tag, attrs = {}, text) => { const e = document.createElementNS(SVGNS, tag); for (const k in attrs) e.setAttribute(k, attrs[k]); if (text != null) e.textContent = text; return e; };
const maxV = Math.max(...MOTORS.map(m => m.iso.worst10RmsMmps));
const vMin = 0.2, vMax = Math.max(maxV * 1.3, 12), l0 = Math.log10(vMin), l1 = Math.log10(vMax);
const PX0 = 70, PX1 = 940, BY0 = 70, BY1 = 110;
const xOf = v => PX0 + (Math.log10(Math.max(vMin, Math.min(vMax, v))) - l0) / (l1 - l0) * (PX1 - PX0);
function renderScale() {
const svg = $('scale'); svg.innerHTML = '';
const bounds = [vMin, cls.A, cls.B, cls.C, vMax], keys = ['A', 'B', 'C', 'D'];
for (let i = 0; i < 4; i++) {
const x1 = xOf(bounds[i]), x2 = xOf(bounds[i + 1]);
svg.appendChild(el('rect', { x: x1, y: BY0, width: Math.max(0, x2 - x1), height: BY1 - BY0, class: 'scale-zone-' + keys[i] }));
if (x2 - x1 > 16) svg.appendChild(el('text', { x: (x1 + x2) / 2, y: (BY0 + BY1) / 2 + 5, class: 'zone-letter' }, keys[i]));
}
[['A', cls.A], ['B', cls.B], ['C', cls.C]].forEach(([_, v]) => {
svg.appendChild(el('line', { x1: xOf(v), y1: BY0, x2: xOf(v), y2: BY1 + 6, class: 'scale-tick' }));
svg.appendChild(el('text', { x: xOf(v), y: BY1 + 18, class: 'bnd-txt' }, v.toFixed(2).replace(/\.00$/, '')));
});
[0.2, 0.5, 1, 2, 5, 10, 20, 50, 100].filter(t => t >= vMin && t <= vMax).forEach(t => svg.appendChild(el('text', { x: xOf(t), y: BY1 + 34, class: 'scale-tick-txt' }, String(t))));
svg.appendChild(el('text', { x: PX1, y: BY1 + 34, class: 'scale-tick-txt', style: 'text-anchor:end' }, 'mm/s'));
MOTORS.forEach((m, i) => {
const v = m.iso.worst10RmsMmps, x = xOf(v), z = zoneOf(v, cls), col = ZONES[z].col, yLab = 22 + (i % 2) * 26;
svg.appendChild(el('line', { x1: x, y1: yLab + 4, x2: x, y2: BY1, class: 'marker-line', style: `stroke:${col}` }));
svg.appendChild(el('circle', { cx: x, cy: BY0, r: 6, fill: col, class: 'marker-dot' }));
const anchor = x > (PX0 + PX1) / 2 ? 'end' : 'start', tx = x + (anchor === 'end' ? -10 : 10);
svg.appendChild(el('text', { x: tx, y: yLab, class: 'marker-txt', style: 'text-anchor:' + anchor }, `${m.label} — ${v.toFixed(1)} mm/s`));
svg.appendChild(el('text', { x: tx, y: yLab + 14, class: 'marker-sub', style: 'text-anchor:' + anchor }, `Sone ${z} (${ZONES[z].label})`));
});
}
// ======================================================= velocity tables (2–1000 Hz)
function renderTables() {
const root = $('cards'); root.innerHTML = '';
MOTORS.forEach(m => {
const conds = m.iso.conditions;
let worst = { v: 0 };
conds.forEach(c => AXES.forEach(ax => { if (c.rms2[ax] > worst.v) worst = { v: c.rms2[ax], ax, cond: c.name.split(' ')[0] }; }));
const panel = document.createElement('section'); panel.className = 'panel vt-motor';
const ratio = (worst.v / LIMIT).toFixed(0);
panel.innerHTML =
`<h3>${m.label}</h3>
<p class="vt-status">Verste hastigheit (2–1000 Hz): <b>${worst.v.toFixed(1)} mm/s</b> (${worst.ax}, ${worst.cond}) —
<b class="hot">${ratio}× over referansegrensa ${LIMIT} mm/s RMS</b></p>
${overallTable(conds)}
${peaksTable(conds)}`;
root.appendChild(panel);
});
}
function overallTable(conds) {
let rows = '';
conds.forEach(c => {
rows += `<tr><td class="cond">${c.name}</td>` +
AXES.map(ax => `<td class="${c.rms2[ax] > LIMIT ? 'over' : ''}">${c.rms2[ax].toFixed(2)}</td>`).join('') + '</tr>';
});
return `<table class="vt"><caption>Hastigheit – overall (mm/s RMS, 2–1000 Hz) · raud = over ${LIMIT} mm/s</caption>
<thead><tr><th>Tilstand</th><th>X</th><th>Y</th><th>Z</th></tr></thead><tbody>${rows}</tbody></table>`;
}
function peaksTable(conds) {
const cell = peaks => `<td class="peakcell">${peaks.map(([f, a]) => `<span class="${a > PEAK_LIMIT ? 'hot' : ''}">${a.toFixed(2)} <small>@ ${f.toFixed(1)} Hz</small></span>`).join('')}</td>`;
let rows = '';
conds.forEach(c => { rows += `<tr><td class="cond">${c.name}</td>` + AXES.map(ax => cell(c.peaks[ax])).join('') + '</tr>'; });
return `<table class="vt"><caption>Topp-3 toppar (mm/s @ Hz) · raud = over ${PEAK_LIMIT} mm/s</caption>
<thead><tr><th>Tilstand</th><th>X</th><th>Y</th><th>Z</th></tr></thead><tbody>${rows}</tbody></table>`;
}
// ======================================================= data format export
function records() {
const rows = [];
MOTORS.forEach(m => m.iso.conditions.forEach(c => AXES.forEach(ax => {
const pk = c.peaks[ax];
rows.push({
machine: m.label, condition: c.name, axis: ax,
rms_2_1000hz_mmps: c.rms2[ax], rms_10_1000hz_mmps: c.rms10[ax],
peak1_mmps: pk[0] ? pk[0][1] : null, peak1_hz: pk[0] ? pk[0][0] : null,
peak2_mmps: pk[1] ? pk[1][1] : null, peak2_hz: pk[1] ? pk[1][0] : null,
peak3_mmps: pk[2] ? pk[2][1] : null, peak3_hz: pk[2] ? pk[2][0] : null,
over_limit_4_5: c.rms2[ax] > LIMIT,
});
})));
return rows;
}
function renderFormat() { $('dataFormat').textContent = JSON.stringify(records(), null, 1); }
function download(name, text, type) { const a = document.createElement('a'); a.href = URL.createObjectURL(new Blob([text], { type })); a.download = name; a.click(); URL.revokeObjectURL(a.href); }
$('dlJson').onclick = () => download('velocity_assessment.json', JSON.stringify(records(), null, 2), 'application/json');
$('dlCsv').onclick = () => {
const rows = records(), cols = Object.keys(rows[0]);
const csv = [cols.join(',')].concat(rows.map(r => cols.map(k => `"${String(r[k]).replace(/"/g, '""')}"`).join(','))).join('\n');
download('velocity_assessment.csv', csv, 'text/csv');
};
$('disclaimer').innerHTML =
'<b>Datatype:</b> vibrasjonshastigheit i <b>mm/s RMS, 2–1000 Hz</b>, per akse X/Y/Z, med topp-3 spektraltoppar (mm/s @ Hz) ' +
'og ei valbar referansegrense (<b>4.5 mm/s RMS</b>). Splitta i Opp/Ned (begge med batteri). ' +
'Den øvste skalaen er ISO 10816/20816-klassifisering (10–1000 Hz, valbar maskinklasse).' +
'<br><br><b>Atterhald:</b> opptaket er transient løftedrift (ikkje steady-state), sensoren sit ~45°, og hastigheita er ' +
'avleidd ved å integrere akselerasjon frå ein MSR-datalogger i frekvensdomenet — ikkje målt med dedikert vibrasjonsmålar. ' +
'Verdiane er dominert av 2–5 Hz (løfterørsle), medan typisk motor-/gir-vibrasjon ligg på 20–35 Hz. Dei er difor rettleiande, ikkje ei formell måling.';
renderScale(); renderTables(); renderFormat();
})();