"""
Base class for radiometric converters sharing helper functions.
"""
from tudatpy.dynamics.environment_setup.ground_station import (
# from tudatpy.dynamics.environment import (
get_approximate_dsn_ground_station_positions,
)
from tudatpy.estimation.observations_setup.ancillary_settings import FrequencyBands # type:ignore
from tudatpy.estimation.observable_models_setup import links
from tudatpy.astro import time_representation
from . import Converter
from trk234 import bands, SFDU
from datetime import datetime
[docs]
class RadioBase(Converter):
trkModeDict = {
0: "Unknown",
1: "1W",
2: "2W",
3: "3W",
}
time_scale_converter = time_representation.default_time_scale_converter()
frequencyBandsDict = {
"S": FrequencyBands.s_band,
"X": FrequencyBands.x_band,
# "K": FrequencyBands.ku_band,
"Ka": FrequencyBands.ka_band,
}
stationDict = get_approximate_dsn_ground_station_positions()
[docs]
def get_link_ends(self, sfdu: SFDU) -> tuple[str, str, str]:
"""
Returns the uplink, spacecraft, and downlink IDs for a given SFDU record.
The secondary CHDO has to be decoded before calling this function.
Parameters
----------
sfdu : trk234.SFDU
The SFDU record to extract the link ends from.
Returns
-------
tuple(str, str, str)
A tuple containing the uplink, spacecraft, and downlink IDs.
If the uplink is unknown or not valid, the uplink entry is a `"nan"` string.
"""
upLink = (
sfdu.sec_chdo.vld_ul_stn
if sfdu.sec_chdo.vld_ul_stn != 0
else sfdu.sec_chdo.ul_prdx_stn if sfdu.sec_chdo.ul_prdx_stn != 0 else "nan"
)
upLink = "DSS-" + str(upLink) if upLink != "nan" else upLink
# Add minus sign to comply with NAIF convention
scId = str(-sfdu.sec_chdo.scft_id)
dlLink = "DSS-" + str(sfdu.sec_chdo.dl_dss_id)
return (upLink, scId, dlLink)
[docs]
def get_band(self, sfdu: SFDU) -> tuple[str, str]:
"""
Returns the uplink and downlink radio bands for a given SFDU record.
The secondary CHDO has to be decoded before calling this function.
Parameters
----------
sfdu : trk234.SFDU
The SFDU record to extract the radio bands from.
Returns
-------
tuple(str, str)
A tuple containing the uplink and downlink radio bands.
"""
return (
bands[sfdu.sec_chdo.ul_band_dl],
bands[sfdu.sec_chdo.vld_dl_band],
)
[docs]
def get_tracking_mode(self, sfdu: SFDU) -> str:
"""
Returns the tracking mode for a given SFDU record.
The secondary CHDO has to be decoded before calling this function.
Parameters
----------
sfdu : trk234.SFDU
The SFDU record to extract the tracking mode from.
Returns
-------
str
The tracking mode of the SFDU record.
"""
trkMode = (
self.trkModeDict[sfdu.sec_chdo.vld_dop_mode]
if sfdu.sec_chdo.vld_dop_mode != 0
else sfdu.tracking_mode()
)
return trkMode
[docs]
def build_link_ends_dict(
self, link_end_tuple: tuple[str, str, str], spacecraftName: str | None = None
) -> dict:
"""
Construct a link ends dictionary for Doppler/Range observation creation.
Parameters
----------
link_end_tuple : tuple
A tuple containing the uplink, spacecraft, and downlink identifiers.
spacecraftName : str, optional
The name of the spacecraft to use in the simulation. If not provided, the spacecraft name
is extracted from the TNF file.
Returns
-------
dict
A dictionary with link ends constructed according to the following logic:
- If the uplink identifier (first element) is "nan", use the spacecraft as the transmitter
and assign the downlink using Earth's reference point (from the third element).
- Otherwise, assign the transmitter using Earth's reference point from the first element,
the reflector as the spacecraft, and the receiver using Earth's reference point from the third element.
"""
if len(link_end_tuple) != 3:
raise ValueError(
"Error when processing TNF file, building link ends dictionary: \n"
+ f"the link end tuple should contain exactly 3 elements: {link_end_tuple} provided."
)
# Set custom spacecraft name if provided
if spacecraftName is not None:
spacecraft = links.body_origin_link_end_id(spacecraftName)
else:
spacecraft = links.body_origin_link_end_id(link_end_tuple[1])
if link_end_tuple[0] == "nan":
return {
links.transmitter: spacecraft,
links.receiver: links.body_reference_point_link_end_id(
"Earth", link_end_tuple[2]
),
}
else:
return {
links.transmitter: links.body_reference_point_link_end_id(
"Earth", link_end_tuple[0]
),
links.reflector1: spacecraft,
links.receiver: links.body_reference_point_link_end_id(
"Earth", link_end_tuple[2]
),
}
[docs]
def from_datetime_UTC_to_TDB(self, datetime_utc: datetime, station: str) -> float:
"""
Convert a datetime object in UTC into seconds since J2000 in TDB.
Parameters
----------
datetime_utc : datetime
The datetime object to convert.
Returns
-------
float
The time in seconds since J2000 in TDB.
"""
if station not in self.stationDict:
raise KeyError(
"Error when processing TNF file, converting time from UTC to TDB: \n"
+ "the position of the ground station {} was not specified.".format(
station
)
)
epoch_utc = time_representation.DateTime.from_python_datetime(datetime_utc).to_epoch()
epoch_tdb = self.time_scale_converter.convert_time(
input_scale=time_representation.utc_scale,
output_scale=time_representation.tdb_scale,
input_value=epoch_utc,
earth_fixed_position=self.stationDict[station],
)
return epoch_tdb