-pds flag and runs in workflow.py via pds_signal_proc and pds_reco.
PDS Data Types
LARDON handles two types of PDS data simultaneously:| Type | Variable | Description |
|---|---|---|
| Streaming | dc.data_stream_pds | Continuous readout data with timestamps relative to delay_pds_stream_time |
| Triggered | dc.data_trig_pds | Self-triggered data with timestamps relative to delay_pds_trig_time |
cf.n_pds_stream_sample, cf.n_pds_trig_sample), and mask arrays. Processing is applied identically to both. If either sample count is ≤ 0, PDS processing is skipped entirely.
PDS Signal Processing
First pedestal pass
raw_adc_thresh = 200 ADC or below a symmetric threshold around zero. This is a simple amplitude cut rather than an RMS-based cut.After the initial masking, the iterative pedestal computation from compute_pedestal_nb runs for n_iter = 3 iterations:rms_thresh = 3 as the mask threshold (samples within 3σ of zero are treated as baseline). The same procedure runs identically for trigger data.Median filter baseline flattening
flat_baseline_window = 4000 samples.This step is applied to streaming data if window ≤ n_pds_stream_sample, and to triggered data if window ≤ n_pds_trig_sample.PDS Hit/Peak Finding
find_pds_peak("stream") and find_pds_peak("trigger").
The algorithm is the same collection-type hit finder used for TPC channels (hit_search_collection_nb), applied to each PDS channel’s ROI:
- Contiguous ROI intervals (where the mask is False) are identified using
np.diff. - Intervals shorter than
dt_min = 50samples are discarded. - Left padding of
pad_left = 30and right padding ofpad_right = 50samples are applied. - The padded excerpt is passed to
hit_search_collection_nbwith thresholds:thr1 = amp_sig[0] × RMS = 5 × RMS(lower threshold, starts the peak)thr2 = amp_sig[1] × RMS = 8 × RMS(upper threshold, used to split overlapping peaks)- Absolute minimum: 0.5 ADC
dc.pds_peak object with:
- Global channel number (
glob_ch) - Module assignment
- Start, stop, and peak-time sample indices
- Peak amplitude (
max_adc) - Integrated charge (sum of ADC over the padded window)
- Absolute timestamp:
delta_time_ref + start / pds_sampling
delta_time_ref is the time offset of the PDS readout window relative to the trigger, so timestamps are expressed in absolute detector time (μs).
Light Clustering
align_waveforms)
Peak timestamps are cross-correlated between channels to account for relative time offsets between PDS readout channels. For each channel, the best lag relative to channel 0 is found using sparse_crosscorr:
max_lag = 50 PDS ticks. Per-channel offsets are stored in dc.evt_list[-1].pds_time_offset.
Step 2: Time-based clustering
An R-tree is built over all PDS peaks indexed by (channel, corrected_timestamp). For each unclustered peak, all other peaks within time_tol = 5 μs are retrieved:
dc.pds_cluster object.
TPC–PDS Matching
-trk and -pds are active, reconstructed 3D tracks are matched to light clusters. This function is called from match_charge_and_pds in workflow.py.
This step requires both
dc.tracks3D_list and dc.pds_cluster_list to be non-empty and runs after track timing has been computed.| Category | Condition | Time tolerance |
|---|---|---|
| Anode-cathode crossers | is_anode_crosser and is_cathode_crosser | ±5 μs (anode settings) |
| Anode crossers | is_anode_crosser only | ±5 μs |
| Cathode crossers | is_cathode_crosser only | ±5 μs |
| Unknown | Neither flag set | ±5 μs |
trk_vol = module_ini / n_drift_volumes) contains the track.
Matching procedure
An R-tree is built over light clusters indexed by timestamp. For each track, a time window query retrieves candidate clusters:
size >= min_cluster_size = 2 and not yet matched to another track are considered. A match is recorded only when exactly one cluster falls within the time window.
For cathode-crossing track pairs, both tracks in the pair are matched to the same cluster.
Post-match timing correction
When a match is found, the track’s absolute Z position is recalibrated using the light cluster timestamp: