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