59 lines
1.7 KiB
Python
59 lines
1.7 KiB
Python
"""Waveform-shape metrics for false-trigger detection.
|
|
|
|
A false trigger is an isolated impulse (quiet → spike → quiet); a real event
|
|
rings for many cycles. Two numbers separate them: crest factor (how far the
|
|
peak stands above the typical sample) and how many samples sit near the peak.
|
|
"""
|
|
from __future__ import annotations
|
|
import numpy as np
|
|
|
|
_GEO_CHANNELS = ("Tran", "Vert", "Long")
|
|
NEAR_PEAK_FRACTION = 0.5 # a sample "near the peak" is >= this * peak amplitude
|
|
|
|
|
|
def channel_shape(x) -> dict | None:
|
|
x = np.asarray(x, dtype=float)
|
|
if x.size < 2:
|
|
return None
|
|
peak = float(np.max(np.abs(x)))
|
|
if peak <= 0:
|
|
return None
|
|
rms = float(np.sqrt(np.mean(x ** 2)))
|
|
if rms <= 0:
|
|
return None
|
|
near = int(np.sum(np.abs(x) >= NEAR_PEAK_FRACTION * peak))
|
|
return {"crest_factor": peak / rms, "near_peak_count": near,
|
|
"sample_count": int(x.size)}
|
|
|
|
|
|
def shape_from_samples(chans: dict) -> dict | None:
|
|
best_axis, best_peak, best_x = None, -1.0, None
|
|
for ax in _GEO_CHANNELS:
|
|
x = chans.get(ax)
|
|
if x is None:
|
|
continue
|
|
x = np.asarray(x, dtype=float)
|
|
if x.size < 2:
|
|
continue
|
|
p = float(np.max(np.abs(x)))
|
|
if p > best_peak:
|
|
best_axis, best_peak, best_x = ax, p, x
|
|
if best_axis is None:
|
|
return None
|
|
s = channel_shape(best_x)
|
|
if s is None:
|
|
return None
|
|
s["axis"] = best_axis
|
|
return s
|
|
|
|
|
|
def shape_from_h5(path) -> dict | None:
|
|
import h5py
|
|
try:
|
|
with h5py.File(path, "r") as f:
|
|
chans = {ax: f[f"samples/{ax}"][:] for ax in _GEO_CHANNELS
|
|
if f"samples/{ax}" in f}
|
|
except Exception:
|
|
return None
|
|
return shape_from_samples(chans)
|