Note
Generated by nbsphinx from a Jupyter notebook. All the examples as Jupyter notebooks are available in the tudatpy-examples repo.
MRO - Comparing Doppler and Range Measurements from TNF Files to Simulated Observables#
Copyright (c) 2010-2022, Delft University of Technology. All rights reserved. This file is part of the Tudat. Redistribution and use in source and binary forms, with or without modification, are permitted exclusively under the terms of the Modified BSD license.
Important Preliminary Remarks#
Running this example automatically downloads required files if not found locally:
Trajectory and orientation kernels for MRO
Atmospheric correction files
TNF files with Doppler measurements
etc.
First run may take ~1 hour depending on internet connection. Files are cached locally for subsequent runs.
[1]:
# Load required standard modules
import multiprocessing as mp
import os
import shutil
import numpy as np
from matplotlib import pyplot as plt
from datetime import datetime
from urllib.request import urlretrieve
[2]:
# Load required tudatpy modules
from tudatpy.interface import spice
from tudatpy.math import interpolators
from tudatpy.astro import time_representation
from tudatpy import util
from tudatpy.data.processTrk234 import Trk234Processor
from tudatpy.dynamics import environment_setup
from tudatpy import estimation
from tudatpy.estimation import observable_models_setup
from tudatpy.estimation import observations, observations_setup
from load_pds_files import download_url_files_time, download_url_files_time_interval
Helper Functions#
1. File Retrieval Function#
This function retrieves all relevant files necessary to run the example over the time interval of interest (and automatically downloads them if they cannot be found locally). It returns a tuple containing the lists of relevant clock files, orientation kernels, tropospheric correction files, ionospheric correction files, odf files, trajectory files, MRO reference frames file, and MRO structure file that should be loaded.
[3]:
def get_mro_files(local_path, start_date, end_date):
"""
Retrieve and download all necessary MRO files for the specified time interval.
Returns: tuple of (clock_files, orientation_files, tro_files, ion_files,
tnf_files, trajectory_files, frames_def_file, structure_file)
"""
# Check if local_path designates an existing directory and creates the directory is not
if not os.path.isdir(local_path):
os.mkdir(local_path)
# Clock file (a single file is necessary)
print("---------------------------------------------")
print("Download MRO clock ")
clock_files = ["mro_sclkscet_00112_65536.tsc"]
# Define url where clock files can be downloaded for MRO
url_clock_files = "https://naif.jpl.nasa.gov/pub/naif/pds/data/mro-m-spice-6-v1.0/mrosp_1000/data/sclk/"
for file in clock_files:
# Check if the relevant clock file exists locally
if os.path.exists(local_path + file) == False:
print("download", local_path + file)
# If not, download it
urlretrieve(url_clock_files + file, local_path + file)
# Print and store all relevant clock file names
print("relevant clock files")
for k in range(len(clock_files)):
clock_files[k] = local_path + clock_files[k]
print(clock_files[k])
# Orientation files (multiple orientation kerneks are required, typically covering intervals of a few days)
# For this MRO example, orientation kernels should be loaded both for the spacecraft and for the MRO antenna specifically.
print("---------------------------------------------")
print("Download MRO orientation kernels")
# Define url where orientation kernels can be downloaded for MRO
url_orientation_files = "https://naif.jpl.nasa.gov/pub/naif/pds/data/mro-m-spice-6-v1.0/mrosp_1000/data/ck/"
# Retrieve the names of all spacecraft orientation kernels required to cover the time interval of interest, and download them if they
# do not exist locally yet.
orientation_files = download_url_files_time_interval(
local_path=local_path,
filename_format="mro_sc_psp_*.bc",
start_date=start_date,
end_date=end_date,
url=url_orientation_files,
time_interval_format="%y%m%d_%y%m%d",
)
# Retrieve the names of all antenna orientation kernels required to cover the time interval of interest, and download them if they
# do not exist locally yet
antenna_files = download_url_files_time_interval(
local_path=local_path,
filename_format="mro_hga_psp_*.bc",
start_date=start_date,
end_date=end_date,
url=url_orientation_files,
time_interval_format="%y%m%d_%y%m%d",
)
# Print and store all relevant orientation file names (both for the MRO spacecraft and antenna)
for file in antenna_files:
orientation_files.append(file)
print("relevant orientation files")
for f in orientation_files:
print(f)
# Tropospheric corrections (multiple tropospheric correction files are required, typically covering intervals of a few days)
print("---------------------------------------------")
print("Download MRO tropospheric corrections files")
# Define url where tropospheric correction files can be downloaded for MRO
url_tro_files = "https://pds-geosciences.wustl.edu/mro/mro-m-rss-1-magr-v1/mrors_0xxx/ancillary/tro/"
# Retrieve the names of all tropospheric correction files required to cover the time interval of interest, and download them if they
# do not exist locally yet
tro_files = download_url_files_time_interval(
local_path=local_path,
filename_format="mromagr*.tro",
start_date=start_date,
end_date=end_date,
url=url_tro_files,
time_interval_format="%Y_%j_%Y_%j",
)
# Print all relevant tropospheric correction file names
print("relevant tropospheric corrections files")
for f in tro_files:
print(f)
# Ionospheric corrections (multiple ionospheric correction files are required, typically covering intervals of a few days)
print("---------------------------------------------")
print("Download MRO ionospheric corrections files")
# Define url where ionospheric correction files can be downloaded for MRO
url_ion_files = "https://pds-geosciences.wustl.edu/mro/mro-m-rss-1-magr-v1/mrors_0xxx/ancillary/ion/"
# Retrieve the names of all ionospheric correction files required to cover the time interval of interest, and download them if they do not exist locally yet
ion_files = download_url_files_time_interval(
local_path=local_path,
filename_format="mromagr*.ion",
start_date=start_date,
end_date=end_date,
url=url_ion_files,
time_interval_format="%Y_%j_%Y_%j",
)
# Print all relevant ionospheric correction file names
print("relevant ionospheric corrections files")
for f in ion_files:
print(f)
# TNF files (multiple TNF files are required, typically one per day)
print("---------------------------------------------")
print("Download MRO TNF files")
# Define url where TNF files can be downloaded for MRO
url_odf = (
"https://pds-geosciences.wustl.edu/mro/mro-m-rss-1-magr-v1/mrors_0xxx/tnf/"
)
# Retrieve the names of all existing TNF files within the time interval of interest, and download them if they do not exist locally yet
tnf_files = download_url_files_time(
local_path=local_path,
filename_format="mromagr*_\w\w\w\wxmmmv1.tnf",
start_date=start_date,
end_date=end_date,
url=url_odf,
time_format="%Y_%j",
indices_date_filename=[7],
)
# Print the name of all relevant TNF files that have been identified over the time interval of interest
print("relevant TNF files")
for f in tnf_files:
print(f)
# MRO trajectory files (multiple files are necessary to cover one entire year, typically each file covers ~ 3-4 months)
# Note that the file names hard coded below cover calendar year 2012. This should be modified in case the time interval
# of the example is modified.
print("---------------------------------------------")
print("Download MRO trajectory files")
trajectory_files = [
"mro_psp21.bsp",
"mro_psp22.bsp",
"mro_psp23.bsp",
"mro_psp24.bsp",
"mro_psp25.bsp",
]
# Define url where trajectory files can be downloaded for MRO
url_trajectory_files = "https://naif.jpl.nasa.gov/pub/naif/pds/data/mro-m-spice-6-v1.0/mrosp_1000/data/spk/"
for file in trajectory_files:
# Check if the relevant trajectory file exists locally
if os.path.exists(local_path + file) == False:
print("download", local_path + file)
# If not, download it
urlretrieve(url_trajectory_files + file, local_path + file)
# Print and store all relevant trajectory file names
print("relevant trajectory files")
for k in range(len(trajectory_files)):
trajectory_files[k] = local_path + trajectory_files[k]
print(trajectory_files[k])
# Frames definition file for the MRO spacecraft (only one file is necessary). This is useful for HGA and
# spacecraft-fixed frames definition.
print("---------------------------------------------")
print("Download MRO frames definition file")
frames_def_file = "mro_v16.tf"
# Define url where the frames definition file can be downloaded for MRO
url_frames_def_file = "https://naif.jpl.nasa.gov/pub/naif/pds/data/mro-m-spice-6-v1.0/mrosp_1000/data/fk/"
# Check if the relevant frames definition file exists locally
if os.path.exists(local_path + frames_def_file) == False:
print("download", local_path + frames_def_file)
# If not, download it
urlretrieve(url_frames_def_file + frames_def_file, local_path + frames_def_file)
# Print and store the frames definition file name
print("relevant MRO frames definition file")
frames_def_file = local_path + frames_def_file
print(frames_def_file)
# Structure file for the MRO spacecraft (only one file is necessary). This is useful to retrieve the antenna
# position in spacecraft-fixed frame.
print("---------------------------------------------")
print("Download MRO structure file")
structure_file = "mro_struct_v10.bsp"
# Define url where the MRO structure file can be downloaded
url_structure_file = "https://naif.jpl.nasa.gov/pub/naif/pds/data/mro-m-spice-6-v1.0/mrosp_1000/data/spk/"
# Check if the relevant structure file exists locally
if os.path.exists(local_path + structure_file) == False:
print("download", local_path + structure_file)
# If not, download it
urlretrieve(url_structure_file + structure_file, local_path + structure_file)
# Print and store the structure file name
print("relevant MRO structure file")
structure_file = local_path + structure_file
print(structure_file)
# Return filenames lists for clock files, orientation kernels, tropospheric and ionospheric corrections, odf files,
# trajectory files, MRO reference frames file, and MRO structure file.
return (
clock_files,
orientation_files,
tro_files,
ion_files,
tnf_files,
trajectory_files,
frames_def_file,
structure_file,
)
2. Residuals Analysis Function#
This function performs Doppler and range residual analysis for the MRO spacecraft by adopting the following approach:
Step 1: Load SPICE kernels and data files
Standard SPICE kernels (planetary ephemerides, leap seconds, etc.)
MRO-specific orientation kernels (spacecraft and antenna attitude)
Clock correlation files
Trajectory files (spacecraft ephemeris)
Reference frames and structure files
Step 2: Create the dynamical environment
Set up celestial bodies (Earth, Sun, Mars, etc.) with appropriate models
Configure Earth with oblate spherical shape, high-precision rotation model (IAU 2006), and DSN ground stations
Create MRO spacecraft with translational and rotational ephemerides from SPICE
Step 3: Load and pre-process TNF observations
Load Doppler and range measurements from TNF files
Filter out observations on dates with incomplete orientation kernel coverage
Split observation sets at discontinuities in kernel coverage
Compress Doppler observations from 1-second to 60-second integration time
Set transponder delay for MRO
Step 4: Set antenna as reference point
Account for offset between MRO center-of-mass and spacecraft-fixed frame origin
Create tabulated ephemeris for the antenna position relative to center-of-mass
Set antenna as the reference point for all link ends (crucial for accurate Doppler modeling)
Step 5: Define observation model settings
Configure light-time corrections:
Second-order relativistic effects (Sun)
Tropospheric corrections (from tabulated files)
Ionospheric corrections (from tabulated files)
Solar corona corrections (for range only, based on MEX 2011 data)
Create observation simulators for both Doppler and range observables
Add dependent variables: elevation angle and Sun-Earth-Probe (SEP) angle
Step 6: Compute residuals and save results
Simulate synthetic observables using the observation models
Compute residuals as the difference between real (TNF) and simulated observations
Filter outliers (residuals > 0.1 Hz for Doppler, > 40 RU for range)
Save various outputs: residuals, RMS/mean statistics, time bounds, elevation/SEP angles, range conversion factors
For the first run (index 0), save detailed first-day results for visualization
Input arguments:
The inputs variable is a list with eleven entries:
Index of the current run (for parallel execution)
Start date of the time interval
End date of the time interval
List of TNF files to load
List of clock files to load
List of orientation kernels to load
List of tropospheric correction files to load
List of ionospheric correction files to load
List of MRO trajectory files to load
MRO reference frames definition file to load
MRO structure file to load
[4]:
def perform_residuals_analysis(inputs):
"""
Perform residuals analysis for MRO Doppler and range observations.
Args:
inputs: list containing [index, start_date, end_date, tnf_files, clock_files,
orientation_files, tro_files, ion_files, trajectory_files,
frames_def_file, structure_file]
"""
# Unpack various input arguments
input_index = inputs[0]
# Convert start and end datetime objects to Tudat Time variables. A time buffer of one day is subtracted/added to the start/end date
# to ensure that the simulation environment covers the full time span of the loaded TNF files. This is mostly needed because some TNF
# files - while typically assigned to a certain date - actually spans over (slightly) longer than one day. Without this time buffer,
# some observation epochs might thus lie outside the time boundaries within which the dynamical environment is defined.
start_time = time_representation.DateTime.from_python_datetime(inputs[1]).to_epoch() - 86400.0
end_time = time_representation.DateTime.from_python_datetime(inputs[2]).to_epoch() + 86400.0
# Retrieve lists of relevant kernels and input files to load (TNF files, clock and orientation kernels,
# tropospheric and ionospheric corrections)
tnf_files = inputs[3]
clock_files = inputs[4]
orientation_files = inputs[5]
tro_files = inputs[6]
ion_files = inputs[7]
trajectory_files = inputs[8]
frames_def_file = inputs[9]
structure_file = inputs[10]
# Redirect the outputs of this run to a file names mro_estimation_output_x.dat, with x the run index
with util.redirect_std(
"outputs/mro_estimation_output_" + str(input_index) + ".dat", True, True
):
print("input_index", input_index)
filename_suffix = str(input_index) + ""
### ------------------------------------------------------------------------------------------
### LOAD ALL REQUESTED KERNELS AND FILES
### ------------------------------------------------------------------------------------------
spice.load_standard_kernels()
# Load MRO orientation kernels (over the entire relevant time period).
# Note: each orientation kernel covers a certain time interval, usually spanning over a few days.
# It must be noted, however, that some dates are not entirely covered, i.e., there is no orientation information available over
# some short periods of time. This typically happens on dates coinciding with the transition from one orientation file to the
# next one. As will be shown later in the examples, this requires the user to manually specify which dates should be overlooked,
# and to filter out observations that were recorded on such dates.
for orientation_file in orientation_files:
spice.load_kernel(orientation_file)
# Load MRO clock files
for clock_file in clock_files:
spice.load_kernel(clock_file)
# Load MRO frame definition file (useful for HGA and spacecraft-fixed frames definition)
spice.load_kernel(frames_def_file)
# Load MRO trajectory kernels
for trajectory_file in trajectory_files:
spice.load_kernel(trajectory_file)
# Load MRO spacecraft structure file (for antenna position in spacecraft-fixed frame)
spice.load_kernel(structure_file)
### ------------------------------------------------------------------------------------------
### CREATE DYNAMICAL ENVIRONMENT
### ------------------------------------------------------------------------------------------
# Create default body settings for celestial bodies
bodies_to_create = [
"Earth",
"Sun",
"Mercury",
"Venus",
"Mars",
"Jupiter",
"Saturn",
"Moon",
]
global_frame_origin = "SSB"
global_frame_orientation = "J2000"
body_settings = environment_setup.get_default_body_settings_time_limited(
bodies_to_create,
start_time,
end_time,
global_frame_origin,
global_frame_orientation,
)
# Modify Earth default settings
body_settings.get("Earth").shape_settings = (
environment_setup.shape.oblate_spherical_spice()
)
body_settings.get("Earth").rotation_model_settings = (
environment_setup.rotation_model.gcrs_to_itrs(
environment_setup.rotation_model.iau_2006,
global_frame_orientation,
interpolators.interpolator_generation_settings(
interpolators.cubic_spline_interpolation(),
start_time,
end_time,
3600.0,
),
interpolators.interpolator_generation_settings(
interpolators.cubic_spline_interpolation(),
start_time,
end_time,
3600.0,
),
interpolators.interpolator_generation_settings(
interpolators.cubic_spline_interpolation(),
start_time,
end_time,
60.0,
),
)
)
body_settings.get("Earth").gravity_field_settings.associated_reference_frame = (
"ITRS"
)
body_settings.get("Earth").ground_station_settings = (
environment_setup.ground_station.dsn_stations()
)
# Create empty settings for the MRO spacecraft
spacecraft_name = "MRO"
spacecraft_central_body = "Mars"
body_settings.add_empty_settings(spacecraft_name)
# Retrieve translational ephemeris from SPICE
body_settings.get(spacecraft_name).ephemeris_settings = (
environment_setup.ephemeris.interpolated_spice(
start_time,
end_time,
10.0,
spacecraft_central_body,
global_frame_orientation,
)
)
# Retrieve rotational ephemeris from SPICE
body_settings.get(spacecraft_name).rotation_model_settings = (
environment_setup.rotation_model.spice(
global_frame_orientation, spacecraft_name + "_SPACECRAFT", ""
)
)
# Create environment
bodies = environment_setup.create_system_of_bodies(body_settings)
### ------------------------------------------------------------------------------------------
### LOAD TNF OBSERVATIONS AND PERFORM PRE-PROCESSING STEPS
### ------------------------------------------------------------------------------------------
# Create observation collection from TNF files, only retaining Doppler and sequential range observations. An observation collection contains
# multiple "observation sets". Within a given observation set, the observables are of the same type (here Doppler and range) and defined from the same link ends.
# However, within the "global" observation collection, multiple observation sets can typically be found for a given observable type and link ends, but they
# will cover different observation time intervals. When loading TNF data, a separate observation set is created for each TNF file (which means the time intervals of each
# set match those of the corresponding TNF file).
# Dates to filter out because of incomplete spacecraft orientation kernels (see note when loading orientation kernels on line 168)
dates_to_filter = [
time_representation.DateTime(2012, 10, 15, 0, 0, 0.0),
time_representation.DateTime(2012, 10, 30, 0, 0, 0),
time_representation.DateTime(2012, 11, 6, 0, 0, 0),
time_representation.DateTime(2012, 11, 7, 0, 0, 0),
]
# Remove latest TNF file.
# This step is necessary because some TNF observation sets - although time-tagged to a specific date - might spill over the next day.
# For the latest TNF data set, this might imply stepping outside the time interval that the loaded spice kernels cover.
tnf_files = tnf_files[:-1]
tnfProcessor = Trk234Processor(
tnf_files, ["doppler", "range"], spacecraft_name="MRO"
)
original_odf_observations = tnfProcessor.process()
tnfProcessor.set_tnf_information_in_bodies(bodies)
# Filter out observations on dates when orientation kernels are incomplete
dates_to_filter_float = []
for date in dates_to_filter:
dates_to_filter_float.append(date.to_epoch())
# Create filter object for specific date
date_filter = observations.observations_processing.observation_filter(
observations.observations_processing.ObservationFilterType.time_bounds_filtering,
date.to_epoch() - 3600.0,
time_representation.add_days_to_datetime(date, 1.0).to_epoch() + 0.0,
)
# Filter out observations from observation collection
original_odf_observations.filter_observations(date_filter)
# Remove empty observation sets, if there is any once the filtering is completed
original_odf_observations.remove_empty_observation_sets()
# Split observation sets at dates when orientation kernels are incomplete.
# While all problematic observation epochs have already been filtered out in the previous step, the splitting is still necessary
# to ensure that the time span of each observation set is fully covered by the available kernels. Without this additional step,
# one could not parse from the lower to upper time bounds of a given observation set without risking accessing unavailable information from spice.
# This step only becomes relevant when retrieving the position of the MRO antenna over the observation time intervals, as will be done later in the example.
date_splitter = observations.observations_processing.observation_set_splitter(
observations.observations_processing.ObservationSetSplitterType.time_tags_splitter,
dates_to_filter_float,
)
original_odf_observations.split_observation_sets(date_splitter)
# Remove empty observation sets, if there is any once both the splitting is completed
original_odf_observations.remove_empty_observation_sets()
print("original_odf_observations")
original_odf_observations.print_observation_sets_start_and_size()
# Compress Doppler observations from 1.0 s integration time to 60.0 s
compressed_observations = observations_setup.observations_wrapper.create_compressed_doppler_collection(
original_odf_observations, 60, 10
)
print("Compressed observations: ")
print(compressed_observations.concatenated_observations.size)
# Add transpondr delay
compressed_observations.set_transponder_delay("MRO", 1.4149e-6)
### ------------------------------------------------------------------------------------------
### SET ANTENNA AS REFERENCE POINT FOR DOPPLER OBSERVATIONS
### ------------------------------------------------------------------------------------------
# Define MRO center-of-mass (COM) position w.r.t. the origin of the MRO-fixed reference frame (frame spice ID: MRO_SPACECRAFT)
# This value was taken from Konopliv et al. (2011) doi:10.1016/j.icarus.2010.10.004
# This is necessary to define the position of the antenna w.r.t. the COM, in the MRO-fixed frame (see below)
com_position = np.array([0.0, -1.11, 0.0])
# In the following lines, we create a tabulated history of the position of the MRO antenna with respect to the COM, in the MRO-fixed frame
# (MRO_SPACECRAFT). This will be used to create a tabulated ephemeris for the antenna, necessary to correct for the position of the spacecraft's
# reference point (antenna) when computing the Doppler observables.
# This (manual) extra step is required to account for the offset between the COM and the origin of the MRO-fixed frame, as using spice kernels directly
# would only provide the antenna position w.r.t. the origin of the MRO-fixed frame (no information on the COM position).
antenna_position_history = dict()
# Parsing the observation times in all observation sets.
# Note: we use a time buffer of one hour with respect to the start and end times of each observation set.
# This is to ensure that the antenna position history spans over a slightly extended time interval than the observation epochs
# of the given set. When simulating Doppler data to compute the MRO residuals, we might indeed need to access the antenna position
# slightly outside the exact time bounds defined by the observation epochs because of the light-time delay.
for obs_times in compressed_observations.get_observation_times_objects():
time = obs_times[0].to_float() - 3600.0
while time <= obs_times[-1].to_float() + 3600.0:
state = np.zeros((6, 1))
# For each observation epoch, retrieve the antenna position (spice ID "-74214") w.r.t. the origin of the MRO-fixed frame (spice ID "-74000")
state[:3, 0] = spice.get_body_cartesian_position_at_epoch(
"-74214", "-74000", "MRO_SPACECRAFT", "none", time
)
# Translate the antenna position to account for the offset between the origin of the MRO-fixed frame and the COM
state[:3, 0] = state[:3, 0] - com_position
# Store antenna position w.r.t. COM in the MRO-fixed frame
antenna_position_history[time] = state
time += 60.0
# Create tabulated ephemeris settings from antenna position history
antenna_ephemeris_settings = environment_setup.ephemeris.tabulated(
antenna_position_history, "-74000", "MRO_SPACECRAFT"
)
# Create tabulated ephemeris for the MRO antenna
antenna_ephemeris = environment_setup.ephemeris.create_ephemeris(
antenna_ephemeris_settings, "Antenna"
)
# Set the spacecraft's reference point position to that of the antenna (in the MRO-fixed frame)
compressed_observations.set_reference_point(
bodies,
antenna_ephemeris,
"Antenna",
"MRO",
observable_models_setup.links.LinkEndType.reflector1,
)
### ------------------------------------------------------------------------------------------
### DEFINE SETTINGS TO SIMULATE OBSERVATIONS AND COMPUTE RESIDUALS
### ------------------------------------------------------------------------------------------
# Create light-time corrections list
light_time_correction_list = list()
light_time_correction_list.append(
observable_models_setup.light_time_corrections.approximated_second_order_relativistic_light_time_correction(
["Sun"]
)
)
# Add tropospheric correction
light_time_correction_list.append(
observable_models_setup.light_time_corrections.dsn_tabulated_tropospheric_light_time_correction(
tro_files
)
)
# Add ionospheric correction
spacecraft_name_per_id = dict()
spacecraft_name_per_id[74] = "MRO"
light_time_correction_list.append(
observable_models_setup.light_time_corrections.dsn_tabulated_ionospheric_light_time_correction(
ion_files, spacecraft_name_per_id
)
)
# Create observation model settings for the Doppler observables. This first implies creating the link ends defining all relevant
# tracking links between various ground stations and the MRO spacecraft. The list of light-time corrections defined above is then
# added to each of these link ends.
doppler_link_ends = compressed_observations.link_definitions_per_observable[
estimation.observable_models_setup.model_settings.dsn_n_way_averaged_doppler_type
]
observation_model_settings = list()
for current_link_definition in doppler_link_ends:
observation_model_settings.append(
observable_models_setup.model_settings.dsn_n_way_doppler_averaged(
current_link_definition, light_time_correction_list
)
)
# Add solar corona correction only for range observables.
# Values form Verma et al. (2013), from MEX 2011 solar conjunction data
light_time_correction_list.append(
observable_models_setup.light_time_corrections.inverse_power_series_solar_corona_light_time_correction(
[1.70e12],
[2.44],
)
)
# Create observation model settings for the range observables (similar to the Doppler observables).
range_link_ends = compressed_observations.link_definitions_per_observable[
estimation.observable_models_setup.model_settings.dsn_n_way_range_type
]
for current_link_definition in range_link_ends:
observation_model_settings.append(
observable_models_setup.model_settings.dsn_n_way_range(
current_link_definition, light_time_correction_list
)
)
# Create observation simulators.
observation_simulators = observations_setup.observations_simulation_settings.create_observation_simulators(
observation_model_settings, bodies
)
# Add elevation and SEP angles dependent variables to the compressed observation collection
elevation_angle_settings = observations_setup.observations_dependent_variables.elevation_angle_dependent_variable(
observable_models_setup.links.LinkEndType.receiver
)
elevation_angle_parser = compressed_observations.add_dependent_variable(
elevation_angle_settings
)
sep_angle_settings = observations_setup.observations_dependent_variables.avoidance_angle_dependent_variable(
"Sun",
observable_models_setup.links.LinkEndType.retransmitter,
observable_models_setup.links.LinkEndType.receiver,
)
sep_angle_parser = compressed_observations.add_dependent_variable(
sep_angle_settings
)
# Compute and set residuals in the compressed observation collection
observations.compute_residuals_and_dependent_variables(
compressed_observations, observation_simulators, bodies
)
### ------------------------------------------------------------------------------------------
### RETRIEVE AND SAVE VARIOUS OBSERVATION OUTPUTS
### ------------------------------------------------------------------------------------------
for obsType, obsName in zip(
[
estimation.observable_models_setup.model_settings.dsn_n_way_range_type,
estimation.observable_models_setup.model_settings.dsn_n_way_averaged_doppler_type,
],
["range", "doppler"],
):
obsType_parser = observations.observations_processing.observation_parser(
obsType
)
parsed_observations = observations.create_new_observation_collection(
compressed_observations, obsType_parser
)
# Retrieve RMS and mean of the residuals, sorted per observation set
rms_residuals = parsed_observations.get_rms_residuals()
mean_residuals = parsed_observations.get_mean_residuals()
np.savetxt(
"outputs/mro_{}_unfiltered_residuals_rms_".format(obsName)
+ filename_suffix
+ ".dat",
np.vstack(rms_residuals),
delimiter=",",
)
np.savetxt(
"outputs/mro_{}_unfiltered_residuals_mean_".format(obsName)
+ filename_suffix
+ ".dat",
np.vstack(mean_residuals),
delimiter=",",
)
# Retrieve the time bounds of each observation set within the observation collection
time_bounds_per_set = (
parsed_observations.get_time_bounds_per_set_time_object(obsType_parser)
)
time_bounds_array = np.zeros((len(time_bounds_per_set), 2))
for j in range(len(time_bounds_per_set)):
time_bounds_array[j, 0] = time_bounds_per_set[j][0].to_float()
time_bounds_array[j, 1] = time_bounds_per_set[j][1].to_float()
# Save time bounds of the (unfiltered) observation sets
np.savetxt(
"outputs/mro_{}_unfiltered_time_bounds_".format(obsName)
+ filename_suffix
+ ".dat",
time_bounds_array,
delimiter=",",
)
# Filter out outliers (i.e.,
if obsName == "doppler":
threshold = 0.1 # residuals > 0.1 Hz
elif obsName == "range":
threshold = 40 # residuals > 40 RU
filter_residuals = observations.observations_processing.observation_filter(
observations.observations_processing.ObservationFilterType.residual_filtering,
threshold,
)
parsed_observations.filter_observations(filter_residuals, obsType_parser)
# Remove empty observation sets, if there is any once the filtering is performed
parsed_observations.remove_empty_observation_sets()
# Save unfiltered residuals, observation times and link end IDs.
np.savetxt(
"outputs/mro_{}_filtered_residuals_".format(obsName)
+ filename_suffix
+ ".dat",
parsed_observations.get_concatenated_residuals(),
delimiter=",",
)
np.savetxt(
"outputs/mro_{}_filtered_time_".format(obsName)
+ filename_suffix
+ ".dat",
parsed_observations.concatenated_times,
delimiter=",",
)
# Retrieve RMS and mean residuals after outliers filtering
rms_filtered_residuals = parsed_observations.get_rms_residuals()
mean_filtered_residuals = parsed_observations.get_mean_residuals()
# Save RMS and mean residuals
np.savetxt(
"outputs/mro_{}_filtered_residuals_rms_".format(obsName)
+ filename_suffix
+ ".dat",
np.vstack(rms_filtered_residuals),
delimiter=",",
)
np.savetxt(
"outputs/mro_{}_filtered_residuals_mean_".format(obsName)
+ filename_suffix
+ ".dat",
np.vstack(mean_filtered_residuals),
delimiter=",",
)
# Retrieve time bounds per observation set
time_bounds_per_filtered_set = (
parsed_observations.get_time_bounds_per_set_time_object()
)
time_bounds_filtered_array = np.zeros(
(len(time_bounds_per_filtered_set), 2)
)
for j in range(len(time_bounds_per_filtered_set)):
time_bounds_filtered_array[j, 0] = time_bounds_per_filtered_set[j][
0
].to_float()
time_bounds_filtered_array[j, 1] = time_bounds_per_filtered_set[j][
1
].to_float()
# Save time bounds of each observation set
np.savetxt(
"outputs/mro_{}_filtered_time_bounds_".format(obsName)
+ filename_suffix
+ ".dat",
time_bounds_filtered_array,
delimiter=",",
)
# Retrieve concatenated elevation angle dependent variables
concatenated_elevation_angles = (
parsed_observations.concatenated_dependent_variable(
elevation_angle_settings
)[0]
)
# Retrieve concatenated SEP angle dependent variables
concatenated_sep_angles = (
parsed_observations.concatenated_dependent_variable(sep_angle_settings)[
0
]
)
# Save elevation and SEP angles
np.savetxt(
"outputs/mro_{}_elevation_angles_".format(obsName)
+ filename_suffix
+ ".dat",
concatenated_elevation_angles,
delimiter=",",
)
np.savetxt(
"outputs/mro_{}_sep_angles_".format(obsName) + filename_suffix + ".dat",
concatenated_sep_angles,
delimiter=",",
)
# Retrieve range conversion factors (from RU to m) from observation ancillary settings
if obsName == "range":
single_obs_sets = parsed_observations.get_single_observation_sets()
rangeConversionFactors = []
for obs_set in single_obs_sets:
rangeConversionFactor = obs_set.ancillary_settings.get_float_settings(
observations_setup.ancillary_settings.range_conversion_factor,
)
rangeConversionFactors.append(rangeConversionFactor)
# This is needed because there are multiple range observation with the same
# time tag.
if obs_set.total_observation_set_size > 1:
rangeConversionFactors.append(rangeConversionFactor)
np.savetxt(
"outputs/mro_range_conversion_factors_" + filename_suffix + ".dat",
rangeConversionFactors,
delimiter=",",
)
if input_index == 0:
# Create observation parser to retrieve observation-related quantities over the first day of data
# (starting from the first observation epoch)
# first_day_parser = estimation.observation_parser((start_time + 2.0 * 86400.0, start_time + 3.0 * 86400.0))
start_obs_times = time_bounds_per_filtered_set[0][0].to_float()
first_day_parser = (
observations.observations_processing.observation_parser(
(start_obs_times, start_obs_times + 86400.0)
)
)
# Retrieve residuals, observation times and dependent variables over the first day
first_day_observation_times = (
parsed_observations.get_concatenated_observation_times(
first_day_parser
)
)
first_day_residuals = parsed_observations.get_concatenated_residuals(
first_day_parser
)
first_day_elevation_angles = (
parsed_observations.concatenated_dependent_variable(
elevation_angle_settings, observation_parser=first_day_parser
)[0]
)
first_day_link_ends_ids = (
parsed_observations.get_concatenated_link_definition_ids(
first_day_parser
)
)
# Save first day results
np.savetxt(
"outputs/mro_{}_first_day_residuals.dat".format(obsName),
first_day_residuals,
delimiter=",",
)
np.savetxt(
"outputs/mro_{}_first_day_times.dat".format(obsName),
first_day_observation_times,
delimiter=",",
)
np.savetxt(
"outputs/mro_{}_first_day_link_end_ids.dat".format(obsName),
first_day_link_ends_ids,
delimiter=",",
)
np.savetxt(
"outputs/mro_{}_first_day_elevation_angles.dat".format(obsName),
first_day_elevation_angles,
delimiter=",",
)
if obsName == "range":
first_day_range_conversion_factors = []
for obs_set in single_obs_sets:
rangeConversionFactor = obs_set.ancillary_settings.get_float_settings(
observations_setup.ancillary_settings.range_conversion_factor,
)
first_day_range_conversion_factors.append(rangeConversionFactor)
np.savetxt(
"outputs/mro_range_conversion_factors_first_day.dat",
first_day_range_conversion_factors,
delimiter=",",
)
3. Output Folder Setup Function#
Function to create the outputs directory if it doesn’t exist and clear its contents if it does.
[5]:
def setup_outputs_folder(folder_path):
"""Create outputs folder or clear it if it already exists."""
if not os.path.exists(folder_path):
os.makedirs(folder_path)
else:
# Check if the directory is empty
if os.listdir(folder_path):
# Remove all contents of the directory
for filename in os.listdir(folder_path):
file_path = os.path.join(folder_path, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
except Exception as e:
print(f"Failed to delete {file_path}. Reason: {e}")
Main Analysis#
Setup#
[6]:
inputs = []
# Setup the outputs folder
setup_outputs_folder("outputs")
# Specify the number of cores over which this example is to run
nb_cores = 6
# Define start and end dates for the six time intervals to be analysed in parallel computations.
# Each parallel run covers two months of data for the example to parse a total timespan of one year.
start_dates = [
datetime(2012, 1, 1),
datetime(2012, 3, 1),
datetime(2012, 5, 1),
datetime(2012, 7, 1),
datetime(2012, 9, 1),
datetime(2012, 11, 1),
]
end_dates = [
datetime(2012, 2, 29),
datetime(2012, 4, 30),
datetime(2012, 6, 30),
datetime(2012, 8, 31),
datetime(2012, 10, 31),
datetime(2012, 12, 31),
]
# For each parallel run
for i in range(nb_cores):
# First retrieve the names of all the relevant kernels and data files necessary to cover the specified time interval
(
clock_files,
orientation_files,
tro_files,
ion_files,
odf_files,
trajectory_files,
frames_def_file,
structure_file,
) = get_mro_files("mro_kernels/", start_dates[i], end_dates[i])
# Construct a list of input arguments containing the arguments needed this specific parallel run.
# These include the start and end dates, along with the names of all relevant kernels and data files that should be loaded
inputs.append(
[
i,
start_dates[i],
end_dates[i],
odf_files,
clock_files,
orientation_files,
tro_files,
ion_files,
trajectory_files,
frames_def_file,
structure_file,
]
)
---------------------------------------------
Download MRO clock
relevant clock files
mro_kernels/mro_sclkscet_00112_65536.tsc
---------------------------------------------
Download MRO orientation kernels
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
relevant orientation files
mro_kernels/mro_sc_psp_120131_120206.bc
mro_kernels/mro_sc_psp_120228_120305.bc
mro_kernels/mro_sc_psp_120103_120109.bc
mro_kernels/mro_sc_psp_120110_120116.bc
mro_kernels/mro_sc_psp_120207_120213.bc
mro_kernels/mro_sc_psp_120117_120123.bc
mro_kernels/mro_sc_psp_111227_120102.bc
mro_kernels/mro_sc_psp_120124_120130.bc
mro_kernels/mro_sc_psp_120214_120220.bc
mro_kernels/mro_sc_psp_120221_120227.bc
mro_kernels/mro_hga_psp_120117_120123.bc
mro_kernels/mro_hga_psp_120221_120227.bc
mro_kernels/mro_hga_psp_120228_120305.bc
mro_kernels/mro_hga_psp_120124_120130.bc
mro_kernels/mro_hga_psp_120207_120213.bc
mro_kernels/mro_hga_psp_120103_120109.bc
mro_kernels/mro_hga_psp_111227_120102.bc
mro_kernels/mro_hga_psp_120131_120206.bc
mro_kernels/mro_hga_psp_120214_120220.bc
mro_kernels/mro_hga_psp_120110_120116.bc
---------------------------------------------
Download MRO tropospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant tropospheric corrections files
mro_kernels/mromagr2012_001_2012_032.tro
mro_kernels/mromagr2012_032_2012_061.tro
mro_kernels/mromagr2011_335_2012_001.tro
---------------------------------------------
Download MRO ionospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant ionospheric corrections files
mro_kernels/mromagr2012_001_2012_032.ion
mro_kernels/mromagr2012_032_2012_061.ion
mro_kernels/mromagr2011_335_2012_001.ion
---------------------------------------------
Download MRO TNF files
nb existing files 328
relevant TNF files
mro_kernels/mromagr2012_001_2220xmmmv1.tnf
mro_kernels/mromagr2012_002_1426xmmmv1.tnf
mro_kernels/mromagr2012_003_1407xmmmv1.tnf
mro_kernels/mromagr2012_004_1550xmmmv1.tnf
mro_kernels/mromagr2012_005_1255xmmmv1.tnf
mro_kernels/mromagr2012_006_1355xmmmv1.tnf
mro_kernels/mromagr2012_007_1640xmmmv1.tnf
mro_kernels/mromagr2012_008_2200xmmmv1.tnf
mro_kernels/mromagr2012_009_0545xmmmv1.tnf
mro_kernels/mromagr2012_010_1345xmmmv1.tnf
mro_kernels/mromagr2012_011_1900xmmmv1.tnf
mro_kernels/mromagr2012_012_0620xmmmv1.tnf
mro_kernels/mromagr2012_013_1405xmmmv1.tnf
mro_kernels/mromagr2012_014_2250xmmmv1.tnf
mro_kernels/mromagr2012_016_0520xmmmv1.tnf
mro_kernels/mromagr2012_017_0520xmmmv1.tnf
mro_kernels/mromagr2012_018_2200xmmmv1.tnf
mro_kernels/mromagr2012_019_1230xmmmv1.tnf
mro_kernels/mromagr2012_020_1315xmmmv1.tnf
mro_kernels/mromagr2012_022_0505xmmmv1.tnf
mro_kernels/mromagr2012_023_1130xmmmv1.tnf
mro_kernels/mromagr2012_024_1326xmmmv1.tnf
mro_kernels/mromagr2012_025_1150xmmmv1.tnf
mro_kernels/mromagr2012_026_1251xmmmv1.tnf
mro_kernels/mromagr2012_027_1200xmmmv1.tnf
mro_kernels/mromagr2012_029_0055xmmmv1.tnf
mro_kernels/mromagr2012_030_1147xmmmv1.tnf
mro_kernels/mromagr2012_031_1217xmmmv1.tnf
mro_kernels/mromagr2012_032_1055xmmmv1.tnf
mro_kernels/mromagr2012_033_1400xmmmv1.tnf
mro_kernels/mromagr2012_034_1205xmmmv1.tnf
mro_kernels/mromagr2012_035_0505xmmmv1.tnf
mro_kernels/mromagr2012_036_1625xmmmv1.tnf
mro_kernels/mromagr2012_037_1730xmmmv1.tnf
mro_kernels/mromagr2012_038_1452xmmmv1.tnf
mro_kernels/mromagr2012_039_2115xmmmv1.tnf
mro_kernels/mromagr2012_040_1950xmmmv1.tnf
mro_kernels/mromagr2012_041_1520xmmmv1.tnf
mro_kernels/mromagr2012_043_0330xmmmv1.tnf
mro_kernels/mromagr2012_044_1115xmmmv1.tnf
mro_kernels/mromagr2012_045_1115xmmmv1.tnf
mro_kernels/mromagr2012_046_1925xmmmv1.tnf
mro_kernels/mromagr2012_047_1132xmmmv1.tnf
mro_kernels/mromagr2012_048_1005xmmmv1.tnf
mro_kernels/mromagr2012_049_1925xmmmv1.tnf
mro_kernels/mromagr2012_051_0955xmmmv1.tnf
mro_kernels/mromagr2012_052_1105xmmmv1.tnf
mro_kernels/mromagr2012_053_0950xmmmv1.tnf
mro_kernels/mromagr2012_054_1218xmmmv1.tnf
mro_kernels/mromagr2012_055_0945xmmmv1.tnf
mro_kernels/mromagr2012_056_0940xmmmv1.tnf
mro_kernels/mromagr2012_057_1110xmmmv1.tnf
mro_kernels/mromagr2012_058_2140xmmmv1.tnf
mro_kernels/mromagr2012_059_1240xmmmv1.tnf
mro_kernels/mromagr2012_060_0930xmmmv1.tnf
---------------------------------------------
Download MRO trajectory files
relevant trajectory files
mro_kernels/mro_psp21.bsp
mro_kernels/mro_psp22.bsp
mro_kernels/mro_psp23.bsp
mro_kernels/mro_psp24.bsp
mro_kernels/mro_psp25.bsp
---------------------------------------------
Download MRO frames definition file
relevant MRO frames definition file
mro_kernels/mro_v16.tf
---------------------------------------------
Download MRO structure file
relevant MRO structure file
mro_kernels/mro_struct_v10.bsp
---------------------------------------------
Download MRO clock
relevant clock files
mro_kernels/mro_sclkscet_00112_65536.tsc
---------------------------------------------
Download MRO orientation kernels
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
relevant orientation files
mro_kernels/mro_sc_psp_120327_120402.bc
mro_kernels/mro_sc_psp_120228_120305.bc
mro_kernels/mro_sc_psp_120410_120416.bc
mro_kernels/mro_sc_psp_120403_120409.bc
mro_kernels/mro_sc_psp_120424_120430.bc
mro_kernels/mro_sc_psp_120417_120423.bc
mro_kernels/mro_sc_psp_120306_120312.bc
mro_kernels/mro_sc_psp_120313_120319.bc
mro_kernels/mro_sc_psp_120320_120326.bc
mro_kernels/mro_hga_psp_120306_120312.bc
mro_kernels/mro_hga_psp_120410_120416.bc
mro_kernels/mro_hga_psp_120417_120423.bc
mro_kernels/mro_hga_psp_120228_120305.bc
mro_kernels/mro_hga_psp_120403_120409.bc
mro_kernels/mro_hga_psp_120424_120430.bc
mro_kernels/mro_hga_psp_120313_120319.bc
mro_kernels/mro_hga_psp_120320_120326.bc
mro_kernels/mro_hga_psp_120327_120402.bc
---------------------------------------------
Download MRO tropospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant tropospheric corrections files
mro_kernels/mromagr2012_092_2012_122.tro
mro_kernels/mromagr2012_061_2012_092.tro
mro_kernels/mromagr2012_032_2012_061.tro
---------------------------------------------
Download MRO ionospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant ionospheric corrections files
mro_kernels/mromagr2012_092_2012_122.ion
mro_kernels/mromagr2012_032_2012_061.ion
mro_kernels/mromagr2012_061_2012_092.ion
---------------------------------------------
Download MRO TNF files
nb existing files 328
relevant TNF files
mro_kernels/mromagr2012_061_1245xmmmv1.tnf
mro_kernels/mromagr2012_062_1340xmmmv1.tnf
mro_kernels/mromagr2012_064_0135xmmmv1.tnf
mro_kernels/mromagr2012_065_2000xmmmv1.tnf
mro_kernels/mromagr2012_066_1105xmmmv1.tnf
mro_kernels/mromagr2012_067_1831xmmmv1.tnf
mro_kernels/mromagr2012_068_1924xmmmv1.tnf
mro_kernels/mromagr2012_069_1400xmmmv1.tnf
mro_kernels/mromagr2012_070_0810xmmmv1.tnf
mro_kernels/mromagr2012_071_1950xmmmv1.tnf
mro_kernels/mromagr2012_072_1000xmmmv1.tnf
mro_kernels/mromagr2012_073_1017xmmmv1.tnf
mro_kernels/mromagr2012_074_1940xmmmv1.tnf
mro_kernels/mromagr2012_075_0850xmmmv1.tnf
mro_kernels/mromagr2012_076_0840xmmmv1.tnf
mro_kernels/mromagr2012_077_1735xmmmv1.tnf
mro_kernels/mromagr2012_079_1020xmmmv1.tnf
mro_kernels/mromagr2012_080_1055xmmmv1.tnf
mro_kernels/mromagr2012_081_1247xmmmv1.tnf
mro_kernels/mromagr2012_082_0715xmmmv1.tnf
mro_kernels/mromagr2012_083_0835xmmmv1.tnf
mro_kernels/mromagr2012_084_1835xmmmv1.tnf
mro_kernels/mromagr2012_085_0820xmmmv1.tnf
mro_kernels/mromagr2012_086_0850xmmmv1.tnf
mro_kernels/mromagr2012_087_0935xmmmv1.tnf
mro_kernels/mromagr2012_088_1020xmmmv1.tnf
mro_kernels/mromagr2012_089_1534xmmmv1.tnf
mro_kernels/mromagr2012_090_1015xmmmv1.tnf
mro_kernels/mromagr2012_091_1525xmmmv1.tnf
mro_kernels/mromagr2012_092_0805xmmmv1.tnf
mro_kernels/mromagr2012_093_0620xmmmv1.tnf
mro_kernels/mromagr2012_094_0605xmmmv1.tnf
mro_kernels/mromagr2012_095_1458xmmmv1.tnf
mro_kernels/mromagr2012_096_0750xmmmv1.tnf
mro_kernels/mromagr2012_097_1019xmmmv1.tnf
mro_kernels/mromagr2012_098_0000xmmmv1.tnf
mro_kernels/mromagr2012_099_0150xmmmv1.tnf
mro_kernels/mromagr2012_100_0640xmmmv1.tnf
mro_kernels/mromagr2012_101_1514xmmmv1.tnf
mro_kernels/mromagr2012_102_1709xmmmv1.tnf
mro_kernels/mromagr2012_103_1755xmmmv1.tnf
mro_kernels/mromagr2012_104_1715xmmmv1.tnf
mro_kernels/mromagr2012_106_0645xmmmv1.tnf
mro_kernels/mromagr2012_107_0815xmmmv1.tnf
mro_kernels/mromagr2012_108_0815xmmmv1.tnf
mro_kernels/mromagr2012_109_1410xmmmv1.tnf
mro_kernels/mromagr2012_110_0615xmmmv1.tnf
mro_kernels/mromagr2012_111_0645xmmmv1.tnf
mro_kernels/mromagr2012_112_0807xmmmv1.tnf
mro_kernels/mromagr2012_113_1930xmmmv1.tnf
mro_kernels/mromagr2012_114_1715xmmmv1.tnf
mro_kernels/mromagr2012_115_0725xmmmv1.tnf
mro_kernels/mromagr2012_116_1430xmmmv1.tnf
mro_kernels/mromagr2012_117_1735xmmmv1.tnf
mro_kernels/mromagr2012_118_1645xmmmv1.tnf
mro_kernels/mromagr2012_119_0711xmmmv1.tnf
mro_kernels/mromagr2012_120_1515xmmmv1.tnf
mro_kernels/mromagr2012_121_1603xmmmv1.tnf
---------------------------------------------
Download MRO trajectory files
relevant trajectory files
mro_kernels/mro_psp21.bsp
mro_kernels/mro_psp22.bsp
mro_kernels/mro_psp23.bsp
mro_kernels/mro_psp24.bsp
mro_kernels/mro_psp25.bsp
---------------------------------------------
Download MRO frames definition file
relevant MRO frames definition file
mro_kernels/mro_v16.tf
---------------------------------------------
Download MRO structure file
relevant MRO structure file
mro_kernels/mro_struct_v10.bsp
---------------------------------------------
Download MRO clock
relevant clock files
mro_kernels/mro_sclkscet_00112_65536.tsc
---------------------------------------------
Download MRO orientation kernels
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
relevant orientation files
mro_kernels/mro_sc_psp_120612_120618.bc
mro_kernels/mro_sc_psp_120508_120514.bc
mro_kernels/mro_sc_psp_120522_120528.bc
mro_kernels/mro_sc_psp_120605_120611.bc
mro_kernels/mro_sc_psp_120515_120521.bc
mro_kernels/mro_sc_psp_120529_120604.bc
mro_kernels/mro_sc_psp_120501_120507.bc
mro_kernels/mro_sc_psp_120626_120702.bc
mro_kernels/mro_sc_psp_120619_120625.bc
mro_kernels/mro_hga_psp_120529_120604.bc
mro_kernels/mro_hga_psp_120522_120528.bc
mro_kernels/mro_hga_psp_120515_120521.bc
mro_kernels/mro_hga_psp_120508_120514.bc
mro_kernels/mro_hga_psp_120612_120618.bc
mro_kernels/mro_hga_psp_120501_120507.bc
mro_kernels/mro_hga_psp_120605_120611.bc
mro_kernels/mro_hga_psp_120619_120625.bc
mro_kernels/mro_hga_psp_120626_120702.bc
---------------------------------------------
Download MRO tropospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant tropospheric corrections files
mro_kernels/mromagr2012_092_2012_122.tro
mro_kernels/mromagr2012_122_2012_153.tro
mro_kernels/mromagr2012_153_2012_183.tro
---------------------------------------------
Download MRO ionospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant ionospheric corrections files
mro_kernels/mromagr2012_092_2012_122.ion
mro_kernels/mromagr2012_153_2012_183.ion
mro_kernels/mromagr2012_122_2012_153.ion
---------------------------------------------
Download MRO TNF files
nb existing files 328
relevant TNF files
mro_kernels/mromagr2012_122_1406xmmmv1.tnf
mro_kernels/mromagr2012_123_1345xmmmv1.tnf
mro_kernels/mromagr2012_124_1401xmmmv1.tnf
mro_kernels/mromagr2012_125_1357xmmmv1.tnf
mro_kernels/mromagr2012_126_1614xmmmv1.tnf
mro_kernels/mromagr2012_127_1315xmmmv1.tnf
mro_kernels/mromagr2012_128_1510xmmmv1.tnf
mro_kernels/mromagr2012_129_1540xmmmv1.tnf
mro_kernels/mromagr2012_130_2000xmmmv1.tnf
mro_kernels/mromagr2012_131_1450xmmmv1.tnf
mro_kernels/mromagr2012_132_1325xmmmv1.tnf
mro_kernels/mromagr2012_133_1555xmmmv1.tnf
mro_kernels/mromagr2012_134_1305xmmmv1.tnf
mro_kernels/mromagr2012_135_1822xmmmv1.tnf
mro_kernels/mromagr2012_136_2035xmmmv1.tnf
mro_kernels/mromagr2012_137_2124xmmmv1.tnf
mro_kernels/mromagr2012_138_1840xmmmv1.tnf
mro_kernels/mromagr2012_139_1745xmmmv1.tnf
mro_kernels/mromagr2012_141_0553xmmmv1.tnf
mro_kernels/mromagr2012_142_1952xmmmv1.tnf
mro_kernels/mromagr2012_143_1740xmmmv1.tnf
mro_kernels/mromagr2012_144_1300xmmmv1.tnf
mro_kernels/mromagr2012_145_1403xmmmv1.tnf
mro_kernels/mromagr2012_146_1452xmmmv1.tnf
mro_kernels/mromagr2012_148_1010xmmmv1.tnf
mro_kernels/mromagr2012_149_1529xmmmv1.tnf
mro_kernels/mromagr2012_150_1931xmmmv1.tnf
mro_kernels/mromagr2012_152_1335xmmmv1.tnf
mro_kernels/mromagr2012_152_1335xmmmv1.tnf
mro_kernels/mromagr2012_153_1339xmmmv1.tnf
mro_kernels/mromagr2012_154_2005xmmmv1.tnf
mro_kernels/mromagr2012_156_1420xmmmv1.tnf
mro_kernels/mromagr2012_157_1225xmmmv1.tnf
mro_kernels/mromagr2012_158_1530xmmmv1.tnf
mro_kernels/mromagr2012_159_1655xmmmv1.tnf
mro_kernels/mromagr2012_160_1636xmmmv1.tnf
mro_kernels/mromagr2012_162_0238xmmmv1.tnf
mro_kernels/mromagr2012_163_1402xmmmv1.tnf
mro_kernels/mromagr2012_164_1515xmmmv1.tnf
mro_kernels/mromagr2012_165_1225xmmmv1.tnf
mro_kernels/mromagr2012_166_1921xmmmv1.tnf
mro_kernels/mromagr2012_167_1505xmmmv1.tnf
mro_kernels/mromagr2012_168_2025xmmmv1.tnf
mro_kernels/mromagr2012_169_1545xmmmv1.tnf
mro_kernels/mromagr2012_170_1202xmmmv1.tnf
mro_kernels/mromagr2012_171_1805xmmmv1.tnf
mro_kernels/mromagr2012_172_1215xmmmv1.tnf
mro_kernels/mromagr2012_173_2015xmmmv1.tnf
mro_kernels/mromagr2012_174_1809xmmmv1.tnf
mro_kernels/mromagr2012_176_0658xmmmv1.tnf
mro_kernels/mromagr2012_177_1700xmmmv1.tnf
mro_kernels/mromagr2012_178_1140xmmmv1.tnf
mro_kernels/mromagr2012_179_1450xmmmv1.tnf
mro_kernels/mromagr2012_180_1250xmmmv1.tnf
mro_kernels/mromagr2012_181_1250xmmmv1.tnf
mro_kernels/mromagr2012_182_2000xmmmv1.tnf
---------------------------------------------
Download MRO trajectory files
relevant trajectory files
mro_kernels/mro_psp21.bsp
mro_kernels/mro_psp22.bsp
mro_kernels/mro_psp23.bsp
mro_kernels/mro_psp24.bsp
mro_kernels/mro_psp25.bsp
---------------------------------------------
Download MRO frames definition file
relevant MRO frames definition file
mro_kernels/mro_v16.tf
---------------------------------------------
Download MRO structure file
relevant MRO structure file
mro_kernels/mro_struct_v10.bsp
---------------------------------------------
Download MRO clock
relevant clock files
mro_kernels/mro_sclkscet_00112_65536.tsc
---------------------------------------------
Download MRO orientation kernels
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
relevant orientation files
mro_kernels/mro_sc_psp_120828_120903.bc
mro_kernels/mro_sc_psp_120703_120709.bc
mro_kernels/mro_sc_psp_120731_120806.bc
mro_kernels/mro_sc_psp_120807_120813.bc
mro_kernels/mro_sc_psp_120814_120820.bc
mro_kernels/mro_sc_psp_120821_120827.bc
mro_kernels/mro_sc_psp_120724_120730.bc
mro_kernels/mro_sc_psp_120717_120723.bc
mro_kernels/mro_sc_psp_120626_120702.bc
mro_kernels/mro_sc_psp_120710_120716.bc
mro_kernels/mro_hga_psp_120724_120730.bc
mro_kernels/mro_hga_psp_120828_120903.bc
mro_kernels/mro_hga_psp_120814_120820.bc
mro_kernels/mro_hga_psp_120717_120723.bc
mro_kernels/mro_hga_psp_120731_120806.bc
mro_kernels/mro_hga_psp_120807_120813.bc
mro_kernels/mro_hga_psp_120703_120709.bc
mro_kernels/mro_hga_psp_120821_120827.bc
mro_kernels/mro_hga_psp_120710_120716.bc
mro_kernels/mro_hga_psp_120626_120702.bc
---------------------------------------------
Download MRO tropospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant tropospheric corrections files
mro_kernels/mromagr2012_153_2012_183.tro
mro_kernels/mromagr2012_183_2012_214.tro
mro_kernels/mromagr2012_214_2012_245.tro
---------------------------------------------
Download MRO ionospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant ionospheric corrections files
mro_kernels/mromagr2012_183_2012_214.ion
mro_kernels/mromagr2012_153_2012_183.ion
mro_kernels/mromagr2012_214_2012_245.ion
---------------------------------------------
Download MRO TNF files
nb existing files 328
relevant TNF files
mro_kernels/mromagr2012_184_1700xmmmv1.tnf
mro_kernels/mromagr2012_185_1715xmmmv1.tnf
mro_kernels/mromagr2012_186_1155xmmmv1.tnf
mro_kernels/mromagr2012_187_1500xmmmv1.tnf
mro_kernels/mromagr2012_188_1645xmmmv1.tnf
mro_kernels/mromagr2012_190_0005xmmmv1.tnf
mro_kernels/mromagr2012_191_1521xmmmv1.tnf
mro_kernels/mromagr2012_192_1200xmmmv1.tnf
mro_kernels/mromagr2012_193_1111xmmmv1.tnf
mro_kernels/mromagr2012_194_1250xmmmv1.tnf
mro_kernels/mromagr2012_195_1331xmmmv1.tnf
mro_kernels/mromagr2012_197_0725xmmmv1.tnf
mro_kernels/mromagr2012_198_1418xmmmv1.tnf
mro_kernels/mromagr2012_199_1616xmmmv1.tnf
mro_kernels/mromagr2012_200_1050xmmmv1.tnf
mro_kernels/mromagr2012_201_1345xmmmv1.tnf
mro_kernels/mromagr2012_202_1815xmmmv1.tnf
mro_kernels/mromagr2012_204_0020xmmmv1.tnf
mro_kernels/mromagr2012_205_1510xmmmv1.tnf
mro_kernels/mromagr2012_206_1515xmmmv1.tnf
mro_kernels/mromagr2012_207_1200xmmmv1.tnf
mro_kernels/mromagr2012_208_1515xmmmv1.tnf
mro_kernels/mromagr2012_209_1206xmmmv1.tnf
mro_kernels/mromagr2012_210_1825xmmmv1.tnf
mro_kernels/mromagr2012_212_1040xmmmv1.tnf
mro_kernels/mromagr2012_213_1155xmmmv1.tnf
mro_kernels/mromagr2012_214_1040xmmmv1.tnf
mro_kernels/mromagr2012_215_1145xmmmv1.tnf
mro_kernels/mromagr2012_216_1206xmmmv1.tnf
mro_kernels/mromagr2012_217_1125xmmmv1.tnf
mro_kernels/mromagr2012_218_1050xmmmv1.tnf
mro_kernels/mromagr2012_219_1035xmmmv1.tnf
mro_kernels/mromagr2012_220_1035xmmmv1.tnf
mro_kernels/mromagr2012_221_1035xmmmv1.tnf
mro_kernels/mromagr2012_222_1035xmmmv1.tnf
mro_kernels/mromagr2012_223_1030xmmmv1.tnf
mro_kernels/mromagr2012_225_0155xmmmv1.tnf
mro_kernels/mromagr2012_226_1039xmmmv1.tnf
mro_kernels/mromagr2012_227_1218xmmmv1.tnf
mro_kernels/mromagr2012_228_1030xmmmv1.tnf
mro_kernels/mromagr2012_229_1120xmmmv1.tnf
mro_kernels/mromagr2012_230_1205xmmmv1.tnf
mro_kernels/mromagr2012_232_0254xmmmv1.tnf
mro_kernels/mromagr2012_233_1400xmmmv1.tnf
mro_kernels/mromagr2012_234_1321xmmmv1.tnf
mro_kernels/mromagr2012_235_1457xmmmv1.tnf
mro_kernels/mromagr2012_236_1430xmmmv1.tnf
mro_kernels/mromagr2012_237_1137xmmmv1.tnf
mro_kernels/mromagr2012_238_1850xmmmv1.tnf
mro_kernels/mromagr2012_239_1625xmmmv1.tnf
mro_kernels/mromagr2012_240_1040xmmmv1.tnf
mro_kernels/mromagr2012_241_1320xmmmv1.tnf
mro_kernels/mromagr2012_242_1035xmmmv1.tnf
mro_kernels/mromagr2012_243_1520xmmmv1.tnf
mro_kernels/mromagr2012_244_1320xmmmv1.tnf
---------------------------------------------
Download MRO trajectory files
relevant trajectory files
mro_kernels/mro_psp21.bsp
mro_kernels/mro_psp22.bsp
mro_kernels/mro_psp23.bsp
mro_kernels/mro_psp24.bsp
mro_kernels/mro_psp25.bsp
---------------------------------------------
Download MRO frames definition file
relevant MRO frames definition file
mro_kernels/mro_v16.tf
---------------------------------------------
Download MRO structure file
relevant MRO structure file
mro_kernels/mro_struct_v10.bsp
---------------------------------------------
Download MRO clock
relevant clock files
mro_kernels/mro_sclkscet_00112_65536.tsc
---------------------------------------------
Download MRO orientation kernels
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
relevant orientation files
mro_kernels/mro_sc_psp_120828_120903.bc
mro_kernels/mro_sc_psp_120911_120917.bc
mro_kernels/mro_sc_psp_120925_121001.bc
mro_kernels/mro_sc_psp_121002_121008.bc
mro_kernels/mro_sc_psp_121023_121029.bc
mro_kernels/mro_sc_psp_120918_120924.bc
mro_kernels/mro_sc_psp_120904_120910.bc
mro_kernels/mro_sc_psp_121009_121015.bc
mro_kernels/mro_sc_psp_121016_121022.bc
mro_kernels/mro_sc_psp_121030_121105.bc
mro_kernels/mro_hga_psp_120904_120910.bc
mro_kernels/mro_hga_psp_121030_121105.bc
mro_kernels/mro_hga_psp_120925_121001.bc
mro_kernels/mro_hga_psp_120828_120903.bc
mro_kernels/mro_hga_psp_121016_121022.bc
mro_kernels/mro_hga_psp_120918_120924.bc
mro_kernels/mro_hga_psp_121002_121008.bc
mro_kernels/mro_hga_psp_120911_120917.bc
mro_kernels/mro_hga_psp_121023_121029.bc
mro_kernels/mro_hga_psp_121009_121015.bc
---------------------------------------------
Download MRO tropospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant tropospheric corrections files
mro_kernels/mromagr2012_245_2012_275.tro
mro_kernels/mromagr2012_214_2012_245.tro
mro_kernels/mromagr2012_275_2012_306.tro
---------------------------------------------
Download MRO ionospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant ionospheric corrections files
mro_kernels/mromagr2012_275_2012_306.ion
mro_kernels/mromagr2012_245_2012_275.ion
mro_kernels/mromagr2012_214_2012_245.ion
---------------------------------------------
Download MRO TNF files
nb existing files 328
relevant TNF files
mro_kernels/mromagr2012_245_1703xmmmv1.tnf
mro_kernels/mromagr2012_247_0620xmmmv1.tnf
mro_kernels/mromagr2012_248_1315xmmmv1.tnf
mro_kernels/mromagr2012_249_1240xmmmv1.tnf
mro_kernels/mromagr2012_250_1406xmmmv1.tnf
mro_kernels/mromagr2012_251_1515xmmmv1.tnf
mro_kernels/mromagr2012_252_1849xmmmv1.tnf
mro_kernels/mromagr2012_254_1015xmmmv1.tnf
mro_kernels/mromagr2012_255_1445xmmmv1.tnf
mro_kernels/mromagr2012_256_1534xmmmv1.tnf
mro_kernels/mromagr2012_257_1135xmmmv1.tnf
mro_kernels/mromagr2012_258_1425xmmmv1.tnf
mro_kernels/mromagr2012_259_2050xmmmv1.tnf
mro_kernels/mromagr2012_261_1015xmmmv1.tnf
mro_kernels/mromagr2012_262_1015xmmmv1.tnf
mro_kernels/mromagr2012_263_1350xmmmv1.tnf
mro_kernels/mromagr2012_264_1200xmmmv1.tnf
mro_kernels/mromagr2012_265_1325xmmmv1.tnf
mro_kernels/mromagr2012_267_0358xmmmv1.tnf
mro_kernels/mromagr2012_268_1206xmmmv1.tnf
mro_kernels/mromagr2012_269_2300xmmmv1.tnf
mro_kernels/mromagr2012_270_1100xmmmv1.tnf
mro_kernels/mromagr2012_271_1032xmmmv1.tnf
mro_kernels/mromagr2012_272_1130xmmmv1.tnf
mro_kernels/mromagr2012_273_1740xmmmv1.tnf
mro_kernels/mromagr2012_275_1125xmmmv1.tnf
mro_kernels/mromagr2012_276_1145xmmmv1.tnf
mro_kernels/mromagr2012_277_1030xmmmv1.tnf
mro_kernels/mromagr2012_278_1125xmmmv1.tnf
mro_kernels/mromagr2012_279_1016xmmmv1.tnf
mro_kernels/mromagr2012_281_0055xmmmv1.tnf
mro_kernels/mromagr2012_282_1015xmmmv1.tnf
mro_kernels/mromagr2012_283_1200xmmmv1.tnf
mro_kernels/mromagr2012_284_1205xmmmv1.tnf
mro_kernels/mromagr2012_285_1030xmmmv1.tnf
mro_kernels/mromagr2012_286_1750xmmmv1.tnf
mro_kernels/mromagr2012_287_1844xmmmv1.tnf
mro_kernels/mromagr2012_289_1010xmmmv1.tnf
mro_kernels/mromagr2012_290_1010xmmmv1.tnf
mro_kernels/mromagr2012_291_1307xmmmv1.tnf
mro_kernels/mromagr2012_292_1010xmmmv1.tnf
mro_kernels/mromagr2012_293_1035xmmmv1.tnf
mro_kernels/mromagr2012_294_2200xmmmv1.tnf
mro_kernels/mromagr2012_296_1005xmmmv1.tnf
mro_kernels/mromagr2012_297_1014xmmmv1.tnf
mro_kernels/mromagr2012_298_1025xmmmv1.tnf
mro_kernels/mromagr2012_299_1010xmmmv1.tnf
mro_kernels/mromagr2012_300_1005xmmmv1.tnf
mro_kernels/mromagr2012_301_1715xmmmv1.tnf
mro_kernels/mromagr2012_303_1005xmmmv1.tnf
mro_kernels/mromagr2012_304_1235xmmmv1.tnf
mro_kernels/mromagr2012_305_1230xmmmv1.tnf
---------------------------------------------
Download MRO trajectory files
relevant trajectory files
mro_kernels/mro_psp21.bsp
mro_kernels/mro_psp22.bsp
mro_kernels/mro_psp23.bsp
mro_kernels/mro_psp24.bsp
mro_kernels/mro_psp25.bsp
---------------------------------------------
Download MRO frames definition file
relevant MRO frames definition file
mro_kernels/mro_v16.tf
---------------------------------------------
Download MRO structure file
relevant MRO structure file
mro_kernels/mro_struct_v10.bsp
---------------------------------------------
Download MRO clock
relevant clock files
mro_kernels/mro_sclkscet_00112_65536.tsc
---------------------------------------------
Download MRO orientation kernels
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
size_time_format 6
size_interval_format 13
nb existing files 53
dates_without_file []
relevant orientation files
mro_kernels/mro_sc_psp_121211_121217.bc
mro_kernels/mro_sc_psp_121120_121126.bc
mro_kernels/mro_sc_psp_121225_121231.bc
mro_kernels/mro_sc_psp_121127_121203.bc
mro_kernels/mro_sc_psp_121106_121112.bc
mro_kernels/mro_sc_psp_121113_121119.bc
mro_kernels/mro_sc_psp_121204_121210.bc
mro_kernels/mro_sc_psp_121218_121224.bc
mro_kernels/mro_sc_psp_121030_121105.bc
mro_kernels/mro_hga_psp_121030_121105.bc
mro_kernels/mro_hga_psp_121218_121224.bc
mro_kernels/mro_hga_psp_121204_121210.bc
mro_kernels/mro_hga_psp_121211_121217.bc
mro_kernels/mro_hga_psp_121113_121119.bc
mro_kernels/mro_hga_psp_121120_121126.bc
mro_kernels/mro_hga_psp_121106_121112.bc
mro_kernels/mro_hga_psp_121225_121231.bc
mro_kernels/mro_hga_psp_121127_121203.bc
---------------------------------------------
Download MRO tropospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant tropospheric corrections files
mro_kernels/mromagr2012_306_2012_336.tro
mro_kernels/mromagr2012_336_2013_001.tro
mro_kernels/mromagr2012_275_2012_306.tro
---------------------------------------------
Download MRO ionospheric corrections files
size_time_format 8
size_interval_format 17
nb existing files 13
dates_without_file []
relevant ionospheric corrections files
mro_kernels/mromagr2012_275_2012_306.ion
mro_kernels/mromagr2012_306_2012_336.ion
mro_kernels/mromagr2012_336_2013_001.ion
---------------------------------------------
Download MRO TNF files
nb existing files 328
relevant TNF files
mro_kernels/mromagr2012_306_1005xmmmv1.tnf
mro_kernels/mromagr2012_307_1435xmmmv1.tnf
mro_kernels/mromagr2012_309_0135xmmmv1.tnf
mro_kernels/mromagr2012_310_1005xmmmv1.tnf
mro_kernels/mromagr2012_311_1210xmmmv1.tnf
mro_kernels/mromagr2012_312_1345xmmmv1.tnf
mro_kernels/mromagr2012_313_1010xmmmv1.tnf
mro_kernels/mromagr2012_314_1115xmmmv1.tnf
mro_kernels/mromagr2012_315_1120xmmmv1.tnf
mro_kernels/mromagr2012_316_1125xmmmv1.tnf
mro_kernels/mromagr2012_317_1400xmmmv1.tnf
mro_kernels/mromagr2012_318_1735xmmmv1.tnf
mro_kernels/mromagr2012_319_1000xmmmv1.tnf
mro_kernels/mromagr2012_320_1000xmmmv1.tnf
mro_kernels/mromagr2012_321_1705xmmmv1.tnf
mro_kernels/mromagr2012_322_1835xmmmv1.tnf
mro_kernels/mromagr2012_324_1000xmmmv1.tnf
mro_kernels/mromagr2012_325_1045xmmmv1.tnf
mro_kernels/mromagr2012_326_1747xmmmv1.tnf
mro_kernels/mromagr2012_327_1700xmmmv1.tnf
mro_kernels/mromagr2012_329_1111xmmmv1.tnf
mro_kernels/mromagr2012_331_1009xmmmv1.tnf
mro_kernels/mromagr2012_332_0951xmmmv1.tnf
mro_kernels/mromagr2012_333_1210xmmmv1.tnf
mro_kernels/mromagr2012_334_0954xmmmv1.tnf
mro_kernels/mromagr2012_335_1517xmmmv1.tnf
mro_kernels/mromagr2012_336_1655xmmmv1.tnf
mro_kernels/mromagr2012_338_1008xmmmv1.tnf
mro_kernels/mromagr2012_339_1705xmmmv1.tnf
mro_kernels/mromagr2012_340_1825xmmmv1.tnf
mro_kernels/mromagr2012_341_0945xmmmv1.tnf
mro_kernels/mromagr2012_342_1050xmmmv1.tnf
mro_kernels/mromagr2012_344_0400xmmmv1.tnf
mro_kernels/mromagr2012_345_0955xmmmv1.tnf
mro_kernels/mromagr2012_346_1415xmmmv1.tnf
mro_kernels/mromagr2012_347_1004xmmmv1.tnf
mro_kernels/mromagr2012_348_2145xmmmv1.tnf
mro_kernels/mromagr2012_349_1650xmmmv1.tnf
mro_kernels/mromagr2012_351_1130xmmmv1.tnf
mro_kernels/mromagr2012_352_0930xmmmv1.tnf
mro_kernels/mromagr2012_353_1715xmmmv1.tnf
mro_kernels/mromagr2012_354_1005xmmmv1.tnf
mro_kernels/mromagr2012_355_1000xmmmv1.tnf
mro_kernels/mromagr2012_356_1355xmmmv1.tnf
mro_kernels/mromagr2012_357_1430xmmmv1.tnf
mro_kernels/mromagr2012_358_1745xmmmv1.tnf
mro_kernels/mromagr2012_360_0929xmmmv1.tnf
mro_kernels/mromagr2012_361_1015xmmmv1.tnf
mro_kernels/mromagr2012_362_1040xmmmv1.tnf
mro_kernels/mromagr2012_363_1725xmmmv1.tnf
mro_kernels/mromagr2012_365_0245xmmmv1.tnf
mro_kernels/mromagr2012_366_1030xmmmv1.tnf
---------------------------------------------
Download MRO trajectory files
relevant trajectory files
mro_kernels/mro_psp21.bsp
mro_kernels/mro_psp22.bsp
mro_kernels/mro_psp23.bsp
mro_kernels/mro_psp24.bsp
mro_kernels/mro_psp25.bsp
---------------------------------------------
Download MRO frames definition file
relevant MRO frames definition file
mro_kernels/mro_v16.tf
---------------------------------------------
Download MRO structure file
relevant MRO structure file
mro_kernels/mro_struct_v10.bsp
Run Parallel Analysis#
[7]:
# Run parallel residuals analyses over several cores
print("---------------------------------------------")
print(
"The output of each parallel run is saved in a separate file named mro_estimation_output_x.dat, with x the index of the run "
"(these files are saved in the ./output directory)"
)
with mp.get_context("fork").Pool(nb_cores) as pool:
pool.map(perform_residuals_analysis, inputs)
---------------------------------------------
The output of each parallel run is saved in a separate file named mro_estimation_output_x.dat, with x the index of the run (these files are saved in the ./output directory)
input_indexinput_indexinput_indexinput_indexinput_indexinput_index 230145
original_odf_observations
original_odf_observations
original_odf_observations
original_odf_observations
original_odf_observations
Compressed observations:
28677
Compressed observations:
38809
Compressed observations:
38730
Compressed observations:
41922
original_odf_observations
Compressed observations:
44208
Compressed observations:
34665
Results Processing and Visualization#
The following cell loads all results from the parallel analyses and generates visualization plots. For each observable type (Doppler and Range), three figures are automatically created:
Plot 1: Residuals Over Time#
Doppler Residuals:
Displays filtered Doppler residuals over the entire year (2012)
Each point represents the difference between observed Doppler measurement (from TNF files) and simulated Doppler observable (computed using SPICE kernels)
Residuals expressed in Hertz (Hz)
Outliers with residuals exceeding 0.1 Hz have been filtered out
Y-axis limited to [-0.1, 0.1] Hz for better visualization
Range Residuals:
Shows filtered range residuals over the entire year (2012)
Each point represents the difference between observed range measurement (from TNF files) and simulated range observable (computed using SPICE kernels)
Left y-axis: residuals in Range Units (RU)
Right y-axis (red): same residuals converted to meters using range conversion factors
Outliers with residuals exceeding 40 RU have been filtered out
Plot 2: Statistics and Angles (6-panel figure)#
This figure provides comprehensive statistical analysis and geometric information:
Top row (RMS and Mean residuals - unfiltered):
Shows root-mean-square (RMS) and mean of residuals per observation set before outlier filtering
Useful to identify observation sets with consistently high residuals
Residuals expressed in Hz for Doppler, RU for Range
Middle row (RMS and Mean residuals - post-filtering):
Shows RMS and mean of residuals per observation set after outliers have been removed (> 0.1 Hz for Doppler, > 40 RU for Range)
Demonstrates the improvement in data quality after filtering
Allows assessment of overall measurement quality
Bottom row (Elevation and SEP angles):
Elevation angle: The angle between the ground station’s horizon and the line-of-sight to the spacecraft
Low elevation angles often correlate with higher residuals due to increased atmospheric effects
Longer signal paths through atmosphere at low elevations increase tropospheric delays
Range: 0-90 degrees
SEP angle (Sun-Earth-Probe angle): The angle between the Sun and the spacecraft as seen from the receiving ground station
Small SEP angles indicate times when the spacecraft is near solar conjunction
Solar plasma can affect signal quality during solar conjunctions
Particularly important for range measurements due to solar corona effects
Plot 3: First Day Analysis#
Doppler - First Day:
Detailed view of Doppler residuals over the first 24-hour period of the dataset
Color-coded scatter points represent residuals from different link ends (different ground station tracking configurations)
Red line shows elevation angle at the receiving ground station throughout the day
Useful for:
Identifying patterns in residuals related to spacecraft orbital geometry
Observing how residuals vary with elevation angle
Detecting systematic effects that repeat with the spacecraft’s orbital period
Comparing residual behavior across different ground station configurations
Range - First Day:
Detailed view of range residuals over the first 24-hour period
Color-coded scatter points represent residuals from different link ends
Red line shows elevation angle at the receiving ground station throughout the day
Helps to:
Identify daily patterns in range residuals
Correlate residual magnitudes with elevation angles
Detect systematic effects related to the orbital period
Compare performance across different tracking configurations
Range residuals shown in Range Units (RU), where conversion to meters varies depending on ranging system configuration
Note: All plots for both Doppler and Range are generated automatically in the following cell and displayed together.
[8]:
for obsName in ["range", "doppler"]:
# Initialize lists to store results from all parallel analyses
filtered_residuals_list = []
filtered_times_list = []
elevation_angles_list = []
sep_angles_list = []
rms_residuals_list = []
mean_residuals_list = []
rms_filtered_residuals_list = []
mean_filtered_residuals_list = []
time_bounds_list = []
time_bounds_filtered_list = []
range_conversion_factors_list = []
# Load and add results from all parallel analyses
for i in range(nb_cores):
filtered_times_list.append(
np.loadtxt(
"outputs/mro_{}_filtered_time_".format(obsName) + str(i) + ".dat",
delimiter=",",
)
)
filtered_residuals_list.append(
np.loadtxt(
"outputs/mro_{}_filtered_residuals_".format(obsName) + str(i) + ".dat",
delimiter=",",
)
)
elevation_angles_list.append(
np.loadtxt(
"outputs/mro_{}_elevation_angles_".format(obsName) + str(i) + ".dat",
delimiter=",",
)
)
sep_angles_list.append(
np.loadtxt(
"outputs/mro_{}_sep_angles_".format(obsName) + str(i) + ".dat",
delimiter=",",
)
)
rms_residuals_list.append(
np.loadtxt(
"outputs/mro_{}_unfiltered_residuals_rms_".format(obsName)
+ str(i)
+ ".dat",
delimiter=",",
)
)
mean_residuals_list.append(
np.loadtxt(
"outputs/mro_{}_unfiltered_residuals_mean_".format(obsName)
+ str(i)
+ ".dat",
delimiter=",",
)
)
rms_filtered_residuals_list.append(
np.loadtxt(
"outputs/mro_{}_filtered_residuals_rms_".format(obsName)
+ str(i)
+ ".dat",
delimiter=",",
)
)
mean_filtered_residuals_list.append(
np.loadtxt(
"outputs/mro_{}_filtered_residuals_mean_".format(obsName)
+ str(i)
+ ".dat",
delimiter=",",
)
)
time_bounds_list.append(
np.loadtxt(
"outputs/mro_{}_unfiltered_time_bounds_".format(obsName)
+ str(i)
+ ".dat",
delimiter=",",
)
)
time_bounds_filtered_list.append(
np.loadtxt(
"outputs/mro_{}_filtered_time_bounds_".format(obsName)
+ str(i)
+ ".dat",
delimiter=",",
)
)
if obsName == "range":
range_conversion_factors_list.append(
np.loadtxt(
"outputs/mro_range_conversion_factors_" + str(i) + ".dat",
delimiter=",",
)
)
# Concatenate the above results into single output variables
filtered_times = np.concatenate(filtered_times_list, axis=0)
filtered_residuals = np.concatenate(filtered_residuals_list, axis=0)
rms_residuals = np.concatenate(rms_residuals_list, axis=0)
mean_residuals = np.concatenate(mean_residuals_list, axis=0)
rms_filtered_residuals = np.concatenate(rms_filtered_residuals_list, axis=0)
mean_filtered_residuals = np.concatenate(mean_filtered_residuals_list, axis=0)
time_bounds = np.concatenate(time_bounds_list, axis=0)
time_bounds_filtered = np.concatenate(time_bounds_filtered_list, axis=0)
elevation_angles = np.concatenate(elevation_angles_list, axis=0)
sep_angles = np.concatenate(sep_angles_list, axis=0)
if obsName == "range":
range_conversion_factors = np.concatenate(range_conversion_factors_list, axis=0)
# Load first day detailed results
first_day_residuals = np.loadtxt(
"outputs/mro_{}_first_day_residuals.dat".format(obsName)
)
first_day_times = np.loadtxt("outputs/mro_{}_first_day_times.dat".format(obsName))
first_day_elevation_angles = np.loadtxt(
"outputs/mro_{}_first_day_elevation_angles.dat".format(obsName)
)
first_day_link_ends_ids = np.loadtxt(
"outputs/mro_{}_first_day_link_end_ids.dat".format(obsName)
)
if obsName == "range":
first_day_range_conversion_factors = np.loadtxt(
"outputs/mro_range_conversion_factors_first_day.dat"
)
if obsName == "doppler":
supTitle = "Averaged Doppler"
unit = "Hz"
elif obsName == "range":
unit = "RU"
supTitle = "Sequential Range"
# Plot residuals over time
fig, ax1 = plt.subplots()
plt.suptitle(supTitle)
ax1.scatter(
(filtered_times - np.min(filtered_times)) / 86400.0, filtered_residuals, s=2
)
ax1.grid()
if obsName == "doppler":
ax1.set_ylim([-0.1, 0.1])
ax1.set_xlim([0, 365])
ax1.set_xlabel("Time [days]")
ax1.set_ylabel("Residuals [{}]".format(unit))
if obsName == "range":
ax2 = ax1.twinx()
color = "tab:red"
ax2.scatter(
(filtered_times - np.min(filtered_times)) / 86400.0,
filtered_residuals * range_conversion_factors,
s=2,
)
ax2.set_ylabel("Residuals [m]", color=color)
ax2.tick_params(axis="y", labelcolor=color)
fig.tight_layout()
# Plot RMS and mean residuals, both pre- and post-filtering of the outliers
# The elevation and SEP angles are also plotted.
fig2, axs = plt.subplots(3, 2, figsize=(10, 8))
plt.suptitle(supTitle)
axs[0, 0].plot(
(time_bounds[:, 0] - np.min(time_bounds)) / 86400,
rms_residuals,
".",
markersize=1,
)
axs[0, 0].grid()
if obsName == "doppler":
axs[0, 0].set_ylim([-0.01, 0.1])
axs[0, 0].set_xlim([0, 365])
axs[0, 0].set_xlabel("Time [days]")
axs[0, 0].set_ylabel("RMS residuals [{}]".format(unit))
axs[0, 0].set_title("RMS residuals")
axs[0, 1].plot(
(time_bounds[:, 0] - np.min(time_bounds)) / 86400,
mean_residuals,
".",
markersize=1,
)
axs[0, 1].grid()
if obsName == "doppler":
axs[0, 1].set_ylim([-0.02, 0.02])
axs[0, 1].set_xlim([0, 365])
axs[0, 1].set_xlabel("Time [days]")
axs[0, 1].set_ylabel("Mean residuals [{}]".format(unit))
axs[0, 1].set_title("Mean residuals")
axs[1, 0].plot(
(time_bounds_filtered[:, 0] - np.min(time_bounds_filtered)) / 86400,
rms_filtered_residuals,
".",
markersize=1,
)
axs[1, 0].grid()
if obsName == "doppler":
axs[1, 0].set_ylim([-0.01, 0.1])
axs[1, 0].set_xlim([0, 365])
axs[1, 0].set_xlabel("Time [days]")
axs[1, 0].set_ylabel("RMS residuals [{}]".format(unit))
axs[1, 0].set_title("RMS residuals (post-filtering)")
axs[1, 1].plot(
(time_bounds_filtered[:, 0] - np.min(time_bounds_filtered)) / 86400,
mean_filtered_residuals,
".",
markersize=1,
)
axs[1, 1].grid()
if obsName == "doppler":
axs[1, 1].set_ylim([-0.02, 0.02])
axs[1, 1].set_xlim([0, 365])
axs[1, 1].set_xlabel("Time [days]")
axs[1, 1].set_ylabel("Mean residuals [{}]".format(unit))
axs[1, 1].set_title("Mean residuals (post-filtering)")
axs[2, 0].plot(
(filtered_times - np.min(filtered_times)) / 86400,
elevation_angles * 180 / np.pi,
".",
markersize=1,
)
axs[2, 0].grid()
axs[2, 0].set_ylim([0, 90])
axs[2, 0].set_xlim([0, 365])
axs[2, 0].set_xlabel("Time [days]")
axs[2, 0].set_ylabel("Elevation angle [deg]")
axs[2, 0].set_title("Elevation angle")
axs[2, 1].plot(
(filtered_times - np.min(filtered_times)) / 86400,
sep_angles * 180 / np.pi,
".",
markersize=1,
)
axs[2, 1].grid()
axs[2, 1].set_xlim([0, 365])
axs[2, 1].set_xlabel("Time [days]")
axs[2, 1].set_ylabel("SEP angle [deg]")
axs[2, 1].set_title("SEP angle")
fig2.tight_layout()
# Plot residuals and elevation angles over one day
fig3, ax1 = plt.subplots()
plt.suptitle(supTitle)
ax1.scatter(
(first_day_times - np.min(first_day_times)) / 3600.0,
first_day_residuals,
c=first_day_link_ends_ids,
s=10,
)
if obsName == "doppler":
ax1.set_ylim([-0.02, 0.02])
ax1.set_ylabel("Residuals [{}]".format(unit))
ax2 = ax1.twinx()
color = "tab:red"
ax2.set_ylabel("Elevation angle [deg]", color=color)
ax2.plot(
(first_day_times - np.min(first_day_times)) / 3600.0,
first_day_elevation_angles * 180 / np.pi,
".",
markersize=1,
color=color,
)
ax2.tick_params(axis="y", labelcolor=color)
plt.grid()
ax1.set_xlim([0, 24])
ax1.set_xlabel("Time [hours]")
fig3.tight_layout()
ax1.set_title("Residuals over one day")
plt.show()