fix: peak0c scope bug and strt cross check fix

This commit is contained in:
2026-04-14 17:46:38 -04:00
parent 171dc2551c
commit 9ae968b108
2 changed files with 39 additions and 13 deletions
+34 -12
View File
@@ -1397,29 +1397,51 @@ def _decode_a5_waveform(
total_samples = struct.unpack_from(">H", strt, 14)[0]
pretrig_samples = struct.unpack_from(">H", strt, 16)[0]
# Sanity check: pretrig must be less than total_samples.
# If not, the STRT layout is suspect (DLE-stuffing shift, different record variant, etc.).
# Log the raw bytes for diagnosis and clamp pretrig to 0 for now — will try to derive
# a better value from the compliance config after the full waveform is decoded.
# ── STRT sanity checks ───────────────────────────────────────────────────
# Check 1: pretrig must be strictly less than total_samples.
# Check 2 (cross-check): if compliance_config is available, the STRT-derived
# post-trigger record time must be within 2× of the configured record_time.
# A 3-second record at 1024 sps = 3072 post-trig samples; if STRT gives
# e.g. 21 s, something is wrong with the byte offsets.
#
# Both failures trigger the same fallback: derive pretrig from the compliance
# monitoring standard (0.25 s) and total from compliance record_time.
_strt_invalid = False
_sample_rate_default = 1024
if pretrig_samples >= total_samples:
log.warning(
"_decode_a5_waveform: pretrig_samples=%d >= total_samples=%d "
"STRT layout suspect. Raw strt[0:21]: %s "
"Will attempt to derive pretrig from compliance config after decode.",
"_decode_a5_waveform: STRT check1 FAIL — pretrig_samples=%d >= "
"total_samples=%d. Raw strt[0:21]: %s "
"Will derive pretrig from compliance config.",
pretrig_samples, total_samples, strt[0:21].hex(' '),
)
pretrig_samples = 0
total_samples = 0 # also invalid; will be filled from decoded count below
total_samples = 0
_strt_invalid = True
elif compliance_config is not None and compliance_config.record_time:
cc_rt = compliance_config.record_time
cc_sr = compliance_config.sample_rate or _sample_rate_default
strt_post_trig = (total_samples - pretrig_samples) / cc_sr
# Allow up to 2× tolerance to account for zero-padding beyond the window.
# Anything more than that is a layout error, not zero-padding.
if strt_post_trig > cc_rt * 2.0 or strt_post_trig < cc_rt * 0.5:
log.warning(
"_decode_a5_waveform: STRT check2 FAIL — STRT-derived rectime "
"%.1fs is implausible vs compliance record_time=%.1fs (ratio=%.1f×). "
"Raw strt[0:21]: %s Falling back to compliance-config values.",
strt_post_trig, cc_rt, strt_post_trig / cc_rt,
strt[0:21].hex(' '),
)
pretrig_samples = 0
total_samples = 0
_strt_invalid = True
# strt[18] is a record-mode/type byte, NOT rectime in seconds.
# Confirmed from analysis of 4-9-26 ACH capture (15 distinct events):
# flags=0xFFFE (single-shot) → strt[18]=0x46 ('F') for all events regardless of duration
# flags=0xFFFD (continuous) → strt[18]=0x0E for all events regardless of duration
# The actual post-trigger record time must be derived from total_samples and pretrig_samples.
# Default sample rate of 1024 is used here; the server overrides with compliance config sr.
_sample_rate_default = 1024
rectime_seconds = int(round(
max(0, total_samples - pretrig_samples) / _sample_rate_default
))
@@ -1428,9 +1450,9 @@ def _decode_a5_waveform(
event.pretrig_samples = pretrig_samples
event.rectime_seconds = rectime_seconds
log.debug(
log.info(
"_decode_a5_waveform: STRT total_samples=%d pretrig=%d "
"strt[18]=0x%02X (mode byte, not seconds) computed_rectime=%ds "
"strt[18]=0x%02X (mode byte) computed_rectime=%ds "
"raw strt[0:21]: %s",
total_samples, pretrig_samples, strt[18], rectime_seconds,
strt[0:21].hex(' '),
+5 -1
View File
@@ -527,6 +527,10 @@
? samples.slice(0, displayCount)
: samples;
// peak0C declared here (function scope) so it is visible in the Chart.js
// config block below (which lives outside the if(isGeo) block).
let peak0C = null;
if (isGeo) {
// Geo channels: counts × (range / 32767) → in/s
// Scale factor for the waveform shape (may need calibration per unit)
@@ -535,7 +539,7 @@
// Use the device-computed 0C record peak for the label (authoritative).
// The raw-sample-computed peak can be inflated by frame-boundary artifacts.
const peak0C = peakValues0C[ch];
peak0C = peakValues0C[ch];
const peakIns = (peak0C !== null && peak0C !== undefined)
? peak0C
: Math.max(...plotSamples.map(Math.abs));