Source code for setigen.funcs.f_profiles

"""
Sample spectral profiles for signal injection.

For any given time sample,
these functions map out the intensity in the frequency direction (centered at
a particular frequency).
"""
import numpy as np
from astropy import units as u

from setigen import unit_utils
from setigen.funcs import func_utils


[docs] def box_f_profile(width): """ Square intensity profile in the frequency direction. Parameters ---------- width : float or astropy.Quantity Width of signal Return ------ f_profile : func """ width = unit_utils.get_value(width, u.Hz) def f_profile(f, f_center): return (np.abs(f - f_center) < width / 2).astype(int) return f_profile
[docs] def gaussian_f_profile(width): """ Gaussian profile. Parameters ---------- width : float or astropy.Quantity FWHM of Gaussian profile Return ------ f_profile : func """ width = unit_utils.get_value(width, u.Hz) factor = 2 * np.sqrt(2 * np.log(2)) sigma = width / factor def f_profile(f, f_center): return func_utils.gaussian(f, f_center, sigma) return f_profile
[docs] def multiple_gaussian_f_profile(width): """ Example adding multiple Gaussians in the frequency direction. Parameters ---------- width : float or astropy.Quantity FWHM of Gaussian profile Return ------ f_profile : func """ width = unit_utils.get_value(width, u.Hz) factor = 2 * np.sqrt(2 * np.log(2)) sigma = width / factor def f_profile(f, f_center): # Offsets by 100 Hz @ a quarter intensity, absolutely arbitrarily return func_utils.gaussian(f, f_center - 100, sigma) / 4 \ + func_utils.gaussian(f, f_center, sigma) \ + func_utils.gaussian(f, f_center + 100, sigma) / 4 return f_profile
[docs] def lorentzian_f_profile(width): """ Lorentzian profile. Parameters ---------- width : float or astropy.Quantity FWHM of Lorentzian profile Return ------ f_profile : func """ width = unit_utils.get_value(width, u.Hz) gamma = width / 2 def f_profile(f, f_center): return func_utils.lorentzian(f, f_center, gamma) return f_profile
[docs] def voigt_f_profile(g_width, l_width): """ Voigt profile. Further information here: https://en.wikipedia.org/wiki/Voigt_profile. Parameters ---------- g_width : float or astropy.Quantity FWHM of Gaussian profile l_width : float or astropy.Quantity FWHM of Lorentzian profile Return ------ f_profile : func """ g_width = unit_utils.get_value(g_width, u.Hz) factor = 2 * np.sqrt(2 * np.log(2)) sigma = g_width / factor l_width = unit_utils.get_value(l_width, u.Hz) gamma = l_width / 2 def f_profile(f, f_center): return func_utils.voigt(f, f_center, sigma, gamma) / func_utils.voigt(f_center, f_center, sigma, gamma) return f_profile
[docs] def sinc2_f_profile(width, width_mode='fwhm', trunc=True): """ Sinc squared profile; width is the FWHM of the squared normalized sinc function. The trunc parameter controls whether or not the sinc squared profile is truncated at the first root (e.g. zeroed out for more distant frequencies). Note that you can model an ideal cosine signal by using ``width=2*frame.df``, ``width_mode="crossing"``, and ``trunc=False``. Parameters ---------- width : float or astropy.Quantity Signal width, in Hz width_mode : {"fwhm", "crossing"}, default: "fwhm" How to interpret ``width``. Can be "fwhm" or "crossing", for zero crossing. trunc : bool, default: True Whether to truncate signal after first zero crossing Return ------ f_profile : func """ width = unit_utils.get_value(width, u.Hz) # Using the numerical solution for the FWHM if width_mode == 'fwhm': zero_crossing = (width / 2) / 0.442946470689452 else: zero_crossing = width / 2 def f_profile(f, f_center): if trunc: return np.where(np.abs(f - f_center) < zero_crossing, np.sinc((f - f_center) / zero_crossing), 0)**2 else: return np.sinc((f - f_center) / zero_crossing)**2 return f_profile