def calculate_initial_values(eph, rundate): """Computing initial values for position and velocity in GCRS system This is for later use in orbit integration, from tables in the prediction files. Use a lagrange polynomial in order to interpolate in the tables. Args: eph: Dict containing ephemeris information Returns: eph: Dict where the initial position and velocity is added """ pos_gcrs = np.empty((3, 0)) times = np.empty((0)) table_of_positions = sorted(eph["positions"].items()) mjd1, mjd2 = zip(*[t for t, d in table_of_positions]) for pos_time, (_, data) in zip(time.Time(val=mjd1, val2=mjd2, fmt="mjd", scale="utc"), table_of_positions): diffsec = (pos_time.utc.datetime - rundate).total_seconds() # Only look at points close to rundate (start of integration) # if abs(diffsec) > 4000: # continue # Table given in ITRF coordinate system. Convert to GCRS, where the integration of the satellite orbit will # be done pos_gcrs = np.hstack((pos_gcrs, np.transpose([rotation.trs2gcrs(pos_time) @ data["pos"]]))) times = np.hstack((times, diffsec)) log.info("Interpolating data from prediction file in order to get initial pos/vel") pos_gcrs_ip, vel_gcrs_ip = interpolation.interpolate_with_derivative( times, np.transpose(pos_gcrs), np.array([0.0]), kind="lagrange", window=10, bounds_error=False ) eph["initial_pos"] = pos_gcrs_ip[0] eph["initial_vel"] = vel_gcrs_ip[0] return eph
def site_pos(dset): """Calculate the partial derivative of the site position for each station Args: data: A Dataset containing model data. Returns: Tuple: Array of partial derivatives, list of their names, and their unit """ # Remove stations that should be fixed stations = np.asarray(dset.unique("station")) fix_stations = config.tech[PARAMETER].fix_stations.list fix_idx = np.in1d(stations, fix_stations) if fix_idx.any(): stations = stations[np.logical_not(fix_idx)] # Calculate partials all_partials = -dset.src_dir.unit_vector[:, None, :] @ rotation.trs2gcrs(dset.time) partials = np.zeros((dset.num_obs, len(stations) * 3)) for idx, station in enumerate(stations): filter_1 = dset.filter(station_1=station) partials[filter_1, idx * 3 : idx * 3 + 3] = all_partials[filter_1][:, 0] * -1 filter_2 = dset.filter(station_2=station) partials[filter_2, idx * 3 : idx * 3 + 3] = all_partials[filter_2][:, 0] column_names = [s + "_" + xyz for s in stations for xyz in "xyz"] return partials, column_names, "dimensionless"
def t2g_pos(trs: "TrsPosition", time: "Time" = None) -> "GcrsPosition": """Transforms input array from trs to gcrs coordinates""" if time is None: time = trs.time if time is None: raise mg_exceptions.InitializationError("Time is not defined") trs = np.asarray(trs)[:, :, None] return (rotation.trs2gcrs(time) @ trs)[:, :, 0]
def t2g_posvel(trs: "TrsPosVel", time: "Time" = None) -> "GcrsPosVel": """Transforms input array from trs to gcrs coordinates""" if time is None: time = trs.time if time is None: raise mg_exceptions.InitializationError("Time is not defined") trs = nputil.col(trs) t2g = rotation.trs2gcrs(time) dt2g = rotation.dtrs2gcrs_dt(time) transformation = np.block([[t2g, np.zeros(t2g.shape)], [dt2g, t2g]]) return _matmul(transformation, trs)
def t2g_posvel(trs: "TrsPosVel", time: "Time" = None) -> "GcrsPosVel": """Transforms input array from trs to gcrs coordinates""" if time is None: time = trs.time if time is None: raise mg_exceptions.InitializationError("Time is not defined") trs = np.asarray(trs)[:, :, None] t2g = rotation.trs2gcrs(time) dt2g = rotation.dtrs2gcrs_dt(time) # Form block diagonal matrix with shape (num_obs, 6, 6) transformation = np.block([[t2g, np.zeros(t2g.shape)], [np.zeros(dt2g.shape), dt2g]]) return (transformation @ trs)[:, :, 0]
def site_pos(dset): """Calculate the partial derivative of the site position for each station Args: data: A Dataset containing model data. Returns: Tuple: Array of partial derivatives, list of their names, and their unit """ # Remove stations that should be fixed stations = np.asarray(dset.unique("station")) fix_stations = config.tech[PARAMETER].fix_stations.list if fix_stations: log.info(f"Not estimating stations {fix_stations}") # Remove stations with less than 10 observations stations_few_obs = [] for station in stations: number_of_observations = np.sum(dset.filter(station=station)) if number_of_observations < 10: stations_few_obs.append(station) fix_stations += stations_few_obs if stations_few_obs: log.info( f"Not estimating stations {stations_few_obs}, less than 10 observations" ) fix_idx = np.in1d(stations, fix_stations) if fix_idx.any(): stations = stations[np.logical_not(fix_idx)] reflect_time = dset.time + TimeDelta( dset.time_bias + dset.up_leg, fmt="seconds", scale="utc") i2g = rotation.trs2gcrs(reflect_time) site_pos_reflect_time = (i2g @ dset.site_pos.val[:, :, None])[:, :, 0] unit_vector = dset.sat_pos.pos.val[:] - site_pos_reflect_time[:] unit_vector = unit_vector / np.linalg.norm(unit_vector) # Calculate partials all_partials = -unit_vector[:, None, :] @ i2g partials = np.zeros((dset.num_obs, len(stations) * 3)) for idx, station in enumerate(stations): filter_1 = dset.filter(station=station) partials[filter_1, idx * 3:idx * 3 + 3] = all_partials[filter_1][:, 0] column_names = [s + "_" + xyz for s in stations for xyz in "xyz"] return partials, column_names, "dimensionless"
def calculate_initial_values(eph, rundate): """Computing initial values for position and velocity in GCRS system This is for later use in orbit integration, from tables in the prediction files. Use a lagrange polynomial in order to interpolate in the tables. Args: eph: Dict containing ephemeris information Returns: eph: Dict where the initial position and velocity is added """ data = sorted(eph["positions"].items()) pos_itrs = np.zeros((len(data), 3)) mjd1, mjd2 = zip(*[t for t, d in data]) rotation_mat = rotation.trs2gcrs( time.Time(val=mjd1, val2=mjd2, fmt="mjd", scale="utc")) tbl = time.Time(val=mjd1, val2=mjd2, fmt="mjd", scale="utc") for i in range(0, len(data)): pos_itrs[i] = data[i][1]["pos"] diffsec = np.array([(t - rundate).total_seconds() for t in tbl.utc.datetime]) # Table given in ITRF coordinate system. Convert to GCRS, where the integration of the satellite orbit will # be done pos_gcrs = np.sum(rotation_mat @ pos_itrs[:, :, None], axis=2) log.info( "Interpolating data from prediction file in order to get initial pos/vel" ) pos_gcrs_ip, vel_gcrs_ip = interpolation.interpolate_with_derivative( diffsec, pos_gcrs, np.array([0.0]), kind="lagrange", window=10, bounds_error=False) eph["initial_pos"] = pos_gcrs_ip[0] eph["initial_vel"] = vel_gcrs_ip[0] return eph
def calculate(stage, dset): """ Integrate differential equation of motion of the satellite Args: stage: Name of current stage dset: Dataset containing the data """ iterations = config.tech.iterations.int # Run models adjusting station positions site.calculate_site("site", dset) delta_pos = site.add("site", dset) dset.site_pos[:] = (dset.site_pos.gcrs + delta_pos[0].gcrs).trs dset.add_float("obs", val=dset.time_of_flight * constant.c / 2, unit="meter") dset.add_float("calc", np.zeros(dset.num_obs), unit="meter") dset.add_float("residual", np.zeros(dset.num_obs), unit="meter") dset.add_float("up_leg", np.zeros(dset.num_obs), unit="second") dset.add_posvel("sat_pos", np.zeros((dset.num_obs, 6)), system="gcrs", time=dset.time) arc_length = config.tech.arc_length.float dset.site_pos.other = dset.sat_pos # First guess for up_leg: dset.up_leg[:] = dset.time_of_flight / 2 for iter_num in itertools.count(start=1): log.blank() log.info(f"Calculating model corrections for iteration {iter_num}") sat_time_list = dset.obs_time + dset.time_bias + dset.up_leg apriori_orbit_provider = config.tech.apriori_orbit.str sat_name = dset.vars["sat_name"] rundate = dset.analysis["rundate"] if apriori_orbit_provider: version = config.tech.apriori_orbit_version.str log.info( f"Using external orbits from {apriori_orbit_provider}, version {version}" ) apriori_orbit = apriori.get( "orbit", rundate=rundate + timedelta(days=arc_length), time=None, day_offset=6, satellite=sat_name, apriori_orbit="slr", file_key="slr_external_orbits", ) dset_external = apriori_orbit._read(dset, apriori_orbit_provider, version) sat_pos = dset_external.sat_pos.gcrs_pos t_sec = TimeDelta( dset_external.time - Time(datetime(rundate.year, rundate.month, rundate.day), scale="utc", fmt="datetime"), fmt="seconds", ) t_sec = t_sec.value else: sat_pos, sat_vel, t_sec = orbit.calculate_orbit( datetime(rundate.year, rundate.month, rundate.day), sat_name, sat_time_list, return_full_table=True) sat_pos_ip, sat_vel_ip = interpolation.interpolate_with_derivative( np.array(t_sec), sat_pos, sat_time_list, kind="interpolated_univariate_spline") dset.sat_pos.gcrs[:] = np.concatenate((sat_pos_ip, sat_vel_ip), axis=1) delay.calculate_delay("kinematic_models", dset) # We observe the time when an observation is done, and the time of flight of the laser pulse. We estimate # the up-leg time with Newton's method applied to the equation (8.84) of :cite:'beutler2005' Gerhard Beutler: # Methods of Celestial Mechanics, Vol I., 2005. for j in range(0, 4): reflect_time = dset.time + TimeDelta( dset.time_bias + dset.up_leg, fmt="seconds", scale="utc") site_pos_reflect_time = (rotation.trs2gcrs(reflect_time) @ dset.site_pos.trs.val[:, :, None])[:, :, 0] sta_sat_vector = dset.sat_pos.gcrs.pos.val - site_pos_reflect_time unit_vector = sta_sat_vector / np.linalg.norm(sta_sat_vector, axis=1)[:, None] rho12 = (np.linalg.norm(sta_sat_vector, axis=1) + delay.add("kinematic_models", dset)) / constant.c correction = (-dset.up_leg + rho12) / ( np.ones(dset.num_obs) - np.sum( unit_vector / constant.c * dset.sat_pos.vel.val, axis=1)) dset.up_leg[:] += correction sat_time_list = dset.obs_time + dset.time_bias + dset.up_leg sat_pos_ip, sat_vel_ip = interpolation.interpolate_with_derivative( np.array(t_sec), sat_pos, sat_time_list, kind="interpolated_univariate_spline") dset.sat_pos.gcrs[:] = np.concatenate((sat_pos_ip, sat_vel_ip), axis=1) delay.calculate_delay("satellite_models", dset) dset.calc[:] = delay.add("satellite_models", dset) dset.residual[:] = dset.obs - dset.calc log.info( f"{dset.num_obs} observations, residual = {dset.rms('residual'):.4f}" ) if not apriori_orbit_provider: orbit.update_orbit(sat_name, dset.site_pos.gcrs, dset.sat_pos.pos, dset.sat_pos.vel, dset.residual, dset.bin_rms) dset.write_as(stage=stage, label=iter_num, sat_name=sat_name) if iter_num >= iterations: break