diff --git a/sfm/event_browser.html b/sfm/event_browser.html index 9be5431..bbd960f 100644 --- a/sfm/event_browser.html +++ b/sfm/event_browser.html @@ -717,8 +717,9 @@ function renderWaveform(data) { // up AND down). Mic + histograms keep default auto-scale (always // positive values; zero at the bottom). let yBounds = {}; - const isGeoWaveform = !isHistogram && ch !== 'MicL'; - if (isGeoWaveform) { + const isGeo = ch !== 'MicL'; + if (isGeo && !isHistogram) { + // Waveform geo: symmetric around zero for full shape detail. let absMax = 0; for (const v of values) { const a = Math.abs(v); @@ -726,13 +727,25 @@ function renderWaveform(data) { } const padded = (absMax || 1) * 1.10; yBounds = { min: -padded, max: padded }; + } else if (isGeo && isHistogram) { + // Histogram geo: enforce minimum chart range so quiet events + // look quiet (matches BW's near-fixed-scale convention). + const HIST_GEO_MIN_INS = 0.05; + let p = 0; + for (const v of values) { const a = Math.abs(v); if (a > p) p = a; } + yBounds = { min: 0, max: Math.max(p * 1.10, HIST_GEO_MIN_INS) }; } else if (ch === 'MicL' && micUnit === 'dBL') { - // Baseline at noise-floor minimum (matches what we floored - // null/quiet samples to), top at peak + 5 dB headroom. + // Mic dBL: baseline at noise-floor minimum, top at peak + 5 dB. const peakDbl = (typeof peak === 'number' && isFinite(peak)) ? peak + 5 : 100; yBounds = { min: MIC_DBL_FLOOR, max: Math.max(peakDbl, MIC_DBL_FLOOR + 20) }; + } else if (ch === 'MicL' && isHistogram && micUnit === 'psi') { + // Mic histogram in psi: same minimum-range treatment as geo. + const HIST_MIC_MIN_PSI = 0.001; + let p = 0; + for (const v of values) { const a = Math.abs(v); if (a > p) p = a; } + yBounds = { min: 0, max: Math.max(p * 1.10, HIST_MIC_MIN_PSI) }; } const chart = new Chart(canvas, { diff --git a/sfm/sfm_webapp.html b/sfm/sfm_webapp.html index 19a3e05..5021c79 100644 --- a/sfm/sfm_webapp.html +++ b/sfm/sfm_webapp.html @@ -2748,8 +2748,9 @@ function _renderScWaveform(data) { // - Mic (always positive sound pressure) + histograms (per-interval // peaks, always positive): default auto-scale, zero at the bottom. let yBounds = {}; - const isGeoWaveform = !isHistogram && ch !== 'MicL'; - if (isGeoWaveform) { + const isGeo = ch !== 'MicL'; + if (isGeo && !isHistogram) { + // Waveform geo: symmetric around zero, full zoom to shape detail. let absMax = 0; for (const v of values) { const a = Math.abs(v); @@ -2757,13 +2758,31 @@ function _renderScWaveform(data) { } const padded = (absMax || 1) * 1.10; yBounds = { min: -padded, max: padded }; + } else if (isGeo && isHistogram) { + // Histogram geo: enforce a minimum chart range so a quiet + // 0.005 in/s event renders as ~10% of chart height instead of + // filling the panel. Matches BW's near-fixed-scale convention + // (their footer is "Geo: 0.002 in/s/div" — a chart-relative scale, + // not auto-zoom). + const HIST_GEO_MIN_INS = 0.05; + let peak = 0; + for (const v of values) { const a = Math.abs(v); if (a > peak) peak = a; } + yBounds = { min: 0, max: Math.max(peak * 1.10, HIST_GEO_MIN_INS) }; } else if (ch === 'MicL' && micUnit === 'dBL') { - // Pin baseline at the chart floor (which matches what we flooded - // null/quiet samples to), top at the actual peak + a few dB headroom. + // Mic in dBL — pin baseline at noise-floor minimum (where we floored + // quiet samples), top at actual peak + a few dB headroom. const peakDbl = (typeof chPeak === 'number' && isFinite(chPeak)) ? chPeak + 5 : 100; yBounds = { min: MIC_DBL_FLOOR, max: Math.max(peakDbl, MIC_DBL_FLOOR + 20) }; + } else if (ch === 'MicL' && isHistogram && micUnit === 'psi') { + // Mic histogram in psi — same minimum-range treatment as geo. + // 0.001 psi ≈ 110 dBL — typical "loud" mic peak. Quiet events + // sit near the bottom. + const HIST_MIC_MIN_PSI = 0.001; + let peak = 0; + for (const v of values) { const a = Math.abs(v); if (a > peak) peak = a; } + yBounds = { min: 0, max: Math.max(peak * 1.10, HIST_MIC_MIN_PSI) }; } _scCharts[ch] = new Chart(canvas, {