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