Source code for NuRadioReco.detector.RNO_G.analog_components

import numpy as np
import logging
from scipy.interpolate import interp1d
import os
from NuRadioReco.utilities import units
from functools import lru_cache
from radiotools import helper as hp
logger = logging.getLogger('NuRadioReco.analog_components')

[docs] @lru_cache(maxsize=128) def load_amp_response(amp_type='rno_surface', temp=293.15, path=os.path.dirname(os.path.realpath(__file__))): # use this function to read in log data """ Read out amplifier gain and phase. These are all 'placeholder' measurements of a single reference amplifier/signal chain; more up-to-date, channel-specific amplifier responses may be loaded via the :class:`rnog_detector <NuRadioReco.detector.RNO_G.rnog_detector.Detector>` class. Temperature dependence: the function loads a reference measurement made at room temperature and will correct it for the temperature. The correction function is obtained empirically for one amplifier of reference (one Surface board and one DRAB + fiber + IGLU chain) by studying its gain in a climate chamber at different temperatures. Parameters ---------- amp_type: string * "rno_surface": the surface signal chain * "iglu": the in-ice signal chain * "phased_array": the additional filter of the phased array channels before going into the phased array trigger. * "rno_surface_impulse": alternative measurement of the surface signal chain response, including the RADIANT * "deep_impulse": alternative measurement of the deep (iglu) signal chain response, including the RADIANT temp: float (default 293.15K) the default temperature in Kelvin that the amplifier response is corrected for """ # definition correction functions: temp in Kelvin, freq in GHz # functions defined in temperature range [223.15 K , 323.15 K] def surface_correction_func(temp, freqs): return 1.0377798029 - 0.00135258197 * (temp - 273.15) + (0.4788208019 - 0.01790064797 * (temp - 273.15)) * (freqs ** 5) def iglu_correction_func(temp, freqs): return 1.1139014286 - 0.00004392995 * ((temp - 273.15) + 28.8331610295) ** 2 + (0.6301058083 - 0.0208741539 * (temp - 273.15)) * (freqs ** 5) amp_response = {} correction_function = None if amp_type == 'rno_surface': ph = os.path.join(path, 'HardwareResponses/surface_placeholder.csv') ff = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=0) ff *= units.Hz amp_gain_discrete = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=1) amp_phase_discrete = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=2) correction_function = surface_correction_func elif amp_type == 'rno_surface_impulse': ph = os.path.join(path, 'HardwareResponses/surface_impulse_response_placeholder.csv') ff = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=0) ff *= units.Hz amp_gain_discrete = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=1) amp_phase_discrete = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=2) elif amp_type == 'iglu': ph = os.path.join(path, 'HardwareResponses/iglu_drab_placeholder.csv') ff = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=0) ff *= units.Hz amp_gain_discrete = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=1) amp_phase_discrete = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=2) correction_function = iglu_correction_func elif amp_type == 'deep_impulse': ph = os.path.join(path, 'HardwareResponses/deep_impulse_response_placeholder.csv') ff = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=0) ff *= units.Hz amp_gain_discrete = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=1) amp_phase_discrete = np.loadtxt(ph, delimiter=',', skiprows=1, usecols=2) elif amp_type == 'phased_array' or amp_type == 'ULP_216': ph = os.path.join(path, 'HardwareResponses/ULP-216+_Plus25DegC.s2p') ff, S11gain, S11deg, S21gain, S21deg, S12gain, S12deg, S22gain, S22deg = np.loadtxt(ph, comments=['#', '!'], unpack=True) ff *= units.MHz # Convert gain in dB power to linear in voltage amp_gain_discrete = 10**(S21gain / 20) amp_phase_discrete = S21deg * units.deg else: msg = f"Amp type `{amp_type}` not recognized. possible values are {get_available_amplifiers()}" logger.error(msg) raise ValueError(msg) amp_gain_f = interp1d(ff, amp_gain_discrete, bounds_error=False, fill_value=0) # all requests outside of measurement range are set to 1 def get_amp_gain(freqs, temp=temp): if correction_function is not None: amp_gain = correction_function(temp, freqs) * amp_gain_f(freqs) else: amp_gain = amp_gain_f(freqs) return amp_gain # Convert to MHz and broaden range (all requests outside of measurement range are set to 0) amp_phase_f = interp1d(ff, np.unwrap(amp_phase_discrete), bounds_error=False, fill_value=0) def get_amp_phase(freqs): amp_phase = amp_phase_f(freqs) return np.exp(1j * amp_phase) amp_response['gain'] = get_amp_gain amp_response['phase'] = get_amp_phase return amp_response
[docs] def get_available_amplifiers(): """Returns a list of available amplifiers""" return ['iglu', 'deep_impulse', 'rno_surface', 'rno_surface_impulse', 'phased_array', 'ULP_216']