Receiver Clock for GNSS-based LEO OD

Hi all,

I am writing an orbit determination script for a LEO satellite based on pseudorange measurements (with a plan to later integrate also Doppler and carrier phase data).

I am using a BatchLSEstimator and parsing the measurements using a new OneWayGNSSRange for every individual time/PRN measurement I have. GPS positions and transmitter clocks are fetched from an SP3 file.

I then process measurements for a given time using the .processMeasurements() method and then loop through all the time instants available.

I am having some trouble in defining how the receiver clock should be handled:.

I am currently defining a new ObservableSatellite for each time instant, so all OneWayGNSSRange measurements relative to the same time instant should be linked to the same ObservableSatellite.

However, the filter seems to output a clock value for each observed PRN rather than a single value: at the end of the for loop with N being the number of time instants, instead of a clock signal with N elements I get a dataset in which a DIFFERENT receiver clock value is computed for all PRNs in view every time instant, so something like “NxM” elements.

General details:

  • I am not adding modifiers to the OneWayGNSSRange calls.
  • For each measurement (so all PRNs at all time) I am using measurement.getSatellites().get(0).getClockOffsetDriver().setSelected(true); to activate the estimation of the clock .
  • GPS clocks estimation is not activated.

Is this the planned behaviour in orekit? Or am I missing something?

Thank you for the support (and for the fantastic tool that is Orekit).

I am not sure Orekit is currently able to do what you want with a batch least squares.
The ObservableSatellite holds together a propagator index and a clock, so it assumes the clock remains the same throughout the propagation. In other words, it doesn’t allow stochastic variables.
For stochastic variables, a Kalman filter is probably better suited as it allows to change the state (here the receiver clock) each time it receives a new set of measurements.
Also if you put by yourself some indices in the ObservableSatellite, you will probably mix things up with the GNSS satellites. I am not really sure I understand what you do.

thank you for the very fast reply.

You are right, I am not using a BatchLSEstimator but rather a KalmanEstimatorBuilder.

final KalmanEstimator kalman = new KalmanEstimatorBuilder().
		                addPropagationConfiguration(propagatorBuilder, new ConstantProcessNoise(initialP, Q)).
		                estimatedMeasurementsParameters(estimatedMeasurementsParameters,new ConstantProcessNoise(measurementP, measurementQ)).

Sorry fo the confusion, I was reading the wrong script file and I mixed things up.

About the indices, I always initialize with new ObservableSatellite(0);, so no new index is being used.

Building a new instance with the same index should be avoided. It just creates a bunch of new parameter drivers with the same names that will ultimately be gathered in a parameter drivers list to be synchronized together as they have the same name. This wastes computing resources. You should build the observable satellite once and reuse the instance, and then you can call setSelected(true) only once.

How do you retrieve the clock offsets you put in the plot? Do you get them by name? Are the names all different or are they similar?

I retrieve the values for the estimated clock by attaching to the KalmanEstimatorBuilder an observer with this code:

		Integer nparams = estimation.getEstimatedMeasurementsParameters().getNbParams();
		for (int i = 0; i< nparams; i++) {
			System.out.println(estimation.getCurrentDate().toString() +" "+estimation.getEstimatedMeasurementsParameters().getDrivers().get(i).getName() + " " + estimation.getEstimatedMeasurementsParameters().getDrivers().get(0).getValue());

And I get an output like this:

2024-02-23T18:45:42.000Z clock-offset-satellite-0 6.061874439835764E-4
2024-02-23T18:45:42.000Z clock-offset-satellite-0 5.840465529591797E-4
2024-02-23T18:45:42.000Z clock-offset-satellite-0 5.857386058050472E-4
2024-02-23T18:45:42.000Z clock-offset-satellite-0 5.903978120956597E-4
2024-02-23T18:45:42.000Z clock-offset-satellite-0 5.8669370339149E-4
2024-02-23T18:45:42.000Z clock-offset-satellite-0 6.143934152323979E-4
2024-02-23T18:45:42.000Z clock-offset-satellite-0 6.310793802136842E-4
2024-02-23T18:46:02.000Z clock-offset-satellite-0 6.136714184946021E-4
2024-02-23T18:46:02.000Z clock-offset-satellite-0 5.915368933795793E-4
2024-02-23T18:46:02.000Z clock-offset-satellite-0 5.934356157128548E-4
2024-02-23T18:46:02.000Z clock-offset-satellite-0 5.976553971157591E-4
2024-02-23T18:46:02.000Z clock-offset-satellite-0 5.943038844101782E-4
2024-02-23T18:46:02.000Z clock-offset-satellite-0 6.216827565187347E-4
2024-02-23T18:46:02.000Z clock-offset-satellite-0 6.388208932590102E-4
2024-02-23T18:46:22.000Z clock-offset-satellite-0 6.211592277316578E-4
2024-02-23T18:46:22.000Z clock-offset-satellite-0 5.990527474848897E-4
2024-02-23T18:46:22.000Z clock-offset-satellite-0 6.011477374206584E-4
2024-02-23T18:46:22.000Z clock-offset-satellite-0 6.049337490136468E-4
2024-02-23T18:46:22.000Z clock-offset-satellite-0 6.01928823031981E-4
2024-02-23T18:46:22.000Z clock-offset-satellite-0 6.28972420764826E-4
2024-02-23T18:46:22.000Z clock-offset-satellite-0 6.465468853411892E-4

As you can see I get multiple values for each time tag.

As a first attempt I will try and use a single ObservableSatellite for all measurements rather then creating new ones for each time step. I will get back to you with the results.

Thanks once again.

Hi @GMari,

With the Kalman, if you have measurements on the same date you should “multiplex” them using the MultiplexedMeasurement class.
Otherwise, you re-estimate the state (including the clock offset) for each measurement instead of using the fact that you have different measurements from different sources on the same date.


1 Like

Dear @MaximeJ, this did the trick.

If I create a new MultiplexedMeasurement with all measurements relative to a given time stamp and then process them with the .estimationStep() method the filter returns a single clock estimate as expected.

I had to replace the .processMeasurements() method with the .estimationStep() one as the former does not seem to accept Multiplexed measurements.

I have also made sure that only a single ObservableSatellite is used for the entire dataset as @luc suggested.

This now looks to be on the right track. Thank you both so much for solving in a matter of hours a matter that has been bugging me for quite some time.