Observation simulation (ps_eor.obssimu)#

Telescope sensitivity models and simulated interferometric UV coverage.

The module combines three related pieces:

  • Telescope subclasses describe an array layout, location, primary beam, useful baseline range, and frequency-dependent SEFD;

  • TelescopeSimu projects the physical baselines through an observation;

  • SimuGridded stores the resulting UV weights and derives thermal noise or a matching power-spectrum estimator.

Sensitivity models can be used independently of a UV simulation:

import numpy as np

from ps_eor import obssimu

freqs = np.arange(50, 80, .2) * 1e6
telescope = obssimu.Telescope.from_name('nenufar')
stokes_i_sefd = telescope.get_i_sefd(freqs)

For an array with an available station layout, configure the declination, hour angle range, and time resolution before choosing a gridding strategy:

telescope = obssimu.DEx(n_antenna_side=16, sep_antenna=6)
observation = obssimu.TelescopeSimu(
    telescope,
    freqs,
    dec_deg=-27,
    hal=-1,
    har=1,
    timeres=60,
)
coverage = observation.image_gridding(
    fov_deg=telescope.fov,
    min_weight=1,
)
noise_std = coverage.get_noise_std_cube(total_time_sec=100 * 3600)

The same SimuGridded object provides a power-spectrum estimator whose frequency range, UV limits, primary beam, and default weights match the simulation. The noise-standard-deviation cube can be passed directly to it to obtain the expected thermal-noise power:

ps_gen = coverage.get_ps_gen(
    filter_kpar_min=.05,
    filter_wedge_theta=0,
)
kbins = np.logspace(np.log10(ps_gen.kmin), np.log10(.5), 8)
noise_spectra = ps_gen.get_all(kbins, noise_std)

noise_spectra.ps.plot()
noise_spectra.ps2d.plot()
noise_spectra.ps3d.plot()

The .data attribute of each result is the expected thermal-noise power, not the sensitivity. The corresponding one-sigma sensitivity is stored in .err; for example, use noise_spectra.ps3d.err for the spherical sensitivity. A random noise realization is only needed when testing a realization-dependent analysis and can be drawn with noise_std.generate_noise_cube().

Frequencies are in Hz, physical coordinates in metres, UV coordinates in wavelengths, angles in degrees unless a parameter explicitly ends in _rad, hour angles in hours, and times in seconds.

class ps_eor.obssimu.CoordinateType(*values)[source]#

Bases: Enum

Enumeration of coordinate systems used to interpret station positions.

ps_eor.obssimu.enu_to_ecef(location, enu)[source]#

Convert local east-north-up coordinates to Earth-fixed coordinates.

Parameters:
  • location (astropy.coordinates.EarthLocation) – Reference geodetic location.

  • enu (np.ndarray) – ENU coordinates, shape (N, 3), in meters.

Returns:

ECEF coordinates, shape (N, 3), in meters.

Return type:

np.ndarray

ps_eor.obssimu.ecef_to_xyz_matrix(long_rad)[source]#

Return the rotation matrix from ECEF to interferometric XYZ.

Parameters:

long_rad (float) – Longitude in radians.

Returns:

3×3 rotation matrix.

Return type:

np.ndarray

ps_eor.obssimu.lla_to_ecef(lat, lon, alt)[source]#

Convert WGS84 geodetic coordinates to ECEF coordinates.

Parameters:
  • lat (float) – Geodetic latitude in radians.

  • lon (float) – Geodetic longitude in radians.

  • alt (float) – Height above ellipsoid in meters.

Returns:

Cartesian ECEF coordinates (x, y, z) in meters.

Return type:

tuple of float

ps_eor.obssimu.xyz_to_uvw_matrix(ha_rad, dec_rad)[source]#

Return the rotation matrix from interferometric XYZ to UVW.

Parameters:
  • ha_rad (float) – Hour angle in radians.

  • dec_rad (float) – Declination in radians.

Returns:

3x3 transformation matrix from XYZ to UVW.

Return type:

np.ndarray

class ps_eor.obssimu.Telescope[source]#

Bases: object

Base description of a radio telescope used by the simulators.

Subclasses provide their station layout and single-polarization SEFD.

name#

Identifier accepted by from_name().

pb_name#

Primary-beam identifier accepted by ps_eor.datacube.PrimaryBeam.from_name().

n_elements_per_stations#

Number of layout elements forming one station.

only_drift_mode#

