feat(offset): DC-offset detector productionized into the shape pipeline
Productionizes the validated scratch/offset_scan3.py: a DC offset (baseline shifted off zero — sensor bumped/settled/drifted) is |median(pre-trigger)| >= 5 counts (0.025 in/s) AND flat across pre/mid/end thirds (spread <= 0.02); a transient moves one third and is rejected by the spread test. - shape_metrics: offset_from_samples / offset_from_h5 (reads .h5 samples + pretrig_samples attr; range-aware via the .h5's in/s float samples) - events schema: shape_offset / _axis / _pre / _spread (via _SCHEMA + the _migrate ADD COLUMN loop only; NOT the Migration-1 rebuild), threaded through insert + upsert mirroring shape_* - ingest: computed at all three waveform_store save paths alongside shape - backfill_event_shape: also computes + stores (and stale-clears) offset - exposed via /db/events automatically (SELECT *) Gating to waveforms is done downstream in terra-view ft_suspicion (mirrors how shape is ignored for histograms), not at the SFM call sites. 13 new tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDXjZCr4RqT2U3QvMDhgzf
This commit is contained in:
+25
-3
@@ -99,6 +99,10 @@ CREATE TABLE IF NOT EXISTS events (
|
||||
shape_near_peak_count INTEGER, -- samples >= 0.5 * peak (FT: few; real: many)
|
||||
shape_sample_count INTEGER, -- total samples (to normalize near_peak_count)
|
||||
shape_axis TEXT, -- geophone channel measured ("Tran"/"Vert"/"Long")
|
||||
shape_offset INTEGER, -- 1 = DC-offset false trigger (pre-trigger baseline off zero + flat). Meaningful for waveforms only.
|
||||
shape_offset_axis TEXT, -- geo channel the offset was measured on
|
||||
shape_offset_pre REAL, -- pre-trigger baseline median (in/s)
|
||||
shape_offset_spread REAL, -- max(pre,mid,end) - min(...) in in/s; small = constant/DC
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
||||
UNIQUE(serial, timestamp)
|
||||
);
|
||||
@@ -225,6 +229,10 @@ class SeismoDb:
|
||||
("shape_near_peak_count", "INTEGER"),
|
||||
("shape_sample_count", "INTEGER"),
|
||||
("shape_axis", "TEXT"),
|
||||
("shape_offset", "INTEGER"),
|
||||
("shape_offset_axis", "TEXT"),
|
||||
("shape_offset_pre", "REAL"),
|
||||
("shape_offset_spread", "REAL"),
|
||||
("reviewed_real", "INTEGER NOT NULL DEFAULT 0"),
|
||||
):
|
||||
if col not in existing_cols:
|
||||
@@ -430,9 +438,11 @@ class SeismoDb:
|
||||
tran_zc_above_range, vert_zc_above_range,
|
||||
long_zc_above_range, mic_zc_above_range,
|
||||
shape_crest_factor, shape_near_peak_count,
|
||||
shape_sample_count, shape_axis)
|
||||
shape_sample_count, shape_axis,
|
||||
shape_offset, shape_offset_axis,
|
||||
shape_offset_pre, shape_offset_spread)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
self._new_id(), serial, key, session_id, ts,
|
||||
@@ -464,6 +474,10 @@ class SeismoDb:
|
||||
rec.get("shape_near_peak_count"),
|
||||
rec.get("shape_sample_count"),
|
||||
rec.get("shape_axis"),
|
||||
rec.get("shape_offset"),
|
||||
rec.get("shape_offset_axis"),
|
||||
rec.get("shape_offset_pre"),
|
||||
rec.get("shape_offset_spread"),
|
||||
),
|
||||
)
|
||||
inserted += 1
|
||||
@@ -517,7 +531,11 @@ class SeismoDb:
|
||||
shape_crest_factor = COALESCE(?, shape_crest_factor),
|
||||
shape_near_peak_count = COALESCE(?, shape_near_peak_count),
|
||||
shape_sample_count = COALESCE(?, shape_sample_count),
|
||||
shape_axis = COALESCE(?, shape_axis)
|
||||
shape_axis = COALESCE(?, shape_axis),
|
||||
shape_offset = COALESCE(?, shape_offset),
|
||||
shape_offset_axis = COALESCE(?, shape_offset_axis),
|
||||
shape_offset_pre = COALESCE(?, shape_offset_pre),
|
||||
shape_offset_spread = COALESCE(?, shape_offset_spread)
|
||||
WHERE serial = ? AND timestamp = ?
|
||||
""",
|
||||
(
|
||||
@@ -549,6 +567,10 @@ class SeismoDb:
|
||||
rec.get("shape_near_peak_count") if rec else None,
|
||||
rec.get("shape_sample_count") if rec else None,
|
||||
rec.get("shape_axis") if rec else None,
|
||||
rec.get("shape_offset") if rec else None,
|
||||
rec.get("shape_offset_axis") if rec else None,
|
||||
rec.get("shape_offset_pre") if rec else None,
|
||||
rec.get("shape_offset_spread") if rec else None,
|
||||
serial,
|
||||
ts,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user