TOD simulation with TODSim
TODSim simulates time-ordered data for a single-dish telescope with a
single-pixel beam. To model a multi-dish or multi-beam instrument, run one
instance per dish/beam. Each call returns the sky temperature TOD, the gain
noise TOD, and the overall TOD combining all components.
Quick start
import numpy as np
from limTOD import TODSim, example_scan
simulator = TODSim(
ant_latitude_deg=-30.7130, # MeerKAT latitude
ant_longitude_deg=21.4430, # MeerKAT longitude
ant_height_m=1054, # MeerKAT altitude [m]
beam_nside=256, # HEALPix resolution for the beam
sky_nside=256, # HEALPix resolution for the sky
)
time_list, azimuth_list = example_scan() # simple raster scan
tod_array, sky_tod, gain_noise = simulator.generate_TOD(
freq_list=[950, 1000, 1050], # MHz
time_list=time_list,
azimuth_deg_list=azimuth_list,
elevation_deg=41.5,
)
print(tod_array.shape) # (3, n_time)
The default
sky_funcisGDSM_sky_model, which needs the[gdsm]extra (pip install "limTOD[gdsm]"). Pass your ownsky_functo run without it.
Worked notebooks: TODsim_examples.ipynb (simulation), mm_example.ipynb (map-making workflow).
Beam and sky functions
beam_func and sky_func are callables taking keyword-only arguments,
two of which must be freq and nside, returning a HEALPix map:
1D array of length
npix— unpolarized (Stokes I);2D array
(3, npix)— polarized (I, Q, U);2D array
(4, npix)— full Stokes (I, Q, U, V).
Beam orientation. The beam map must follow the
beam coordinate convention:
boresight at the map’s north pole (θ = 0); the φ = 0 meridian is
carried to the direction of increasing elevation (ê_el ≡ ∂b̂/∂e)
and φ = 90° to the direction of increasing azimuth (ê_az) at the
pointing, with positive selfrot_deg rotating the pattern from ê_el
toward ê_az. Symmetric beams are unaffected; for asymmetric or
polarized beams this is load-bearing.
Built-ins: example_beam_map (elliptical Gaussian),
example_symm_beam_map (symmetric Gaussian), GDSM_sky_model
(Global Sky Model, [gdsm] extra), and
generate_gaussian_field (correlated Gaussian sky realizations from a
frequency–frequency angular power spectrum).
Input parameters
Telescope configuration (TODSim.__init__)
Parameter |
Type |
Meaning |
|---|---|---|
|
float |
Site latitude [deg] (N positive) |
|
float |
Site longitude [deg] (E positive) |
|
float |
Site altitude [m] |
|
callable |
Beam map factory (see above) |
|
callable |
Sky map factory (see above) |
|
int |
Beam map resolution — large enough to resolve beam features |
|
int |
Sky map resolution — sets how the sky is parametrized |
Observation parameters (generate_TOD / simulate_sky_TOD)
Parameter |
Type |
Meaning |
|---|---|---|
|
array-like |
Frequencies [MHz] |
|
array-like |
Time offsets [s] from |
|
array-like |
Per-sample azimuth [deg], east of north |
|
float or array-like |
Elevation [deg]; a scalar applies to all samples |
|
array-like, optional |
Antenna self-rotation [deg]; default zero |
|
str |
UTC start, e.g. |
|
array, optional |
Binary HEALPix mask in horizontal coordinates (1 = keep) |
|
int, optional |
Upgrade the beam to this nside first (narrow beams) |
|
bool |
Divide each pointed beam by its pixel sum (default False) |
|
float |
Zero pixels below this fraction of the beam peak (default 1e-10) |
Noise and calibration (generate_TOD only)
Parameter |
Type |
Meaning |
|---|---|---|
|
array |
Additional system-temperature components |
|
array |
Background gain (default unity) |
|
array |
Precomputed gain noise (overrides generation) |
|
list |
|
|
float, optional |
White-noise variance (default |
|
bool |
Also return the LST array (default False) |
Outputs
Output |
Shape |
Meaning |
|---|---|---|
|
|
All components combined (model below) |
|
|
Beam-weighted sky signal only |
|
|
The 1/f gain-noise realization |
|
|
Only when |
The combination implemented in generate_TOD is
overall_TOD = G_bg · (1 + G_noise) · (sky_TOD + Tsys_others) · (1 + η)
with G_bg the background gain, G_noise the 1/f gain noise, and η
white noise. See theory.md for how sky_TOD itself is
computed (beam rotation in harmonic space + beam-weighted sum).
MPI parallelism
The time axis is partitioned across ranks; every rank returns the full
(nfreq, ntime) array:
pip install "limTOD[mpi]"
mpirun -n 4 python your_simulation.py
Without mpi4py installed, the same code runs serially (rank=0, size=1).
Launching with mpirun -n N without mpi4py raises a RuntimeError
instead of silently running N duplicate serial copies
(escape hatch: LIMTOD_FORCE_SERIAL=1). Per-frequency work also benefits
from numpy/scipy/healpy internal threading — 2–4 cores per rank is a good
default.
Troubleshooting
Installation errors — use a fresh virtual environment; the base install is wheel-only (no compiler needed).
ImportError: ... limTOD[gdsm]— the default sky model needs the[gdsm]extra, or pass your ownsky_func.RuntimeError: An MPI launcher is detected ...— install the[mpi]extra for parallel runs.Memory errors — reduce
nsideor process fewer frequencies at once.Slow narrow beams — set
nside_hiresfor the beam instead of raisingsky_nside.Time errors —
start_time_utcmust be an ISO-format UTC string.