Whether the model is intended only for drift scans.

redundant_array#

Whether to use the redundant-baseline gridding path.

redundant_baselines#

Representative redundant baseline lengths in metres.

Type:

ClassVar[list]

umin, umax

Default baseline limits in wavelengths.

coord_type#

Coordinate system of the station positions.

location#

Array reference location.

get_stat_pos_file()[source]#

The station-position file supplied by the telescope model.

Returns:

Path to an (n_elements, 3) text array in metres.

Return type:

str

get_stat_pos()[source]#

Load station positions from get_stat_pos_file().

Returns:

Station positions shaped (n_elements, 3) in metres.

Return type:

ndarray

get_sefd(freq)[source]#

Return the single-polarization SEFD in Jy.

Parameters:

freq (np.ndarray or float) – Frequency in Hz.

Returns:

Single-polarization SEFD in Jy.

Return type:

ndarray or float

get_i_sefd(freq)[source]#

Return the Stokes-I SEFD in Jy.

Parameters:

freq (np.ndarray or float) – Frequency in Hz.

Returns:

Stokes-I SEFD in Jy.

Return type:

ndarray or float

sky_temperature(freq, tsys_sky=60, temp_power_law_index=2.55)[source]#

Estimate the sky temperature from a wavelength power law.

Parameters:
  • freq (np.ndarray or float) – Frequency in Hz.

  • tsys_sky (float) – Sky temperature at one-metre wavelength, in K.

  • temp_power_law_index (float) – Wavelength power-law index.

Returns:

Estimated sky temperature in Kelvin.

Return type:

np.ndarray or float

get_dipole_aeff(freq, distance_between_dipole)[source]#

Return the effective area of one dipole in square metres.

Parameters:
  • freq (np.ndarray or float) – Frequency in Hz.

  • distance_between_dipole (float) – Physical spacing between dipoles in meters.

Returns:

Effective area in m².

Return type:

np.ndarray or float

get_dish_aeff(freq, diameter, efficiency)[source]#

Return the effective area of one dish in square metres.

Parameters:
  • freq (np.ndarray or float) – Frequency in Hz.

  • diameter (float) – Diameter of the dish in meters.

  • efficiency (float) – Aperture efficiency.

Returns:

Effective area in m².

Return type:

np.ndarray or float

static from_name(name)[source]#

Create a registered telescope model from its name.

Parameters:

name (str) – Telescope name, for example "ska_low".

Returns:

Instance of the corresponding Telescope subclass.

Return type:

Telescope

Raises:

ValueError – If no matching telescope subclass is found.

class ps_eor.obssimu.DEx(n_antenna_side=32, sep_antenna=6)[source]#

Bases: Telescope

Conceptual lunar dipole array with square grid layout.

property pb_name#

Dipole beam name, following the configured antenna separation.

get_sefd() models one element as an aperture of diameter sep_antenna (see Telescope.get_dipole_aeff()), so the beam uses the same aperture. The tapering matches the other dipole arrays here (a12_lba, ovro_lwa). Unlike every other telescope the element geometry is a constructor argument, so this cannot be a fixed class attribute.

get_stat_pos()[source]#

Generate ENU antenna positions for the square layout.

Returns:

Station positions shaped (n_antenna_side**2, 3) in metres.

Return type:

ndarray

get_sefd(freq, tsys_sky=60)[source]#

The single-polarization dipole SEFD in Jy.

class ps_eor.obssimu.SkaLow[source]#

Bases: Telescope

SKA-Low Phase 1 array (AA4).

get_stat_pos_file()[source]#

Return the packaged SKA-Low AA4 ENU station layout.

get_sefd(freq, tsys_sky=60)[source]#

The interpolated single-polarization SKA-Low SEFD in Jy.

class ps_eor.obssimu.SkaLowAAstar[source]#

Bases: SkaLow

SKA-Low AA* layout.

get_stat_pos_file()[source]#

Return the packaged SKA-Low AA* ENU station layout.

class ps_eor.obssimu.SkaLowAA2[source]#

Bases: SkaLow

SKA-Low AA2 layout.

get_stat_pos_file()[source]#

Return the packaged SKA-Low AA2 ENU station layout.

class ps_eor.obssimu.LofarHBA[source]#

Bases: Telescope

LOFAR High-Band Antenna (HBA) core array.

get_stat_pos_file()[source]#

Return the packaged LOFAR ECEF station layout.

