def gnss_earth_rotation_drift(dset: "Dataset") -> np.ndarray: """Determine earth rotation drift based on precise or broadcast satellite clock information The correction is caluclated after the description in Section 6.2.9 in :cite:`zhang2007`. Args: dset (Dataset): Model data. Returns: numpy.ndarray: GNSS earth rotation drift for each observation """ correction = np.zeros(dset.num_obs) if "site_vel" not in dset.fields: # TODO: This should be replaced by dset.site_posvel dset.add_float("site_vel", val=np.zeros([dset.num_obs, 3]), unit="meter/second") for sys in dset.unique("system"): idx = dset.filter(system=sys) omega = constant.get("omega", source=enums.gnss_id_to_reference_system[sys]) correction[idx] = ( omega / constant.c * (dset.site_vel[:, 0][idx] * dset.sat_posvel.trs.y[idx] - dset.site_vel[:, 1][idx] * dset.sat_posvel.trs.x[idx] + dset.site_pos.trs.x[idx] * dset.sat_posvel.trs.vy[idx] - dset.site_pos.trs.y[idx] * dset.sat_posvel.trs.vx[idx])) return correction
def slr_relativistic(dset): """Calculate relativistic delay for all observations Args: dset: Dataset containing the data Returns: Numpy array: Correction in meters for each observation """ eph = apriori.get("ephemerides") GM = constant.get("GM", source="egm_2008") site_norm = np.linalg.norm(dset.site_pos.gcrs, axis=1) sat_norm = np.linalg.norm(dset.sat_pos.gcrs, axis=1) geocenter_movement = eph.pos_bcrs( "earth", time=dset.time + TimeDelta( dset.up_leg, format="sec")) - eph.pos_bcrs("earth", time=dset.time) sta_sat_norm = np.linalg.norm(dset.sat_pos.gcrs - dset.site_pos.gcrs + geocenter_movement, axis=1) numerator = site_norm + sat_norm + sta_sat_norm denominator = site_norm + sat_norm - sta_sat_norm correction = np.array([ math.log(numerator[i] / denominator[i]) for i in range(0, len(numerator)) ]) return 2 * GM / constant.c**2 * correction
def gnss_relativistic_clock_rate(dset): """Determine relativistic clock rate correction due to orbit eccentricity The correction is caluclated for precise and broadcast orbits after Eq. 6-19 in :cite:`zhang2007`. Args: dset (Dataset): Model data. Returns: numpy.ndarray: Relativistic clock rate correction due to orbit eccentricity corrections for each observation """ gm = constant.get("GM", source="iers_2010") orbit = apriori.get( "orbit", apriori_orbit=dset.vars["orbit"], rundate=dset.analysis["rundate"], system=tuple(dset.unique("system")), station=dset.vars["station"], ) a = np.power(orbit.get_ephemeris_field("sqrt_a", dset), 2) correction = 2 * gm / constant.c * (1 / a - 1 / dset.sat_posvel.trs.pos.length) return correction
def parse_flux(self, line, cache): if not line["day"]: return day = int(line.pop("day")) for month in line: if not line[month]: continue time = None try: time = datetime(cache["year"], int(month), day) self.data[time] = int(line[month]) except ValueError: # Todo: Can we use __missing__ instead? Makes it possible to add warning if time is not None: self.data[time] = constant.get("S", source="book")
def slr_relativistic(dset): """Calculate relativistic delay for all observations Args: dset: Dataset containing the data Returns: Numpy array: Correction in meters for each observation """ GM = constant.get("GM", source="egm_2008") site_norm = np.linalg.norm(dset.site_pos.gcrs, axis=1) sat_norm = np.linalg.norm(dset.sat_pos.gcrs, axis=1) sta_sat_norm = np.linalg.norm(dset.sat_pos.gcrs.pos - dset.site_pos.gcrs, axis=1) numerator = site_norm + sat_norm + sta_sat_norm denominator = site_norm + sat_norm - sta_sat_norm correction = np.array([math.log(numerator[i] / denominator[i]) for i in range(0, len(numerator))]) return 2 * GM / constant.c ** 2 * correction
# External imports import scipy.constants as scp from scipy import stats from scipy.optimize import lsq_linear import numpy as np # Midgard imports from midgard.data.position import Position # Import Position class from midgard.collections import enums from midgard.math.constant import constant # define constants # wavelength for E1 (D1X) - lambda_E1 lambda_E1 = constant.c / enums.gnss_freq_E.E1 # eller constant.c /enums.gnss_freq_E.E1.value E_OMGA = constant.get( "omega", source="wgs84") # Earth Angular Velocity (IS-GPS) (rad/s) logger = print # ================================================= # class definition of Single Point Velocity (SPV) # ================================================= class spvDoppler(object): # ========================================= # METHOD 1: Constructor/Initializer # ========================================= def __init__(self, z, H, x, dx, Qx): """Initialize the single point velocity estimation by Doppler Args:
def vlbi_grav_delay(dset): """Calculate the gravitational delay The implementation is described in IERS Conventions [1]_, section 11.1, in particular equation (11.9). Args: dset: A Dataset containing model data. Returns: Numpy array: Gravitational delay in meters for each observation. """ eph = apriori.get("ephemerides", time=dset.time) grav_delay = np.zeros(dset.num_obs) # List of celestial bodies. Major moons are also recommended, like Titan, Ganymedes, ... bodies = [ "mercury barycenter", "venus barycenter", "earth", "moon", "mars barycenter", "jupiter barycenter", "saturn barycenter", "uranus barycenter", "neptune barycenter", "pluto barycenter", "sun", ] bcrs_vel_earth = eph.vel_bcrs("earth") baseline_gcrs = dset.site_pos_2.gcrs.pos - dset.site_pos_1.gcrs.pos src_dot_baseline = (dset.src_dir.unit_vector[:, None, :] @ baseline_gcrs.mat)[:, 0, 0] # Equation 11.6 bcrs_site1 = eph.pos_bcrs("earth") + dset.site_pos_1.gcrs.pos.val bcrs_site2 = eph.pos_bcrs("earth") + dset.site_pos_2.gcrs.pos.val for body in bodies: try: GM_name = "GM" if body == "earth" else f"GM_{body.split()[0]}" GM_body = constant.get(GM_name, source=eph.ephemerides) except KeyError: log.warn( f"The GM value of {body.split()[0].title()} is not defined for {eph.ephemerides}. " f"Correction set to zero." ) continue bcrs_body_t1 = eph.pos_bcrs(body) # Equation 11.3 delta_t = TimeDelta( np.maximum(0, dset.src_dir.unit_vector[:, None, :] @ (bcrs_body_t1 - bcrs_site1)[:, :, None])[:, 0, 0] * Unit.second2day / constant.c, fmt="jd", scale="tdb", ) time_1J = dset.time.tdb - delta_t # Equation 11.4 bcrs_body_t1J = eph.pos_bcrs(body, time=time_1J) vector_body_site1 = bcrs_site1 - bcrs_body_t1J # Equation 11.5 vector_body_site2 = bcrs_site2 - bcrs_body_t1J - bcrs_vel_earth / constant.c * src_dot_baseline[:, None] # Needed for equation 11.1 norm_body_site1 = np.linalg.norm(vector_body_site1, axis=1) src_dot_vector_body_site1 = (dset.src_dir.unit_vector[:, None, :] @ vector_body_site1[:, :, None])[:, 0, 0] nomJ = norm_body_site1 + src_dot_vector_body_site1 denomJ = ( np.linalg.norm(vector_body_site2, axis=1) + (dset.src_dir.unit_vector[:, None, :] @ vector_body_site2[:, :, None])[:, 0, 0] ) # Main correction (equation 11.1) grav_delay += 2 * GM_body / constant.c ** 2 * np.log(nomJ / denomJ) # Higher order correction (equation 11.14) baseline_dot_vector_body_site1 = (baseline_gcrs.val[:, None, :] @ vector_body_site1[:, :, None])[:, 0, 0] grav_delay += ( 4 * GM_body ** 2 / constant.c ** 4 * (baseline_dot_vector_body_site1 / norm_body_site1 + src_dot_baseline) / (norm_body_site1 + src_dot_vector_body_site1) ** 2 ) # Denominator (equation 11.9) denominator = ( 1 + ( (bcrs_vel_earth + dset.site_pos_2.gcrs.vel.val)[:, None, :] @ dset.src_dir.unit_vector[:, :, None] / constant.c )[:, 0, 0] ) return grav_delay / denominator
def _get_pco_sat(self, sat, sys_freq, used_date): """Get satellite PCO in satellite reference system If two frequencies are given over the 'sys_freq' argument, then the PCOs are determined as an ionospheric linear combination. Args: sat (str): Satellite identifier. sys_freq (dict): Dictionary with frequency or frequency combination given for GNSS identifier: sys_freq = { <sys_id>: <freq> } (e.g. sys_freq = {'E': 'E1', 'G': 'L1_L2'} ) used_date (datetime.datetime): Correct date for use of satellite antenna corrections Returns: numpy.ndarray: Satellite PCO in satellite reference system """ # GNSS GNSS freq ANTEX freq # ___________________________________________ # C (BeiDou): B1 'C02' # B2 'C07' # B3 'C06' # G (GPS): L1 'G01' # L2 'G02' # L5 'G05' # R (GLONASS): G1 'R01' # G2 'R02' # E (Galileo): E1 'E01' # E5 (E5a+E5b) 'E08' # E5a 'E05' # E5b 'E07' # E6 'E06' # I (IRNSS): L5 'I05' # S 'I09' # J (QZSS): L1 'J01' # L2 'J02' # L5 'J05' # LEX 'J06' # S (SBAS): L1 'S01' # L5 'S05' gnss_to_antex_freq = { "C": {"B1": "C02", "B2": "C07", "B3": "C06"}, "E": {"E1": "E01", "E5": "E08", "E5a": "E05", "E5b": "E07", "E6": "E06"}, "G": {"L1": "G01", "L2": "G02", "L5": "G05"}, "I": {"L5": "I05", "S": "I09"}, "J": {"L1": "J01", "L2": "J02", "L5": "J05", "LEX": "J06"}, "R": {"G1": "R01", "G2": "R02", "G3": "R03"}, "S": {"L1": "S01", "L5": "S05"}, } # Get GNSS and frequency/frequencies sys = sat[0] # GNSS identifier freq = sys_freq[sys] if "_" in freq: freq = freq.split("_") else: freq = [freq] # Get satellite PCO for one frequency if len(freq) == 1: # Get satellite phase center offset (PCO) given in satellite reference system pco_sat = np.array([self.data[sat][used_date][gnss_to_antex_freq[sys][freq[0]]]["neu"]]) log.debug(f"PCO of satellite {sat} for frequency {sys}:{sys_freq[sys]}: {pco_sat.tolist()[0]}.") # Get satellite PCO for ionospheric-free linear combination based on two-frequencies elif len(freq) == 2: # Coefficient of ionospheric-free linear combination f1 = constant.get("gnss_freq_" + sys, source=freq[0]) # Frequency of 1st band f2 = constant.get("gnss_freq_" + sys, source=freq[1]) # Frequency of 2nd band n = f1 ** 2 / (f1 ** 2 - f2 ** 2) m = -f2 ** 2 / (f1 ** 2 - f2 ** 2) # Get satellite phase center offset (PCO) given in satellite reference system pco_sat_f1 = np.array([self.data[sat][used_date][gnss_to_antex_freq[sys][freq[0]]]["neu"]]) pco_sat_f2 = np.array([self.data[sat][used_date][gnss_to_antex_freq[sys][freq[1]]]["neu"]]) # Generate ionospheric-free linear combination pco_sat = n * pco_sat_f1 + m * pco_sat_f2 log.debug( f"Ionospheric-free linear combination PCOs of satellite {sat} for" f" frequency combination {sys}:{sys_freq[sys]}: {pco_sat.tolist()[0]}." ) else: log.fatal( f"Wrong frequency type '{sys}:{'_'.join(freq)}'. Note: 'signals' configuration option" f" should represent one- or two-frequencies (e.g. E:E1 or E:E1_E5a)." ) return pco_sat
from midgard.math.constant import constant # Where imports from where import data from where import cleaners from where import parsers from where.apriori import orbit from where.lib import config from where.lib import log from where.lib import plugins from where.lib import rotation from where.lib.unit import Unit # Earth's gravitational constant GM = { "C": constant.get("GM", source="cgcs2000"), "E": constant.get("GM", source="gtrf"), "G": constant.get("GM", source="wgs84"), "I": constant.get("GM", source="wgs84"), "J": constant.get("GM", source="jgs"), } # Earth's rotation rate OMEGA = { "C": constant.get("omega", source="cgcs2000"), "E": constant.get("omega", source="gtrf"), "G": constant.get("omega", source="wgs84"), "I": constant.get("omega", source="wgs84"), "J": constant.get("omega", source="jgs"), }