Coverage for src/pyhiperta/calibration.py: 100%
6 statements
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-07 14:41 +0000
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-07 14:41 +0000
1# Copyright 2026 CNRS
2# This software is distributed under the terms of the CeCILL-C free software license.
4"""Calibration of R0 data: going from 2 gain ADC counts to number of photo-electrons."""
7import numpy as np
10def select_channel(
11 waveform_high: np.ndarray,
12 waveform_low: np.ndarray,
13 gains: np.ndarray,
14 pedestals: np.ndarray,
15 window_integration_correction: np.ndarray,
16 threshold: float,
17) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
18 """Select values to use in waveforms high/low gain and corresponding gains and pedestals based on threshold.
20 The choice is independent per shower and per pixel, but shared in time for a given pixel:
21 For each pixel, if any value of `waveform_high` is above `threshold` then the low gain and
22 corresponding waveform channel and pedestal is chosen. Otherwise the high gain is chosen.
24 Parameters
25 ----------
26 waveform_high : np.ndarray
27 R0 waveform high gain. Shape: (N_batch, N_frames, N_pixels)
28 waveform_low : np.ndarray
29 R0 waveform low gain. Shape: (N_batch, N_frames, N_pixels)
30 gains : np.ndarray
31 Per-pixel high and low gains. `gains[0]` is high gain, `gains[1]` is low gains. shape (2, N_pixels)
32 pedestals : np.ndarray
33 Per-pixel pedestal for low and high gains. `pedestals[0]` corresponds to high gain, `pedestals[1]`
34 corresponds to low gain. Shape (2, N_pixels)
35 window_integration_correction : np.ndarray
36 Array of shape (2,) containing the correction to apply after a windowed integration, for each gain.
37 threshold : float
38 Threshold to chose the waveform channel. A value above `threshold` indicates that the high gain waveform
39 saturated and low gain should be used.
41 Returns
42 -------
43 Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]
44 The waveform selected from each gains based on `threshold`, associated gains, pedestals and integration
45 correction to used. The order is:
46 - waveform : np.ndarray
47 waveform where the appropriate gain has been selected. Shape (N_batch, N_frames, N_pixels)
48 - gains : np.ndarray
49 Gain to use to calibrate `waveform` (high gain when waveform_high wasn't above `threshold` and
50 low gain otherwise). Shape (N_batch, N_pixels)
51 - pedestals : np.ndarray
52 Pedestals to use to calibrate `waveform`. Shape (N_batch, N_pixels)
53 - window_integration_correction : np.ndarray
54 Correction to use after the integration. Shape(N_batch, N_pixels)
55 """
56 idx_saturated = (waveform_high > threshold).any(axis=-2, keepdims=True)
57 return (
58 np.where(idx_saturated, waveform_low, waveform_high),
59 np.where(np.squeeze(idx_saturated, -2), gains[1], gains[0]),
60 np.where(np.squeeze(idx_saturated, -2), pedestals[1], pedestals[0]),
61 np.where(np.squeeze(idx_saturated, -2), window_integration_correction[1], window_integration_correction[0]),
62 )
65def calibrate(waveform: np.ndarray, gains: np.ndarray, pedestals: np.ndarray) -> np.ndarray:
66 """Apply pedestal and gain calibration to waveforms.
68 Parameters
69 ----------
70 waveform : np.ndarray
71 Batch or single video samples of the shower events. Shape: (N_batch, N_frames, N_pixels)
72 gains : np.ndarray
73 For each waveform, the gains to apply to each pixel. The same gain is applied for all
74 frames of a shower pixel. Shape: (N_batch, N_pixels).
75 pedestals : np.ndarray
76 For each waveform, the pedestals to apply to each pixel. The same pedestal is applied for
77 all frames of a shower pixel. Shape (N_batch, N_pixels)
79 Returns
80 -------
81 np.ndarray
82 Calibrated waveforms (number of photo-electrons). Shape is identical to `waveform`.
83 """
84 return (waveform - pedestals[..., np.newaxis, :]) * gains[..., np.newaxis, :]