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
20 import java.util.List;
21
22 import org.hipparchus.CalculusFieldElement;
23 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24 import org.hipparchus.util.FastMath;
25 import org.hipparchus.util.MathUtils;
26 import org.hipparchus.util.Pair;
27 import org.orekit.annotation.DefaultDataContext;
28 import org.orekit.attitudes.AttitudeProvider;
29 import org.orekit.attitudes.FieldAttitude;
30 import org.orekit.attitudes.FrameAlignedProvider;
31 import org.orekit.data.DataContext;
32 import org.orekit.errors.OrekitException;
33 import org.orekit.errors.OrekitMessages;
34 import org.orekit.frames.Frame;
35 import org.orekit.orbits.FieldCartesianOrbit;
36 import org.orekit.orbits.FieldOrbit;
37 import org.orekit.propagation.FieldSpacecraftState;
38 import org.orekit.propagation.analytical.FieldAbstractAnalyticalPropagator;
39 import org.orekit.propagation.analytical.tle.generation.TleGenerationAlgorithm;
40 import org.orekit.time.FieldAbsoluteDate;
41 import org.orekit.time.TimeScale;
42 import org.orekit.utils.FieldPVCoordinates;
43 import org.orekit.utils.PVCoordinates;
44 import org.orekit.utils.ParameterDriver;
45 import org.orekit.utils.TimeSpanMap;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 public abstract class FieldTLEPropagator<T extends CalculusFieldElement<T>> extends FieldAbstractAnalyticalPropagator<T> {
77
78
79
80
81 protected FieldTLE<T> tle;
82
83
84 protected final TimeScale utc;
85
86
87 protected T xnode;
88
89
90 protected T a;
91
92
93 protected T e;
94
95
96 protected T i;
97
98
99 protected T omega;
100
101
102 protected T xl;
103
104
105 protected T a0dp;
106
107
108 protected T xn0dp;
109
110
111 protected T cosi0;
112
113
114 protected T theta2;
115
116
117 protected T sini0;
118
119
120 protected T xmdot;
121
122
123 protected T omgdot;
124
125
126 protected T xnodot;
127
128
129 protected T e0sq;
130
131 protected T beta02;
132
133
134 protected T beta0;
135
136
137 protected T perige;
138
139
140 protected T etasq;
141
142
143 protected T eeta;
144
145
146 protected T s4;
147
148
149 protected T tsi;
150
151
152 protected T eta;
153
154
155 protected T coef;
156
157
158 protected T coef1;
159
160
161 protected T c1;
162
163
164 protected T c2;
165
166
167 protected T c4;
168
169
170 protected T xnodcf;
171
172
173 protected T t2cof;
174
175
176
177
178 private final Frame teme;
179
180
181 private TimeSpanMap<Pair<FieldTLE<T>, T>> tlesAndMasses;
182
183
184 private TleGenerationAlgorithm generationAlgorithm;
185
186
187
188
189
190
191
192
193
194
195
196
197 @DefaultDataContext
198 protected FieldTLEPropagator(final FieldTLE<T> initialTLE, final AttitudeProvider attitudeProvider, final T mass,
199 final T[] parameters) {
200 this(initialTLE, attitudeProvider, mass, DataContext.getDefault().getFrames().getTEME(), parameters);
201 }
202
203
204
205
206
207
208
209
210 protected FieldTLEPropagator(final FieldTLE<T> initialTLE, final AttitudeProvider attitudeProvider, final T mass,
211 final Frame teme, final T[] parameters) {
212 super(initialTLE.getE().getField(), attitudeProvider);
213 setStartDate(initialTLE.getDate());
214 this.utc = initialTLE.getUtc();
215 initializeTle(initialTLE);
216 this.teme = teme;
217 this.tlesAndMasses = new TimeSpanMap<>(new Pair<>(tle, mass));
218 this.generationAlgorithm = TLEPropagator.getDefaultTleGenerationAlgorithm(this.utc, teme);
219
220 initializeCommons(parameters);
221 sxpInitialize(parameters);
222
223 final FieldOrbit<T> orbit = propagateOrbit(initialTLE.getDate(), parameters);
224 final FieldAttitude<T> attitude = attitudeProvider.getAttitude(orbit, orbit.getDate(), orbit.getFrame());
225 super.resetInitialState(new FieldSpacecraftState<>(orbit, attitude).withMass(mass));
226 }
227
228
229
230
231
232
233
234
235
236
237
238 @DefaultDataContext
239 public static <T extends CalculusFieldElement<T>> FieldTLEPropagator<T> selectExtrapolator(final FieldTLE<T> tle, final T[] parameters) {
240 return selectExtrapolator(tle, DataContext.getDefault().getFrames().getTEME(), parameters);
241 }
242
243
244
245
246
247
248
249
250
251
252
253 public static <T extends CalculusFieldElement<T>> FieldTLEPropagator<T> selectExtrapolator(final FieldTLE<T> tle, final Frame teme, final T[] parameters) {
254 return selectExtrapolator(
255 tle,
256 FrameAlignedProvider.of(teme),
257 tle.getE().getField().getZero().newInstance(DEFAULT_MASS),
258 teme,
259 parameters);
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273
274 @DefaultDataContext
275 public static <T extends CalculusFieldElement<T>> FieldTLEPropagator<T> selectExtrapolator(final FieldTLE<T> tle,
276 final AttitudeProvider attitudeProvider,
277 final T mass,
278 final T[] parameters) {
279 return selectExtrapolator(tle, attitudeProvider, mass,
280 DataContext.getDefault().getFrames().getTEME(), parameters);
281 }
282
283
284
285
286
287
288
289
290
291
292
293 public static <T extends CalculusFieldElement<T>> FieldTLEPropagator<T> selectExtrapolator(
294 final FieldTLE<T> tle,
295 final AttitudeProvider attitudeProvider,
296 final T mass,
297 final Frame teme,
298 final T[] parameters) {
299
300 final T a1 = tle.getMeanMotion().multiply(60.0).reciprocal().multiply(TLEConstants.XKE).pow(TLEConstants.TWO_THIRD);
301 final T cosi0 = FastMath.cos(tle.getI());
302 final T temp1 = cosi0.multiply(cosi0.multiply(3.0)).subtract(1.0).multiply(1.5 * TLEConstants.CK2);
303 final T temp2 = tle.getE().multiply(tle.getE()).negate().add(1.0).pow(-1.5);
304 final T temp = temp1.multiply(temp2);
305 final T delta1 = temp.divide(a1.multiply(a1));
306 final T a0 = a1.multiply(delta1.multiply(delta1.multiply(
307 delta1.multiply(134.0 / 81.0).add(1.0)).add(TLEConstants.ONE_THIRD)).negate().add(1.0));
308 final T delta0 = temp.divide(a0.multiply(a0));
309
310
311 final T xn0dp = tle.getMeanMotion().multiply(60.0).divide(delta0.add(1.0));
312
313 final FieldTLEPropagator<T> propagator;
314
315 if (MathUtils.TWO_PI / (xn0dp.multiply(TLEConstants.MINUTES_PER_DAY).getReal()) >= (1.0 / 6.4)) {
316 propagator = new FieldDeepSDP4<>(tle, attitudeProvider, mass, teme, parameters);
317 } else {
318 propagator = new FieldSGP4<>(tle, attitudeProvider, mass, teme, parameters);
319 }
320
321 return propagator;
322 }
323
324
325
326
327 public static double getMU() {
328 return TLEConstants.MU;
329 }
330
331
332
333
334
335
336 public FieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> date, final T[] parameters) {
337
338 sxpPropagate(date.durationFrom(tle.getDate()).divide(60.0), parameters);
339
340
341 return computePVCoordinates();
342 }
343
344
345
346
347 private void initializeCommons(final T[] parameters) {
348
349 final T zero = tle.getDate().getField().getZero();
350 final T bStar = parameters[0];
351 final T a1 = tle.getMeanMotion().multiply(60.0).reciprocal().multiply(TLEConstants.XKE).pow(TLEConstants.TWO_THIRD);
352 cosi0 = FastMath.cos(tle.getI());
353 theta2 = cosi0.multiply(cosi0);
354 final T x3thm1 = theta2.multiply(3.0).subtract(1.0);
355 e0sq = tle.getE().square();
356 beta02 = e0sq.negate().add(1.0);
357 beta0 = FastMath.sqrt(beta02);
358 final T tval = x3thm1.multiply(1.5 * TLEConstants.CK2).divide(beta0.multiply(beta02));
359 final T delta1 = tval.divide(a1.multiply(a1));
360 final T a0 = a1.multiply(delta1.multiply(
361 delta1.multiply(134.0 / 81.0).add(1.0).multiply(delta1).add(TLEConstants.ONE_THIRD)).negate().add(1.0));
362 final T delta0 = tval.divide(a0.multiply(a0));
363
364
365 xn0dp = tle.getMeanMotion().multiply(60.0).divide(delta0.add(1.0));
366 a0dp = a0.divide(delta0.negate().add(1.0));
367
368
369 s4 = zero.newInstance(TLEConstants.S);
370 T q0ms24 = zero.newInstance(TLEConstants.QOMS2T);
371
372 perige = a0dp.multiply(tle.getE().negate().add(1.0)).subtract(TLEConstants.NORMALIZED_EQUATORIAL_RADIUS).multiply(
373 TLEConstants.EARTH_RADIUS);
374
375
376 if (perige.getReal() < 156.0) {
377 if (perige.getReal() <= 98.0) {
378 s4 = zero.newInstance(20.0);
379 } else {
380 s4 = perige.subtract(78.0);
381 }
382 final T temp_val = s4.negate().add(120.0).multiply(TLEConstants.NORMALIZED_EQUATORIAL_RADIUS / TLEConstants.EARTH_RADIUS);
383 final T temp_val_squared = temp_val.multiply(temp_val);
384 q0ms24 = temp_val_squared.square();
385 s4 = s4.divide(TLEConstants.EARTH_RADIUS).add(TLEConstants.NORMALIZED_EQUATORIAL_RADIUS);
386 }
387
388 final T pinv = a0dp.multiply(beta02).reciprocal();
389 final T pinvsq = pinv.square();
390 tsi = a0dp.subtract(s4).reciprocal();
391 eta = a0dp.multiply(tle.getE()).multiply(tsi);
392 etasq = eta.square();
393 eeta = tle.getE().multiply(eta);
394
395 final T psisq = etasq.negate().add(1.0).abs();
396 final T tsi_squared = tsi.multiply(tsi);
397 coef = q0ms24.multiply(tsi_squared.square());
398 coef1 = coef.divide(psisq.pow(3.5));
399
400
401 c2 = coef1.multiply(xn0dp).multiply(a0dp.multiply(
402 etasq.multiply(1.5).add(eeta.multiply(etasq.add(4.0))).add(1.0)).add(
403 tsi.divide(psisq).multiply(x3thm1).multiply(0.75 * TLEConstants.CK2).multiply(
404 etasq.multiply(etasq.add(8.0)).multiply(3.0).add(8.0))));
405 c1 = bStar.multiply(c2);
406 sini0 = FastMath.sin(tle.getI());
407
408 final T x1mth2 = theta2.negate().add(1.0);
409
410
411 c4 = xn0dp.multiply(coef1).multiply(a0dp).multiply(2.0).multiply(beta02).multiply(
412 eta.multiply(etasq.multiply(0.5).add(2.0)).add(tle.getE().multiply(etasq.multiply(2.0).add(0.5))).subtract(
413 tsi.divide(a0dp.multiply(psisq)).multiply(2 * TLEConstants.CK2).multiply(
414 x3thm1.multiply(-3).multiply(etasq.multiply(eeta.multiply(-0.5).add(1.5)).add(eeta.multiply(-2.0)).add(1.0)).add(
415 x1mth2.multiply(0.75).multiply(etasq.multiply(2.0).subtract(eeta.multiply(etasq.add(1.0)))).multiply(FastMath.cos(tle.getPerigeeArgument().multiply(2.0)))))));
416
417 final T theta4 = theta2.multiply(theta2);
418 final T temp1 = pinvsq.multiply(xn0dp).multiply(3 * TLEConstants.CK2);
419 final T temp2 = temp1.multiply(pinvsq).multiply(TLEConstants.CK2);
420 final T temp3 = pinvsq.multiply(pinvsq).multiply(xn0dp).multiply(1.25 * TLEConstants.CK4);
421
422
423 xmdot = xn0dp.add(
424 temp1.multiply(0.5).multiply(beta0).multiply(x3thm1)).add(
425 temp2.multiply(0.0625).multiply(beta0).multiply(
426 theta2.multiply(78.0).negate().add(13.0).add(theta4.multiply(137.0))));
427
428 final T x1m5th = theta2.multiply(5.0).negate().add(1.0);
429
430 omgdot = temp1.multiply(-0.5).multiply(x1m5th).add(
431 temp2.multiply(0.0625).multiply(theta2.multiply(114.0).negate().add(
432 theta4.multiply(395.0)).add(7.0))).add(
433 temp3.multiply(theta2.multiply(36.0).negate().add(theta4.multiply(49.0)).add(3.0)));
434
435 final T xhdot1 = temp1.negate().multiply(cosi0);
436
437 xnodot = xhdot1.add(temp2.multiply(0.5).multiply(theta2.multiply(19.0).negate().add(4.0)).add(
438 temp3.multiply(2.0).multiply(theta2.multiply(7.0).negate().add(3.0))).multiply(cosi0));
439 xnodcf = beta02.multiply(xhdot1).multiply(c1).multiply(3.5);
440 t2cof = c1.multiply(1.5);
441
442 }
443
444
445
446
447 private FieldPVCoordinates<T> computePVCoordinates() {
448
449 final T zero = tle.getDate().getField().getZero();
450
451 final T axn = e.multiply(FastMath.cos(omega));
452 T temp = a.multiply(e.multiply(e).negate().add(1.0)).reciprocal();
453 final T xlcof = sini0.multiply(0.125 * TLEConstants.A3OVK2).multiply(
454 cosi0.multiply(5.0).add(3.0).divide(cosi0.add(1.0)));
455 final T aycof = sini0.multiply(0.25 * TLEConstants.A3OVK2);
456 final T xll = temp.multiply(xlcof).multiply(axn);
457 final T aynl = temp.multiply(aycof);
458 final T xlt = xl.add(xll);
459 final T ayn = e.multiply(FastMath.sin(omega)).add(aynl);
460 final T elsq = axn.square().add(ayn.square());
461 final T capu = MathUtils.normalizeAngle(xlt.subtract(xnode), zero.getPi());
462 T epw = capu;
463 T ecosE = zero;
464 T esinE = zero;
465 T sinEPW = zero;
466 T cosEPW = zero;
467
468
469 final T cosi0Sq = cosi0.square();
470 final T x3thm1 = cosi0Sq.multiply(3.0).subtract(1.0);
471 final T x1mth2 = cosi0Sq.negate().add(1.0);
472 final T x7thm1 = cosi0Sq.multiply(7.0).subtract(1.0);
473
474 if (e.getReal() > (1 - 1e-6)) {
475 throw new OrekitException(OrekitMessages.TOO_LARGE_ECCENTRICITY_FOR_PROPAGATION_MODEL, e.getReal());
476 }
477
478
479 final double newtonRaphsonEpsilon = 1e-12;
480 for (int j = 0; j < 10; j++) {
481
482 boolean doSecondOrderNewtonRaphson = true;
483
484 sinEPW = FastMath.sin( epw);
485 cosEPW = FastMath.cos( epw);
486 ecosE = axn.multiply(cosEPW).add(ayn.multiply(sinEPW));
487 esinE = axn.multiply(sinEPW).subtract(ayn.multiply(cosEPW));
488 final T f = capu.subtract(epw).add(esinE);
489 if (FastMath.abs(f.getReal()) < newtonRaphsonEpsilon) {
490 break;
491 }
492 final T fdot = ecosE.negate().add(1.0);
493 T delta_epw = f.divide(fdot);
494 if (j == 0) {
495 final T maxNewtonRaphson = e.abs().multiply(1.25);
496 doSecondOrderNewtonRaphson = false;
497 if (delta_epw.getReal() > maxNewtonRaphson.getReal()) {
498 delta_epw = maxNewtonRaphson;
499 } else if (delta_epw.getReal() < -maxNewtonRaphson.getReal()) {
500 delta_epw = maxNewtonRaphson.negate();
501 } else {
502 doSecondOrderNewtonRaphson = true;
503 }
504 }
505 if (doSecondOrderNewtonRaphson) {
506 delta_epw = f.divide(fdot.add(esinE.multiply(0.5).multiply(delta_epw)));
507 }
508 epw = epw.add(delta_epw);
509 }
510
511
512 temp = elsq.negate().add(1.0);
513 final T pl = a.multiply(temp);
514 final T r = a.multiply(ecosE.negate().add(1.0));
515 T temp2 = a.divide(r);
516 final T betal = FastMath.sqrt(temp);
517 temp = esinE.divide(betal.add(1.0));
518 final T cosu = temp2.multiply(cosEPW.subtract(axn).add(ayn.multiply(temp)));
519 final T sinu = temp2.multiply(sinEPW.subtract(ayn).subtract(axn.multiply(temp)));
520 final T u = FastMath.atan2(sinu, cosu);
521 final T sin2u = sinu.multiply(cosu).multiply(2.0);
522 final T cos2u = cosu.multiply(cosu).multiply(2.0).subtract(1.0);
523 final T temp1 = pl.reciprocal().multiply(TLEConstants.CK2);
524 temp2 = temp1.divide(pl);
525
526
527 final T rk = r.multiply(temp2.multiply(betal).multiply(x3thm1).multiply(-1.5).add(1.0)).add(
528 temp1.multiply(x1mth2).multiply(cos2u).multiply(0.5));
529 final T uk = u.subtract(temp2.multiply(x7thm1).multiply(sin2u).multiply(0.25));
530 final T xnodek = xnode.add(temp2.multiply(cosi0).multiply(sin2u).multiply(1.5));
531 final T xinck = i.add(temp2.multiply(cosi0).multiply(sini0).multiply(cos2u).multiply(1.5));
532
533
534 final T sinuk = FastMath.sin(uk);
535 final T cosuk = FastMath.cos(uk);
536 final T sinik = FastMath.sin(xinck);
537 final T cosik = FastMath.cos(xinck);
538 final T sinnok = FastMath.sin(xnodek);
539 final T cosnok = FastMath.cos(xnodek);
540 final T xmx = sinnok.negate().multiply(cosik);
541 final T xmy = cosnok.multiply(cosik);
542 final T ux = xmx.multiply(sinuk).add(cosnok.multiply(cosuk));
543 final T uy = xmy.multiply(sinuk).add(sinnok.multiply(cosuk));
544 final T uz = sinik.multiply(sinuk);
545
546
547 final T cr = rk.multiply(1000 * TLEConstants.EARTH_RADIUS);
548 final FieldVector3D<T> pos = new FieldVector3D<>(cr.multiply(ux), cr.multiply(uy), cr.multiply(uz));
549
550 final T sqrtA = FastMath.sqrt(a);
551 final T rdot = sqrtA.multiply(esinE.divide(r)).multiply(TLEConstants.XKE);
552 final T rfdot = FastMath.sqrt(pl).divide(r).multiply(TLEConstants.XKE);
553 final T xn = a.multiply(sqrtA).reciprocal().multiply(TLEConstants.XKE);
554 final T rdotk = rdot.subtract(xn.multiply(temp1).multiply(x1mth2).multiply(sin2u));
555 final T rfdotk = rfdot.add(xn.multiply(temp1).multiply(x1mth2.multiply(cos2u).add(x3thm1.multiply(1.5))));
556 final T vx = xmx.multiply(cosuk).subtract(cosnok.multiply(sinuk));
557 final T vy = xmy.multiply(cosuk).subtract(sinnok.multiply(sinuk));
558 final T vz = sinik.multiply(cosuk);
559
560 final double cv = 1000.0 * TLEConstants.EARTH_RADIUS / 60.0;
561 final FieldVector3D<T> vel = new FieldVector3D<>(rdotk.multiply(ux).add(rfdotk.multiply(vx)).multiply(cv),
562 rdotk.multiply(uy).add(rfdotk.multiply(vy)).multiply(cv),
563 rdotk.multiply(uz).add(rfdotk.multiply(vz)).multiply(cv));
564 return new FieldPVCoordinates<>(pos, vel);
565
566 }
567
568
569 @Override
570 public List<ParameterDriver> getParametersDrivers() {
571 return tle.getParametersDrivers();
572 }
573
574
575
576
577 protected abstract void sxpInitialize(T[] parameters);
578
579
580
581
582
583 protected abstract void sxpPropagate(T t, T[] parameters);
584
585
586
587
588
589
590
591
592
593 public void resetInitialState(final FieldSpacecraftState<T> state) {
594 super.resetInitialState(state);
595 resetTle(state);
596 tlesAndMasses = new TimeSpanMap<>(new Pair<>(tle, state.getMass()));
597 }
598
599
600 protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
601 resetTle(state);
602 final Pair<FieldTLE<T>, T> tleAndMass = new Pair<>(tle, state.getMass());
603 if (forward) {
604 tlesAndMasses.addValidAfter(tleAndMass, state.getDate().toAbsoluteDate(), false);
605 } else {
606 tlesAndMasses.addValidBefore(tleAndMass, state.getDate().toAbsoluteDate(), false);
607 }
608 stateChanged(state);
609 }
610
611
612
613
614
615 public void setTleGenerationAlgorithm(final TleGenerationAlgorithm tleGenerationAlgorithm) {
616 this.generationAlgorithm = tleGenerationAlgorithm;
617 }
618
619
620
621
622 private void resetTle(final FieldSpacecraftState<T> state) {
623 final FieldTLE<T> newTle = generationAlgorithm.generate(state, tle);
624 initializeTle(newTle);
625 }
626
627
628
629
630 private void initializeTle(final FieldTLE<T> newTle) {
631 tle = newTle;
632 final T[] parameters = tle.getParameters(tle.getDate().getField());
633 initializeCommons(parameters);
634 sxpInitialize(parameters);
635 }
636
637
638 protected T getMass(final FieldAbsoluteDate<T> date) {
639 return tlesAndMasses.get(date.toAbsoluteDate()).getValue();
640 }
641
642
643 public FieldOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date, final T[] parameters) {
644 final FieldTLE<T> closestTle = tlesAndMasses.get(date.toAbsoluteDate()).getKey();
645 if (!tle.equals(closestTle)) {
646 initializeTle(closestTle);
647 }
648 final T mu = date.getField().getZero().newInstance(TLEConstants.MU);
649 return new FieldCartesianOrbit<>(getPVCoordinates(date, parameters), teme, date, mu);
650 }
651
652
653
654
655
656
657 public FieldTLE<T> getTLE() {
658 return tle;
659 }
660
661
662 public Frame getFrame() {
663 return teme;
664 }
665
666 }