1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.analytical.tle;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.Field;
21 import org.hipparchus.analysis.differentiation.DSFactory;
22 import org.hipparchus.analysis.differentiation.DerivativeStructure;
23 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24 import org.hipparchus.util.Binary64;
25 import org.hipparchus.util.Binary64Field;
26 import org.hipparchus.util.CombinatoricsUtils;
27 import org.hipparchus.util.FastMath;
28 import org.hipparchus.util.MathArrays;
29 import org.junit.jupiter.api.Assertions;
30 import org.junit.jupiter.api.BeforeEach;
31 import org.junit.jupiter.api.DisplayName;
32 import org.junit.jupiter.api.Test;
33 import org.orekit.Utils;
34 import org.orekit.errors.OrekitException;
35 import org.orekit.errors.OrekitMessages;
36 import org.orekit.propagation.FieldSpacecraftState;
37 import org.orekit.propagation.conversion.osc2mean.FixedPointConverter;
38 import org.orekit.propagation.conversion.osc2mean.OsculatingToMeanConverter;
39 import org.orekit.time.AbsoluteDate;
40 import org.orekit.time.DateComponents;
41 import org.orekit.time.FieldAbsoluteDate;
42 import org.orekit.time.TimeComponents;
43 import org.orekit.time.TimeOffset;
44 import org.orekit.time.TimeScalesFactory;
45 import org.orekit.utils.Constants;
46 import org.orekit.utils.FieldPVCoordinates;
47
48 import java.io.BufferedReader;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.io.InputStreamReader;
52 import java.text.ParseException;
53
54 public class FieldTLETest {
55
56
57
58 @Test
59 public void testTLEFormat() {
60 doTestTLEFormat(Binary64Field.getInstance());
61 }
62
63 @Test
64 public void TestIssue196() {
65 doTestIssue196(Binary64Field.getInstance());
66 }
67
68 @Test
69 public void testSymmetry() {
70 doTestSymmetry(Binary64Field.getInstance());
71 }
72
73 @Test
74 public void testBug74() {
75 doTestBug74(Binary64Field.getInstance());
76 }
77
78 @Test
79 public void testBug77() {
80 doTestBug77(Binary64Field.getInstance());
81 }
82
83 @Test
84 public void testDirectConstruction() {
85 doTestDirectConstruction(Binary64Field.getInstance());
86 }
87
88 @Test
89 public void testGenerateAlpha5() {
90 doTestGenerateAlpha5(Binary64Field.getInstance());
91 }
92
93 @Test
94 public void testBug77TooLargeSecondDerivative() {
95 doTestBug77TooLargeSecondDerivative(Binary64Field.getInstance());
96 }
97
98 @Test
99 public void testBug77TooLargeBStar() {
100 doTestBug77TooLargeBStar(Binary64Field.getInstance());
101 }
102
103 @Test
104 public void testBug77TooLargeEccentricity() {
105 doTestBug77TooLargeEccentricity(Binary64Field.getInstance());
106 }
107
108 @Test
109 public void testBug77TooLargeSatelliteNumber1() {
110 doTestBug77TooLargeSatelliteNumber1(Binary64Field.getInstance());
111 }
112
113 @Test
114 public void testBug77TooLargeSatelliteNumber2() {
115 doTestBug77TooLargeSatelliteNumber2(Binary64Field.getInstance());
116 }
117
118 @Test
119 public void testDifferentSatNumbers() {
120 Assertions.assertThrows(OrekitException.class, () -> {
121 doTestDifferentSatNumbers(Binary64Field.getInstance());
122 });
123 }
124
125 @Test
126 public void testChecksumOK() {
127 doTestChecksumOK();
128 }
129
130 @Test
131 public void testWrongChecksum1() {
132 doTestWrongChecksum1();
133 }
134
135 @Test
136 public void testWrongChecksum2() {
137 doTestWrongChecksum2();
138 }
139
140 @Test
141 public void testSatCodeCompliance() throws IOException, OrekitException, ParseException {
142 doTestSatCodeCompliance(Binary64Field.getInstance());
143 }
144
145 @Test
146 public void testZeroInclination() {
147 doTestZeroInclination(Binary64Field.getInstance());
148 }
149
150 @Test
151 public void testSymmetryAfterLeapSecondIntroduction() {
152 doTestSymmetryAfterLeapSecondIntroduction(Binary64Field.getInstance());
153 }
154
155 @Test
156 public void testOldTLE() {
157 doTestOldTLE(Binary64Field.getInstance());
158 }
159
160 @Test
161 public void testEqualTLE() {
162 doTestEqualTLE(Binary64Field.getInstance());
163 }
164
165 @Test
166 public void testNonEqualTLE() {
167 doTestNonEqualTLE(Binary64Field.getInstance());
168 }
169
170 @Test
171 public void testIssue388() {
172 doTestIssue388(Binary64Field.getInstance());
173 }
174
175 @Test
176 public void testIssue664NegativeRaanPa() {
177 doTestIssue664NegativeRaanPa(Binary64Field.getInstance());
178 }
179
180 @Test
181 public void testDifferentFields() {
182 String line1 = "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20";
183 String line2 = "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62";
184 final DSFactory factory = new DSFactory(1, 1);
185 FieldTLE<DerivativeStructure> tleA = new FieldTLE<>(factory.getDerivativeField(), line1, line2);
186 FieldTLE<Binary64> tleB = new FieldTLE<>(Binary64Field.getInstance(), line1, line2);
187 Assertions.assertNotEquals(tleA, tleB);
188 }
189
190 public <T extends CalculusFieldElement<T>> void doTestTLEFormat(Field<T> field) {
191
192 String line1 = "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20";
193 String line2 = "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62";
194
195 Assertions.assertTrue(TLE.isFormatOK(line1, line2));
196
197 FieldTLE<T> tle = new FieldTLE<T>(field, line1, line2);
198 Assertions.assertEquals(27421, tle.getSatelliteNumber(), 0);
199 Assertions.assertEquals(2002, tle.getLaunchYear());
200 Assertions.assertEquals(21, tle.getLaunchNumber());
201 Assertions.assertEquals("A", tle.getLaunchPiece());
202 Assertions.assertEquals(-0.0089879, tle.getBStar(), 0);
203 Assertions.assertEquals(0, tle.getEphemerisType());
204 Assertions.assertEquals(98.749, FastMath.toDegrees(tle.getI().getReal()), 1e-10);
205 Assertions.assertEquals(199.5121, FastMath.toDegrees(tle.getRaan().getReal()), 1e-10);
206 Assertions.assertEquals(0.0001333, tle.getE().getReal(), 1e-10);
207 Assertions.assertEquals(133.9522, FastMath.toDegrees(tle.getPerigeeArgument().getReal()), 1e-10);
208 Assertions.assertEquals(226.1918, FastMath.toDegrees(tle.getMeanAnomaly().getReal()), 1e-10);
209 Assertions.assertEquals(14.26113993, tle.getMeanMotion().getReal() * Constants.JULIAN_DAY / (2 * FastMath.PI), 0);
210 Assertions.assertEquals(7182888.814633288, tle.computeSemiMajorAxis().getReal(), 1e-10);
211 Assertions.assertEquals(tle.getRevolutionNumberAtEpoch(), 6, 0);
212 Assertions.assertEquals(tle.getElementNumber(), 2 , 0);
213
214 line1 = "1 T7421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 28";
215 line2 = "2 T7421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 60";
216 Assertions.assertTrue(TLE.isFormatOK(line1, line2));
217
218 tle = new FieldTLE<T>(field, line1, line2);
219 Assertions.assertEquals(277421, tle.getSatelliteNumber(), 0);
220
221 line1 = "1 I7421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 28";
222 line2 = "2 I7421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 60";
223 Assertions.assertFalse(TLE.isFormatOK(line1, line2));
224 try {
225 new FieldTLE<T>(field, line1, line2);
226 Assertions.fail("an exception should have been thrown");
227 } catch (NumberFormatException nfe) {
228
229 }
230
231 line1 = "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20";
232 line2 = "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14*26113993 62";
233 Assertions.assertFalse(TLE.isFormatOK(line1, line2));
234
235 line1 = "1 27421 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20";
236 line2 = "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62";
237 Assertions.assertFalse(TLE.isFormatOK(line1, line2));
238
239 line1 = "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20";
240 line2 = "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 10006113993 62";
241 Assertions.assertFalse(TLE.isFormatOK(line1, line2));
242
243 line1 = "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879 2 0 20";
244 line2 = "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62";
245 Assertions.assertFalse(TLE.isFormatOK(line1, line2));
246 }
247
248
249 public <T extends CalculusFieldElement<T>> void doTestIssue196(Field<T> field) {
250
251 String line1A = "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20";
252 String line1B = "1 27421U 02021A 02124.48976499 -.0002147 00000-0 -89879-2 0 20";
253 String line2 = "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62";
254
255 Assertions.assertTrue(TLE.isFormatOK(line1A, line2));
256 FieldTLE<T> tleA = new FieldTLE<T>(field, line1A, line2);
257 Assertions.assertTrue(TLE.isFormatOK(line1B, line2));
258 TLE tleB = new TLE(line1B, line2);
259 Assertions.assertEquals(tleA.getSatelliteNumber(), tleB.getSatelliteNumber(), 0);
260 Assertions.assertEquals(tleA.getLaunchYear(), tleB.getLaunchYear());
261 Assertions.assertEquals(tleA.getLaunchNumber(), tleB.getLaunchNumber());
262 Assertions.assertEquals(tleA.getLaunchPiece(), tleB.getLaunchPiece());
263 Assertions.assertEquals(tleA.getBStar(), tleB.getBStar(), 0);
264 Assertions.assertEquals(tleA.getEphemerisType(), tleB.getEphemerisType());
265 Assertions.assertEquals(tleA.getI().getReal(), tleB.getI(), 1e-10);
266 Assertions.assertEquals(tleA.getRaan().getReal(), tleB.getRaan(), 1e-10);
267 Assertions.assertEquals(tleA.getE().getReal(), tleB.getE(), 1e-10);
268 Assertions.assertEquals(tleA.getPerigeeArgument().getReal(), tleB.getPerigeeArgument(), 1e-10);
269 Assertions.assertEquals(tleA.getMeanAnomaly().getReal(), tleB.getMeanAnomaly(), 1e-10);
270 Assertions.assertEquals(tleA.getMeanMotion().getReal(), tleB.getMeanMotion(), 0);
271 Assertions.assertEquals(tleA.getRevolutionNumberAtEpoch(), tleB.getRevolutionNumberAtEpoch(), 0);
272 Assertions.assertEquals(tleA.getElementNumber(), tleB.getElementNumber(), 0);
273
274 }
275
276 public <T extends CalculusFieldElement<T>>void doTestSymmetry(Field<T> field) {
277 checkSymmetry(field, "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20",
278 "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62");
279 checkSymmetry(field, "1 31928U 98067BA 08269.84884916 .00114257 17652-4 13615-3 0 4412",
280 "2 31928 51.6257 175.4142 0001703 41.9031 318.2112 16.08175249 68368");
281 checkSymmetry(field, "1 T7421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 28",
282 "2 T7421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 60");
283 }
284
285 private <T extends CalculusFieldElement<T>> void checkSymmetry(Field<T> field, String line1, String line2) {
286 FieldTLE<T> tleRef = new FieldTLE<T>(field, line1, line2);
287 FieldTLE<T> tle = new FieldTLE<T>(tleRef.getSatelliteNumber(), tleRef.getClassification(),
288 tleRef.getLaunchYear(), tleRef.getLaunchNumber(), tleRef.getLaunchPiece(),
289 tleRef.getEphemerisType(), tleRef.getElementNumber(), tleRef.getDate(),
290 tleRef.getMeanMotion(), tleRef.getMeanMotionFirstDerivative(),
291 tleRef.getMeanMotionSecondDerivative(), tleRef.getE(), tleRef.getI(),
292 tleRef.getPerigeeArgument(), tleRef.getRaan(), tleRef.getMeanAnomaly(),
293 tleRef.getRevolutionNumberAtEpoch(), tleRef.getBStar());
294 Assertions.assertEquals(line1, tle.getLine1());
295 Assertions.assertEquals(line2, tle.getLine2());
296 }
297
298 public <T extends CalculusFieldElement<T>> void doTestBug74(Field<T> field) {
299 checkSymmetry(field, "1 00001U 00001A 12026.45833333 2.94600864 39565-9 16165-7 1 12",
300 "2 00001 127.0796 254.4522 0000000 224.9662 0.4817 0.00000000 11");
301 }
302
303 public <T extends CalculusFieldElement<T> >void doTestBug77(Field<T> field) {
304 checkSymmetry(field, "1 05555U 71086J 12026.96078249 -.00000004 00001-9 01234-9 0 9082",
305 "2 05555 74.0161 228.9750 0075476 328.9888 30.6709 12.26882470804545");
306 }
307
308 public <T extends CalculusFieldElement<T>> void doTestDirectConstruction(Field<T> field) {
309 final T T_zero = field.getZero();
310 FieldTLE<T> tleA = new FieldTLE<T>(5555, 'U', 1971, 86, "J", 0, 908,
311 new FieldAbsoluteDate<T>(field, new DateComponents(2012, 26),
312 new TimeComponents(0.96078249 * Constants.JULIAN_DAY),
313 TimeScalesFactory.getUTC()),
314 T_zero.add(taylorConvert(12.26882470, 1)), T_zero.add(taylorConvert(-0.00000004, 2)), T_zero.add(taylorConvert(0.00001e-9, 3)),
315 T_zero.add(0.0075476), T_zero.add(FastMath.toRadians(74.0161)), T_zero.add(FastMath.toRadians(328.9888)),
316 T_zero.add(FastMath.toRadians(228.9750)), T_zero.add(FastMath.toRadians(30.6709)), 80454, 0.01234e-9);
317 FieldTLE<T> tleB = new FieldTLE<T>(field, "1 05555U 71086J 12026.96078249 -.00000004 00001-9 01234-9 0 9082",
318 "2 05555 74.0161 228.9750 0075476 328.9888 30.6709 12.26882470804545");
319 Assertions.assertEquals(tleA.getSatelliteNumber(), tleB.getSatelliteNumber(), 0);
320 Assertions.assertEquals(tleA.getLaunchYear(), tleB.getLaunchYear());
321 Assertions.assertEquals(tleA.getLaunchNumber(), tleB.getLaunchNumber());
322 Assertions.assertEquals(tleA.getLaunchPiece(), tleB.getLaunchPiece());
323 Assertions.assertEquals(tleA.getBStar() , tleB.getBStar(), 0);
324 Assertions.assertEquals(tleA.getEphemerisType(), tleB.getEphemerisType());
325 Assertions.assertEquals(tleA.getI().getReal(), tleB.getI().getReal(), 1e-10);
326 Assertions.assertEquals(tleA.getRaan().getReal(), tleB.getRaan().getReal(), 1e-10);
327 Assertions.assertEquals(tleA.getE().getReal(), tleB.getE().getReal(), 1e-10);
328 Assertions.assertEquals(tleA.getPerigeeArgument().getReal(), tleB.getPerigeeArgument().getReal(), 1e-10);
329 Assertions.assertEquals(tleA.getMeanAnomaly().getReal(), tleB.getMeanAnomaly().getReal(), 1e-10);
330 Assertions.assertEquals(tleA.getMeanMotion().getReal(), tleB.getMeanMotion().getReal(), 0);
331 Assertions.assertEquals(tleA.getRevolutionNumberAtEpoch(), tleB.getRevolutionNumberAtEpoch(), 0);
332 Assertions.assertEquals(tleA.getElementNumber(), tleB.getElementNumber(), 0);
333 }
334
335 public <T extends CalculusFieldElement<T>> void doTestGenerateAlpha5(Field<T> field) {
336 final T T_zero = field.getZero();
337 FieldTLE<T> tle = new FieldTLE<T>(339999, 'U', 1971, 86, "J", 0, 908,
338 new FieldAbsoluteDate<T>(field, new DateComponents(2012, 26),
339 new TimeComponents(0.96078249 * Constants.JULIAN_DAY),
340 TimeScalesFactory.getUTC()),
341 T_zero.add(taylorConvert(12.26882470, 1)),
342 T_zero.add(taylorConvert(-0.00000004, 2)),
343 T_zero.add(taylorConvert(0.00001e-9, 3)),
344 T_zero.add(0.0075476), T_zero.add(FastMath.toRadians(74.0161)),
345 T_zero.add(FastMath.toRadians(328.9888)),
346 T_zero.add(FastMath.toRadians(228.9750)),
347 T_zero.add(FastMath.toRadians(30.6709)),
348 80454, 0.01234e-9);
349 Assertions.assertEquals("1 Z9999U 71086J 12026.96078249 -.00000004 00001-9 01234-9 0 9088", tle.getLine1());
350 Assertions.assertEquals("2 Z9999 74.0161 228.9750 0075476 328.9888 30.6709 12.26882470804541", tle.getLine2());
351 }
352
353 public <T extends CalculusFieldElement<T>> void doTestBug77TooLargeSecondDerivative(Field<T> field) {
354 try {
355 final T T_zero = field.getZero();
356 FieldTLE<T> tle = new FieldTLE<T>(5555, 'U', 1971, 86, "J", 0, 908,
357 new FieldAbsoluteDate<T>(field, new DateComponents(2012, 26),
358 new TimeComponents(0.96078249 * Constants.JULIAN_DAY),
359 TimeScalesFactory.getUTC()),
360 T_zero.add(taylorConvert(12.26882470, 1)), T_zero.add(taylorConvert(-0.00000004, 2)), T_zero.add(taylorConvert(0.99999e11, 3)),
361 T_zero.add(0.0075476), T_zero.add(FastMath.toRadians(74.0161)), T_zero.add(FastMath.toRadians(328.9888)),
362 T_zero.add(FastMath.toRadians(228.9750)), T_zero.add(FastMath.toRadians(30.6709)), 80454, 0.01234e-9);
363 tle.getLine1();
364 Assertions.fail("an exception should have been thrown");
365 } catch (OrekitException oe) {
366 Assertions.assertEquals(OrekitMessages.TLE_INVALID_PARAMETER, oe.getSpecifier());
367 Assertions.assertEquals(5555, ((Integer) oe.getParts()[0]).intValue());
368 Assertions.assertEquals("meanMotionSecondDerivative", oe.getParts()[1]);
369 }
370 }
371
372 public <T extends CalculusFieldElement<T>> void doTestBug77TooLargeBStar(Field<T> field) {
373 try {
374 final T T_zero = field.getZero();
375 FieldTLE<T> tle = new FieldTLE<T>(5555, 'U', 1971, 86, "J", 0, 908,
376 new FieldAbsoluteDate<T>(field, new DateComponents(2012, 26),
377 new TimeComponents(0.96078249 * Constants.JULIAN_DAY),
378 TimeScalesFactory.getUTC()),
379 T_zero.add(taylorConvert(12.26882470, 1)), T_zero.add(taylorConvert(-0.00000004, 2)), T_zero.add(taylorConvert(0.00001e-9, 3)),
380 T_zero.add(0.0075476), T_zero.add(FastMath.toRadians(74.0161)), T_zero.add(FastMath.toRadians(328.9888)),
381 T_zero.add(FastMath.toRadians(228.9750)), T_zero.add(FastMath.toRadians(30.6709)), 80454, 0.99999e11);
382 tle.getLine1();
383 Assertions.fail("an exception should have been thrown");
384 } catch (OrekitException oe) {
385 Assertions.assertEquals(OrekitMessages.TLE_INVALID_PARAMETER, oe.getSpecifier());
386 Assertions.assertEquals(5555, ((Integer) oe.getParts()[0]).intValue());
387 Assertions.assertEquals("B*", oe.getParts()[1]);
388 }
389 }
390
391 public <T extends CalculusFieldElement<T>> void doTestBug77TooLargeEccentricity(Field<T> field) {
392 try {
393 final T T_zero = field.getZero();
394 FieldTLE<T> tle = new FieldTLE<T>(5555, 'U', 1971, 86, "J", 0, 908,
395 new FieldAbsoluteDate<T>(field, new DateComponents(2012, 26),
396 new TimeComponents(0.96078249 * Constants.JULIAN_DAY),
397 TimeScalesFactory.getUTC()),
398 T_zero.add(taylorConvert(12.26882470, 1)), T_zero.add(taylorConvert(-0.00000004, 2)), T_zero.add(taylorConvert(0.00001e-9, 3)),
399 T_zero.add(1.0075476), T_zero.add(FastMath.toRadians(74.0161)), T_zero.add(FastMath.toRadians(328.9888)),
400 T_zero.add(FastMath.toRadians(228.9750)), T_zero.add(FastMath.toRadians(30.6709)), 80454, 0.01234e-9);
401 tle.getLine2();
402 Assertions.fail("an exception should have been thrown");
403 } catch (OrekitException oe) {
404 Assertions.assertEquals(OrekitMessages.TLE_INVALID_PARAMETER, oe.getSpecifier());
405 Assertions.assertEquals(5555, ((Integer) oe.getParts()[0]).intValue());
406 Assertions.assertEquals("eccentricity", oe.getParts()[1]);
407 }
408 }
409
410 public <T extends CalculusFieldElement<T>> void doTestBug77TooLargeSatelliteNumber1(Field<T> field) {
411 try {
412 final T T_zero = field.getZero();
413 FieldTLE<T> tle = new FieldTLE<T>(1000000, 'U', 1971, 86, "J", 0, 908,
414 new FieldAbsoluteDate<T>(field, new DateComponents(2012, 26),
415 new TimeComponents(0.96078249 * Constants.JULIAN_DAY),
416 TimeScalesFactory.getUTC()),
417 T_zero.add(taylorConvert(12.26882470, 1)), T_zero.add(taylorConvert(-0.00000004, 2)), T_zero.add(taylorConvert(0.00001e-9, 3)),
418 T_zero.add(0.0075476), T_zero.add(FastMath.toRadians(74.0161)), T_zero.add(FastMath.toRadians(328.9888)),
419 T_zero.add(FastMath.toRadians(228.9750)), T_zero.add(FastMath.toRadians(30.6709)), 80454, 0.01234e-9);
420 tle.getLine1();
421 Assertions.fail("an exception should have been thrown");
422 } catch (OrekitException oe) {
423 Assertions.assertEquals(OrekitMessages.TLE_INVALID_PARAMETER, oe.getSpecifier());
424 Assertions.assertEquals(1000000, ((Integer) oe.getParts()[0]).intValue());
425 Assertions.assertEquals("satelliteNumber-1", oe.getParts()[1]);
426 }
427 }
428
429 public <T extends CalculusFieldElement<T>> void doTestBug77TooLargeSatelliteNumber2(Field<T> field) {
430 try {
431 final T T_zero = field.getZero();
432 FieldTLE<T> tle = new FieldTLE<T>(1000000, 'U', 1971, 86, "J", 0, 908,
433 new FieldAbsoluteDate<T>(field, new DateComponents(2012, 26),
434 new TimeComponents(0.96078249 * Constants.JULIAN_DAY),
435 TimeScalesFactory.getUTC()),
436 T_zero.add(taylorConvert(12.26882470, 1)), T_zero.add(taylorConvert(-0.00000004, 2)), T_zero.add(taylorConvert(0.00001e-9, 3)),
437 T_zero.add(0.0075476), T_zero.add(FastMath.toRadians(74.0161)), T_zero.add(FastMath.toRadians(328.9888)),
438 T_zero.add(FastMath.toRadians(228.9750)), T_zero.add(FastMath.toRadians(30.6709)), 80454, 0.01234e-9);
439 tle.getLine2();
440 Assertions.fail("an exception should have been thrown");
441 } catch (OrekitException oe) {
442 Assertions.assertEquals(OrekitMessages.TLE_INVALID_PARAMETER, oe.getSpecifier());
443 Assertions.assertEquals(1000000, ((Integer) oe.getParts()[0]).intValue());
444 Assertions.assertEquals("satelliteNumber-2", oe.getParts()[1]);
445 }
446 }
447
448 final double taylorConvert(final double m, final int n) {
449
450 return m * 2 * FastMath.PI * CombinatoricsUtils.factorial(n) / FastMath.pow(Constants.JULIAN_DAY, n);
451 }
452
453 public <T extends CalculusFieldElement<T>> void doTestDifferentSatNumbers(Field<T> field) {
454 new FieldTLE<T>(field, "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20",
455 "2 27422 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62");
456 }
457
458 public void doTestChecksumOK() {
459 FieldTLE.isFormatOK("1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20",
460 "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62");
461 }
462
463 public void doTestWrongChecksum1() {
464 try {
465 FieldTLE.isFormatOK("1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 21",
466 "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62");
467 Assertions.fail("an exception should have been thrown");
468 } catch (OrekitException oe) {
469 Assertions.assertEquals(OrekitMessages.TLE_CHECKSUM_ERROR, oe.getSpecifier());
470 Assertions.assertEquals(1, ((Integer) oe.getParts()[0]).intValue());
471 Assertions.assertEquals("0", oe.getParts()[1]);
472 Assertions.assertEquals("1", oe.getParts()[2]);
473 Assertions.assertEquals("1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 21",
474 oe.getParts()[3]);
475 }
476 }
477
478 public void doTestWrongChecksum2() {
479 try {
480 FieldTLE.isFormatOK("1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20",
481 "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 61");
482 Assertions.fail("an exception should have been thrown");
483 } catch (OrekitException oe) {
484 Assertions.assertEquals(OrekitMessages.TLE_CHECKSUM_ERROR, oe.getSpecifier());
485 Assertions.assertEquals(2, ((Integer) oe.getParts()[0]).intValue());
486 Assertions.assertEquals("2", oe.getParts()[1]);
487 Assertions.assertEquals("1", oe.getParts()[2]);
488 Assertions.assertEquals("2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 61",
489 oe.getParts()[3]);
490 }
491 }
492
493 public <T extends CalculusFieldElement<T>>void doTestSatCodeCompliance(Field<T> field) throws IOException, OrekitException, ParseException {
494
495 BufferedReader rEntry = null;
496 BufferedReader rResults = null;
497 final T T_zero = field.getZero();
498
499 InputStream inEntry =
500 FieldTLETest.class.getResourceAsStream("/tle/extrapolationTest-data/SatCode-entry");
501 rEntry = new BufferedReader(new InputStreamReader(inEntry));
502
503 try {
504 InputStream inResults =
505 FieldTLETest.class.getResourceAsStream("/tle/extrapolationTest-data/SatCode-results");
506 rResults = new BufferedReader(new InputStreamReader(inResults));
507
508 try {
509 double cumulated = 0;
510 boolean stop = false;
511
512 String rline = rResults.readLine();
513
514 while (!stop) {
515 if (rline == null) break;
516
517 String[] title = rline.split(" ");
518
519 if (title[0].matches("r")) {
520
521 String eline;
522 int count = 0;
523 String[] header = new String[4];
524 for (eline = rEntry.readLine(); (eline != null) && (eline.charAt(0)=='#'); eline = rEntry.readLine()) {
525 header[count++] = eline;
526 }
527 String line1 = eline;
528 String line2 = rEntry.readLine();
529 Assertions.assertTrue(TLE.isFormatOK(line1, line2));
530
531 FieldTLE<T> tle = new FieldTLE<T>(field, line1, line2);
532
533 int satNum = Integer.parseInt(title[1]);
534 Assertions.assertEquals(satNum, tle.getSatelliteNumber());
535 final T[] parameters;
536 parameters = MathArrays.buildArray(field, 1);
537 parameters[0] = field.getZero().add(tle.getBStar());
538 FieldTLEPropagator<T> ex = FieldTLEPropagator.selectExtrapolator(tle, parameters);
539 for (rline = rResults.readLine(); (rline!=null)&&(rline.charAt(0)!='r'); rline = rResults.readLine()) {
540
541 String[] data = rline.split(" ");
542 double minFromStart = Double.parseDouble(data[0]);
543 T pX = T_zero.add(1000*Double.parseDouble(data[1]));
544 T pY = T_zero.add(1000*Double.parseDouble(data[2]));
545 T pZ = T_zero.add(1000*Double.parseDouble(data[3]));
546 T vX = T_zero.add(1000*Double.parseDouble(data[4]));
547 T vY = T_zero.add(1000*Double.parseDouble(data[5]));
548 T vZ = T_zero.add(1000*Double.parseDouble(data[6]));
549 FieldVector3D<T> testPos = new FieldVector3D<T>(pX, pY, pZ);
550 FieldVector3D<T> testVel = new FieldVector3D<T>(vX, vY, vZ);
551
552 FieldAbsoluteDate<T> date = tle.getDate().shiftedBy(minFromStart * 60);
553 FieldPVCoordinates<T> results = ex.getPVCoordinates(date, parameters);
554 double normDifPos = testPos.subtract(results.getPosition()).getNorm().getReal();
555 double normDifVel = testVel.subtract(results.getVelocity()).getNorm().getReal();
556
557 cumulated += normDifPos;
558 Assertions.assertEquals(0, normDifPos, 2e-3);
559 Assertions.assertEquals(0, normDifVel, 7e-4);
560
561 }
562 }
563 }
564 Assertions.assertEquals(0, cumulated, 0.026);
565 } finally {
566 if (rResults != null) {
567 rResults.close();
568 }
569 }
570 } finally {
571 if (rEntry != null) {
572 rEntry.close();
573 }
574 }
575 }
576
577 public <T extends CalculusFieldElement<T>> void doTestZeroInclination(Field<T> field) {
578 FieldTLE<T> tle = new FieldTLE<T>(field,"1 26451U 00043A 10130.13784012 -.00000276 00000-0 10000-3 0 3866",
579 "2 26451 000.0000 266.1044 0001893 160.7642 152.5985 01.00271160 35865");
580 final T[] parameters;
581 parameters = MathArrays.buildArray(field, 1);
582 parameters[0].add(tle.getBStar());
583 FieldTLEPropagator<T> propagator = FieldTLEPropagator.selectExtrapolator(tle, parameters);
584 FieldPVCoordinates<T> pv = propagator.propagate(tle.getDate().shiftedBy(100)).getPVCoordinates();
585 Assertions.assertEquals(42171546.979560345, pv.getPosition().getNorm().getReal(), 1.0e-3);
586 Assertions.assertEquals(3074.1890089357994, pv.getVelocity().getNorm().getReal(), 1.0e-6);
587 }
588
589 public <T extends CalculusFieldElement<T>> void doTestSymmetryAfterLeapSecondIntroduction(Field<T> field) {
590 checkSymmetry(field, "1 34602U 09013A 12187.35117436 .00002472 18981-5 42406-5 0 9995",
591 "2 34602 96.5991 210.0210 0006808 112.8142 247.3865 16.06008103193411");
592 }
593
594 public <T extends CalculusFieldElement<T>> void doTestOldTLE(Field<T> field) {
595 String line1 = "1 15427U 85091.94293084 0.00000051 00000+0 32913-4 0 179";
596 String line2 = "2 15427 98.9385 46.0219 0015502 321.4354 38.5705 14.11363211 15580";
597 Assertions.assertTrue(TLE.isFormatOK(line1, line2));
598 FieldTLE<T> tle = new FieldTLE<T>(field, line1, line2);
599 Assertions.assertEquals(15427, tle.getSatelliteNumber());
600 Assertions.assertEquals(0.00000051,
601 tle.getMeanMotionFirstDerivative().getReal() * Constants.JULIAN_DAY * Constants.JULIAN_DAY / (4 * FastMath.PI),
602 1.0e-15);
603 }
604
605 public <T extends CalculusFieldElement<T>> void doTestEqualTLE(Field<T> field) {
606 FieldTLE<T> tleA = new FieldTLE<T>(field, "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20",
607 "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62");
608 FieldTLE<T> tleB = new FieldTLE<T>(field, "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20",
609 "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62");
610 Assertions.assertEquals(tleA, tleB);
611 }
612
613 public <T extends CalculusFieldElement<T>> void doTestNonEqualTLE(Field<T> field) {
614 FieldTLE<T> tleA = new FieldTLE<T>(field, "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20",
615 "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62");
616 FieldTLE<T> tleB = new FieldTLE<T>(field, "1 05555U 71086J 12026.96078249 -.00000004 00001-9 01234-9 0 9082",
617 "2 05555 74.0161 228.9750 0075476 328.9888 30.6709 12.26882470804545");
618 Assertions.assertNotEquals(tleA, tleB);
619 }
620
621 public <T extends CalculusFieldElement<T>> void doTestIssue388(Field<T> field) {
622 final T T_zero = field.getZero();
623 FieldTLE<T> tleRef = new FieldTLE<T>(field, "1 27421U 02021A 02124.48976499 -.00021470 00000-0 -89879-2 0 20",
624 "2 27421 98.7490 199.5121 0001333 133.9522 226.1918 14.26113993 62");
625 FieldTLE<T> tleOriginal = new FieldTLE<T>(27421, 'U', 2002, 21, "A", TLE.DEFAULT, 2,
626 new FieldAbsoluteDate<T>(field, "2002-05-04T11:45:15.695", TimeScalesFactory.getUTC()),
627 T_zero.add(FastMath.toRadians(14.26113993 * 360 / Constants.JULIAN_DAY)),
628 T_zero.add(FastMath.toRadians(-.00021470 * 360 * 2 / (Constants.JULIAN_DAY * Constants.JULIAN_DAY))),
629 T_zero.add(FastMath.toRadians(0.0)),
630 T_zero.add(1.333E-4), T_zero.add(FastMath.toRadians(98.7490)),
631 T_zero.add(FastMath.toRadians(133.9522)), T_zero.add(FastMath.toRadians(199.5121)), T_zero.add(FastMath.toRadians(226.1918)),
632 6, -0.0089879);
633 Assertions.assertEquals(tleRef.getLine1(), tleOriginal.getLine1());
634 Assertions.assertEquals(tleRef.getLine2(), tleOriginal.getLine2());
635 FieldTLE<T> changedBStar = new FieldTLE<T>(27421, 'U', 2002, 21, "A", TLE.DEFAULT, 2,
636 new FieldAbsoluteDate<T>(field, "2002-05-04T11:45:15.695", TimeScalesFactory.getUTC()),
637 T_zero.add(FastMath.toRadians(14.26113993 * 360 / Constants.JULIAN_DAY)),
638 T_zero.add(FastMath.toRadians(-.00021470 * 360 * 2 / (Constants.JULIAN_DAY * Constants.JULIAN_DAY))),
639 T_zero.add(FastMath.toRadians(0.0)),
640 T_zero.add(1.333E-4), T_zero.add(FastMath.toRadians(98.7490)),
641 T_zero.add(FastMath.toRadians(133.9522)), T_zero.add(FastMath.toRadians(199.5121)), T_zero.add(FastMath.toRadians(226.1918)),
642 6, 1.0e-4);
643 Assertions.assertEquals(tleRef.getLine1().replace("-89879-2", " 10000-3"), changedBStar.getLine1());
644 Assertions.assertEquals(tleRef.getLine2(), changedBStar.getLine2());
645 Assertions.assertEquals(1.0e-4, new FieldTLE<T>(field, changedBStar.getLine1(), changedBStar.getLine2()).getBStar(), 1.0e-15);
646 }
647
648 public <T extends CalculusFieldElement<T>> void doTestIssue664NegativeRaanPa(Field<T> field) {
649 final T T_zero = field.getZero();
650 FieldTLE<T> tle = new FieldTLE<T>(99999, 'X', 2020, 42, "F", 0, 999,
651 new FieldAbsoluteDate<T>(field, "2020-01-01T01:00:00.000", TimeScalesFactory.getUTC()), T_zero.add(0.0011010400252833312), T_zero.add(0.0),
652 T_zero.add(0.0), T_zero.add(0.0016310523359516962), T_zero.add(1.6999188604164899),
653 T_zero.add(-3.219351286726724), T_zero.add(-2.096689019811356),
654 T_zero.add(2.157567545975006), 1, 1e-05);
655
656
657 Assertions.assertEquals(tle.getLine1(), "1 99999X 20042F 20001.04166667 .00000000 00000-0 10000-4 0 9997");
658 Assertions.assertEquals(tle.getLine2(), "2 99999 97.3982 239.8686 0016311 175.5448 123.6195 15.14038717 18");
659 }
660
661 @Test
662 public void testStateToTleISS() {
663 doTestStateToTleISS(Binary64Field.getInstance());
664 }
665
666 private <T extends CalculusFieldElement<T>> void doTestStateToTleISS(final Field<T> field) {
667
668
669 final FieldTLE<T> tleISS = new FieldTLE<>(field, "1 25544U 98067A 21035.14486477 .00001026 00000-0 26816-4 0 9998",
670 "2 25544 51.6455 280.7636 0002243 335.6496 186.1723 15.48938788267977");
671
672
673 final FieldTLEPropagator<T> propagator = FieldTLEPropagator.selectExtrapolator(tleISS, tleISS.getParameters(field));
674
675
676 final FieldSpacecraftState<T> state = propagator.propagate(tleISS.getDate());
677
678
679 final OsculatingToMeanConverter converter = new FixedPointConverter();
680
681
682 final FieldTLE<T> rebuilt = FieldTLE.stateToTLE(state, tleISS, converter);
683
684
685 final double eps = 1.0e-7;
686 Assertions.assertEquals(tleISS.getSatelliteNumber(), rebuilt.getSatelliteNumber());
687 Assertions.assertEquals(tleISS.getClassification(), rebuilt.getClassification());
688 Assertions.assertEquals(tleISS.getLaunchYear(), rebuilt.getLaunchYear());
689 Assertions.assertEquals(tleISS.getLaunchNumber(), rebuilt.getLaunchNumber());
690 Assertions.assertEquals(tleISS.getLaunchPiece(), rebuilt.getLaunchPiece());
691 Assertions.assertEquals(tleISS.getElementNumber(), rebuilt.getElementNumber());
692 Assertions.assertEquals(tleISS.getRevolutionNumberAtEpoch(), rebuilt.getRevolutionNumberAtEpoch());
693 Assertions.assertEquals(tleISS.getMeanMotion().getReal(), rebuilt.getMeanMotion().getReal(), eps * tleISS.getMeanMotion().getReal());
694 Assertions.assertEquals(tleISS.getE().getReal(), rebuilt.getE().getReal(), eps * tleISS.getE().getReal());
695 Assertions.assertEquals(tleISS.getI().getReal(), rebuilt.getI().getReal(), eps * tleISS.getI().getReal());
696 Assertions.assertEquals(tleISS.getPerigeeArgument().getReal(), rebuilt.getPerigeeArgument().getReal(), eps * tleISS.getPerigeeArgument().getReal());
697 Assertions.assertEquals(tleISS.getRaan().getReal(), rebuilt.getRaan().getReal(), eps * tleISS.getRaan().getReal());
698 Assertions.assertEquals(tleISS.getMeanAnomaly().getReal(), rebuilt.getMeanAnomaly().getReal(), eps * tleISS.getMeanAnomaly().getReal());
699 Assertions.assertEquals(tleISS.getMeanAnomaly().getReal(), rebuilt.getMeanAnomaly().getReal(), eps * tleISS.getMeanAnomaly().getReal());
700 Assertions.assertEquals(tleISS.getBStar(), rebuilt.getBStar(), eps * tleISS.getBStar());
701 }
702
703 @Test
704 public void testToTLE() {
705 doTestToTLE(Binary64Field.getInstance());
706 }
707
708 private <T extends CalculusFieldElement<T>> void doTestToTLE(final Field<T> field) {
709 final TLE tle = new TLE("1 25544U 98067A 21035.14486477 .00001026 00000-0 26816-4 0 9998",
710 "2 25544 51.6455 280.7636 0002243 335.6496 186.1723 15.48938788267977");
711 final FieldTLE<T> fieldTle = new FieldTLE<T>(field, tle.getLine1(), tle.getLine2());
712 final TLE rebuilt = fieldTle.toTLE();
713 Assertions.assertEquals(rebuilt, tle);
714 Assertions.assertEquals(tle.toString(), rebuilt.toString());
715 }
716
717 @Test
718 void roundToNextDayError() {
719
720 final Field<Binary64> field = Binary64Field.getInstance();
721 final Binary64 zero = field.getZero();
722
723 final FieldAbsoluteDate<Binary64> tleDate =
724 new FieldAbsoluteDate<>(field, new AbsoluteDate("2022-01-01T23:59:59.99999999", TimeScalesFactory.getUTC()));
725
726 final FieldTLE<Binary64> tle =
727 new FieldTLE<>(99999, 'U', 2022, 999, "A", 0, 1, tleDate, zero, zero, zero, zero, zero, zero, zero, zero, 99,
728 11606 * 1e-4, TimeScalesFactory.getUTC());
729
730
731 final FieldAbsoluteDate<Binary64> returnedDate = tle.getDate();
732
733
734
735 Assertions.assertEquals(tleDate, returnedDate);
736 }
737
738 @Test
739 @DisplayName("fix issue 1773 : with Orekit 13 new date representation, TLE parsing from lines may introduce " +
740 "some attoseconds of error")
741 void testFixIssue1773() {
742
743 final Field<Binary64> field = Binary64Field.getInstance();
744 final String line1WithDateParsingError = "1 00005U 58002B 25047.63247525. .00000268 00000-0 35695-3 0 9999";
745 final String line2WithDateParsingError = "2 00005 34.2494 12.9875 1841261 109.2290 271.5928 10.85874828390491";
746
747 final DateComponents dateComponents = new DateComponents(2025, 2, 16);
748 final TimeOffset timeOffset = new TimeOffset(45, TimeOffset.MICROSECOND.multiply(861600).getAttoSeconds());
749 final TimeComponents timeComponents = new TimeComponents(15, 10, timeOffset);
750 final FieldAbsoluteDate<Binary64> reconstructedExactDate =
751 new FieldAbsoluteDate<>(field, dateComponents, timeComponents, TimeScalesFactory.getUTC());
752
753
754 final FieldTLE<Binary64> parsedTle = new FieldTLE<>(field, line1WithDateParsingError, line2WithDateParsingError);
755
756
757 Assertions.assertEquals(reconstructedExactDate, parsedTle.getDate());
758 }
759
760 @BeforeEach
761 public void setUp() {
762 Utils.setDataRoot("regular-data");
763 }
764
765 }