Some context first: this is not about a big earthquake. It is about the small ones that keep showing up in my logs and never make the feeds. I run a three-station Raspberry Shake network on a farm in the eastern foothills, all on a local WiFi bridge, and every morning I pull the previous day’s miniSEED off each unit over SSH. For about two years I did nothing with the data except archive it. The archive is now about 14 GB, which is small, but the file count is what kills you.
What I wanted was a nightly list of local events with arrival times, not a web dashboard. So the pipeline I settled on is deliberately boring:
# per station, per day
scp shake@station1:/opt/data/AM.R1234.00.*.mseed ./raw/
for f in raw/*.mseed; do
obspy-scan "$f" >> scan.log
done
Then a small Python script that reads each day, merges the streams, and runs a simple STA/LTA trigger on the vertical channel. The trigger is not a detector; it is a filter for candidates. I found that a 1 s STA over 20 s LTA with a threshold of 3.5 gave me roughly one candidate every 40 minutes on a quiet day, which is a number I can actually review over coffee.
from obspy import read, UTCDateTime
from obspy.signal.trigger import recursive_sta_lta, trigger_onset
st = read('raw/*.mseed').merge(method=1)
tr = st.select(component='Z')[0]
df = tr.copy().detrend('linear').filter('bandpass', freqmin=2.0, freqmax=12.0).data
sta_lta = recursive_sta_lta(df, int(1.0 * tr.stats.sampling_rate), int(20.0 * tr.stats.sampling_rate))
on_off = trigger_onset(sta_lta, 3.5, 1.5)
print(tr.stats.starttime, len(on_off))
The reason for bandpassing 2–12 Hz before triggering is that the farm has a well pump and a wind turbine, and the pump lives around 0.5–1 Hz. Without the high-pass, every pump cycle is a candidate. The cost is that you lose long-period content, which for local small events is fine, but it means I cannot use this same pipeline for anything teleseismic.
Where this fails: it fails hard on the windiest days. The turbine noise shows up as coherent 3–8 Hz energy on all three stations at once, and because I only filter single-station triggers, a gust produces a cluster that looks like a small swarm. I have also been burned by the merge call. On days when one station drops out for a few minutes, merge(method=1) fills gaps with masked arrays and the filter silently produces zeros around the gap, which then triggers nothing. I now check gap count before running the trigger and skip days with more than two gaps.
Another failure: I have no magnitude. The trigger list gives me times and rough durations, and I have to eyeball the waveforms to decide if something is worth keeping. That is fine for a hobby archive, but it is not a catalog, and I should stop calling it one.
If you run a small network and have solved the wind-noise false-positive problem without three-component back-azimuth checking, how did you do it? I am specifically curious whether a coherence threshold between stations is worth the extra dependency or whether people just accept the noisy days.
0 条评论
还没有评论,写下第一条。