1515
1616# Tudat imports for propagation and estimation
1717from tudatpy .interface import spice
18- from tudatpy .dynamics import environment_setup , parameters_setup , parameters , propagation , propagation_setup
18+ from tudatpy .dynamics import environment_setup , parameters_setup , propagation_setup
1919from tudatpy import estimation
20- from tudatpy .estimation import observable_models_setup ,observable_models , observations_setup , observations , estimation_analysis
20+ from tudatpy .estimation import observable_models_setup , estimation_analysis
2121from tudatpy .constants import GRAVITATIONAL_CONSTANT
2222from tudatpy .astro .frame_conversion import inertial_to_rsw_rotation_matrix
23- from tudatpy .astro .time_representation import DateTime
24- from tudatpy .astro import element_conversion
25-
26- # import MPC, SBDB and Horizons interface
23+ import matplotlib .gridspec as gridspec
2724from tudatpy .data .mpc import BatchMPC
2825from tudatpy .data .horizons import HorizonsQuery
2926from tudatpy .data .sbdb import SBDBquery
501498
502499# Create numerical integrator settings
503500integrator_settings = propagation_setup .integrator .runge_kutta_variable_step_size (
504- time_representation .Time (epoch_start_buffer ),
505501 time_representation .Time (timestep_global ),
506502 propagation_setup .integrator .CoefficientSets .rkf_78 ,
507503 time_representation .Time (timestep_global ),
@@ -1022,58 +1018,66 @@ def plot_cartesian_single(
10221018 return fig , ax
10231019
10241020
1025-
1026- import matplotlib .gridspec as gridspec
1027- from matplotlib .lines import Line2D
1028-
1029-
10301021def plot_star_catalog_corrections (
10311022 mpc_batch : BatchMPC , include_satellites : bool = True , figsize = (9 , 6 )
10321023):
1033-
1024+ """
1025+ Plot star catalog RA/DEC corrections per observation with optional satellite observations.
1026+
1027+ Parameters
1028+ ----------
1029+ mpc_batch : BatchMPC
1030+ Batch containing table with 'epochJ2000secondsTDB', 'corr_RA_EFCC18', 'corr_DEC_EFCC18', 'note2'.
1031+ include_satellites : bool, optional
1032+ Whether to include satellite observations, by default True
1033+ figsize : tuple, optional
1034+ Figure size, by default (9, 6)
1035+
1036+ Returns
1037+ -------
1038+ fig, ax1, ax2, hist1, hist2
1039+ Figure, RA axis, Dec axis, RA histogram, Dec histogram
1040+ """
1041+
1042+ # Extract data
10341043 if include_satellites :
1035- epochs = mpc_batch .table ["epochUTC" ].values
1044+ epochsUTC = mpc_batch .table ["epochUTC" ].values
10361045 ra_corrections = mpc_batch .table ["corr_RA_EFCC18" ].values
10371046 dec_corrections = mpc_batch .table ["corr_DEC_EFCC18" ].values
10381047 else :
1039- epochs = mpc_batch .table [mpc_batch . table [ "note2" ] != "S" ][ "epochUTC" ]. values
1040- ra_corrections = mpc_batch .table [mpc_batch . table [ "note2" ] != "S" ][
1041- "corr_RA_EFCC18"
1042- ].values
1043- dec_corrections = mpc_batch . table [ mpc_batch . table [ "note2" ] != "S" ][
1044- "corr_DEC_EFCC18"
1045- ]. values
1048+ mask = mpc_batch .table ["note2" ] != "S"
1049+ epochsUTC = mpc_batch .table ["epochUTC" ][ mask ]. values
1050+ ra_corrections = mpc_batch . table [ "corr_RA_EFCC18" ][ mask ]. values
1051+ dec_corrections = mpc_batch . table [ "corr_DEC_EFCC18" ][ mask ].values
1052+
1053+ # Convert epochs to ISO strings (YYYY-MM-DD)
1054+ iso_labels = [ DateTime . from_epoch ( t ). to_iso_string ()[: 10 ] for t in epochsUTC ]
10461055
1056+ # Numeric x-axis positions
1057+ x = np .arange (len (epochsUTC ))
1058+
1059+ # Set up figure and GridSpec
10471060 fig = plt .figure (figsize = figsize , constrained_layout = True )
10481061 gs = gridspec .GridSpec (
10491062 2 , 2 , width_ratios = [4 , 1 ], height_ratios = [1 , 1 ], hspace = 0.1 , wspace = 0.05
10501063 )
10511064
1052- # Scatter plots
10531065 ax1 = fig .add_subplot (gs [0 , 0 ])
10541066 ax2 = fig .add_subplot (gs [1 , 0 ], sharex = ax1 )
10551067
1056- # Histograms on the right
10571068 hist1 = fig .add_subplot (gs [0 , 1 ], sharey = ax1 )
10581069 hist2 = fig .add_subplot (gs [1 , 1 ], sharey = ax2 )
10591070
10601071 # Scatter plots
1061- ax1 .scatter (epochs , ra_corrections , color = "tab:blue" , marker = "+" )
1062- ax2 .scatter (epochs , dec_corrections , color = "tab:orange" , marker = "+" )
1072+ ax1 .scatter (x , ra_corrections , color = "tab:blue" , marker = "+" )
1073+ ax2 .scatter (x , dec_corrections , color = "tab:orange" , marker = "+" )
10631074
10641075 # Histograms
1065- hist1 .hist (
1066- ra_corrections , bins = 50 , orientation = "horizontal" , color = "tab:blue" , alpha = 0.6
1067- )
1068- hist2 .hist (
1069- dec_corrections ,
1070- bins = 50 ,
1071- orientation = "horizontal" ,
1072- color = "tab:orange" ,
1073- alpha = 0.6 ,
1074- )
1076+ hist1 .hist (ra_corrections , bins = 50 , orientation = "horizontal" , color = "tab:blue" , alpha = 0.6 )
1077+ hist2 .hist (dec_corrections , bins = 50 , orientation = "horizontal" , color = "tab:orange" , alpha = 0.6 )
10751078 hist2 .set_xlabel ("Occurrences" )
10761079
1080+ # Axis labels
10771081 ax1 .set_ylabel (r"Right Ascension $[rad]$" )
10781082 ax2 .set_ylabel (r"Declination $[rad]$" )
10791083 ax2 .set_xlabel ("Epoch [UTC]" )
@@ -1082,83 +1086,93 @@ def plot_star_catalog_corrections(
10821086 ax1 .tick_params (labelbottom = False )
10831087 hist1 .tick_params (labelleft = False , labelbottom = False )
10841088 hist2 .tick_params (labelleft = False )
1089+
1090+ # X-axis ISO tick labels
1091+ tick_spacing = max (1 , len (x )// 10 ) # show ~10 ticks max
1092+ ax2 .set_xticks (x [::tick_spacing ])
1093+ ax2 .set_xticklabels ([iso_labels [i ] for i in range (0 , len (x ), tick_spacing )], rotation = 45 , ha = 'right' )
1094+
10851095 fig .suptitle ("Star Catalog Corrections (per observation)" )
10861096
10871097 return fig , ax1 , ax2 , hist1 , hist2
10881098
1089-
10901099def plot_observation_weights (
1091- mpc_batch : BatchMPC , include_satellites : bool = True , figsize = (9 , 4 )
1100+ mpc_batch , include_satellites : bool = True , figsize = (9 , 4 )
10921101):
1102+ """
1103+ Plot observation weights per RA/DEC pair with optional satellite observations.
1104+
1105+ Parameters
1106+ ----------
1107+ mpc_batch : BatchMPC
1108+ Batch containing table with 'epochUTC', 'weight', and 'note2'.
1109+ include_satellites : bool, optional
1110+ Whether to include satellite observations, by default True
1111+ figsize : tuple, optional
1112+ Figure size, by default (9, 4)
1113+
1114+ Returns
1115+ -------
1116+ fig, ax, hist_ax
1117+ Figure, main scatter axis, histogram axis
1118+ """
1119+
1120+ # Extract regular and satellite observations
1121+ reg_mask = mpc_batch .table ["note2" ] != "S"
1122+ sat_mask = mpc_batch .table ["note2" ] == "S"
1123+
1124+ reg_epochsUTC = mpc_batch .table ["epochUTC" ][reg_mask ].values
1125+ reg_weights = mpc_batch .table ["weight" ][reg_mask ].values
1126+ reg_iso = [DateTime .from_epoch (t ).to_iso_string ()[:10 ] for t in reg_epochsUTC ] # YYYY-MM-DD
10931127
1094- sat_epochs = mpc_batch .table [mpc_batch .table ["note2" ] == "S" ]["epochUTC" ].values
1095- sat_weights = mpc_batch .table [mpc_batch .table ["note2" ] == "S" ]["weight" ].values
1128+ if include_satellites :
1129+ sat_epochsUTC = mpc_batch .table ["epochUTC" ][sat_mask ].values
1130+ sat_weights = mpc_batch .table ["weight" ][sat_mask ].values
1131+ sat_iso = [DateTime .from_epoch (t ).to_iso_string ()[:10 ] for t in sat_epochsUTC ]
10961132
1097- reg_epochs = mpc_batch .table [mpc_batch .table ["note2" ] != "S" ]["epochUTC" ].values
1098- reg_weights = mpc_batch .table [mpc_batch .table ["note2" ] != "S" ]["weight" ].values
1133+ # Numeric x-axis for plotting
1134+ reg_x = np .arange (len (reg_epochsUTC ))
1135+ if include_satellites :
1136+ sat_x = np .arange (len (sat_epochsUTC )) + len (reg_x ) # offset to avoid overlap
10991137
1100- # Set up figure and GridSpec for scatter + histogram
1138+ # Set up figure and GridSpec
11011139 fig = plt .figure (figsize = figsize )
11021140 gs = gridspec .GridSpec (1 , 2 , width_ratios = [4 , 1 ], wspace = 0.05 )
1103-
11041141 ax = fig .add_subplot (gs [0 ])
1105- ax .scatter (reg_epochs , reg_weights , marker = "+" )
1106-
1107- if include_satellites :
1108- ax .scatter (
1109- sat_epochs , sat_weights , marker = "+" , color = "tab:red" , label = "Satellite"
1110- )
1111-
11121142 hist_ax = fig .add_subplot (gs [1 ])
11131143
1114- hist_ranges = (
1115- min (reg_weights .min (), sat_weights .min ()),
1116- max (reg_weights .max (), sat_weights .max ()),
1117- )
1118-
1119- hist_ax .hist (
1120- reg_weights ,
1121- range = hist_ranges if include_satellites else None ,
1122- bins = 30 ,
1123- orientation = "horizontal" ,
1124- color = "tab:blue" ,
1125- alpha = 0.6 ,
1126- log = False ,
1127- )
1128-
1144+ # Scatter plots
1145+ ax .scatter (reg_x , reg_weights , marker = "+" , color = "tab:blue" , label = "Regular" )
11291146 if include_satellites :
1130- hist_ax .hist (
1131- sat_weights ,
1132- range = hist_ranges ,
1133- bins = 30 ,
1134- orientation = "horizontal" ,
1135- color = "tab:red" ,
1136- alpha = 0.6 ,
1137- log = False ,
1138- )
1147+ ax .scatter (sat_x , sat_weights , marker = "+" , color = "tab:red" , label = "Satellite" )
1148+
1149+ # X-axis ticks and labels
1150+ all_x = np .concatenate ([reg_x , sat_x ]) if include_satellites else reg_x
1151+ all_iso = np .concatenate ([reg_iso , sat_iso ]) if include_satellites else reg_iso
1152+
1153+ tick_spacing = max (1 , len (all_x ) // 10 ) # show ~10 ticks max
1154+ ax .set_xticks (all_x [::tick_spacing ])
1155+ ax .set_xticklabels (all_iso [::tick_spacing ], rotation = 45 , ha = 'right' )
1156+
1157+ # Histogram
1158+ hist_ranges = (min (reg_weights .min (), sat_weights .min () if include_satellites else reg_weights .min ()),
1159+ max (reg_weights .max (), sat_weights .max () if include_satellites else reg_weights .max ()))
1160+ hist_ax .hist (reg_weights , bins = 30 ,
1161+ range = hist_ranges if include_satellites else None ,
1162+ orientation = "horizontal" , color = "tab:blue" , alpha = 0.6 , log = False )
1163+ if include_satellites :
1164+ hist_ax .hist (sat_weights , bins = 30 , range = hist_ranges ,
1165+ orientation = "horizontal" , color = "tab:red" , alpha = 0.6 , log = False )
11391166
11401167 hist_ax .tick_params (labelleft = False )
11411168 hist_ax .grid (False )
11421169 hist_ax .set_xlabel ("Occurrences" )
11431170
1171+ # Legends
11441172 if include_satellites :
11451173 legend_elements = [
1146- Line2D (
1147- [0 ],
1148- [0 ],
1149- marker = "+" ,
1150- color = "tab:blue" ,
1151- linestyle = "None" ,
1152- label = "Regular" ,
1153- ),
1154- Line2D (
1155- [0 ],
1156- [0 ],
1157- marker = "+" ,
1158- color = "tab:red" ,
1159- linestyle = "None" ,
1160- label = "Satellite" ,
1161- ),
1174+ Line2D ([0 ], [0 ], marker = "+" , color = "tab:blue" , linestyle = "None" , label = "Regular" ),
1175+ Line2D ([0 ], [0 ], marker = "+" , color = "tab:red" , linestyle = "None" , label = "Satellite" ),
11621176 ]
11631177 ax .legend (handles = legend_elements , title = "Observatory Type" )
11641178
@@ -1169,7 +1183,6 @@ def plot_observation_weights(
11691183
11701184 return fig , ax , hist_ax
11711185
1172-
11731186"""
11741187## Comparison Round 1: Acceleration models
11751188With our core estimation and plotting functions ready, we can now perform a comparison of the three acceleration models. For this first comparison, we turn the remaining options: including satelite data, star catalog corrections and observations weights off. The setups can be described as follows:
@@ -1751,7 +1764,6 @@ def plot_observation_weights(
17511764fig = batch .plot_observations_sky (figsize = (6 , 4 ))
17521765fig .suptitle (f"{ batch .size } observations for { target_name } in the sky" )
17531766fig .axes [0 ].get_legend ().remove ()
1754-
17551767# fig.savefig("Eros_observations_sky.pdf")
17561768
17571769
@@ -1902,4 +1914,4 @@ def plot_observation_weights(
19021914# fig.savefig("Eros_estimation_error_overview.pdf", dpi=400)
19031915
19041916
1905- plt .show ()
1917+ plt .show ()
0 commit comments