"""
Sample signal paths for signal injection.
For any given starting frequency,
these functions map out the path of a signal as a function of time in
time-frequency space.
"""
import sys
import numpy as np
from astropy import units as u
from setigen import unit_utils
[docs]
def constant_path(f_start, drift_rate):
"""
Constant drift rate.
Parameters
----------
f_start : float or astropy.Quantity
Starting center frequency
drift_rate : float or astropy.Quantity
Doppler drift rate
Return
------
path : func
"""
f_start = unit_utils.get_value(f_start, u.Hz)
drift_rate = unit_utils.get_value(drift_rate, u.Hz / u.s)
def path(t):
return f_start + drift_rate * t
return path
[docs]
def squared_path(f_start, drift_rate):
"""
Quadratic signal path; drift_rate here only refers to the starting slope.
Parameters
----------
f_start : float or astropy.Quantity
Starting center frequency
drift_rate : float or astropy.Quantity
Doppler drift rate
Return
------
path : func
"""
f_start = unit_utils.get_value(f_start, u.Hz)
drift_rate = unit_utils.get_value(drift_rate, u.Hz / u.s)
def path(t):
return f_start + 0.5 * drift_rate * t**2
return path
[docs]
def sine_path(f_start, drift_rate, period, amplitude):
"""
Sine path in time-frequency space.
Parameters
----------
f_start : float or astropy.Quantity
Starting center frequency
drift_rate : float or astropy.Quantity
Doppler drift rate
period : float or astropy.Quantity
Modulation period
amplitude : float or astropy.Quantity
Modulation amplitude
Return
------
path : func
"""
f_start = unit_utils.get_value(f_start, u.Hz)
drift_rate = unit_utils.get_value(drift_rate, u.Hz / u.s)
period = unit_utils.get_value(period, u.s)
amplitude = unit_utils.get_value(amplitude, u.Hz)
def path(t):
return f_start + amplitude * np.sin(2*np.pi*t/period) + drift_rate * t
return path
[docs]
def simple_rfi_path(f_start, drift_rate, spread, spread_type='uniform',
rfi_type='stationary', seed=None):
"""
A crude simulation of one style of RFI that shows up, in which the signal
jumps around in frequency. This method samples the center frequency for
each time sample from either a uniform or normal distribution.
Parameters
----------
f_start : float or astropy.Quantity
Starting center frequency
drift_rate : float or astropy.Quantity
Doppler drift rate
spread : float or astropy.Quantity
Range of center frequency variations
spread_type : {"uniform", "normal"}, default: "uniform"
Type of frequency variation
rfi_type : {"stationary", "random_walk"}, default: "stationary"
The "stationary" option only offsets with respect to a straight-line
path, but "random_walk" accumulates frequency offsets over time.
seed : None, int, Generator, optional
Random seed or seed generator
Return
------
path : func
"""
rng = np.random.default_rng(seed)
f_start = unit_utils.get_value(f_start, u.Hz)
drift_rate = unit_utils.get_value(drift_rate, u.Hz / u.s)
spread = unit_utils.get_value(spread, u.Hz)
def path(t):
if spread_type == 'uniform':
f_offset = rng.uniform(-spread / 2., spread / 2., size=t.shape)
elif spread_type == 'normal':
factor = 2 * np.sqrt(2 * np.log(2))
f_offset = rng.normal(0, spread / factor, size=t.shape)
else:
raise ValueError(f"'{spread_type}' is not a valid spread type!")
if rfi_type == 'random_walk':
f_offset = np.cumsum(f_offset)
return f_start + drift_rate * t + f_offset
return path