1   package org.orekit.estimation.sequential;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.hipparchus.linear.MatrixUtils;
7   import org.hipparchus.linear.RealMatrix;
8   import org.hipparchus.linear.RealVector;
9   import org.junit.Assert;
10  import org.junit.Before;
11  import org.junit.Test;
12  import org.orekit.estimation.DSSTContext;
13  import org.orekit.estimation.DSSTEstimationTestUtils;
14  import org.orekit.estimation.DSSTForce;
15  import org.orekit.estimation.measurements.GroundStation;
16  import org.orekit.estimation.measurements.ObservableSatellite;
17  import org.orekit.estimation.measurements.Range;
18  import org.orekit.estimation.measurements.modifiers.Bias;
19  import org.orekit.forces.radiation.RadiationSensitive;
20  import org.orekit.orbits.Orbit;
21  import org.orekit.orbits.OrbitType;
22  import org.orekit.orbits.PositionAngle;
23  import org.orekit.propagation.PropagationType;
24  import org.orekit.propagation.SpacecraftState;
25  import org.orekit.propagation.conversion.DSSTPropagatorBuilder;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.utils.ParameterDriver;
28  import org.orekit.utils.ParameterDriversList;
29  
30  public class SemiAnalyticalKalmanModelTest {
31  
32      /** Orbit type for propagation. */
33      private final OrbitType orbitType = OrbitType.EQUINOCTIAL;
34      
35      /** Position angle for propagation. */
36      private final PositionAngle positionAngle = PositionAngle.MEAN;
37      
38      /** Initial orbit. */
39      private Orbit orbit0;
40      
41      /** Propagator builder. */
42      private DSSTPropagatorBuilder propagatorBuilder;
43      
44      /** Covariance matrix provider. */
45      private CovarianceMatrixProvider covMatrixProvider;
46      
47      /** Estimated measurement parameters list. */
48      private ParameterDriversList estimatedMeasurementsParameters;
49      
50      /** Kalman extended estimator containing models. */
51      private SemiAnalyticalKalmanEstimator kalman;
52      
53      /** Kalman observer. */
54      private ModelLogger modelLogger;
55      
56      /** State size. */
57      private int M;
58  
59      /** Range after t0. */
60      private Range range;
61  
62      /** Driver for satellite range bias. */
63      private ParameterDriver satRangeBiasDriver;
64      
65      /** Driver for SRP coefficient. */
66      private ParameterDriver srpCoefDriver;
67      
68      /** Tolerance for the test. */
69      private final double tol = 1e-16;
70      
71      @Before
72      public void setup() {
73  
74          // Create context
75          DSSTContext context = DSSTEstimationTestUtils.eccentricContext("regular-data:potential:tides");
76          
77          // Initial orbit and date
78          this.orbit0 = context.initialOrbit;
79          ObservableSatellite sat = new ObservableSatellite(0);
80          
81          // Create propagator builder
82          this.propagatorBuilder = context.createBuilder(PropagationType.MEAN, PropagationType.OSCULATING, true,
83                                                         1.0e-6, 60.0, 10., DSSTForce.SOLAR_RADIATION_PRESSURE);
84  
85          // Create PV at t0
86          final AbsoluteDate date0 = context.initialOrbit.getDate();
87          
88          // Create one 0m range measurement at t0 + 10s
89          final AbsoluteDate date  = date0.shiftedBy(10.);
90          final GroundStation station = context.stations.get(0);
91          this.range = new Range(station, true, date, 18616150., 10., 1., sat);
92          // Exact range value is 1.8616150246470984E7 m
93  
94          // Add sat range bias to PV and select it
95          final Bias<Range> satRangeBias = new Bias<Range>(new String[] {"sat range bias"},
96                                                           new double[] {100.},
97                                                           new double[] {10.},
98                                                           new double[] {0.},
99                                                           new double[] {100.});
100         this.satRangeBiasDriver = satRangeBias.getParametersDrivers().get(0);
101         satRangeBiasDriver.setSelected(true);
102         satRangeBiasDriver.setReferenceDate(date);
103         range.addModifier(satRangeBias);
104         for (ParameterDriver driver : range.getParametersDrivers()) {
105             driver.setReferenceDate(date);
106         }
107 
108         // Gather list of meas parameters (only sat range bias here)
109         this.estimatedMeasurementsParameters = new ParameterDriversList();
110         for (final ParameterDriver driver : range.getParametersDrivers()) {
111             if (driver.isSelected()) {
112                 estimatedMeasurementsParameters.add(driver);
113             }
114         }
115         // Select SRP coefficient
116         this.srpCoefDriver = propagatorBuilder.getPropagationParametersDrivers().
117                         findByName(RadiationSensitive.REFLECTION_COEFFICIENT);
118         srpCoefDriver.setReferenceDate(date);
119         srpCoefDriver.setSelected(true);
120         
121         // Create a covariance matrix using the scales of the estimated parameters
122         final double[] scales = getParametersScale(propagatorBuilder, estimatedMeasurementsParameters);
123         this.M = scales.length;
124         this.covMatrixProvider = setInitialCovarianceMatrix(scales);
125 
126         // Initialize Kalman
127         final SemiAnalyticalKalmanEstimatorBuilder kalmanBuilder = new SemiAnalyticalKalmanEstimatorBuilder();
128         kalmanBuilder.addPropagationConfiguration(propagatorBuilder, covMatrixProvider);
129         kalmanBuilder.estimatedMeasurementsParameters(estimatedMeasurementsParameters, null);
130         this.kalman = kalmanBuilder.build();
131         this.modelLogger = new ModelLogger();
132         kalman.setObserver(modelLogger);
133     }
134 
135     @Test
136     public void ModelPhysicalOutputsTest() {
137         
138         // Check model at t0 before any measurement is added
139         // -------------------------------------------------
140         checkModelAtT0();
141 
142     }
143 
144     /** Check the model physical outputs at t0 before any measurement is added. */
145     private void checkModelAtT0() {
146 
147         // Instantiate a Model from attributes
148         final SemiAnalyticalKalmanModel model = new SemiAnalyticalKalmanModel(propagatorBuilder,
149                                                   covMatrixProvider,
150                                                   estimatedMeasurementsParameters,
151                                                   null);
152 
153         // Evaluate at t0
154         // --------------
155         
156         // Time
157         Assert.assertEquals(0., model.getEstimate().getTime(), 0.);
158         Assert.assertEquals(0., model.getCurrentDate().durationFrom(orbit0.getDate()), 0.);
159         
160         // Measurement number
161         Assert.assertEquals(0, model.getCurrentMeasurementNumber());
162         
163         // Normalized state - is zeros
164         final RealVector stateN = model.getEstimate().getState();
165         Assert.assertArrayEquals(new double[M], stateN.toArray(), tol);
166         
167         // Physical state - = initialized
168         final RealVector x = model.getPhysicalEstimatedState();
169         final RealVector expX = MatrixUtils.createRealVector(M);
170         final double[] orbitState0 = new double[6];
171         orbitType.mapOrbitToArray(orbit0, positionAngle, orbitState0, null);
172         expX.setSubVector(0, MatrixUtils.createRealVector(orbitState0));
173         expX.setEntry(6, srpCoefDriver.getReferenceValue());
174         expX.setEntry(7, satRangeBiasDriver.getReferenceValue());
175         final double[] dX = x.subtract(expX).toArray();
176         Assert.assertArrayEquals(new double[M], dX, tol);
177         
178         // Normalized covariance - filled with 1
179         final double[][] Pn = model.getEstimate().getCovariance().getData();
180         final double[][] expPn = new double[M][M];
181         for (int i = 0; i < M; i++) {
182             for (int j = 0; j < M; j++) {
183                 expPn[i][j] = 1.;
184             }
185             Assert.assertArrayEquals("Failed on line " + i, expPn[i], Pn[i], tol);
186         }
187         
188         // Physical covariance = initialized
189         final RealMatrix P   = model.getPhysicalEstimatedCovarianceMatrix();
190         final RealMatrix expP = covMatrixProvider.getInitialCovarianceMatrix(new SpacecraftState(orbit0));
191         final double[][] dP = P.subtract(expP).getData();
192         for (int i = 0; i < M; i++) {
193             Assert.assertArrayEquals("Failed on line " + i, new double[M], dP[i], tol);
194         }
195         
196         // Check that other "physical" matrices are null
197         Assert.assertNull(model.getEstimate().getInnovationCovariance());
198         Assert.assertNull(model.getPhysicalInnovationCovarianceMatrix());
199         Assert.assertNull(model.getEstimate().getKalmanGain());
200         Assert.assertNull(model.getPhysicalKalmanGain());
201         Assert.assertNull(model.getEstimate().getMeasurementJacobian());
202         Assert.assertNull(model.getPhysicalMeasurementJacobian());
203         Assert.assertNull(model.getEstimate().getStateTransitionMatrix());
204         Assert.assertNull(model.getPhysicalStateTransitionMatrix());
205     }
206     
207     /** Get an array of the scales of the estimated parameters.
208      * @param builder propagator builder
209      * @param estimatedMeasurementsParameters estimated measurements parameters
210      * @return array containing the scales of the estimated parameter
211      */
212     private double[] getParametersScale(final DSSTPropagatorBuilder builder,
213                                         final ParameterDriversList estimatedMeasurementsParameters) {
214         final List<Double> scaleList = new ArrayList<>();
215         
216         // Orbital parameters
217         for (ParameterDriver driver : builder.getOrbitalParametersDrivers().getDrivers()) {
218             if (driver.isSelected()) {
219                 scaleList.add(driver.getScale());
220             }
221         }
222         
223         // Propagation parameters
224         for (ParameterDriver driver : builder.getPropagationParametersDrivers().getDrivers()) {
225             if (driver.isSelected()) {
226                 scaleList.add(driver.getScale());
227             }
228         }
229         
230         // Measurement parameters
231         for (ParameterDriver driver : estimatedMeasurementsParameters.getDrivers()) {
232             if (driver.isSelected()) {
233                 scaleList.add(driver.getScale());
234             }
235         }
236         
237         final double[] scales = new double[scaleList.size()];
238         for (int i = 0; i < scaleList.size(); i++) {
239             scales[i] = scaleList.get(i);
240         }
241         return scales;
242     }
243     
244     /** Create a covariance matrix provider with initial and process noise matrix constant and identical.
245      * Each element Pij of the initial covariance matrix equals:
246      * Pij = scales[i]*scales[j]
247      * @param scales scales of the estimated parameters
248      * @return covariance matrix provider
249      */
250     private CovarianceMatrixProvider setInitialCovarianceMatrix(final double[] scales) {
251 
252         final int n = scales.length;
253         final RealMatrix cov = MatrixUtils.createRealMatrix(n, n);
254         for (int i = 0; i < n; i++) {
255             for (int j = 0; j < n; j++) {
256                 cov.setEntry(i, j, scales[i] * scales[j]);
257             }
258         }
259         return new ConstantProcessNoise(cov); 
260     }
261     
262     
263     /** Observer allowing to get Kalman model after a measurement was processed in the Kalman filter. */
264     public class ModelLogger implements KalmanObserver {
265         KalmanEstimation estimation;
266 
267         @Override
268         public void evaluationPerformed(KalmanEstimation estimation) {
269             this.estimation = estimation;
270         }
271     }
272 
273 }