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