Orbit Determination Example

In this tutorial we will perform a basic orbit determination, using user defined data.

First, load all the godot modules we will need:

In [1]:
from godot.core import util, tempo, autodif as ad
from godot import cosmos
import godot.core.astro as astro
import godot.core.events as events
import godot.model.common as common
import godot.model.obs as obs

Load the universe configuration and create the universe object.

We print out all the parameters and their status. Notice all are fixed at this time.

In [2]:
# avoid verbose output
util.suppressLogger()

uni_cfg = cosmos.util.load_yaml("universe.yml")
uni = cosmos.Universe(uni_cfg)

print(uni.parameters)
Parameter name          Type        Physical value Scale          Scaled value   Lower bound    Upper bound    
NGA_x_bias              Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_106               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_107               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_108               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_109               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_110               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_111               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_112               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_113               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_114               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_115               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_116               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_117               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_118               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_119               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_120               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_121               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_122               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_123               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_124               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_125               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_126               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_127               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_bias              Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_106               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_107               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_108               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_109               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_110               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_111               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_112               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_113               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_114               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_115               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_116               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_117               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_118               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_119               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_120               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_121               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_122               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_123               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_124               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_125               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_126               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_127               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_bias              Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_106               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_107               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_108               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_109               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_110               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_111               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_112               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_113               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_114               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_115               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_116               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_117               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_118               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_119               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_120               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_121               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_122               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_123               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_124               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_125               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_126               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_127               Fixed       0              1              0              -1.79769e+308  1.79769e+308   

We have created a simple trajectory for a Lunar orbiter with a single control point. We load this trajectory configuration and create the trajectory object.

Again, we print out all the parameters and their status. Notice the trajectory has created more parameters, but all are still fixed.

In [3]:
tra_cfg = cosmos.util.load_yaml("trajectory.yml")
tra = cosmos.Trajectory(uni, tra_cfg, True)

print(uni.parameters)
Parameter name          Type        Physical value Scale          Scaled value   Lower bound    Upper bound    
NGA_x_bias              Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_106               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_107               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_108               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_109               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_110               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_111               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_112               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_113               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_114               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_115               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_116               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_117               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_118               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_119               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_120               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_121               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_122               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_123               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_124               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_125               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_126               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_127               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_bias              Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_106               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_107               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_108               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_109               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_110               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_111               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_112               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_113               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_114               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_115               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_116               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_117               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_118               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_119               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_120               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_121               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_122               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_123               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_124               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_125               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_126               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_127               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_bias              Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_106               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_107               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_108               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_109               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_110               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_111               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_112               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_113               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_114               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_115               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_116               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_117               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_118               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_119               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_120               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_121               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_122               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_123               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_124               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_125               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_126               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_127               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
initial_state_dt        Fixed       0              1e+06          0              -1.79769e+308  1.79769e+308   
initial_state_SC_center_smaFixed       10000          1e+06          0.01           -1.79769e+308  1.79769e+308   
initial_state_SC_center_eccFixed       0              0.1            0              -1.79769e+308  1.79769e+308   
initial_state_SC_center_incFixed       1.5708         0.1            15.708         -1.79769e+308  1.79769e+308   
initial_state_SC_center_ranFixed       -1.19306       0.1            -11.9306       -1.79769e+308  1.79769e+308   
initial_state_SC_center_aopFixed       2.25115        0.1            22.5115        -1.79769e+308  1.79769e+308   
initial_state_SC_center_tanFixed       0              0.1            0              -1.79769e+308  1.79769e+308   
initial_state_SC_mass   Fixed       6289.11        100            62.8911        -1.79769e+308  1.79769e+308   
initial_state_SC_dv     Fixed       0.840879       0.01           84.0879        -1.79769e+308  1.79769e+308   
start_dt                Fixed       43200          1e+06          0.0432         1e-06          1.79769e+308   
end_dt                  Fixed       864000         1e+06          0.864          1e-06          1.79769e+308   

We have created a simple od problem for our Lunar orbiter. We load this problem configuration and create the problem object.

In [4]:
pro_cfg = cosmos.util.load_yaml("problem.yml")
prob = cosmos.orb.Problem(uni,pro_cfg)

