Source code for ska_ost_senscalc.common.pss

import numpy as np
from astropy import units as u

from ska_ost_senscalc.common.model import CalculatorInputPSS

# Correction factor for quantisation loss in beamformed data
BETA = 1.05
# Correction factor for FFT-based search loss in beamformed data
EPSILON = 0.77


def _find_scatter_broadening(dm: float, frequency_ghz: float) -> float:
    """
    Calculate scatter broadening for a given dispersion measure and observing frequency
    using the relation from Bhat et al (2004).

    :param dm: Dispersion measure in pc/cm^3
    :param frequency_ghz: Frequency in GHz

    :return: scatter broadening in milliseconds
    """
    if dm > 0.0:
        return_value = 10 ** (
            -6.46
            + (0.154 * np.log10(dm))
            + (1.07 * np.log10(dm) ** 2)
            - (3.86 * np.log10(frequency_ghz))
        )
    else:
        return_value = 0.0

    return return_value


def _find_dispersion_broadening(
    dm: float, frequency_mhz: float, chan_width_mhz: float
) -> float:
    """
    Calculate pulse broadening due to interstellar dispersion.

    :param dm: Dispersion measure in pc/cm^3
    :param frequency_mhz: Representative freqency in MHz
    :param chan_width_mhz: Channel frequency resolution in MHz

    :return: Pulse broadening due to dispersion in milliseconds
    """
    return 8.3e6 * dm * chan_width_mhz / frequency_mhz**3


def _find_observed_pulse_width(
    intrinsic_width: float,
    dm: float,
    frequency_mhz: float,
    chan_width_mhz: float,
) -> float:
    """
    For a pulse with intrinsic_width in milliseconds, calculate
    the observed pulse width taking dispersive and scattering
    broadening into account.

    :param intrinsic_width: Intrinsic pulse width in milliseconds
    :param dm: Dispersion measure in pc/cm^3
    :param frequency_mhz: Representative freqency in MHz
    :param chan_width_mhz: Channel frequency resolution in MHz

    :return: Observed pulse width in milliseconds
    """
    return np.sqrt(
        intrinsic_width**2
        + _find_dispersion_broadening(dm, frequency_mhz, chan_width_mhz) ** 2
        + _find_scatter_broadening(dm, frequency_mhz / 1e3)
    )


[docs] def convert_continuum_to_bf_sensitivity( continuum_sensitivity: u.Quantity, calculator_input: CalculatorInputPSS, ) -> u.Quantity: """ Convert a given continuum sensitivity to beamformed senstivity for an observation defined by calculator_input. :param continuum_sensitivity: Continuum sensitivity :param calculator_input: an instance of BeamformedInput with validated user parameters :return: Folded pulse sensitivity in the same units as continuum_sensitivity """ # Work out the effective pulse width effective_width = _find_observed_pulse_width( intrinsic_width=calculator_input.intrinsic_pulse_width, dm=calculator_input.dm, frequency_mhz=calculator_input.freq_centre_mhz, chan_width_mhz=calculator_input.chan_width * 1e-6, # convert to MHz ) if calculator_input.pulse_period > effective_width: sensitivity = ( (BETA / EPSILON) * continuum_sensitivity.value * np.sqrt( (calculator_input.num_stations - 1) / calculator_input.num_stations ) * np.sqrt( effective_width / (calculator_input.pulse_period - effective_width) ) ) else: raise ValueError( "The effective pulse width (due to interstellar dispersion and" " scattering) is larger than the pulse period. Check your inputs." ) return u.Quantity(sensitivity, continuum_sensitivity.unit * u.beam)