get_sefd(freq)[source]#

The representative single-polarization LOFAR-HBA SEFD in Jy.

class ps_eor.obssimu.A12HBA[source]#

Bases: Telescope

AARTFAAC-12 LOFAR HBA subarray with 48-element stations.

get_stat_pos_file()[source]#

Return the packaged AARTFAAC-12 HBA ECEF element layout.

get_sefd(freq)[source]#

The scaled single-polarization AARTFAAC-12 HBA SEFD in Jy.

class ps_eor.obssimu.A12LBA[source]#

Bases: Telescope

AARTFAAC-12 LOFAR LBA subarray with wide FoV and drift scan.

get_stat_pos_file()[source]#

Return the packaged AARTFAAC-12 LBA ECEF element layout.

get_sefd(freq, tsys_sky=60)[source]#

The sky-noise dominated single-polarization LBA SEFD in Jy.

class ps_eor.obssimu.MWA1[source]#

Bases: Telescope

First-phase MWA core layout.

get_stat_pos_file()[source]#

Return the packaged MWA Phase-I ECEF tile layout.

get_sefd(freq, tsys_sky=60)[source]#

The sky-noise dominated single-polarization MWA SEFD in Jy.

class ps_eor.obssimu.HERA(hex_num=11, split_core=True, sep=14.6)[source]#

Bases: Telescope

HERA telescope core array with redundant hexagonal layout.

redundant_baselines: ClassVar[list] = array([14.6       , 25.28794179, 29.2       , 38.62796914, 43.8       ,        50.57588358, 52.64104862, 58.4       , 63.63992458, 66.90560515,        73.        , 75.86382537, 77.25593828, 81.2893597 , 87.6       ])#
get_stat_pos()[source]#

Generate ENU antenna positions for the hexagonal layout.

Returns:

Antenna positions shaped (n_antennas, 3) in metres.

Return type:

ndarray

get_sefd(freq, tsys_sky=60)[source]#

The single-polarization dish SEFD in Jy.

class ps_eor.obssimu.HERA56[source]#

Bases: HERA

HERA sub-array with 56 antennas.

class ps_eor.obssimu.HERA120[source]#

Bases: HERA

HERA sub-array with 120 antennas.

class ps_eor.obssimu.HERA208[source]#

Bases: HERA

HERA sub-array with 208 antennas.

class ps_eor.obssimu.HERA320[source]#

Bases: HERA

HERA full array with 320 antennas.

class ps_eor.obssimu.NenuFAR[source]#

Bases: Telescope

Full NenuFAR array in Nançay (France).

get_stat_pos_file()[source]#

Return the packaged full-NenuFAR ECEF mini-array layout.

inst_temperature(freq)[source]#

Return the measured receiver temperature in K.

The interpolation data come from nenupy.instru.

Parameters:

freq – Frequency in Hz.

Returns:

Receiver temperature in K.

Return type:

ndarray or float

get_sefd(freq, tsys_sky=60)[source]#

The modeled single-polarization NenuFAR SEFD in Jy.

class ps_eor.obssimu.NenuFAR80[source]#

Bases: NenuFAR

Subset of NenuFAR using 80 mini-arrays.

get_stat_pos_file()[source]#

Return the packaged 80-mini-array NenuFAR ECEF layout.

class ps_eor.obssimu.OVROLWA[source]#

Bases: Telescope

OVRO-LWA dipole array in California with large FoV.

get_stat_pos_file()[source]#

Return the packaged OVRO-LWA ENU station layout.

get_sefd(freq, tsys_sky=60)[source]#

The sky-noise dominated single-polarization OVRO-LWA SEFD in Jy.

class ps_eor.obssimu.TelescopeSimu(telescop: Telescope, freqs, dec_deg, hal, har, umin=None, umax=None, timeres=100, remove_intra_baselines=True)[source]#

Bases: object

Simulate a telescope’s UV coverage over an observation.

static from_dict(d, freqs)[source]#

Build a simulation from its PE* metadata fields.

Parameters:
  • d – Mapping containing the fields returned by to_dict().

  • freqs – Observing frequencies in Hz; these are not stored in the metadata mapping.

Returns:

The reconstructed observation.

Return type:

TelescopeSimu

to_dict()[source]#

Serialize the observation as PE* metadata fields.

Returns:

Telescope name, pointing, hour-angle range, baseline limits, time resolution, and intra-station selection.

Return type:

dict

