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