1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.estimation.leastsquares;
18
19 import org.hipparchus.geometry.euclidean.threed.Vector3D;
20 import org.hipparchus.linear.RealMatrix;
21 import org.hipparchus.util.FastMath;
22 import org.junit.jupiter.api.Assertions;
23 import org.junit.jupiter.api.Test;
24 import org.orekit.KeyValueFileParser;
25 import org.orekit.Utils;
26 import org.orekit.attitudes.AttitudeProvider;
27 import org.orekit.bodies.CelestialBody;
28 import org.orekit.bodies.OneAxisEllipsoid;
29 import org.orekit.errors.OrekitException;
30 import org.orekit.estimation.common.AbstractOrbitDetermination;
31 import org.orekit.estimation.common.ParameterKey;
32 import org.orekit.estimation.common.ResultBatchLeastSquares;
33 import org.orekit.forces.ForceModel;
34 import org.orekit.forces.drag.DragForce;
35 import org.orekit.forces.drag.DragSensitive;
36 import org.orekit.forces.empirical.AccelerationModel;
37 import org.orekit.forces.empirical.ParametricAcceleration;
38 import org.orekit.forces.empirical.PolynomialAccelerationModel;
39 import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel;
40 import org.orekit.forces.gravity.OceanTides;
41 import org.orekit.forces.gravity.Relativity;
42 import org.orekit.forces.gravity.SolidTides;
43 import org.orekit.forces.gravity.ThirdBodyAttraction;
44 import org.orekit.forces.gravity.potential.GravityFieldFactory;
45 import org.orekit.forces.gravity.potential.ICGEMFormatReader;
46 import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider;
47 import org.orekit.forces.radiation.KnockeRediffusedForceModel;
48 import org.orekit.forces.radiation.RadiationSensitive;
49 import org.orekit.forces.radiation.SolarRadiationPressure;
50 import org.orekit.models.earth.atmosphere.Atmosphere;
51 import org.orekit.orbits.Orbit;
52 import org.orekit.orbits.PositionAngleType;
53 import org.orekit.propagation.conversion.NumericalPropagatorBuilder;
54 import org.orekit.propagation.conversion.ODEIntegratorBuilder;
55 import org.orekit.time.TimeScalesFactory;
56 import org.orekit.utils.IERSConventions;
57 import org.orekit.utils.ParameterDriver;
58 import org.orekit.utils.ParameterDriversList;
59 import org.orekit.utils.ParameterDriversList.DelegatingDriver;
60
61 import java.io.File;
62 import java.io.IOException;
63 import java.net.URISyntaxException;
64 import java.text.ParseException;
65 import java.util.ArrayList;
66 import java.util.List;
67 import java.util.NoSuchElementException;
68
69 public class NumericalOrbitDeterminationTest extends AbstractOrbitDetermination<NumericalPropagatorBuilder> {
70
71
72 private NormalizedSphericalHarmonicsProvider gravityField;
73
74
75 @Override
76 protected void createGravityField(final KeyValueFileParser<ParameterKey> parser)
77 throws NoSuchElementException {
78
79 final int degree = parser.getInt(ParameterKey.CENTRAL_BODY_DEGREE);
80 final int order = FastMath.min(degree, parser.getInt(ParameterKey.CENTRAL_BODY_ORDER));
81 gravityField = GravityFieldFactory.getNormalizedProvider(degree, order);
82 }
83
84
85 @Override
86 protected double getMu() {
87 return gravityField.getMu();
88 }
89
90
91 @Override
92 protected NumericalPropagatorBuilder createPropagatorBuilder(final Orbit referenceOrbit,
93 final ODEIntegratorBuilder builder,
94 final double positionScale) {
95 return new NumericalPropagatorBuilder(referenceOrbit, builder, PositionAngleType.MEAN,
96 positionScale);
97 }
98
99
100 @Override
101 protected void setMass(final NumericalPropagatorBuilder propagatorBuilder, final double mass) {
102 propagatorBuilder.setMass(mass);
103 }
104
105
106 @Override
107 protected List<ParameterDriver> setGravity(final NumericalPropagatorBuilder propagatorBuilder,
108 final OneAxisEllipsoid body) {
109 final ForceModel gravityModel = new HolmesFeatherstoneAttractionModel(body.getBodyFrame(), gravityField);
110 propagatorBuilder.addForceModel(gravityModel);
111 return gravityModel.getParametersDrivers();
112 }
113
114
115 @Override
116 protected List<ParameterDriver> setOceanTides(final NumericalPropagatorBuilder propagatorBuilder,
117 final IERSConventions conventions,
118 final OneAxisEllipsoid body,
119 final int degree, final int order) {
120 final ForceModel tidesModel = new OceanTides(body.getBodyFrame(),
121 gravityField.getAe(), gravityField.getMu(),
122 degree, order, conventions,
123 TimeScalesFactory.getUT1(conventions, true));
124 propagatorBuilder.addForceModel(tidesModel);
125 return tidesModel.getParametersDrivers();
126 }
127
128
129 @Override
130 protected List<ParameterDriver> setSolidTides(final NumericalPropagatorBuilder propagatorBuilder,
131 final IERSConventions conventions,
132 final OneAxisEllipsoid body,
133 final CelestialBody[] solidTidesBodies) {
134 final ForceModel tidesModel = new SolidTides(body.getBodyFrame(),
135 gravityField.getAe(), gravityField.getMu(),
136 gravityField.getTideSystem(), conventions,
137 TimeScalesFactory.getUT1(conventions, true),
138 solidTidesBodies);
139 propagatorBuilder.addForceModel(tidesModel);
140 return tidesModel.getParametersDrivers();
141 }
142
143
144 @Override
145 protected List<ParameterDriver> setThirdBody(final NumericalPropagatorBuilder propagatorBuilder,
146 final CelestialBody thirdBody) {
147 final ForceModel thirdBodyModel = new ThirdBodyAttraction(thirdBody);
148 propagatorBuilder.addForceModel(thirdBodyModel);
149 return thirdBodyModel.getParametersDrivers();
150 }
151
152
153
154 @Override
155 protected List<ParameterDriver> setDrag(final NumericalPropagatorBuilder propagatorBuilder,
156 final Atmosphere atmosphere, final DragSensitive spacecraft) {
157 final ForceModel dragModel = new DragForce(atmosphere, spacecraft);
158 propagatorBuilder.addForceModel(dragModel);
159 return dragModel.getParametersDrivers();
160 }
161
162
163 @Override
164 protected List<ParameterDriver> setSolarRadiationPressure(final NumericalPropagatorBuilder propagatorBuilder, final CelestialBody sun,
165 final OneAxisEllipsoid earth, final RadiationSensitive spacecraft) {
166 final ForceModel srpModel = new SolarRadiationPressure(sun, earth, spacecraft);
167 propagatorBuilder.addForceModel(srpModel);
168 return srpModel.getParametersDrivers();
169 }
170
171
172 @Override
173 protected List<ParameterDriver> setAlbedoInfrared(final NumericalPropagatorBuilder propagatorBuilder,
174 final CelestialBody sun, final double equatorialRadius,
175 final double angularResolution,
176 final RadiationSensitive spacecraft) {
177 final ForceModel albedoIR = new KnockeRediffusedForceModel(sun, spacecraft, equatorialRadius, angularResolution);
178 propagatorBuilder.addForceModel(albedoIR);
179 return albedoIR.getParametersDrivers();
180 }
181
182
183 @Override
184 protected List<ParameterDriver> setRelativity(final NumericalPropagatorBuilder propagatorBuilder) {
185 final ForceModel relativityModel = new Relativity(gravityField.getMu());
186 propagatorBuilder.addForceModel(relativityModel);
187 return relativityModel.getParametersDrivers();
188 }
189
190
191 @Override
192 protected List<ParameterDriver> setPolynomialAcceleration(final NumericalPropagatorBuilder propagatorBuilder,
193 final String name, final Vector3D direction, final int degree) {
194 final AccelerationModel accModel = new PolynomialAccelerationModel(name, null, degree);
195 final ForceModel polynomialModel = new ParametricAcceleration(direction, true, accModel);
196 propagatorBuilder.addForceModel(polynomialModel);
197 return polynomialModel.getParametersDrivers();
198 }
199
200
201 @Override
202 protected void setAttitudeProvider(final NumericalPropagatorBuilder propagatorBuilder,
203 final AttitudeProvider attitudeProvider) {
204 propagatorBuilder.setAttitudeProvider(attitudeProvider);
205 }
206
207 @Test
208
209 public void testLageos2()
210 throws URISyntaxException, IllegalArgumentException, IOException, OrekitException {
211
212
213 final String inputPath = NumericalOrbitDeterminationTest.class.getClassLoader().getResource("orbit-determination/Lageos2/od_test_Lageos2.in").toURI().getPath();
214 final File input = new File(inputPath);
215
216
217 Utils.setDataRoot("orbit-determination/february-2016:potential/icgem-format");
218 GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("eigen-6s-truncated", true));
219
220
221 ResultBatchLeastSquares odLageos2 = runBLS(input, false);
222
223
224
225 final double distanceAccuracy = 0.62;
226 final double velocityAccuracy = 1.4e-4;
227
228
229 final int numberOfIte = 5;
230 final int numberOfEval = 5;
231
232 Assertions.assertEquals(numberOfIte, odLageos2.getNumberOfIteration());
233 Assertions.assertEquals(numberOfEval, odLageos2.getNumberOfEvaluation());
234
235
236 final Vector3D estimatedPos = odLageos2.getEstimatedPV().getPosition();
237 final Vector3D estimatedVel = odLageos2.getEstimatedPV().getVelocity();
238
239 final Vector3D refPos = new Vector3D(7526994.072, -9646309.832, 1464110.239);
240 final Vector3D refVel = new Vector3D(3033.794, 1715.265, -4447.659);
241 Assertions.assertEquals(0.0, Vector3D.distance(refPos, estimatedPos), distanceAccuracy);
242 Assertions.assertEquals(0.0, Vector3D.distance(refVel, estimatedVel), velocityAccuracy);
243
244
245 final long nbRange = 95;
246 final double[] RefStatRange = { -0.756, 0.845, 0.0, 0.261 };
247 Assertions.assertEquals(nbRange, odLageos2.getRangeStat().getN());
248 Assertions.assertEquals(RefStatRange[0], odLageos2.getRangeStat().getMin(), distanceAccuracy);
249 Assertions.assertEquals(RefStatRange[1], odLageos2.getRangeStat().getMax(), distanceAccuracy);
250 Assertions.assertEquals(RefStatRange[2], odLageos2.getRangeStat().getMean(), distanceAccuracy);
251 Assertions.assertEquals(RefStatRange[3], odLageos2.getRangeStat().getStandardDeviation(), distanceAccuracy);
252 }
253
254 @Test
255
256 public void testGNSS()
257 throws URISyntaxException, IllegalArgumentException, IOException, OrekitException {
258
259
260 final String inputPath = NumericalOrbitDeterminationTest.class.getClassLoader().getResource("orbit-determination/GNSS/od_test_GPS07.in").toURI().getPath();
261 final File input = new File(inputPath);
262
263
264 Utils.setDataRoot("orbit-determination/february-2016:potential/icgem-format");
265 GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("eigen-6s-truncated", true));
266
267
268 ResultBatchLeastSquares odGNSS = runBLS(input, false);
269
270
271
272
273 final double distanceAccuracy = 1.06;
274 final double velocityAccuracy = 2.27e-3;
275
276
277 final int numberOfIte = 2;
278 final int numberOfEval = 3;
279
280 Assertions.assertEquals(numberOfIte, odGNSS.getNumberOfIteration());
281 Assertions.assertEquals(numberOfEval, odGNSS.getNumberOfEvaluation());
282
283
284 final Vector3D estimatedPos = odGNSS.getEstimatedPV().getPosition();
285 final Vector3D estimatedVel = odGNSS.getEstimatedPV().getVelocity();
286 final Vector3D refPos = new Vector3D(-2747606.680868164, 22572091.30648564, 13522761.402325712);
287 final Vector3D refVel = new Vector3D(-2729.5151218788005, 1142.6629459030657, -2523.9055974487947);
288 Assertions.assertEquals(0.0, Vector3D.distance(refPos, estimatedPos), distanceAccuracy);
289 Assertions.assertEquals(0.0, Vector3D.distance(refVel, estimatedVel), velocityAccuracy);
290
291
292 final long nbRangeInit = 8981;
293 final long nbRangeExcluded = 305;
294 final double[] RefStatRange = { -3.853, 8.307, 0.0, 0.873 };
295 Assertions.assertEquals(nbRangeInit - nbRangeExcluded, odGNSS.getRangeStat().getN());
296 Assertions.assertEquals(RefStatRange[0], odGNSS.getRangeStat().getMin(), 1.0e-3);
297 Assertions.assertEquals(RefStatRange[1], odGNSS.getRangeStat().getMax(), 1.0e-3);
298 Assertions.assertEquals(RefStatRange[2], odGNSS.getRangeStat().getMean(), 1.0e-3);
299 Assertions.assertEquals(RefStatRange[3], odGNSS.getRangeStat().getStandardDeviation(), 1.0e-3);
300
301 }
302
303 @Test
304
305 public void testW3B()
306 throws URISyntaxException, IllegalArgumentException, IOException,
307 OrekitException, ParseException {
308
309
310 final String inputPath = NumericalOrbitDeterminationTest.class.getClassLoader().getResource("orbit-determination/W3B/od_test_W3.in").toURI().getPath();
311 final File input = new File(inputPath);
312
313
314 Utils.setDataRoot("orbit-determination/W3B:potential/icgem-format");
315 GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("eigen-6s-truncated", true));
316
317
318 ResultBatchLeastSquares odsatW3 = runBLS(input, false);
319
320
321 final double distanceAccuracy = 0.1;
322 final double velocityAccuracy = 1e-4;
323 final double angleAccuracy = 1e-5;
324
325
326 Assertions.assertTrue(odsatW3.getNumberOfIteration() < 6);
327 Assertions.assertTrue(odsatW3.getNumberOfEvaluation() < 10);
328
329
330 final Vector3D estimatedPos = odsatW3.getEstimatedPV().getPosition();
331 final Vector3D estimatedVel = odsatW3.getEstimatedPV().getVelocity();
332 final Vector3D refPos = new Vector3D(-40541446.236, -9905357.943, 206777.082);
333 final Vector3D refVel = new Vector3D(759.0685, -1476.5156, 54.7931);
334 Assertions.assertEquals(0.0, Vector3D.distance(refPos, estimatedPos), distanceAccuracy);
335 Assertions.assertEquals(0.0, Vector3D.distance(refVel, estimatedVel), velocityAccuracy);
336
337
338 final double dragCoef = -0.2154;
339 final ParameterDriversList propagatorParameters = odsatW3.getPropagatorParameters();
340 Assertions.assertEquals(dragCoef, propagatorParameters.getDrivers().get(0).getValue(), 1e-3);
341 final Vector3D leakAcceleration0 =
342 new Vector3D(propagatorParameters.getDrivers().get(1).getValue(),
343 propagatorParameters.getDrivers().get(3).getValue(),
344 propagatorParameters.getDrivers().get(5).getValue());
345
346 Assertions.assertEquals(8.005e-6, leakAcceleration0.getNorm(), 1.0e-8);
347 final Vector3D leakAcceleration1 =
348 new Vector3D(propagatorParameters.getDrivers().get(2).getValue(),
349 propagatorParameters.getDrivers().get(4).getValue(),
350 propagatorParameters.getDrivers().get(6).getValue());
351 Assertions.assertEquals(3.060e-10, leakAcceleration1.getNorm(), 1.0e-12);
352
353
354 final List<DelegatingDriver> list = new ArrayList<>(odsatW3.getMeasurementsParameters().getDrivers());
355 sortParametersChanges(list);
356
357
358 final double[] CastleAzElBias = { 0.062701342, -0.003613508 };
359 final double CastleRangeBias = 11274.4195;
360 Assertions.assertEquals(CastleAzElBias[0], FastMath.toDegrees(list.get(0).getValue()), angleAccuracy);
361 Assertions.assertEquals(CastleAzElBias[1], FastMath.toDegrees(list.get(1).getValue()), angleAccuracy);
362 Assertions.assertEquals(CastleRangeBias, list.get(2).getValue(), distanceAccuracy);
363
364
365 final double[] FucAzElBias = { -0.053526137, 0.075483886 };
366 final double FucRangeBias = 13467.8361;
367 Assertions.assertEquals(FucAzElBias[0], FastMath.toDegrees(list.get(3).getValue()), angleAccuracy);
368 Assertions.assertEquals(FucAzElBias[1], FastMath.toDegrees(list.get(4).getValue()), angleAccuracy);
369 Assertions.assertEquals(FucRangeBias, list.get(5).getValue(), distanceAccuracy);
370
371
372 final double[] KumAzElBias = { -0.023574208, -0.054520756 };
373 final double KumRangeBias = 13512.4898;
374 Assertions.assertEquals(KumAzElBias[0], FastMath.toDegrees(list.get(6).getValue()), angleAccuracy);
375 Assertions.assertEquals(KumAzElBias[1], FastMath.toDegrees(list.get(7).getValue()), angleAccuracy);
376 Assertions.assertEquals(KumRangeBias, list.get(8).getValue(), distanceAccuracy);
377
378
379 final double[] PreAzElBias = { 0.030201539, 0.009747877 };
380 final double PreRangeBias = 13594.1758;
381 Assertions.assertEquals(PreAzElBias[0], FastMath.toDegrees(list.get( 9).getValue()), angleAccuracy);
382 Assertions.assertEquals(PreAzElBias[1], FastMath.toDegrees(list.get(10).getValue()), angleAccuracy);
383 Assertions.assertEquals(PreRangeBias, list.get(11).getValue(), distanceAccuracy);
384
385
386 final double[] UraAzElBias = { 0.167814449, -0.12305252 };
387 final double UraRangeBias = 13450.2320;
388 Assertions.assertEquals(UraAzElBias[0], FastMath.toDegrees(list.get(12).getValue()), angleAccuracy);
389 Assertions.assertEquals(UraAzElBias[1], FastMath.toDegrees(list.get(13).getValue()), angleAccuracy);
390 Assertions.assertEquals(UraRangeBias, list.get(14).getValue(), distanceAccuracy);
391
392
393 final long nbRange = 182;
394
395 final double[] RefStatRange = { -18.39149369, 12.54165259, -4.32E-05, 4.374712716 };
396 Assertions.assertEquals(nbRange, odsatW3.getRangeStat().getN());
397 Assertions.assertEquals(RefStatRange[0], odsatW3.getRangeStat().getMin(), distanceAccuracy);
398 Assertions.assertEquals(RefStatRange[1], odsatW3.getRangeStat().getMax(), distanceAccuracy);
399 Assertions.assertEquals(RefStatRange[2], odsatW3.getRangeStat().getMean(), distanceAccuracy);
400 Assertions.assertEquals(RefStatRange[3], odsatW3.getRangeStat().getStandardDeviation(), distanceAccuracy);
401
402
403 final long nbAzi = 339;
404
405 final double[] RefStatAzi = { -0.043033616, 0.025297558, -1.39E-10, 0.010063041 };
406 Assertions.assertEquals(nbAzi, odsatW3.getAzimStat().getN());
407 Assertions.assertEquals(RefStatAzi[0], odsatW3.getAzimStat().getMin(), angleAccuracy);
408 Assertions.assertEquals(RefStatAzi[1], odsatW3.getAzimStat().getMax(), angleAccuracy);
409 Assertions.assertEquals(RefStatAzi[2], odsatW3.getAzimStat().getMean(), angleAccuracy);
410 Assertions.assertEquals(RefStatAzi[3], odsatW3.getAzimStat().getStandardDeviation(), angleAccuracy);
411
412
413 final long nbEle = 339;
414 final double[] RefStatEle = { -0.025061971, 0.056294405, -4.10E-11, 0.011604931 };
415 Assertions.assertEquals(nbEle, odsatW3.getElevStat().getN());
416 Assertions.assertEquals(RefStatEle[0], odsatW3.getElevStat().getMin(), angleAccuracy);
417 Assertions.assertEquals(RefStatEle[1], odsatW3.getElevStat().getMax(), angleAccuracy);
418 Assertions.assertEquals(RefStatEle[2], odsatW3.getElevStat().getMean(), angleAccuracy);
419 Assertions.assertEquals(RefStatEle[3], odsatW3.getElevStat().getStandardDeviation(), angleAccuracy);
420
421 RealMatrix covariances = odsatW3.getCovariances();
422 Assertions.assertEquals(28, covariances.getRowDimension());
423 Assertions.assertEquals(28, covariances.getColumnDimension());
424
425
426 Assertions.assertEquals(0.687998, covariances.getEntry(6, 6), 1.0e-4);
427
428
429 Assertions.assertEquals(2.0540e-12, covariances.getEntry(7, 7), 1.0e-16);
430
431
432 Assertions.assertEquals(2.4930e-11, covariances.getEntry(9, 9), 1.0e-15);
433
434
435 Assertions.assertEquals(7.6720e-11, covariances.getEntry(11, 11), 1.0e-15);
436 }
437
438 }