Replaying a Week of P-Wave Alerts From a Raspberry Pi Shake Node

这篇内容暂时只有 English 版本,以下是原文。

Last spring I rebuilt the alert path on my home shake node: a Raspberry Pi 4 (2 GB, Raspberry Pi OS bullseye, kernel 6.1), a Raspberry Shake 1D, and a 64 GB card that had been quietly filling with miniSEED for about fourteen months. The trigger was mundane — the node rebooted mid-event during a local M3.6 and the alert email arrived eleven minutes late, timestamped after the shaking. Total data at that point: 41 GB of miniSEED, roughly 1.2 million traces across three channels, plus a sqlite index I had never vacuumed.

I stopped trusting the real-time path and started replaying it offline instead. The pipeline is small: read miniSEED with ObsPy, bandpass 2-8 Hz, run a classic STA/LTA with 1 s / 10 s windows, then check whether a catalog pick exists nearby. Nothing clever.

import obspy
from obspy.signal.trigger import classic_sta_lta, trigger_onset

st = obspy.read("EHZ.D.*.2024*.mseed")
st.merge(method=1, fill_value=0)
st.detrend("linear").filter("bandpass", freqmin=2, freqmax=8, corners=4, zerophase=True)
tr = st.select(channel="EHZ")[0]
df = tr.stats.sampling_rate
cft = classic_sta_lta(tr.data.astype(float), int(1.0 * df), int(10.0 * df))
on_off = trigger_onset(cft, 3.5, 1.0)
for on, off in on_off:
    print(tr.stats.starttime + on / df, (off - on) / df)

On 14 months of data that produced 2,317 triggers. Two were real local events above M3; the rest were wind on the fence, a neighbour’s gate, and one very persistent pump. Raising the on-threshold to 5.0 cut triggers to 180 but missed the smaller of the two real events at 9 km distance. That trade is the whole problem in miniature: on a single vertical channel at 100 sps, a distant P arrival and a fence rattle look similar in the 2-8 Hz band, and no threshold separates them cleanly. The shortcut I took — trusting STA/LTA alone — is exactly where the pipeline fails.

What actually worked was two things. First, a coincidence check across channels: require the vertical and one horizontal to trigger within 0.5 s, which killed most of the wind noise. Second, pre-computing a 30-day rolling noise floor per channel so the threshold scales with conditions instead of being a fixed 3.5. Neither is novel; both cost me a weekend of backfill and made the sqlite index three times larger.

Where it still breaks: teleseisms arriving at low SNR get filtered out by the coincidence rule, and the pump near the fence occasionally trips two channels at once. I have not solved that one, and I am not sure a single station can.

If you run a hobby node, what is your false-trigger rate after coincidence gating, and did you ever find a threshold that survived a windy week without missing a local M3?

0
赞同度 100% · 0 条评论 · 1 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。