# The xengine_metadata file represents all FRB-related metadata from the X-engine.
# It is sent from the X-engine to every FRB node, and is also one of three metadata
# files sent from pirate to the grouper.
#
# The purpose of this git-controlled example file is to document the file format.
version: 2
# Frequency channels. The observed frequency band is divided into "zones".
# Within each zone, all frequency channels have the same width, but the
# channel width may differ between zones.
# zone_nfreq: number of frequency channels in each zone.
# zone_freq_edges: frequency band edges in MHz.
# For example:
# zone_nfreq: [N] zone_freq_edges: [400,800] one zone, channel width (400/N) MHz
# zone_nfreq: [2*N,N] zone_freq_edges: [400,600,800] width (100/N), (200/N) MHz in lower/upper band
#
# In this config, we have:
# Total frequency channels: 28160
# Channel widths (MHz): [ 0.00610352, 0.012207, 0.0244141, 0.0976562, 0.195312 ]
zone_nfreq: [8192, 8192, 6144, 2048, 3584]
zone_freq_edges: [300, 350, 450, 600, 800, 1500]
# Optional: which frequency channels are present?
# A list of distinct integers 0 <= (channel_id) < (total frequency channels).
# Only makes sense in "context 1" (see above), to indicate which frequency channels
# are sent by a particular X-engine node.
freq_channels: [ 0, 10000, 20000, 28159 ]
# Data for each beam received by this node.
# beamset: an integer identifier for this set of beams
# beam_ids: length Nbeams; integer id
# beam_positions_x: float, length Nbeams &
# beam_positions_y: float, length Nbeams;
# direction cosines in the grid frame. The grid frame is defined by x & y unit vectors
# which are orthogonal and lie along (or close to) the axes of the telescope grid. Each
# beam has a skywards-directed unit vector b. The grid_x and grid_y values are the x & y direction
# cosines: b.x and b.y.
beamset: 42
beam_ids: [ 100, 200, 300 ]
beam_positions_x: [0.0, 0.1, 0.0 ]
beam_positions_y: [0.0, 0.0, 0.1 ]
#############
# Timekeeping
#############
# The X-engine uses fpga sequence number (seq) to keep track of time.
# To keep time in pirate, we need to know:
#
# - unix_ns_at_seq_0: the epoch (the UNIX time at seq = 0, in nanoseconds).
# - dt_ns_per_seq: the rate at which seqs tick, number of nanoseconds per seq tick.
# - seq_per_frb_time_sample: the number of seq ticks covered by an frb time sample.
#
# In Kotekan language:
# - unix_ns_at_seq_0 = time0_ns
# - dt_ns_per_seq = fengine_fft_length / ADC_sampling_rate_GHz
# - seq_per_frb_time_sample = upchanelization factor * frb_downsampling_factor (not sure if this exists)
#
# The sifter will need Earth Orientation Parameters (EOP) (which change in time and Kotekan has) and
# a precession/nutation model (which Kotekan does *not* have) to compute RA/DEC for the beams.
# Since the sifter has to do this calculation anyways, I propose we *don't* sent UT1 or EOP data
# from Kotekan to Pirate, and instead rely on the sifter to make the astropy calls itself.
#
# This means the sifter may infer a *slightly* different UT1 for the same seq number compared to
# the X-engine (if it has more up-to-date EOP data). The difference will be sub-ms, which I think is
# acceptable?
#
# unix_ns_at_seq_0 will change whenever the F-engine reboots, which will also require a reboot of
# the X-engine.
unix_ns_at_seq_0: 1772483060000000000
dt_ns_per_seq: 5120 # note long, not double
seq_per_frb_time_sample: 256
##################################################
# Telescope alignment and localization parameters.
##################################################
# Coordinate Systems
#
# Topocentric: origin at the given lat/lon. x-axis is directed exactly East (increasing Longitude),
# y-axis is directed exactly North (increasing Latitude), z-axis is directed exactly "up" (increasing
# altitude). orthogonal, Z = X x Y.
#
# Grid: origin at SW corner of Dish Array, aligned with Dish Array. x-axis directed "east-ish"
# parallel to dish "e/w" separatation vector. y-axis directed "north-ish" parallel to "n/s"
# separation vector. Z = X x Y points normal to grid plane. Dish grid lives in x-y plane at a
# constant Z. Orthogonal. Rotated by O(1) degrees from "Topocentric"
#
# Dish Elevation Axis: The axis around which the dishes pivot. positive is in the east direction.
# *Not* parallel to the dish grid "e/w" separation. "Coelevation" pointing measures an angle around
# this axis.
#
# Dish Vertical Axis: Local "up/zenith" for the dishes. The direction which has coelevation = 0.0.
# Orthogonal to the Dish Elevation axis.
# Position on the Earth in degrees
tel_origin_itrs_lat_deg: 49.32075144444
tel_origin_itrs_lon_deg: -119.62081125
# Unit vectors in the x & y grid directions, in topocentric coordinates.
tel_grid_x_axis: [ 0.999974342398359362,
-0.000037539331442772,
-0.007163318767675494]
tel_grid_y_axis: [0.000065403387739210,
0.999992433220348809,
0.003889630373557614]
# Unit vectors for the dish frame, the elevation axis and vertical axis, in
# topocentric coordinates.
tel_dish_elev_axis: [0.99999999838132391,
-0.000056897733584327,
0.0]
tel_dish_vert_axis: [0.0, 0.0, 1.0]
# The dish pointing angle, co-elevation in degrees: angle away from vertical,
# north is positive
tel_dish_coelev_deg: 0.0
# Values of dish separation in x and y directions in meters.
tel_dish_separation_x_m: 6.300156854906823
tel_dish_separation_y_m: 8.500057809796308
#####################################################
# Temporary kludge: per-frequency-zone noise variance
#####################################################
# For now, the FRB server assumes that the noise is mean-zero, uncorrelated
# between samples, with variance known in advance! We assume that the noise
# variance is constant in time, and depends only on frequency "zone" (see above).
# (A per-frequency-channel variance was awkward to implement.)
#
# In a future revision, this will be generalized, and the 'noise_variance'
# metadata will go away.
#
# noise_variance: an array of length nzones (=len(zone_nfreq)). If a scalar is
# specified, then all frequency zones are assumed to have the same variance.
noise_variance: 1.0
###############################################
# Sender-consistency rules
###############################################
# When multiple X-engine nodes connect to a single FRB node, the FRB
# receiver enforces that all senders agree on (almost all of) the
# metadata above. The check is implemented in
# XEngineMetadata::check_sender_consistency() (in
# src_lib/XEngineMetadata.cpp). Every field above falls into one of
# three groups:
#
# 1. NOT checked across senders:
# freq_channels (each sender deliberately sends a different
# subset of the frequency channels)
#
# 2. Required to be bit-identical across senders (compared with ==):
# version
# zone_nfreq
# beamset
# beam_ids
# unix_ns_at_seq_0
# dt_ns_per_seq
# seq_per_frb_time_sample
#
# 3. Required to match within an absolute tolerance |a - b| <= eps
# (NOT bit-identical). All tolerances are hard-coded near the top
# of src_lib/XEngineMetadata.cpp:
#
# zone_freq_edges eps = 1.0e-3 MHz
# beam_positions_x eps = 1.0e-9 (direction cosine)
# beam_positions_y eps = 1.0e-9 (direction cosine)
# tel_origin_itrs_lat_deg eps = 1.0e-6 degrees
# tel_origin_itrs_lon_deg eps = 1.0e-6 degrees
# tel_grid_x_axis eps = 1.0e-9 (direction cosine)
# tel_grid_y_axis eps = 1.0e-9 (direction cosine)
# tel_dish_elev_axis eps = 1.0e-9 (direction cosine)
# tel_dish_vert_axis eps = 1.0e-9 (direction cosine)
# tel_dish_coelev_deg eps = 1.0e-6 degrees
# tel_dish_separation_x_m eps = 1.0e-6 meters
# tel_dish_separation_y_m eps = 1.0e-6 meters
# noise_variance eps = 1.0e-12