excursion_band_AI: removing pulse-like traces from the noise selection, and the good_noise archive

Note 6 · Author(s): Anthony Villano · 23 Sept 2026 (revised 22 Oct 2026) · Status: In progress

Caution (2026-10-22): the sample time has changed. The phonon sample period is 0.8 µs (1.25 MHz), not the 1.6 µs (625 kHz) this note was written with (see The sample period in python/README.md for the evidence). What changed in this note:

Code Repository

Motivation

The Tight noise cut of Note 2 (log10(ratio) in [0.5, 0.7), 500-sample window) keeps 192 of 1517 traces and is the cleanest slice found, but a few real pulses still get through. excursion_band_AI is the same cut with a second criterion added: remove whatever looks like a real pulse. The name is literal: the pulse judgment is a heuristic worked out with an AI assistant, not a validated physical criterion, and the cut is tagged under_development.

The pulse-shape criterion

A real pulse rises and then decays slowly, so it stays near its own peak for a long time. Noise does not. The quantity excursion_duration is the longest run of consecutive post-pretrigger samples whose deviation is at least half of the trace’s own dev. looks_like_pulse flags a trace when that run is at least min_duration samples.

A first version that failed

The first attempt counted the total number of samples above half of dev. On real data it flagged all 192 traces of the Tight cut as pulses. With ~2500 post-pretrigger samples and dev only 3–5 times the noise standard deviation, half of dev is just 1.5–2.5 sigma, which ordinary Gaussian noise exceeds in a few percent of samples. Requiring the samples to be consecutive removes that effect, since the chance of a long unbroken run in noise falls off geometrically.

Choosing min_duration

With the consecutive-run definition, the 192 traces of the Tight cut split cleanly (Detector 0 / Channel 0, dump 1, 500-sample window):

The default min_duration = 50 sits inside that gap. It was picked by eye from this one dataset, so it may need a different value elsewhere.

What it removes

excursion_band_AI keeps 179 of the 192 traces. All 13 rejected traces are visually unambiguous real pulses or slow drifts:

The 13 traces rejected by excursion_band_AI: real pulses and slow baseline drifts
The 13 traces kept by excursion_band but rejected by excursion_band_AI: pulses (rising near samples 450–600 and 2400) and slow monotonic drifts.

The 179 kept traces are flat noise (30 shown; the spike at sample 0 is the known leading glitch):

30 of the 179 traces kept by excursion_band_AI, flat noise
excursion_band_AI: 179 of 1517 traces.

Because slow drifts also stay near their peak for a long time, the same criterion rejects drifting baselines, not only pulses. That is desirable for a noise selection, and relevant to Note 5, where drift is the problem.

Effect on the noise PSD

The clearest practical check is the average PSD of each selection (Detector 0 / Channel 0, dump 1). Below ~4 kHz, excursion_band and excursion_band_loose lie well above excursion_band_AI, because a pulse’s rise and decay is low-frequency dominated and a few of them are enough to raise a mean spectrum:

Frequencytight / AIloose / AI
305 Hz (first bin)164165
2.1 kHz6461
4.0 kHz2320
10 kHz4.34.0
20 kHz1.81.4
60 kHz1.10.7

Ratio of the mean |FFT|2 of each selection to that of excursion_band_AI at that frequency (nearest bin; bins are 305 Hz apart).

Average PSD for excursion_band, excursion_band_loose and excursion_band_AI on the same vertical scale as the 14-trace PSD
Average PSD for the three selections (N = 192, 744, 179), on the same vertical scale as the 14-trace PSD of Note 3; the first two run off the top at low frequency.

The PSD is therefore an independent check of the pulse criterion, on top of the visual one. It is not a proof: the same data were used to choose min_duration.

The good_noise archive

Since the AI selection is the one to build on, its detector_ids are stored in an HDF5 file, archives/good_noise.h5, written and read through python/pulse_archive.py. Layout: one group per (series, detector, channel) at /<series>/detector<N>/channel<C>, containing a detector_ids dataset plus attributes recording how the selection was made: cut name and parameters, the cut’s status (under_development here), the PulseConfig values, dump, source notebook, counts kept and total, and a UTC timestamp.

Status / Next Steps