1   /* Copyright 2002-2022 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.leastsquares;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.net.URISyntaxException;
22  import java.text.ParseException;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.NoSuchElementException;
26  
27  import org.hipparchus.exception.LocalizedCoreFormats;
28  import org.hipparchus.geometry.euclidean.threed.Vector3D;
29  import org.junit.Assert;
30  import org.junit.Test;
31  import org.orekit.KeyValueFileParser;
32  import org.orekit.Utils;
33  import org.orekit.attitudes.AttitudeProvider;
34  import org.orekit.bodies.CelestialBody;
35  import org.orekit.bodies.OneAxisEllipsoid;
36  import org.orekit.errors.OrekitException;
37  import org.orekit.estimation.common.AbstractOrbitDetermination;
38  import org.orekit.estimation.common.ParameterKey;
39  import org.orekit.estimation.common.ResultBatchLeastSquares;
40  import org.orekit.forces.drag.DragSensitive;
41  import org.orekit.forces.gravity.potential.GravityFieldFactory;
42  import org.orekit.forces.gravity.potential.ICGEMFormatReader;
43  import org.orekit.forces.radiation.RadiationSensitive;
44  import org.orekit.frames.FramesFactory;
45  import org.orekit.frames.Transform;
46  import org.orekit.models.earth.atmosphere.Atmosphere;
47  import org.orekit.orbits.Orbit;
48  import org.orekit.orbits.PositionAngle;
49  import org.orekit.propagation.analytical.tle.TLE;
50  import org.orekit.propagation.analytical.tle.TLEConstants;
51  import org.orekit.propagation.conversion.ODEIntegratorBuilder;
52  import org.orekit.propagation.conversion.TLEPropagatorBuilder;
53  import org.orekit.utils.IERSConventions;
54  import org.orekit.utils.PVCoordinates;
55  import org.orekit.utils.ParameterDriver;
56  import org.orekit.utils.TimeStampedPVCoordinates;
57  
58  public class TLEOrbitDeterminationTest extends AbstractOrbitDetermination<TLEPropagatorBuilder> {
59      
60      /** Initial TLE. */
61      public TLE templateTLE;
62  
63      /** {@inheritDoc} */
64      @Override
65      protected void createGravityField(final KeyValueFileParser<ParameterKey> parser)
66          throws NoSuchElementException {
67          // TLE OD does not need gravity field
68      }
69  
70      /** {@inheritDoc} */
71      @Override
72      protected double getMu() {
73          return TLEConstants.MU;
74      }
75  
76      /** {@inheritDoc} */
77      @Override
78      protected TLEPropagatorBuilder createPropagatorBuilder(final Orbit referenceOrbit,
79                                                             final ODEIntegratorBuilder builder,
80                                                             final double positionScale) {
81          return new TLEPropagatorBuilder(templateTLE, PositionAngle.MEAN,
82                                           positionScale);
83      }
84  
85      /** {@inheritDoc} */
86      @Override
87      protected void setMass(final TLEPropagatorBuilder propagatorBuilder,
88                             final double mass) {
89          // TLE OD does not need to set mass
90      }
91  
92      /** {@inheritDoc} */
93      @Override
94      protected List<ParameterDriver> setGravity(final TLEPropagatorBuilder propagatorBuilder,
95                                                 final OneAxisEllipsoid body) {
96          return Collections.emptyList();
97  
98      }
99  
100     /** {@inheritDoc} */
101     @Override
102     protected List<ParameterDriver> setOceanTides(final TLEPropagatorBuilder propagatorBuilder,
103                                                   final IERSConventions conventions,
104                                                   final OneAxisEllipsoid body,
105                                                   final int degree, final int order) {
106         throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
107                         "Ocean tides not implemented in TLE Propagator");
108     }
109 
110     /** {@inheritDoc} */
111     @Override
112     protected List<ParameterDriver> setSolidTides(final TLEPropagatorBuilder propagatorBuilder,
113                                                   final IERSConventions conventions,
114                                                   final OneAxisEllipsoid body,
115                                                   final CelestialBody[] solidTidesBodies) {
116         throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
117                                   "Solid tides not implemented in TLE Propagator");
118     }
119 
120     /** {@inheritDoc} */
121     @Override
122     protected List<ParameterDriver> setThirdBody(final TLEPropagatorBuilder propagatorBuilder,
123                                                  final CelestialBody thirdBody) {
124         throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
125                         "Third body not implemented in TLE Propagator");
126     }
127 
128     /** {@inheritDoc} */
129     @Override
130     protected List<ParameterDriver> setDrag(final TLEPropagatorBuilder propagatorBuilder,
131                                             final Atmosphere atmosphere, final DragSensitive spacecraft) {
132         throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
133                         "Drag not implemented in TLE Propagator");
134     }
135 
136     /** {@inheritDoc} */
137     @Override
138     protected List<ParameterDriver> setSolarRadiationPressure(final TLEPropagatorBuilder propagatorBuilder, final CelestialBody sun,
139                                                               final double equatorialRadius, final RadiationSensitive spacecraft) {
140         throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
141                         "SRP not implemented in TLE Propagator");
142     }
143     
144     /** {@inheritDoc} */
145     @Override
146     protected List<ParameterDriver> setAlbedoInfrared(final TLEPropagatorBuilder propagatorBuilder,
147                                                       final CelestialBody sun, final double equatorialRadius,
148                                                       final double angularResolution,
149                                                       final RadiationSensitive spacecraft) {
150         throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
151                         "Albedo and infrared not implemented in TLE Propagator");
152     }
153 
154     /** {@inheritDoc} */
155     @Override
156     protected List<ParameterDriver> setRelativity(final TLEPropagatorBuilder propagatorBuilder) {
157         throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
158                         "Relativity not implemented in TLE Propagator");
159     }
160 
161     /** {@inheritDoc} */
162     @Override
163     protected List<ParameterDriver> setPolynomialAcceleration(final TLEPropagatorBuilder propagatorBuilder,
164                                                               final String name, final Vector3D direction, final int degree) {
165         throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE,
166                         "Polynomial acceleration not implemented in TLE Propagator");
167     }
168 
169     /** {@inheritDoc} */
170     @Override
171     protected void setAttitudeProvider(final TLEPropagatorBuilder propagatorBuilder,
172                                        final AttitudeProvider attitudeProvider) {
173         propagatorBuilder.setAttitudeProvider(attitudeProvider);
174     }
175 
176     /** Orbit determination for GNSS satellite based on range measurements */
177     @Test
178     public void testGNSS()
179         throws URISyntaxException, IllegalArgumentException, IOException,
180                OrekitException, ParseException {
181         
182         // input in resources directory
183         final String inputPath = TLEOrbitDeterminationTest.class.getClassLoader().getResource("orbit-determination/analytical/tle_od_test_GPS07.in").toURI().getPath();
184         final File input  = new File(inputPath);
185 
186         // configure Orekit data access
187         Utils.setDataRoot("orbit-determination/february-2016:potential/icgem-format");
188         GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("eigen-6s-truncated", true));
189         
190         // initiate TLE (from Celestrak)
191         final String line1 = "1 32711U 08012A   16044.40566026 -.00000039  00000-0  00000+0 0  9991";
192         final String line2 = "2 32711  55.4362 301.3402 0091577 207.7302 151.8353  2.00563580 58013";
193         templateTLE = new TLE(line1, line2);
194         templateTLE.getParametersDrivers().get(0).setSelected(false);
195 
196         //orbit determination run.
197         ResultBatchLeastSquares odGNSS = runBLS(input, false);
198         
199         //test
200 
201         //definition of the accuracy for the test
202         final double distanceAccuracy = 113.46;
203 
204         //test on the convergence
205         final int numberOfIte  = 2;
206         final int numberOfEval = 3;
207         Assert.assertEquals(numberOfIte, odGNSS.getNumberOfIteration());
208         Assert.assertEquals(numberOfEval, odGNSS.getNumberOfEvaluation());
209         
210         //test on the estimated position (reference from file esa18836.sp3)
211         TimeStampedPVCoordinates odPV = odGNSS.getEstimatedPV();
212         final Transform transform = FramesFactory.getTEME().getTransformTo(FramesFactory.getEME2000(), odPV.getDate());
213         odPV = transform.transformPVCoordinates(odPV);
214         final Vector3D estimatedPos = odPV.getPosition();
215         
216         // Reference position from GPS ephemeris (esa18836.sp3)
217         final Vector3D refPos = new Vector3D(13848957.285213307, -22916266.10257542, -23458.8341713716);  
218 
219         //test on the estimated position
220         Assert.assertEquals(0.0, Vector3D.distance(refPos, estimatedPos), distanceAccuracy);
221         
222         //test on statistic for the range residuals
223         final long nbRange = 8211;
224         final double[] RefStatRange = { -14.448, 18.736, 0.132, 6.323 };        
225         Assert.assertEquals(nbRange, odGNSS.getRangeStat().getN());
226         Assert.assertEquals(RefStatRange[0], odGNSS.getRangeStat().getMin(),               1.0e-3);
227         Assert.assertEquals(RefStatRange[1], odGNSS.getRangeStat().getMax(),               1.0e-3);
228         Assert.assertEquals(RefStatRange[2], odGNSS.getRangeStat().getMean(),              1.0e-3);
229         Assert.assertEquals(RefStatRange[3], odGNSS.getRangeStat().getStandardDeviation(), 1.0e-3);
230         
231     }
232     
233     @Test
234     public void testLageos2()
235         throws URISyntaxException, IllegalArgumentException, IOException,
236                OrekitException, ParseException {
237 
238         // input in resources directory
239         final String inputPath = TLEOrbitDeterminationTest.class.getClassLoader().getResource("orbit-determination/Lageos2/tle_od_test_Lageos2.in").toURI().getPath();
240         final File input  = new File(inputPath);
241 
242         // configure Orekit data access
243         Utils.setDataRoot("orbit-determination/february-2016:potential/icgem-format");
244         GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("eigen-6s-truncated", true));
245         
246         // initiate TLE
247         final String line1 = "1 22195U 92070B   16045.51027931 -.00000009  00000-0  00000+0 0  9990";
248         final String line2 = "2 22195  52.6508 132.9147 0137738 336.2706   1.6348  6.47294052551192";
249         templateTLE = new TLE(line1, line2);
250         templateTLE.getParametersDrivers().get(0).setSelected(false);
251         
252         //orbit determination run.
253         ResultBatchLeastSquares odLageos2 = runBLS(input, false);
254 
255         //test
256         //definition of the accuracy for the test
257         final double distanceAccuracy = 212.82;
258         final double velocityAccuracy = 6.17e-2;
259 
260         //test on the convergence
261         final int numberOfIte  = 4;
262         final int numberOfEval = 4;
263 
264         Assert.assertEquals(numberOfIte, odLageos2.getNumberOfIteration());
265         Assert.assertEquals(numberOfEval, odLageos2.getNumberOfEvaluation());
266 
267         //test on the estimated position and velocity
268         PVCoordinates odPV = odLageos2.getEstimatedPV();
269         final Transform transform = FramesFactory.getTEME().getTransformTo(FramesFactory.getEME2000(), templateTLE.getDate());
270         odPV = transform.transformPVCoordinates(odPV);
271         final Vector3D estimatedPos = odPV.getPosition();
272         final Vector3D estimatedVel = odPV.getVelocity();
273 
274         final Vector3D refPos = new Vector3D(-5532131.956902, 10025696.592156, -3578940.040009);
275         final Vector3D refVel = new Vector3D(-3871.275109, -607.880985, 4280.972530);
276         Assert.assertEquals(0.0, Vector3D.distance(refPos, estimatedPos), distanceAccuracy);
277         Assert.assertEquals(0.0, Vector3D.distance(refVel, estimatedVel), velocityAccuracy);
278 
279         //test on statistic for the range residuals
280         final long nbRange = 95;
281         final double[] RefStatRange = { -67.331, 79.823, 6.668E-8, 32.296 };
282         Assert.assertEquals(nbRange, odLageos2.getRangeStat().getN());
283         Assert.assertEquals(RefStatRange[0], odLageos2.getRangeStat().getMin(),               1.0e-3);
284         Assert.assertEquals(RefStatRange[1], odLageos2.getRangeStat().getMax(),               1.0e-3);
285         Assert.assertEquals(RefStatRange[2], odLageos2.getRangeStat().getMean(),              1.0e-3);
286         Assert.assertEquals(RefStatRange[3], odLageos2.getRangeStat().getStandardDeviation(), 1.0e-3);
287 
288     }
289 
290 }
291