1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.estimation.sequential;
18
19 import org.hipparchus.exception.LocalizedCoreFormats;
20 import org.hipparchus.geometry.euclidean.threed.Vector3D;
21 import org.hipparchus.linear.MatrixUtils;
22 import org.hipparchus.linear.RealMatrix;
23 import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator;
24 import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
25 import org.hipparchus.util.FastMath;
26 import org.junit.jupiter.api.Assertions;
27 import org.junit.jupiter.api.Test;
28 import org.orekit.KeyValueFileParser;
29 import org.orekit.Utils;
30 import org.orekit.attitudes.AttitudeProvider;
31 import org.orekit.bodies.CelestialBody;
32 import org.orekit.bodies.CelestialBodyFactory;
33 import org.orekit.bodies.OneAxisEllipsoid;
34 import org.orekit.errors.OrekitException;
35 import org.orekit.estimation.common.AbstractOrbitDetermination;
36 import org.orekit.estimation.common.ParameterKey;
37 import org.orekit.estimation.common.ResultKalman;
38 import org.orekit.forces.ForceModel;
39 import org.orekit.forces.drag.DragForce;
40 import org.orekit.forces.drag.DragSensitive;
41 import org.orekit.forces.drag.IsotropicDrag;
42 import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel;
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.IsotropicRadiationSingleCoefficient;
48 import org.orekit.forces.radiation.RadiationSensitive;
49 import org.orekit.forces.radiation.SolarRadiationPressure;
50 import org.orekit.frames.FramesFactory;
51 import org.orekit.frames.StaticTransform;
52 import org.orekit.frames.Transform;
53 import org.orekit.models.earth.atmosphere.Atmosphere;
54 import org.orekit.models.earth.atmosphere.HarrisPriester;
55 import org.orekit.orbits.CartesianOrbit;
56 import org.orekit.orbits.Orbit;
57 import org.orekit.orbits.OrbitType;
58 import org.orekit.orbits.PositionAngleType;
59 import org.orekit.propagation.SpacecraftState;
60 import org.orekit.propagation.ToleranceProvider;
61 import org.orekit.propagation.analytical.tle.TLE;
62 import org.orekit.propagation.analytical.tle.TLEConstants;
63 import org.orekit.propagation.analytical.tle.generation.FixedPointTleGenerationAlgorithm;
64 import org.orekit.propagation.conversion.ODEIntegratorBuilder;
65 import org.orekit.propagation.conversion.TLEPropagatorBuilder;
66 import org.orekit.propagation.numerical.NumericalPropagator;
67 import org.orekit.time.AbsoluteDate;
68 import org.orekit.time.TimeScalesFactory;
69 import org.orekit.utils.*;
70
71 import java.io.File;
72 import java.io.IOException;
73 import java.net.URISyntaxException;
74 import java.util.*;
75
76 public class TLEKalmanOrbitDeterminationTest extends AbstractOrbitDetermination<TLEPropagatorBuilder> {
77
78
79 public TLE templateTLE;
80
81
82 @Override
83 protected void createGravityField(final KeyValueFileParser<ParameterKey> parser)
84 throws NoSuchElementException {
85
86
87 }
88
89
90 @Override
91 protected double getMu() {
92 return TLEConstants.MU;
93 }
94
95
96 @Override
97 protected TLEPropagatorBuilder createPropagatorBuilder(final Orbit referenceOrbit,
98 final ODEIntegratorBuilder builder,
99 final double positionScale) {
100 return new TLEPropagatorBuilder(templateTLE, PositionAngleType.MEAN, positionScale,
101 new FixedPointTleGenerationAlgorithm());
102 }
103
104
105 @Override
106 protected void setMass(final TLEPropagatorBuilder propagatorBuilder,
107 final double mass) {
108
109
110 }
111
112
113 @Override
114 protected List<ParameterDriver> setGravity(final TLEPropagatorBuilder propagatorBuilder,
115 final OneAxisEllipsoid body) {
116 return Collections.emptyList();
117
118 }
119
120
121 @Override
122 protected List<ParameterDriver> setOceanTides(final TLEPropagatorBuilder propagatorBuilder,
123 final IERSConventions conventions,
124 final OneAxisEllipsoid body,
125 final int degree, final int order) {
126 throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
127 "Ocean tides not implemented in DSST");
128 }
129
130
131 @Override
132 protected List<ParameterDriver> setSolidTides(final TLEPropagatorBuilder propagatorBuilder,
133 final IERSConventions conventions,
134 final OneAxisEllipsoid body,
135 final CelestialBody[] solidTidesBodies) {
136 throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
137 "Solid tides not implemented in DSST");
138 }
139
140
141 @Override
142 protected List<ParameterDriver> setThirdBody(final TLEPropagatorBuilder propagatorBuilder,
143 final CelestialBody thirdBody) {
144 return Collections.emptyList();
145 }
146
147
148 @Override
149 protected List<ParameterDriver> setDrag(final TLEPropagatorBuilder propagatorBuilder,
150 final Atmosphere atmosphere, final DragSensitive spacecraft) {
151 return Collections.emptyList();
152 }
153
154
155 @Override
156 protected List<ParameterDriver> setSolarRadiationPressure(final TLEPropagatorBuilder propagatorBuilder, final CelestialBody sun,
157 final OneAxisEllipsoid body, final RadiationSensitive spacecraft) {
158 return Collections.emptyList();
159 }
160
161
162 @Override
163 protected List<ParameterDriver> setAlbedoInfrared(final TLEPropagatorBuilder propagatorBuilder,
164 final CelestialBody sun, final double equatorialRadius,
165 final double angularResolution,
166 final RadiationSensitive spacecraft) {
167 throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
168 "Albedo and infrared not implemented in TLE Propagator");
169 }
170
171
172 @Override
173 protected List<ParameterDriver> setRelativity(final TLEPropagatorBuilder propagatorBuilder) {
174 throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
175 "Relativity not implemented in TLE Propagator");
176 }
177
178
179 @Override
180 protected List<ParameterDriver> setPolynomialAcceleration(final TLEPropagatorBuilder propagatorBuilder,
181 final String name, final Vector3D direction, final int degree) {
182 throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
183 "Polynomial acceleration not implemented in TLE Propagator");
184 }
185
186
187 @Override
188 protected void setAttitudeProvider(final TLEPropagatorBuilder propagatorBuilder,
189 final AttitudeProvider attitudeProvider) {
190 propagatorBuilder.setAttitudeProvider(attitudeProvider);
191 }
192
193 @Test
194
195 public void testLageos2() throws URISyntaxException, IOException {
196
197
198 final boolean print = false;
199
200
201 final String inputPath = TLEKalmanOrbitDeterminationTest.class.getClassLoader().getResource("orbit-determination/Lageos2/tle_od_test_Lageos2.in").toURI().getPath();
202 final File input = new File(inputPath);
203
204
205 Utils.setDataRoot("orbit-determination/february-2016:potential/icgem-format");
206 GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("eigen-6s-truncated", true));
207
208
209 final String line1 = "1 22195U 92070B 16045.51027931 -.00000009 00000-0 00000+0 0 9990";
210 final String line2 = "2 22195 52.6508 132.9147 0137738 336.2706 1.6348 6.47294052551192";
211 templateTLE = new TLE(line1, line2);
212 templateTLE.getParametersDrivers().get(0).setSelected(false);
213
214
215 final OrbitType orbitType = OrbitType.CARTESIAN;
216
217
218 final double posVar = FastMath.pow(1e3, 2);
219 final double velVar = FastMath.pow(0.1, 2);
220 final RealMatrix cartesianOrbitalP = MatrixUtils.createRealDiagonalMatrix(new double [] {
221 posVar, posVar, posVar, velVar, velVar, velVar
222 });
223
224
225 final double posVarQ = FastMath.pow(0.0, 2);
226 final double velVarQ = FastMath.pow(0.01, 2);
227 final RealMatrix cartesianOrbitalQ = MatrixUtils.createRealDiagonalMatrix(new double [] {
228 posVarQ, posVarQ, posVarQ, velVarQ, velVarQ, velVarQ
229 });
230
231
232 final double measVar = FastMath.pow(1.0, 2);
233 final RealMatrix measurementP = MatrixUtils.createRealDiagonalMatrix(new double [] {
234 measVar, measVar, measVar, measVar
235 });
236 final RealMatrix measurementQ = MatrixUtils.createRealMatrix(4, 4);
237
238
239 ResultKalman kalmanLageos2 = runKalman(input, orbitType, print,
240 cartesianOrbitalP, cartesianOrbitalQ,
241 null, null,
242 measurementP, measurementQ, false);
243
244
245
246 final double distanceAccuracy = 192.61;
247 final double velocityAccuracy = 0.116;
248 final double parameterAccuracy = 1e-6;
249
250
251
252
253 final int numberOfMeas = 95;
254 Assertions.assertEquals(numberOfMeas, kalmanLageos2.getNumberOfMeasurements());
255
256
257 final TimeStampedPVCoordinates odPV = kalmanLageos2.getEstimatedPV();
258 final Vector3D estimatedPos = odPV.getPosition();
259 final Vector3D estimatedVel = odPV.getVelocity();
260
261
262 final Vector3D refPos0 = new Vector3D(-5532131.956902, 10025696.592156, -3578940.040009);
263 final Vector3D refVel0 = new Vector3D(-3871.275109, -607.880985, 4280.972530);
264 final TimeStampedPVCoordinates refPV = createRef(odPV.getDate(), refPos0, refVel0);
265
266
267 final Vector3D refPos = refPV.getPosition();
268 final Vector3D refVel = refPV.getVelocity();
269
270
271 final double dP = Vector3D.distance(refPos, estimatedPos);
272 final double dV = Vector3D.distance(refVel, estimatedVel);
273
274
275 if (print) {
276 System.out.println("Test performances:");
277 System.out.format("\t%-30s\n",
278 "ΔEstimated / Reference");
279 System.out.format(Locale.US, "\t%-10s %20.6f\n",
280 "ΔP [m]", dP);
281 System.out.format(Locale.US, "\t%-10s %20.6f\n",
282 "ΔV [m/s]", dV);
283 }
284
285 Assertions.assertEquals(0.0, dP, distanceAccuracy);
286 Assertions.assertEquals(0.0, dV, velocityAccuracy);
287
288
289 final List<ParameterDriversList.DelegatingDriver> list = new ArrayList<>();
290 list.addAll(kalmanLageos2.getMeasurementsParameters().getDrivers());
291 sortParametersChanges(list);
292 final double[] stationOffSet = { 0.069571, -0.114921, -0.084817 };
293 final double rangeBias = -0.041797;
294 Assertions.assertEquals(stationOffSet[0], list.get(0).getValue(), parameterAccuracy);
295 Assertions.assertEquals(stationOffSet[1], list.get(1).getValue(), parameterAccuracy);
296 Assertions.assertEquals(stationOffSet[2], list.get(2).getValue(), parameterAccuracy);
297 Assertions.assertEquals(rangeBias, list.get(3).getValue(), parameterAccuracy);
298
299
300 final long nbRange = 95;
301
302
303 final double[] RefStatRange = { -13.191873, 10.038898, 0.134278, 4.189626 };
304 Assertions.assertEquals(nbRange, kalmanLageos2.getRangeStat().getN());
305 Assertions.assertEquals(RefStatRange[0], kalmanLageos2.getRangeStat().getMin(), parameterAccuracy);
306 Assertions.assertEquals(RefStatRange[1], kalmanLageos2.getRangeStat().getMax(), parameterAccuracy);
307 Assertions.assertEquals(RefStatRange[2], kalmanLageos2.getRangeStat().getMean(), parameterAccuracy);
308 Assertions.assertEquals(RefStatRange[3], kalmanLageos2.getRangeStat().getStandardDeviation(), parameterAccuracy);
309
310 }
311
312 @Test
313
314 public void testGNSS() throws URISyntaxException, IOException {
315
316
317 final boolean print = false;
318
319
320 final String inputPath = TLEKalmanOrbitDeterminationTest.class.getClassLoader().getResource("orbit-determination/analytical/tle_od_test_GPS07.in").toURI().getPath();
321 final File input = new File(inputPath);
322
323
324 Utils.setDataRoot("orbit-determination/february-2016:potential/icgem-format");
325 GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("eigen-6s-truncated", true));
326
327
328 final String line1 = "1 32711U 08012A 16044.40566018 -.00000039 +00000-0 +00000-0 0 9993";
329 final String line2 = "2 32711 055.4362 301.3402 0091581 207.7162 151.8496 02.00563594058026";
330 templateTLE = new TLE(line1, line2);
331 templateTLE.getParametersDrivers().get(0).setSelected(false);
332
333
334 final OrbitType orbitType = OrbitType.CARTESIAN;
335
336
337 final double posVar = FastMath.pow(1e3, 2);
338 final double velVar = FastMath.pow(0.1, 2);
339 final RealMatrix cartesianOrbitalP = MatrixUtils.createRealDiagonalMatrix(new double [] {
340 posVar, posVar, posVar, velVar, velVar, velVar
341 });
342
343
344 final double posVarQ = FastMath.pow(0.0, 2);
345 final double velVarQ = FastMath.pow(1e-2, 2);
346 final RealMatrix cartesianOrbitalQ = MatrixUtils.createRealDiagonalMatrix(new double [] {
347 posVarQ, posVarQ, posVarQ, velVarQ, velVarQ, velVarQ
348 });
349
350
351 final double measVar = FastMath.pow(1e-7, 2);
352 final RealMatrix measurementP = MatrixUtils.createRealDiagonalMatrix(new double [] {
353 measVar, measVar, measVar, measVar, measVar, measVar
354 });
355
356 final double measVarQ = FastMath.pow(1e-8, 2);
357 final RealMatrix measurementQ = MatrixUtils.createRealDiagonalMatrix(new double [] {
358 measVarQ, measVarQ, measVarQ, measVarQ, measVarQ, measVarQ
359 });
360
361
362 ResultKalman kalmanGNSS = runKalman(input, orbitType, print,
363 cartesianOrbitalP, cartesianOrbitalQ,
364 null, null,
365 measurementP, measurementQ, false);
366
367
368
369 final double distanceAccuracy = 77.17;
370 final double parameterAccuracy = 1e-3;
371
372
373
374
375 final int numberOfMeas = 661;
376 Assertions.assertEquals(numberOfMeas, kalmanGNSS.getNumberOfMeasurements());
377
378
379 TimeStampedPVCoordinates odPV = kalmanGNSS.getEstimatedPV();
380 final StaticTransform transform = FramesFactory.getTEME().getStaticTransformTo(FramesFactory.getGCRF(), odPV.getDate());
381 final Vector3D estimatedPos = transform.transformPosition(odPV.getPosition());
382
383
384 final Vector3D refPos = new Vector3D(2167703.453226041, 19788555.311260417, 17514805.616900872);
385
386
387 final double dP = Vector3D.distance(refPos, estimatedPos);
388
389
390 if (print) {
391 System.out.println("Test performances:");
392 System.out.format("\t%-30s\n",
393 "ΔEstimated / Reference");
394 System.out.format(Locale.US, "\t%-10s %20.6f\n",
395 "ΔP [m]", dP);
396 }
397
398 Assertions.assertEquals(0.0, dP, distanceAccuracy);
399
400
401 final long nbRange = 8211;
402
403 final double[] RefStatRange = { -8.285, 4.496, -6.3e-4, 1.195 };
404 Assertions.assertEquals(nbRange, kalmanGNSS.getRangeStat().getN());
405 Assertions.assertEquals(RefStatRange[0], kalmanGNSS.getRangeStat().getMin(), parameterAccuracy);
406 Assertions.assertEquals(RefStatRange[1], kalmanGNSS.getRangeStat().getMax(), parameterAccuracy);
407 Assertions.assertEquals(RefStatRange[2], kalmanGNSS.getRangeStat().getMean(), parameterAccuracy);
408 Assertions.assertEquals(RefStatRange[3], kalmanGNSS.getRangeStat().getStandardDeviation(), parameterAccuracy);
409
410 }
411
412
413 public TimeStampedPVCoordinates createRef(final AbsoluteDate date, final Vector3D refPos0, final Vector3D refVel0) {
414
415
416 final AbsoluteDate initDate = new AbsoluteDate(2016, 02, 14, 12, 14, 48.132, TimeScalesFactory.getUTC());
417 final CartesianOrbit initOrbit= new CartesianOrbit(new PVCoordinates(refPos0, refVel0), FramesFactory.getEME2000(), initDate, TLEConstants.MU);
418 final SpacecraftState initState = new SpacecraftState(initOrbit);
419
420
421 double[][] tolerance = ToleranceProvider.getDefaultToleranceProvider(0.001).getTolerances(initOrbit, OrbitType.CARTESIAN);
422 AdaptiveStepsizeIntegrator integrator =
423 new DormandPrince853Integrator(0.001, 200, tolerance[0], tolerance[1]);
424 integrator.setInitialStepSize(60);
425 final NumericalPropagator propagator = new NumericalPropagator(integrator);
426 propagator.setInitialState(initState);
427
428
429 final int degree = 20;
430 final int order = 20;
431 final double spacecraftArea = 1.0;
432 final double spacecraftDragCoefficient = 2.0;
433 final double spacecraftReflectionCoefficient = 2.0;
434
435
436 final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
437 Constants.WGS84_EARTH_FLATTENING,
438 FramesFactory.getITRF(IERSConventions.IERS_2010, true));
439 final NormalizedSphericalHarmonicsProvider harmonicsGravityProvider = GravityFieldFactory.getNormalizedProvider(degree, order);
440 propagator.addForceModel(new HolmesFeatherstoneAttractionModel(earth.getBodyFrame(), harmonicsGravityProvider));
441
442
443 propagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getSun()));
444 propagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getMoon()));
445
446
447 ForceModel drag = new DragForce(new HarrisPriester(CelestialBodyFactory.getSun(), earth),
448 new IsotropicDrag(spacecraftArea, spacecraftDragCoefficient));
449 propagator.addForceModel(drag);
450
451
452 propagator.addForceModel(new SolarRadiationPressure(CelestialBodyFactory.getSun(), earth,
453 new IsotropicRadiationSingleCoefficient(spacecraftArea, spacecraftReflectionCoefficient)));
454
455
456 TimeStampedPVCoordinates endPV = propagator.propagate(date).getPVCoordinates();
457 final Transform transform = FramesFactory.getEME2000().getTransformTo(FramesFactory.getTEME(), date);
458 endPV = transform.transformPVCoordinates(endPV);
459 return endPV;
460 }
461 }