From ed926de3f44ca868309fe917b133fecb97c1c939 Mon Sep 17 00:00:00 2001 From: serversdown Date: Wed, 27 May 2026 02:30:56 +0000 Subject: [PATCH] =?UTF-8?q?viewers:=20default=20mic=20to=20dB(L)=20+=20add?= =?UTF-8?q?=20Mic-unit=20toggle=20(dBL=20=E2=86=94=20psi)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sidecar-modal waveform plot was rendering mic in raw psi, while the rest of SFM (history table column, peaks block, live-device chart, event detail modal mic field) had already converted to dB(L) — matching the BW Event Report convention. Unifying. Both viewers now: - Default mic chart values + axis title + peak label to dB(L) - Provide a header toggle ("Mic: dBL" pill) to flip to psi - Persist the preference via localStorage (sfm_mic_unit) - Re-render the open chart immediately on toggle Conversion: dBL = 20 * log10(psi / 2.9e-9), where 2.9e-9 psi is the 20 µPa reference pressure already defined for the rest of the webapp. Non-positive psi samples (log undefined) render as null; Chart.js handles them as gaps in line mode and missing bars in histogram mode. Also fixes event_browser.html's stats table — the MicL row was hard-coding " psi"; now honors the same toggle. Co-Authored-By: Claude Opus 4.7 (1M context) --- sfm/event_browser.html | 66 ++++++++++++++++++++++++++++++++++++++---- sfm/sfm_webapp.html | 55 +++++++++++++++++++++++++++++++---- 2 files changed, 110 insertions(+), 11 deletions(-) diff --git a/sfm/event_browser.html b/sfm/event_browser.html index 5d7a493..1ef883b 100644 --- a/sfm/event_browser.html +++ b/sfm/event_browser.html @@ -289,7 +289,12 @@ - + + @@ -328,6 +333,29 @@ const CHANNEL_COLORS = { }; const CHANNEL_ORDER = ['MicL', 'Long', 'Vert', 'Tran']; +// Reference pressure for dB(L) — 20 µPa expressed in psi (≈ 2.9e-9 psi). +const DBL_REF = 2.9e-9; + +// User-toggleable mic display unit: 'dBL' (default, matches BW printout +// + the rest of SFM) or 'psi' (raw sample unit). +function _getMicUnit() { + return localStorage.getItem('sfm_mic_unit') === 'psi' ? 'psi' : 'dBL'; +} +function _setMicUnit(u) { + localStorage.setItem('sfm_mic_unit', u === 'psi' ? 'psi' : 'dBL'); + _refreshMicUnitToggle(); + if (currentEventId) loadEvent(currentEventId); +} +function _refreshMicUnitToggle() { + const b = document.getElementById('mic-unit-toggle'); + if (b) b.textContent = `Mic: ${_getMicUnit()}`; +} +// psi → dB(L). Null for non-positive (log undefined; Chart.js renders as a gap). +function _psiToDbl(psi) { + if (psi == null || !(psi > 0)) return null; + return 20 * Math.log10(psi / DBL_REF); +} + // Adaptive decimal formatter — scientific notation only for truly extreme // values. Normal-range peaks render as plain decimals with sensible // precision (was previously forcing toExponential(3) which produced ugly @@ -502,6 +530,19 @@ function renderMeta(data, ev) { ['Vert', ev?.vert_ppv], ['Long', ev?.long_ppv], ]; + // Mic display honors the current user preference (dBL default). + // mic_ppv is stored as raw psi on series3 events; convert when needed. + const micPsi = ev?.mic_ppv; + const micUnitDisplay = _getMicUnit(); + let micStr; + if (micPsi == null) { + micStr = '—'; + } else if (micUnitDisplay === 'dBL') { + const d = _psiToDbl(Number(micPsi)); + micStr = (d != null ? d.toFixed(1) : '—') + ' dBL'; + } else { + micStr = Number(micPsi).toExponential(2) + ' psi'; + } const statsHtml = ` @@ -509,7 +550,7 @@ function renderMeta(data, ev) { ${rows.map(([ch, ppv]) => ``).join('')} - +
${ch}${fmt(ppv)}
MicL${fmt(ev?.mic_ppv)} psi
MicL${micStr}
`; @@ -560,11 +601,11 @@ function renderWaveform(data) { ); const lastDataCh = channelsWithData[channelsWithData.length - 1]; + const micUnit = _getMicUnit(); for (const ch of CHANNEL_ORDER) { const chData = channels[ch]; if (!chData) continue; - const values = chData.values || []; - if (values.length === 0) { + if ((chData.values || []).length === 0) { // Render an empty card so user sees the channel exists but is missing const wrap = document.createElement('div'); wrap.className = 'chart-wrap'; @@ -579,9 +620,19 @@ function renderWaveform(data) { continue; } - const unit = chData.unit || 'unit'; - const peak = chData.peak; + // Mic channel: convert from raw psi to dB(L) when the user prefers dBL + // (the default). We mutate `values`, `peak`, and `unit` locally so the + // chart datasets + axis title + tooltip + peak label all stay aligned. + let values = chData.values || []; + let unit = chData.unit || 'unit'; + let peak = chData.peak; const peakT = chData.peak_t_ms; + if (ch === 'MicL' && unit === 'psi' && micUnit === 'dBL') { + values = values.map(_psiToDbl); + peak = _psiToDbl(peak); + unit = 'dB(L)'; + } + const peakLabel = peak != null ? `peak ${_fmtPeak(peak, unit)}` + (!isHistogram && peakT != null ? ` @ ${peakT.toFixed(1)} ms` : '') @@ -781,6 +832,9 @@ document.getElementById('serial-select').addEventListener('change', e => { }); document.getElementById('event-filter').addEventListener('input', applyFilter); +// Reflect any persisted mic-unit preference in the header pill on load +_refreshMicUnitToggle(); + // Initial load loadSerials(); diff --git a/sfm/sfm_webapp.html b/sfm/sfm_webapp.html index 2c4a912..ad2b6e9 100644 --- a/sfm/sfm_webapp.html +++ b/sfm/sfm_webapp.html @@ -818,6 +818,12 @@ Force refresh +
+