Once the problem is created, the track-status of the parameters may be changed to free if they are to be estimated or considered.

In [5]:
print(uni.parameters)
Parameter name          Type        Physical value Scale          Scaled value   Lower bound    Upper bound    
initial_state_SC_center_aopFree        2.25115        0.1            22.5115        -1.79769e+308  1.79769e+308   
initial_state_SC_center_eccFree        0              0.1            0              -1.79769e+308  1.79769e+308   
initial_state_SC_center_incFree        1.5708         0.1            15.708         -1.79769e+308  1.79769e+308   
initial_state_SC_center_ranFree        -1.19306       0.1            -11.9306       -1.79769e+308  1.79769e+308   
initial_state_SC_center_smaFree        10000          1e+06          0.01           -1.79769e+308  1.79769e+308   
initial_state_SC_center_tanFree        0              0.1            0              -1.79769e+308  1.79769e+308   
NGA_x_bias              Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_106               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_107               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_108               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_109               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_110               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_111               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_112               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_113               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_114               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_115               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_116               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_117               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_118               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_119               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_120               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_121               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_122               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_123               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_124               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_125               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_126               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_x_127               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_bias              Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_106               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_107               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_108               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_109               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_110               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_111               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_112               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_113               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_114               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_115               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_116               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_117               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_118               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_119               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_120               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_121               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_122               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_123               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_124               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_125               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_126               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_y_127               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_bias              Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_106               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_107               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_108               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_109               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_110               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_111               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_112               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_113               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_114               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_115               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_116               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_117               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_118               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_119               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_120               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_121               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_122               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_123               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_124               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_125               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_126               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
NGA_z_127               Fixed       0              1              0              -1.79769e+308  1.79769e+308   
initial_state_dt        Fixed       0              1e+06          0              -1.79769e+308  1.79769e+308   
initial_state_SC_mass   Fixed       6289.11        100            62.8911        -1.79769e+308  1.79769e+308   
initial_state_SC_dv     Fixed       0.840879       0.01           84.0879        -1.79769e+308  1.79769e+308   
start_dt                Fixed       43200          1e+06          0.0432         1e-06          1.79769e+308   
end_dt                  Fixed       864000         1e+06          0.864          1e-06          1.79769e+308   

Now we can propagate the trajectory, since we have established - via the problem configuration - which parameters to track

In [6]:
tra.compute(True)

First, we will perform a very simple OD solution, using only the a priori information which is specified in the problem configuration:

In [7]:
# create the solver from the problem
solv=cosmos.orb.Solver(prob)

# add equations from the problem configuration to the solver
solv.processProblemEquations()

# solve
solv.solve()

# generate a filter solution
fs = solv.filterSolution()

# print the solution and covariance

print(f"The solution {fs.solution()}")

print(f"The solution covariance {fs.covariance()}")
The solution [ 2.25115010e+00  0.00000000e+00  1.57079633e+00 -1.19306470e+00
  1.00000000e+04  0.00000000e+00]
The solution covariance [[ 1.0000000e-02 -0.0000000e+00 -0.0000000e+00 -0.0000000e+00
  -0.0000000e+00 -0.0000000e+00]
 [-0.0000000e+00  1.0000000e-02 -0.0000000e+00 -0.0000000e+00
  -0.0000000e+00 -0.0000000e+00]
 [-0.0000000e+00  0.0000000e+00  3.0461742e-06 -0.0000000e+00
  -0.0000000e+00 -0.0000000e+00]
 [-0.0000000e+00  0.0000000e+00  0.0000000e+00  1.0000000e-02
  -0.0000000e+00 -0.0000000e+00]
 [-0.0000000e+00  0.0000000e+00  0.0000000e+00  0.0000000e+00
   1.0000000e+02 -0.0000000e+00]
 [-0.0000000e+00  0.0000000e+00  0.0000000e+00  0.0000000e+00
  -0.0000000e+00  3.0461742e-06]]

Adding tracking data

We can add equations to the filter, which means adding either a priori information or observations.

The user can add arbitrary equations by creating their own classes.

We use the OneWayLightTime class to build a simple Range observable:

