1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.estimation.sequential;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.linear.MatrixDecomposer;
23  import org.hipparchus.linear.QRDecomposer;
24  import org.hipparchus.util.UnscentedTransformProvider;
25  import org.orekit.errors.OrekitException;
26  import org.orekit.errors.OrekitMessages;
27  import org.orekit.propagation.conversion.DSSTPropagatorBuilder;
28  import org.orekit.propagation.conversion.PropagatorBuilder;
29  import org.orekit.utils.ParameterDriversList;
30  
31  /** Builder for an Unscented Kalman filter estimator.
32   * <p>
33   * The builder is generalized to accept any {@link PropagatorBuilder}.
34   * Howerver, it is absolutely not recommended to use a {@link DSSTPropagatorBuilder}.
35   * A specific {@link SemiAnalyticalUnscentedKalmanEstimatorBuilder semi-analytical
36   * unscented Kalman Filter} is implemented and shall be used.
37   * </p>
38   * @author Gaƫtan Pierre
39   * @author Bryan Cazabonne
40   * @since 11.3
41   */
42  public class UnscentedKalmanEstimatorBuilder {
43  
44      /** Decomposer to use for the correction phase. */
45      private MatrixDecomposer decomposer;
46  
47      /** Builders for propagators. */
48      private List<PropagatorBuilder> propagatorBuilders;
49  
50      /** Estimated measurements parameters. */
51      private ParameterDriversList estimatedMeasurementsParameters;
52  
53      /** Process noise matrix providers. */
54      private List<CovarianceMatrixProvider> processNoiseMatrixProviders;
55  
56      /** Process noise matrix provider for measurement parameters. */
57      private CovarianceMatrixProvider measurementProcessNoiseMatrix;
58  
59      /** Unscend transform provider. */
60      private UnscentedTransformProvider utProvider;
61  
62      /** Default constructor.
63       *  Set an Unscented Kalman filter.
64       */
65      public UnscentedKalmanEstimatorBuilder() {
66          this.decomposer                      = new QRDecomposer(1.0e-15);
67          this.propagatorBuilders              = new ArrayList<>();
68          this.estimatedMeasurementsParameters = new ParameterDriversList();
69          this.processNoiseMatrixProviders     = new ArrayList<>();
70          this.measurementProcessNoiseMatrix   = null;
71          this.utProvider                      = null;
72      }
73  
74      /** Construct a {@link UnscentedKalmanEstimator} from the data in this builder.
75       * <p>
76       * Before this method is called, {@link #addPropagationConfiguration(PropagatorBuilder,
77       * CovarianceMatrixProvider) addPropagationConfiguration()} must have been called
78       * at least once, otherwise configuration is incomplete and an exception will be raised.
79       * <p>
80       * In addition, the {@link #unscentedTransformProvider(UnscentedTransformProvider)
81       * unscentedTransformProvider()} must be called to configure the unscented transform
82       * provider use during the estimation process, otherwise configuration is
83       * incomplete and an exception will be raised.
84       * </p>
85       * @return a new {@link UnscentedKalmanEstimator}.
86       */
87      public UnscentedKalmanEstimator build() {
88          if (propagatorBuilders.size() == 0) {
89              throw new OrekitException(OrekitMessages.NO_PROPAGATOR_CONFIGURED);
90          }
91          if (utProvider == null) {
92              throw new OrekitException(OrekitMessages.NO_UNSCENTED_TRANSFORM_CONFIGURED);
93          }
94          return new UnscentedKalmanEstimator(decomposer, propagatorBuilders, processNoiseMatrixProviders,
95                                              estimatedMeasurementsParameters, measurementProcessNoiseMatrix,
96                                              utProvider);
97  
98      }
99  
100     /** Configure the matrix decomposer.
101      * @param matrixDecomposer decomposer to use for the correction phase
102      * @return this object.
103      */
104     public UnscentedKalmanEstimatorBuilder decomposer(final MatrixDecomposer matrixDecomposer) {
105         decomposer = matrixDecomposer;
106         return this;
107     }
108 
109     /** Configure the unscented transform provider.
110      * @param transformProvider unscented transform to use for the prediction phase
111      * @return this object.
112      */
113     public UnscentedKalmanEstimatorBuilder unscentedTransformProvider(final UnscentedTransformProvider transformProvider) {
114         this.utProvider = transformProvider;
115         return this;
116     }
117 
118     /** Add a propagation configuration.
119      * <p>
120      * This method must be called once for each propagator to managed with the
121      * {@link UnscentedKalmanEstimator unscented kalman estimatior}. The
122      * propagators order in the Kalman filter will be the call order.
123      * </p>
124      * <p>
125      * The {@code provider} should return a matrix with dimensions and ordering
126      * consistent with the {@code builder} configuration. The first 6 rows/columns
127      * correspond to the 6 orbital parameters which must all be present, regardless
128      * of the fact they are estimated or not. The remaining elements correspond
129      * to the subset of propagation parameters that are estimated, in the
130      * same order as propagatorBuilder.{@link
131      * org.orekit.propagation.conversion.PropagatorBuilder#getPropagationParametersDrivers()
132      * getPropagationParametersDrivers()}.{@link org.orekit.utils.ParameterDriversList#getDrivers()
133      * getDrivers()} (but filtering out the non selected drivers).
134      * </p>
135      * @param builder The propagator builder to use in the Kalman filter.
136      * @param provider The process noise matrices provider to use, consistent with the builder.
137      * @see CovarianceMatrixProvider#getProcessNoiseMatrix(org.orekit.propagation.SpacecraftState,
138      * org.orekit.propagation.SpacecraftState) getProcessNoiseMatrix(previous, current)
139      * @return this object.
140      */
141     public UnscentedKalmanEstimatorBuilder addPropagationConfiguration(final PropagatorBuilder builder,
142                                                                        final CovarianceMatrixProvider provider) {
143         propagatorBuilders.add(builder);
144         processNoiseMatrixProviders.add(provider);
145         return this;
146     }
147 
148     /** Configure the estimated measurement parameters.
149      * <p>
150      * If this method is not called, no measurement parameters will be estimated.
151      * </p>
152      * @param estimatedMeasurementsParams The estimated measurements' parameters list.
153      * @param provider covariance matrix provider for the estimated measurement parameters
154      * @return this object.
155      */
156     public UnscentedKalmanEstimatorBuilder estimatedMeasurementsParameters(final ParameterDriversList estimatedMeasurementsParams,
157                                                                            final CovarianceMatrixProvider provider) {
158         estimatedMeasurementsParameters = estimatedMeasurementsParams;
159         measurementProcessNoiseMatrix   = provider;
160         return this;
161     }
162 
163 }