Ingests MSR data-logger CSVs of 3-axis acceleration and visualizes them in one interactive dashboard with a dataset selector:
- Lifting table — double-integrates acceleration to velocity & position and animates a scissor lift moving up/down, synced to a position-vs-time chart.
- Motor 1 / Motor 2 (slave) — standstill motors: the housing doesn't translate, so instead of (meaningless) position we show a vibration envelope (RMS / peak per 50 ms) driving a shaking-motor animation.
Every view shares a moving time playhead, scrubbing, and playback controls. Runs
fully offline (double-click index.html) and deploys unchanged to
GitHub Pages.
| File | Purpose |
|---|---|
MSR…*.csv |
Raw measurements (timestamp + ACC x/y/z in g). |
build.mjs |
Node script: parses each CSV, integrates / computes vibration + ISO velocity, writes data.js. |
data.js |
Baked data for all datasets (window.LIFT_DATA). Generated — don't edit. |
index.html / styles.css / app.js |
The main dashboard. No dependencies. |
iso.html / iso.js |
ISO 10816/20816 machine-health page (linked from the dashboard). |
Open index.html in a browser. Because all data is pre-baked into data.js,
there is no server or CORS issue — it works from file://.
Controls: dataset tabs (Lifting table / Motor 1 / Motor 2), Play/Pause (or
Spacebar), Restart, Loop, speed (0.5–8×), the timeline scrubber, and click/drag
on the chart to seek. Toggle the chart signal (Position/Velocity/Acceleration, or
RMS/Peak for motors). Deep-link a moment with index.html#ds=motor1&t=113&sig=peak.
Datasets are declared in the DATASETS array at the top of build.mjs (key,
kind, label, file). Add or edit an entry, then:
node build.mjskind: 'position' → double-integration view; kind: 'vibration' → motor view.
This regenerates data.js; refresh the page. The gravity direction is detected
from the data, so the logger's mounting orientation doesn't matter (the lift
sensor sits on Y; the motor sensor sits at ~45°, split across Y+Z).
Position (lifting table). Project acceleration onto the measured gravity
direction and subtract |g| → vertical linear acceleration (m/s²). Integrate →
velocity, remove a linear trend so v = 0 at both ends (the table is at rest
there → kills bias drift). Integrate → position, remove a linear trend so it
returns to its start height. Orient up = positive, floor = 0 m. Recovered travel
is 1.505 m, matching the ~1.5 m physical range, with a clean rise → ~5 s hold
→ descent and only ~3 cm drift across the hold.
Double integration is drift-prone; the linear detrend works here only because the table is genuinely at rest at start and end. For arbitrary motion you'd use zero-velocity updates (ZUPT) on each detected rest interval instead.
Vibration (motors). These motors don't translate, so integrating to position is just drift (it would read 11 m / 33 m — not real). Instead, remove the gravity vector and take the magnitude of the residual acceleration, then summarize it per 50 ms window as RMS (sustained vibration level) and peak (worst sample).
Each raw recording is ~90 % idle (~0.02 g) with a single ~18 s operating burst, so
the motor datasets are auto-trimmed to that burst plus a few seconds of context:
Motor 1's 213 s → ~24 s, Motor 2's 274 s → ~23 s. Detection keeps runs that peak
above ~1 g (real operation) and ignores isolated knocks; tune it via the VIB_TRIM
object in build.mjs. Gravity and the bias are still estimated from the full
recording (the idle stretches give the cleanest reference).
A separate page presents the motors in standard condition-monitoring format: velocity in mm/s RMS per axis (X/Y/Z), reported for both the 2–1000 Hz and 10–1000 Hz bands, plus the top-3 spectral peaks (mm/s @ Hz) per axis — split into the Up and Down phases of the lift cycle. A configurable reference limit (default 4.5 mm/s RMS) red-marks exceedances. An ISO 10816/20816 zone scale (A–D, 10–1000 Hz, selectable machine class) sits on top, and everything exports as JSON/CSV.
The velocity is derived from the acceleration in build.mjs: per Up/Down phase,
an FFT over a power-of-2 window of that phase, integrated to velocity in the
frequency domain (V = A/jω), band-limited, RMS via Parseval; spectral peaks are the
strongest velocity lines. The worst axis lands both motors deep in Zone D.
Important caveats (shown on the page). This is indicative, not a formal ISO measurement: (1) ISO 10816/20816 assumes continuous steady-state running, but these motors run a transient lift cycle; (2) the energy is dominated by 2–5 Hz (the lift motion), below the standard 10 Hz band floor, whereas motor/gear vibration would sit ~20–35 Hz; (3) the sensor sits at ~45° and velocity is integrated from a logger, not measured with a dedicated vibration meter — so the values are drift-sensitive at these low frequencies and not directly comparable to a proper steady-state measurement.
Push the files and enable Pages (Settings → Pages → deploy from branch, root).
Pure static HTML/JS/CSS — nothing to build server-side. The CSVs aren't needed at
runtime (only build.mjs reads them) but are fine to keep in the repo.