get_XYZ_positions()[source]#

Station positions in interferometric XYZ coordinates.

Input positions are converted according to Telescope.coord_type and the array reference location.

Returns:

Positions shaped (n_elements, 3) in metres.

Return type:

ndarray

simu_uv(include_conj=True)[source]#

Simulate baseline coordinates over the observation.

Physical baselines are sampled from hal up to, but excluding, har at timeres intervals. A baseline is retained if it enters the requested wavelength range at any supplied frequency.

Parameters:

include_conj – Include the conjugate (-u, -v, w) samples.

Returns:

Flattened (u, v, w) coordinates in metres, containing every selected baseline and time sample.

Return type:

tuple of ndarray

redundant_gridding(max_distance=1)[source]#

Cluster physically redundant baselines.

This path keeps coordinates in metres so a redundant group represents the same physical baseline across the band.

Parameters:

max_distance – DBSCAN clustering distance in metres.

Returns:

Metre-coordinate weights, with one column per redundant baseline group.

Return type:

SimuGridded

image_gridding(fov_deg, oversampling_factor=4, min_weight=10, win_fct=None)[source]#

Bin simulated baselines onto a regular UV grid.

win_fct is recorded in the output metadata for later noise and power-spectrum corrections; it is not applied to the weights.

Parameters:
  • fov_deg – Image field of view in degrees. It sets the UV-cell size.

  • oversampling_factor – Number of image pixels per finest requested angular scale.

  • min_weight – Keep cells with at least this many samples at every frequency.

  • win_fct – Optional WindowFunction to record in the output metadata.

Returns:

Frequency-dependent counts on the selected UV cells.

Return type:

SimuGridded

class ps_eor.obssimu.SimuGridded(weights, telescope_simu)[source]#

Bases: object

Gridded UV weights together with their telescope simulation.

save(filename)[source]#

Save the weights and simulation metadata.

Parameters:

filename – Destination HDF5 filename.

static load(filename)[source]#

Load weights and reconstruct their telescope simulation.

Parameters:

filename – HDF5 file created by save().

Returns:

The restored coverage and observation settings.

Return type:

SimuGridded

get_slice(freq_start=None, freq_end=None)[source]#

Select an inclusive frequency interval.

Metre-coordinate redundant weights are converted to wavelength coordinates at the interval’s mean frequency.

Parameters:
  • freq_start – Interval limits in Hz. Omitted limits use the first or last available channel.

  • freq_end – Interval limits in Hz. Omitted limits use the first or last available channel.

Returns:

A new frequency-sliced simulation.

Return type:

SimuGridded

get_sefd()[source]#

The single-polarization SEFD across the simulated frequencies.

Returns:

SEFD in Jy, with at least one dimension.

Return type:

ndarray

get_i_sefd()[source]#

The Stokes-I SEFD across the simulated frequencies.

Returns:

Stokes-I SEFD in Jy.

Return type:

ndarray

get_ps_gen(filter_kpar_min=None, filter_wedge_theta=0)[source]#

Create a Cartesian power-spectrum estimator for this coverage.

The estimator inherits the telescope baseline limits and primary beam, uses the simulated weights by default, and spans the full simulated frequency interval. Pass the output of get_noise_std_cube() directly to its get_ps, get_ps2d, get_ps3d, or get_all methods to estimate thermal-noise power. The returned spectrum’s .err attribute is the corresponding one-sigma sensitivity.

Parameters:
  • filter_kpar_min – Optional minimum line-of-sight mode retained by the estimator.

  • filter_wedge_theta – Optional wedge angle in degrees.

Returns:

Configured estimator.

Return type:

ps_eor.pspec.PowerSpectraCart

get_noise_std_cube(total_time_sec, sefd=None, min_weight=1)[source]#

Estimate the thermal-noise standard deviation in every UV cell.

A window recorded during gridding is included through its equivalent noise-bandwidth correction. The returned cube can be passed directly to the estimator from get_ps_gen(); drawing an explicit noise realization is not required for the expected noise spectrum. Its .err attribute gives the corresponding one-sigma sensitivity.

Parameters:
  • total_time_sec – Target total integration time in seconds.

  • sefd – Optional Stokes-I SEFD in Jy, scalar or one value per frequency. By default use the telescope model.

  • min_weight – Remove cells whose weight is below this value.

Returns:

Real standard deviation per frequency and UV cell.

Return type:

ps_eor.datacube.NoiseStdCube