New Kalman filters in Orekit

Hi all,

With my intern Gaëtan we are working on adding the Unscented Kalman Filter (UKF) and its semi-analytical version, the Unscented Semi-analytical Kalman Filter (USKF), in Orekit. We are very happy with the results of the two algorithms.

The first task of the internship was to add the mathematical algorithm of the UKF in Hipparchus. This task is completed and the algorithm available in Hipparchus 2.2.

The second task was the implementation of the two filters to perform satellite orbit determination in Orekit. The two filters are implemented and validated. The work is available in a merge request and can be introduced for a minor version.

The purpose of the last task is to reduce the code duplication and have more “generic” classes to initialize the Kalman Filters. Indeed, with this addition, Orekit has 4 differents Kalman filters.
However, we’re having some issues.

Context

In Orekit, a Kalman filter is implemented using 3 classes:

  • XxxModel: The model which combines the mathematics and orbital mechanics point of views.
  • XxxEstimator: The object used by the user to perform the estimation.
  • XxxEstimatorBuilder: The builder for the estimator.

As the XxxModel is specific for each Kalman filter, it is require to have one class per filter.
Currently, we are not thinking about having a generic XxxEstimator class since the implementation is a bit different for the semi-analytical and non semi-analytical filter.

The class we have to optimize is the XxxEstimatorBuilder. We want to optimize this class in order to have only one (i.e., not 4) and let the user initialize any Kalman filter using this single class.

Please find below some idea. We didn’t try them, they are just here to open discussions.

Proposal 1

  1. Add an interface SequentialEstimator implemented by the 4 Kalman filters. It could contain the methods estimationStep() and processMeasurements()

  2. Add a new parameter to the KalmanEstimatorBuilder class: utProvider (type UnscentedTransformProvider) and a new method to initialize it: unscentedTransformProvider

    /** Configure the unscented transform provider.
     * @param transformProvider unscented transform to use for the prediction phase
     * @return this object.
     */
    public KalmanEstimatorBuilder unscentedTransformProvider(final UnscentedTransformProvider transformProvider) {
        this.utProvider = transformProvider;
        return this;
    }
  1. Add a type generic to the KalmanEstimatorBuilder class.
    The class could be something like:
public class KalmanEstimatorBuilder<K extends SequentialEstimator> {

...

    public K build() {
        ...
    }

Advantage: Easy to implement and extendable if a user implements its own filter.
Drawback: Can be done only for a major release.

Proposal 2

  1. Add an interface SequentialEstimator implemented by the 4 Kalman filters. It could contain the methods estimationStep() and processMeasurements()

  2. Add a new parameter to the KalmanEstimatorBuilder class: utProvider (type UnscentedTransformProvider) and a new method to initialize it: unscentedTransformProvider

    /** Configure the unscented transform provider.
     * @param transformProvider unscented transform to use for the prediction phase
     * @return this object.
     */
    public KalmanEstimatorBuilder unscentedTransformProvider(final UnscentedTransformProvider transformProvider) {
        this.utProvider = transformProvider;
        return this;
    }
  1. Add an enumerate KalmanType containing the method build(…) (implemented for each filter) and 4 entries: EXTENDED, EXTENDED_SEMI_ANALYTICAL, UNSCENTED, and UNSCENTED_SEMI_ANALYTICAL.

  2. Add a new parameter to the KalmanEstimatorBuilder: kalmanType. It could be set by default to KalmanType.EXTENDED (to be compatible with a minor version) and modifiable using

    public KalmanEstimatorBuilder kalmanType(final KalmanType type) {
        this.kalmanType= type;
        return this;
    }
  1. Call the build(...) method of the kalmanType inside the build(...) method of the estimator builder.
    public SequentialEstimator build() {
          return kalmanType.build(decomposer, propagatorBuilders, processNoiseMatrixProviders,
                                  estimatedMeasurementsParameters, measurementProcessNoiseMatrix,
                                  utProvider);
    }

Advantage: Easy to implement and can be done for a minor release.
Drawback: Not extendable for a user having its own filter

Proposal 3

Imagine something with a single XxxEstimator too.

Advantage: Reduce a lot of code (i.e., two factorizations), could include user-specific Kalman Filter, could be done for a minor release.
Drawback: Probably difficult to implement.

Conclusion

We would be very happy to have your comments on the different proposals and tell us if you think that one is interesting to implement.
Also, I somebody has a fourth idea, we would be very happy too.

Thank you for your help,
Bryan

Could I suggest that you do the simplest thing (i.e. implement the two new XxxEstimatorBuilder classes) so that we can enjoy the UKF at the next minor release in a way that we’re used to using the sequential estimators? Then introduce the simplifying changes in your Proposal 1 at the next major release?

Hi,

Great work guys !

I agree it would be really nice to have the UKF and USKF in version 11.3.

To solve the drawback of Proposal 2, KalmanType could be an interface and the enumerate KalmanTypes (or OrekitKalmanType or BuiltInKalmanType) could implement this interface.
That way a user would just have to implement the KalmanType interface to add his own Kalman filter, he wouldn’t be blocked by the fact that an enumerate is not extendable.

That being said, I tend to prefer proposal 1 because I find it cleaner, but it would delay too much the integration of your work to the library.

Hope this helps,
Maxime

Hi Mark and Maxime,

Thank you both for your comments. I appreciate! :slight_smile:

I also agree that the best option is to have this functionality for the 11.3 release.

Maxime, I like the idea of having an interface implemented by the enumerate. It’s easy to implement, extendable for users that want to implement their own Kalman filters, and suitable for a minor release. Thank you.

As Mark said, we can think about the proposal 1 for the next major release, because it is the cleaner way.

Before implementing this, I have a last question.Do you think it might not be inconvenient for users to have proposal 2 for 11.3 release and proposal 1 for 11.0 release?
Knowing that a user using the extended kalman filter (EKF) will not have to make any changes in his code with proposal 2. because it will be the default configuration of the builder.

Bryan

Hi Bryan,

Yes of course it is and it will somehow double the amount of work for the developers.
But if users like Mark want it released fast I see no better option.
Besides, waiting for 12.0 and changing the interfaces would still break the API for a user already using an EKF.
So the real question is, are you or are we willing to do the work twice to have the UKF/USKF released faster ? :wink:

Hi,

Finally, we will follow Mark’s recommendations. The current statuts of the merge request could be merge dor 11.3 and we will implement for 12.0 the proposal 1.

Best regards,
Bryan