"""Implements the "calibration" of R0 data: going from 2 gain ADC counts to number of photo-electrons"""
from typing import Tuple
import numpy as np
[docs]
def select_channel(
waveform_high: np.ndarray,
waveform_low: np.ndarray,
gains: np.ndarray,
pedestals: np.ndarray,
window_integration_correction: np.ndarray,
threshold: float,
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""Select values to use in waveforms high/low gain and corresponding gains and pedestals based on threshold.
The choice is independent per shower and per pixel, but shared in time for a given pixel:
For each pixel, if any value of `waveform_high` is above `threshold` then the low gain and
corresponding waveform channel and pedestal is chosen. Otherwise the high gain is chosen.
Parameters
----------
waveforms_high : np.ndarray
R0 waveform high gain. Shape: (N_batch, N_frames, N_pixels)
waveform_low : np.ndarray
R0 waveform low gain. Shape: (N_batch, N_frames, N_pixels)
gains : np.ndarray
Per-pixel high and low gains. `gains[0]` is high gain, `gains[1]` is low gains. shape (2, N_pixels)
pedestals : np.ndarray
Per-pixel pedestal for low and high gains. `pedestals[0]` corresponds to high gain, `pedestals[1]`
corresponds to low gain. Shape (2, N_pixels)
window_integration_correction : np.ndarray
Array of shape (2,) containing the correction to apply after a windowed integration, for each gain.
threshold : float
Threshold to chose the waveform channel. A value above `threshold` indicates that the high gain waveform
saturated and low gain should be used.
Returns
-------
Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]
The waveform selected from each gains based on `threshold`, associated gains, pedestals and integration
correction to used. The order is:
- waveform : np.ndarray
waveform where the appropriate gain has been selected. Shape (N_batch, N_frames, N_pixels)
- gains : np.ndarray
Gain to use to calibrate `waveform` (high gain when waveform_high wasn't above `threshold` and
low gain otherwise). Shape (N_batch, N_pixels)
- pedestals : np.ndarray
Pedestals to use to calibrate `waveform`. Shape (N_batch, N_pixels)
- window_integration_correction : np.ndarray
Correction to use after the integration. Shape(N_batch, N_pixels)
"""
idx_saturated = (waveform_high > threshold).any(axis=-2, keepdims=True)
return (
np.where(idx_saturated, waveform_low, waveform_high),
np.where(np.squeeze(idx_saturated, -2), gains[1], gains[0]),
np.where(np.squeeze(idx_saturated, -2), pedestals[1], pedestals[0]),
np.where(np.squeeze(idx_saturated, -2), window_integration_correction[1], window_integration_correction[0]),
)
[docs]
def calibrate(waveform: np.ndarray, gains: np.ndarray, pedestals: np.ndarray) -> np.ndarray:
"""Apply pedestal and gain calibration to waveforms.
Parameters
----------
waveform : np.ndarray
Batch or single video samples of the shower events. Shape: (N_batch, N_frames, N_pixels)
gains : np.ndarray
For each waveform, the gains to apply to each pixel. The same gain is applied for all
frames of a shower pixel. Shape: (N_batch, N_pixels).
pedestals : np.ndarray
For each waveform, the pedestals to apply to each pixel. The same pedestal is applied for
all frames of a shower pixel. Shape (N_batch, N_pixels)
Returns
-------
np.ndarray
Calibrated waveforms (number of photo-electrons). Shape is identical to `waveform`.
"""
return (waveform - pedestals[..., np.newaxis, :]) * gains[..., np.newaxis, :]