Source code for lib.Calibration.Qsaturation

import numpy as np


[docs] class saturation: def __init__(self, sat_value: float = 4.19e6, TES_number: int = 256): """ Detect saturation in Time-Ordered Data (TOD). This class identifies saturated TES in the focal plane by checking whether the TOD values exceed a specified threshold. Parameters ---------- sat_value : float, optional Threshold value above which a TES is considered saturated (default: 4.19e6). TES_number : int, optional Number of TES in the focal plane (default: 256). """ self.sat_value = sat_value self.TES_number = TES_number
[docs] def detect_saturation(self, todarray: np.ndarray, return_time_indices: bool = False): """ Detect saturated TES in a TOD array. For each TES, computes the fraction of time samples exceeding the saturation threshold (either above +sat_value or below -sat_value). A TES is considered saturated if any of its samples exceed the threshold. Parameters ---------- todarray : ndarray Array of shape (TES_number, time_samples) containing TOD data. return_time_indices : bool, optional If True, also return indices of time samples where saturation occurs for each TES. Returns ------- is_valid : ndarray of bool Boolean array (True for valid TES, False for saturated TES). saturated_indices : ndarray Indices of saturated TES. saturation_fraction : ndarray Fraction of saturated samples for each TES. num_saturated : int Number of saturated TES. saturated_time_indices : dict, optional Dictionary mapping TES index to 1D array of time indices where saturation occurs. Returned only if `return_time_indices=True`. Raises ------ ValueError If the first dimension of `todarray` does not match `TES_number`. """ # Input validation if todarray.shape[0] != self.TES_number: raise ValueError( f"todarray first dimension ({todarray.shape[0]}) must match " f"TES_number ({self.TES_number})" ) # Vectorized computation of saturation fractions upper_satval = self.sat_value lower_satval = -self.sat_value # Create masks for upper and lower saturation upper_mask = todarray > upper_satval lower_mask = todarray < lower_satval sat_mask = upper_mask | lower_mask # Calculate saturation fraction for each TES (vectorized) size = todarray.shape[1] saturation_fraction = (np.sum(upper_mask, axis=1) + np.sum(lower_mask, axis=1)) / size # TES is valid (not saturated) if saturation fraction is zero is_valid = saturation_fraction == 0.0 # Get indices of saturated TES saturated_indices = np.where(~is_valid)[0] num_saturated = len(saturated_indices) if not return_time_indices: return is_valid, saturated_indices, saturation_fraction, num_saturated saturated_time_indices = {int(tes): np.where(sat_mask[tes])[0] for tes in saturated_indices} return ( is_valid, saturated_indices, saturation_fraction, num_saturated, saturated_time_indices, )