In [8]:
class Range(common.VectorTimeEvaluable):
    """
    Range Data
    """
    def __init__(self, uni, station, spacecraft, ul_bias=None, dl_bias=None, xpr_bias=None, noise=None):
        common.VectorTimeEvaluable.__init__(self)
        self.__uni = uni
        self.__station_point = self.__uni.frames.pointId(station)
        self.__spacecraft_point = self.__uni.frames.pointId(spacecraft)
        # optional biases and noise - not implemented below
        self.__ul_bias = ul_bias
        self.__dl_bias = dl_bias
        self.__xpr_bias = xpr_bias
        self.__noise = noise
        self.__owlt = obs.OneWayLightTime(
            self.__uni.frames, 
            self.__uni.frames.pointId("SSB"), # Light Time center
            self.__uni.frames.axesId("ICRF"), # Light Time axes
            maxIter = 5,
            thdIter = 1e-6
            )

    def eval(self, epoch):

        lt_downlink = self.__owlt.eval(
            epoch,
            self.__station_point, # receiver
            self.__spacecraft_point, # transmitter
            obs.Backward
            ) 
        if self.__dl_bias is not None:
            lt_downlink += self.__dl_bias.eval(epoch)
        if self.__xpr_bias is not None:
            lt_downlink += self.__xpr_bias.eval(epoch - lt_downlink)        
        lt_uplink = self.__owlt.eval(
            epoch - lt_downlink,
            self.__spacecraft_point, # transmitter
            self.__station_point, # receiver
            obs.Backward
            )
        if self.__ul_bias is not None:
            lt_uplink += self.__ul_bias.eval(epoch)            
        noise = self.__noise.eval(epoch) if self.__noise is not None else 0
        return ad.concatenate([lt_downlink + lt_uplink + noise])

We can evaluate this as follows:

In [9]:
nno_rng = Range(uni, 'New_Norcia', 'SC_center')
o = nno_rng.eval(tempo.XEpoch("2026-01-07T16:42:13.815276 TDB"))
print(o)
print(common.resolve(o))
         Value |  @ 2026-01-07T16:42:12.540 TDB[0]  @ 2026-01-07T16:42:12.540 TDB[1]  @ 2026-01-07T16:42:12.540 TDB[2]  @ 2026-01-07T16:42:12.540 TDB[3]  @ 2026-01-07T16:42:12.540 TDB[4]  @ 2026-01-07T16:42:12.540 TDB[5]  @ 2026-01-07T16:42:12.540 TDB[6]  @ 2026-01-07T16:42:12.540 TDB[7] |  @ 2026-01-07T16:42:12.540 TDB[0]  @ 2026-01-07T16:42:12.540 TDB[1]  @ 2026-01-07T16:42:12.540 TDB[2]  @ 2026-01-07T16:42:12.540 TDB[3]  @ 2026-01-07T16:42:12.540 TDB[4]  @ 2026-01-07T16:42:12.540 TDB[5]  @ 2026-01-07T16:42:12.540 TDB[6]  @ 2026-01-07T16:42:12.540 TDB[7]
  2.551570e+00 |                     -3.175426e-06                      8.945559e-07                      4.910089e-07                      0.000000e+00                      0.000000e+00                      0.000000e+00                      0.000000e+00                      0.000000e+00 |                     -3.176076e-06                      8.943715e-07                      4.909304e-07                      0.000000e+00                      0.000000e+00                      0.000000e+00                      0.000000e+00                      0.000000e+00

         Value | initial_state_SC_center_sma | initial_state_SC_center_ecc | initial_state_SC_center_inc | initial_state_SC_center_ran | initial_state_SC_center_aop | initial_state_SC_center_tan
  2.551570e+00 |                1.240256e-06 |               -1.240311e-02 |                5.003692e-02 |                4.048482e-02 |                1.241400e-02 |                1.241400e-02

We can also compute random noise as follows:

In [10]:
import numpy as np
class GaussianNoise(common.ScalarTimeEvaluable):
    """Simple Gaussian noise"""

    def __init__(self, std_dev, bias=0.0):
        """Constructor"""
        super().__init__()
        self.__bias = bias
        self.__std_dev = std_dev

    def eval(self, e) -> np.ndarray:
        """Eval method"""
        return np.random.normal(self.__bias, self.__std_dev, 1)[0]

