Source code for realtime.receive.core.antenna

from dataclasses import dataclass
from typing import List, Optional
from warnings import warn

from astropy import units
from astropy.coordinates import EarthLocation
from katpoint import Antenna as KatPointAntenna
from katpoint import DelayModel as KatPointDelayModel
from katpoint.conversion import ecef_to_enu


[docs] @dataclass class Antenna: """ A fixed antenna. """ interface: str diameter: float location: dict fixed_delays: List[dict] niao: float station_name: Optional[str] = None station_label: Optional[str] = None station_id: Optional[int] = None def __post_init__(self): """Used to ensure the Antenna has been instantiated correctly Raises: ValueError: if a value is missing """ if self.station_name is None and self.station_label is None: raise ValueError("Antenna must have station_name or station_label") if self.station_label is None: warn("station_name is deprecated, use station_label instead") self.station_label = self.station_name if self.station_name is None: self.station_name = self.station_label if self.station_id is None: raise ValueError("Antenna must have station_id") @property def pos(self): """A tuple representing the geocentric coordinates of this antenna""" return ( self.location["geocentric"]["x"], self.location["geocentric"]["y"], self.location["geocentric"]["z"], ) @property def x(self): """X coordinate of geocentric location""" return self.location["geocentric"]["x"] @property def y(self): """Y coordinate of geocentric location""" return self.location["geocentric"]["y"] @property def z(self): """Z coordinate of geocentric location""" return self.location["geocentric"]["z"] @property def lat(self): """Latitude of geocentric location""" return self.location["geodetic"]["lat"] @property def lon(self): """Longitude of geocentric location""" return self.location["geodetic"]["lon"] @property def h(self): """Height of geocentric location""" return self.location["geodetic"]["h"] @property def name(self): """The name of this antenna""" warn("station name is deprecated, use label instead") return self.station_name @property def label(self): """The label of this antenna""" return self.station_label @property def id(self): """The ID of this antenna""" if self.station_id is None: raise ValueError("station_id not included in this model") return self.station_id @property def dish_diameter(self): """The diameter of this antenna""" return self.diameter @property def fixed_delay_h(self): """Fixed delay for H-POL""" return self.fixed_delays[0]["delay"] @property def fixed_delay_v(self): """Fixed delay for V-POL""" return self.fixed_delays[1]["delay"] def _calc_KatPointDesc(self, ant_location: EarthLocation = None): """Return a katpoint description string for this antenna (or a reference location). This is used to initialise the KatPoint Antenna object. Essentially the katpoint antennas are initialised by string. And this formulates the string """ if ant_location is None: ant_location = EarthLocation.from_geocentric( self.x * units.m, self.y * units.m, self.z * units.m ) longitude, latitude, height = ant_location.to_geodetic(ellipsoid="WGS84") label = self.station_label lat = latitude.deg long = longitude.deg ht = height.value diam = self.dish_diameter desc = f"{label},{lat},{long},{ht},{diam},0,0,0,0" return desc def _calc_delay_model(self, ref_location: EarthLocation): """Initialise the delay models for the antennas. The KatPoint model object is initialised ENU and the fixed delays. There is a different delay model for each antenna (and reference location) However a wrinkle here is that the Katpoint Antenna object should now have a location that is the reference location. This is required by the instatiation of the Antenna object. """ enu = ecef_to_enu( ref_location.lat.rad, ref_location.lon.rad, ref_location.height.to_value(units.m), self.x, self.y, self.z, ) POS_E = enu[0] POS_N = enu[1] POS_U = enu[2] FIX_H = self.fixed_delay_h FIX_V = self.fixed_delay_v NIAO = self.niao desc = f"{POS_E},{POS_N},{POS_U},{FIX_H},{FIX_V},{NIAO}" return KatPointDelayModel(desc)
[docs] def as_KatPointAntenna(self, ref_location: EarthLocation | None = None): """Return a katpoint.Antenna object for this antenna. There are two types of KatPoint antenna. One is initialised with a delay model and a reference location and this corresponds to an antenna in an array. A single antenna is not initialised with a delay model, and it is initialised at the location of the antenna. Parameters: ref_location: EarthLocation object for the reference location. This implicitly creates an antenna in an array. The delay model will be calculated for this antenna and the reference postion will be used to initialise the antenna. """ if ref_location is not None: return KatPointAntenna( self._calc_KatPointDesc(ref_location), delay_model=self._calc_delay_model(ref_location), ) else: return KatPointAntenna(self._calc_KatPointDesc())