Observation Schedules

We can use the events system to compute when the observations can be made

In [11]:
def sc_nno_elev( epo ):
    x = uni.frames.vector3('New_Norcia', 'SC_center', 'New_Norcia', epo)
    return astro.sphericalFromCart(x)[2]
grid = tra.range().createGrid(86400/2)
sc_visible = events.generateEventIntervalSet( sc_nno_elev, 1e-6, grid, 1e-6 )
# TBD add occultation events and merge with sc_visible
# see https://gitlab.esa.int/midas/midas/-/blob/master/midas/od/_scheduler_filters.py#L307
# ...
# sc_occulted = events.generateEventIntervalSet( func, 1e-6, grid, 1e-6 )
# sc_not_occulted = events.complement(sc_occulted)
# get overlap of all 
#sc_visible = events.overlap([sc_occulted, sc_visible])

# create observation times during visibility
time_tags = []
for pss in sc_visible:
    for tt in pss.createGrid(600):
        time_tags.append(tt.value())

Next we compute the True trajectory (in this case a perturbed initial state from the pre-loaded trajectory)

In [12]:
tra_true_cfg = cosmos.util.load_yaml("trajectory_true.yml")
tra_true = cosmos.Trajectory(uni, tra_true_cfg, True)
tra_true.compute(False)

Now we can process these observations, weighted by a noise value:

In [13]:
# create a new solver
solv=cosmos.orb.Solver(prob)
# add apriori information from the problem
solv.processProblemEquations()
# range noise std dev in seconds
range_noise = 0.33e-8
# create a modelled range object
rng_comp = Range(uni, "New_Norcia", "SC_center")
# create a observed range object
rng_obs = Range(uni, "New_Norcia", "SC_true_center", noise=GaussianNoise(range_noise))
# create residuals
# define a reference epoch
epoch = tempo.Epoch("2026-01-07T16:42:13.815276 TDB")
# process one hour of range data with 60 second time step
residuals0 = []
for ep in time_tags:
    residual = rng_obs.eval(ep) - rng_comp.eval((tempo.XEpoch(ep)))
    # process weighted residuals
    solv.process(residual/range_noise)
    residuals0.append([ep, residual.value()[0]])
# solve the od
solv.solve()
# create a solution object
fs = solv.filterSolution()
print(fs.covariance())
[[ 3.04524656e-06  2.80352335e-18  3.84407123e-17 -1.11059034e-17
   3.27205340e-14 -3.04524656e-06]
 [ 2.80352335e-18  5.25925292e-18  4.90117758e-19 -2.39525765e-18
   6.03961414e-16  7.32649001e-22]
 [ 3.84407123e-17  4.90117758e-19  1.92148346e-17 -1.96116874e-18
   5.23090137e-15  1.13449470e-20]
 [-1.11059034e-17 -2.39525765e-18 -1.96116874e-18  1.44354150e-17
  -1.50163469e-15 -3.44763480e-21]
 [ 3.27205340e-14  6.03961414e-16  5.23090137e-15 -1.50163469e-15
   4.93033254e-12  1.00700057e-17]
 [-3.04524656e-06  7.32649001e-22  1.13449470e-20 -3.44763480e-21
   1.00700057e-17  3.04524656e-06]]
In [14]:
solv.update()
tra.compute(True)
residuals1 = []
for ep in time_tags:
    residual = rng_obs.eval(ep) - rng_comp.eval(ep)
    residuals1.append([ep, residual.value()[0]])

GODOT has powerful functionality for transforming and propagating the solution and covariance, for example:

In [15]:
class Spherical(common.VectorTimeEvaluable):
    """Class for converting Cartesian to Spherical Polar Coordinates
    """
    def __init__(self, uni, spacecraft):
        common.VectorTimeEvaluable.__init__(self)
        self.__uni = uni
        self.__spacecraft_point = spacecraft
    def eval(self, epoch):
        x = self.__uni.frames.vector3('Earth', self.__spacecraft_point, 'ITRF', epoch)
        return astro.sphericalFromCart(x)

spherical = Spherical(uni, 'SC_center')

# now compute the covariance in spherical coordinates
epoch = tempo.Epoch("2026-01-07T16:42:13.815276 TDB")
for ep in tempo.EpochRange(epoch,epoch+86400/2).createGrid(3600):
    print(fs.covariance(spherical, tempo.XEpoch(ep)))
[[ 3.28692874e-09 -1.53065017e-14 -5.62711263e-15]
 [-1.53064690e-14  1.27762391e-19  4.53594522e-20]
 [-5.62710089e-15  4.53594471e-20  1.98798504e-20]]
[[ 5.70229233e-08 -2.50636998e-13  7.62579707e-13]
 [-2.50636997e-13  1.16695702e-18 -3.32264652e-18]
 [ 7.62579699e-13 -3.32264640e-18  1.08599890e-17]]
[[ 2.33691827e-07 -1.13235074e-12  3.31260481e-12]
 [-1.13235074e-12  5.55967081e-18 -1.60565133e-17]
 [ 3.31260481e-12 -1.60565131e-17  4.74992549e-17]]
[[ 6.05866255e-07 -3.41061050e-12  8.44995867e-12]
 [-3.41061050e-12  1.92847773e-17 -4.76150311e-17]
 [ 8.44995866e-12 -4.76150312e-17  1.18241201e-16]]
[[ 1.30800213e-06 -8.74257006e-12  1.71378426e-11]
 [-8.74257007e-12  5.85425818e-17 -1.14631886e-16]
 [ 1.71378426e-11 -1.14631886e-16  2.24813448e-16]]
[[ 2.48711796e-06 -1.96607535e-11  2.94817782e-11]
 [-1.96607535e-11  1.55561962e-16 -2.33165430e-16]
 [ 2.94817782e-11 -2.33165430e-16  3.49659035e-16]]
[[ 4.19832168e-06 -3.86978617e-11  4.35090567e-11]
 [-3.86978617e-11  3.56886596e-16 -4.01171078e-16]
 [ 4.35090567e-11 -4.01171078e-16  4.51040291e-16]]
[[ 6.28453614e-06 -6.65652200e-11  5.47204612e-11]
 [-6.65652200e-11  7.05301976e-16 -5.79727661e-16]
 [ 5.47204612e-11 -5.79727661e-16  4.76557871e-16]]
[[ 8.33203856e-06 -1.00257422e-10  5.73542275e-11]
 [-1.00257422e-10  1.20668966e-15 -6.90253609e-16]
 [ 5.73542276e-11 -6.90253609e-16  3.94865896e-16]]
[[ 9.77714159e-06 -1.32623171e-10  4.72395315e-11]
 [-1.32623171e-10  1.79936881e-15 -6.40881514e-16]
 [ 4.72395315e-11 -6.40881514e-16  2.28277027e-16]]
[[ 1.01423933e-05 -1.54426375e-10  2.47018383e-11]
 [-1.54426375e-10  2.35172622e-15 -3.76151718e-16]
 [ 2.47018383e-11 -3.76151718e-16  6.01726203e-17]]
[[ 9.27409002e-06 -1.58299942e-10 -4.54340957e-12]
 [-1.58299942e-10  2.70255503e-15  7.75790978e-17]
 [-4.54340957e-12  7.75790978e-17  2.23223034e-18]]
[[ 7.43045932e-06 -1.42432546e-10 -3.15201043e-11]
 [-1.42432546e-10  2.73085085e-15  6.04330878e-16]
 [-3.15201043e-11  6.04330878e-16  1.33741058e-16]]

Load the universe configuration and create the universe object

In [16]:
%matplotlib inline

import matplotlib.pyplot as plt
plt.plot([e.mjd() for e,x in residuals0], [x for e,x in residuals0],'.',label='pre-fit')
plt.plot([e.mjd() for e,x in residuals1], [x for e,x in residuals1],'.',label='post-fit')
plt.legend()
Out[16]:
<matplotlib.legend.Legend at 0x7f74c8790198>