1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.numerical;
18
19 import java.util.Arrays;
20
21 import org.hipparchus.geometry.euclidean.threed.Vector3D;
22 import org.hipparchus.ode.ODEIntegrator;
23 import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaIntegrator;
24 import org.hipparchus.util.FastMath;
25 import org.hipparchus.util.MathUtils;
26 import org.hipparchus.util.SinCos;
27 import org.orekit.attitudes.Attitude;
28 import org.orekit.attitudes.AttitudeProvider;
29 import org.orekit.data.DataContext;
30 import org.orekit.errors.OrekitException;
31 import org.orekit.errors.OrekitMessages;
32 import org.orekit.frames.Frame;
33 import org.orekit.orbits.CartesianOrbit;
34 import org.orekit.orbits.Orbit;
35 import org.orekit.orbits.OrbitType;
36 import org.orekit.orbits.PositionAngle;
37 import org.orekit.propagation.PropagationType;
38 import org.orekit.propagation.SpacecraftState;
39 import org.orekit.propagation.analytical.gnss.data.GLONASSOrbitalElements;
40 import org.orekit.propagation.analytical.gnss.data.GNSSConstants;
41 import org.orekit.propagation.integration.AbstractIntegratedPropagator;
42 import org.orekit.propagation.integration.StateMapper;
43 import org.orekit.time.AbsoluteDate;
44 import org.orekit.time.GLONASSDate;
45 import org.orekit.utils.AbsolutePVCoordinates;
46 import org.orekit.utils.Constants;
47 import org.orekit.utils.IERSConventions;
48 import org.orekit.utils.PVCoordinates;
49 import org.orekit.utils.TimeStampedPVCoordinates;
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 class GLONASSNumericalPropagator extends AbstractIntegratedPropagator {
78
79
80 private static final double GLONASS_J20 = 1.08262575e-3;
81
82
83 private static final double GLONASS_EARTH_EQUATORIAL_RADIUS = 6378136;
84
85
86 private static final double GLONASS_AV = 7.2921151467e-5;
87
88
89
90 private static final double A;
91
92
93 private static final double B;
94
95 static {
96 final double k1 = 3 * FastMath.PI + 2;
97 final double k2 = FastMath.PI - 1;
98 final double k3 = 6 * FastMath.PI - 1;
99 A = 3 * k2 * k2 / k1;
100 B = k3 * k3 / (6 * k1);
101 }
102
103
104 private final GLONASSOrbitalElements glonassOrbit;
105
106
107 private final GLONASSDate initDate;
108
109
110 private final double mass;
111
112
113 private final Frame eci;
114
115
116
117
118
119
120
121
122
123
124
125 private double[] moonElements;
126
127
128
129
130
131
132
133
134
135
136
137 private double[] sunElements;
138
139
140 private final boolean isAccAvailable;
141
142
143 private final DataContext dataContext;
144
145
146
147
148
149
150
151
152
153
154
155 public GLONASSNumericalPropagator(final ClassicalRungeKuttaIntegrator integrator,
156 final GLONASSOrbitalElements glonassOrbit,
157 final Frame eci, final AttitudeProvider provider,
158 final double mass, final DataContext context,
159 final boolean isAccAvailable) {
160 super(integrator, PropagationType.MEAN);
161 this.dataContext = context;
162 this.isAccAvailable = isAccAvailable;
163
164 this.glonassOrbit = glonassOrbit;
165
166 this.eci = eci;
167
168 this.mass = mass;
169 this.initDate = new GLONASSDate(
170 glonassOrbit.getDate(),
171 dataContext.getTimeScales().getGLONASS());
172
173
174 initMapper();
175 setInitialState();
176 setAttitudeProvider(provider);
177 setOrbitType(OrbitType.CARTESIAN);
178
179 setPositionAngleType(PositionAngle.TRUE);
180 setMu(GNSSConstants.GLONASS_MU);
181
182
183
184 if (!isAccAvailable) {
185 computeMoonElements(initDate);
186 computeSunElements(initDate);
187 }
188 }
189
190
191
192
193
194
195 public GLONASSOrbitalElements getGLONASSOrbitalElements() {
196 return glonassOrbit;
197 }
198
199
200 @Override
201 public SpacecraftState propagate(final AbsoluteDate date) {
202
203 final SpacecraftState stateInInertial = super.propagate(date);
204
205
206 final PVCoordinates pvInPZ90 = getPVInPZ90(stateInInertial);
207 final AbsolutePVCoordinates absPV = new AbsolutePVCoordinates(
208 dataContext.getFrames().getPZ9011(IERSConventions.IERS_2010, true),
209 stateInInertial.getDate(), pvInPZ90);
210 final TimeStampedPVCoordinates pvInInertial = absPV.getPVCoordinates(eci);
211 final SpacecraftState transformedState = new SpacecraftState(new CartesianOrbit(pvInInertial, eci, pvInInertial.getDate(), GNSSConstants.GLONASS_MU),
212 stateInInertial.getAttitude(),
213 stateInInertial.getMass(), stateInInertial.getAdditionalStates());
214
215 return transformedState;
216 }
217
218
219
220
221
222
223
224
225 private void setInitialState() {
226
227
228 final PVCoordinates pvInInertial = getPVInInertial(initDate);
229
230
231 final Orbit orbit = new CartesianOrbit(pvInInertial,
232 eci, initDate.getDate(),
233 GNSSConstants.GLONASS_MU);
234
235
236 resetInitialState(new SpacecraftState(orbit, mass));
237 }
238
239
240
241
242
243
244
245 private void computeMoonElements(final GLONASSDate date) {
246
247 moonElements = new double[4];
248
249
250
251 final double am = 3.84385243e8;
252
253 final double em = 0.054900489;
254
255 final double im = 0.0898041080;
256
257
258
259 final double dtoJD = (glonassOrbit.getTime() - 10800.) / Constants.JULIAN_DAY;
260 final double t = (date.getJD0() + dtoJD - 2451545.0) / 36525;
261 final double t2 = t * t;
262
263 final double eps = 0.4090926006 - 0.0002270711 * t;
264
265 final double gammaM = 1.4547885346 + 71.0176852437 * t - 0.0001801481 * t2;
266
267 final double omegaM = 2.1824391966 - 33.7570459536 * t + 0.0000362262 * t2;
268
269 final double qm = 2.3555557435 + 8328.6914257190 * t + 0.0001545547 * t2;
270
271
272 final SinCos scOm = FastMath.sinCos(omegaM);
273 final SinCos scIm = FastMath.sinCos(im);
274 final SinCos scEs = FastMath.sinCos(eps);
275 final SinCos scGm = FastMath.sinCos(gammaM);
276 final double cosOm = scOm.cos();
277 final double sinOm = scOm.sin();
278 final double cosIm = scIm.cos();
279 final double sinIm = scIm.sin();
280 final double cosEs = scEs.cos();
281 final double sinEs = scEs.sin();
282 final double cosGm = scGm.cos();
283 final double sinGm = scGm.sin();
284
285
286 final double psiStar = cosOm * sinIm;
287 final double etaStar = sinOm * sinIm;
288 final double epsStar = 1. - cosOm * cosOm * (1. - cosIm);
289 final double eps11 = sinOm * cosOm * (1. - cosIm);
290 final double eps12 = 1. - sinOm * sinOm * (1. - cosIm);
291 final double eta11 = epsStar * cosEs - psiStar * sinEs;
292 final double eta12 = eps11 * cosEs + etaStar * sinEs;
293 final double psi11 = epsStar * sinEs + psiStar * cosEs;
294 final double psi12 = eps11 * sinEs - etaStar * cosEs;
295
296
297 final double ek = getEccentricAnomaly(qm, em);
298
299
300 final double vk = getTrueAnomaly(ek, em);
301 final SinCos scVk = FastMath.sinCos(vk);
302 final double sinVk = scVk.sin();
303 final double cosVk = scVk.cos();
304
305
306 final double epsM = eps11 * (sinVk * cosGm + cosVk * sinGm) + eps12 * (cosVk * cosGm - sinVk * sinGm);
307 final double etaM = eta11 * (sinVk * cosGm + cosVk * sinGm) + eta12 * (cosVk * cosGm - sinVk * sinGm);
308 final double psiM = psi11 * (sinVk * cosGm + cosVk * sinGm) + psi12 * (cosVk * cosGm - sinVk * sinGm);
309
310
311 final double rm = am * (1. - em * FastMath.cos(ek));
312
313 moonElements[0] = epsM;
314 moonElements[1] = etaM;
315 moonElements[2] = psiM;
316 moonElements[3] = rm;
317
318 }
319
320
321
322
323
324
325
326 private void computeSunElements(final GLONASSDate date) {
327
328 sunElements = new double[4];
329
330
331
332 final double as = 1.49598e11;
333
334 final double es = 0.016719;
335
336
337
338 final double dtoJD = (glonassOrbit.getTime() - 10800.) / Constants.JULIAN_DAY;
339 final double t = (date.getJD0() + dtoJD - 2451545.0) / 36525;
340 final double t2 = t * t;
341
342 final double eps = 0.4090926006 - 0.0002270711 * t;
343
344 final double ws = -7.6281824375 + 0.0300101976 * t + 0.0000079741 * t2;
345
346 final double qs = 6.2400601269 + 628.3019551714 * t - 0.0000026820 * t2;
347
348
349 final double ek = getEccentricAnomaly(qs, es);
350
351
352 final double vk = getTrueAnomaly(ek, es);
353 final SinCos scVk = FastMath.sinCos(vk);
354 final double sinVk = scVk.sin();
355 final double cosVk = scVk.cos();
356
357
358 final SinCos scWs = FastMath.sinCos(ws);
359 final SinCos scEs = FastMath.sinCos(eps);
360 final double cosWs = scWs.cos();
361 final double sinWs = scWs.sin();
362 final double cosEs = scEs.cos();
363 final double sinEs = scEs.sin();
364
365
366 final double epsS = cosVk * cosWs - sinVk * sinWs;
367 final double etaS = cosEs * (sinVk * cosWs + cosVk * sinWs);
368 final double psiS = sinEs * (sinVk * cosWs + cosVk * sinWs);
369
370
371 final double rs = as * (1. - es * FastMath.cos(ek));
372
373 sunElements[0] = epsS;
374 sunElements[1] = etaS;
375 sunElements[2] = psiS;
376 sunElements[3] = rs;
377
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393 private double getEccentricAnomaly(final double M, final double e) {
394
395
396 final double reducedM = MathUtils.normalizeAngle(M, 0.0);
397
398
399 double E;
400 if (FastMath.abs(reducedM) < 1.0 / 6.0) {
401 E = reducedM + e * (FastMath.cbrt(6 * reducedM) - reducedM);
402 } else {
403 if (reducedM < 0) {
404 final double w = FastMath.PI + reducedM;
405 E = reducedM + e * (A * w / (B - w) - FastMath.PI - reducedM);
406 } else {
407 final double w = FastMath.PI - reducedM;
408 E = reducedM + e * (FastMath.PI - A * w / (B - w) - reducedM);
409 }
410 }
411
412 final double e1 = 1 - e;
413 final boolean noCancellationRisk = (e1 + E * E / 6) >= 0.1;
414
415
416 for (int j = 0; j < 2; ++j) {
417 final double f;
418 double fd;
419 final SinCos scE = FastMath.sinCos(E);
420 final double fdd = e * scE.sin();
421 final double fddd = e * scE.cos();
422 if (noCancellationRisk) {
423 f = (E - fdd) - reducedM;
424 fd = 1 - fddd;
425 } else {
426 f = eMeSinE(E, e) - reducedM;
427 final double s = FastMath.sin(0.5 * E);
428 fd = e1 + 2 * e * s * s;
429 }
430 final double dee = f * fd / (0.5 * f * fdd - fd * fd);
431
432
433 final double w = fd + 0.5 * dee * (fdd + dee * fddd / 3);
434 fd += dee * (fdd + 0.5 * dee * fddd);
435 E -= (f - dee * (fd - w)) / fd;
436
437 }
438
439
440 E += M - reducedM;
441
442 return E;
443
444 }
445
446
447
448
449
450
451
452
453 private static double eMeSinE(final double E, final double e) {
454 double x = (1 - e) * FastMath.sin(E);
455 final double mE2 = -E * E;
456 double term = E;
457 double d = 0;
458
459 for (double x0 = Double.NaN; !Double.valueOf(x).equals(Double.valueOf(x0));) {
460 d += 2;
461 term *= mE2 / (d * (d + 1));
462 x0 = x;
463 x = x - term;
464 }
465 return x;
466 }
467
468
469
470
471
472
473
474
475 private double getTrueAnomaly(final double ek, final double ecc) {
476 final SinCos scek = FastMath.sinCos(ek);
477 final double svk = FastMath.sqrt(1. - ecc * ecc) * scek.sin();
478 final double cvk = scek.cos() - ecc;
479 return FastMath.atan2(svk, cvk);
480 }
481
482
483
484
485
486
487
488
489 private PVCoordinates getPVInPZ90(final SpacecraftState state) {
490
491
492 final double dt = state.getDate().durationFrom(initDate.getDate());
493
494
495 final PVCoordinates pv = state.getPVCoordinates();
496 final Vector3D pos = pv.getPosition();
497 final Vector3D vel = pv.getVelocity();
498
499
500 final double x0 = pos.getX();
501 final double y0 = pos.getY();
502 final double z0 = pos.getZ();
503 final double vx0 = vel.getX();
504 final double vy0 = vel.getY();
505 final double vz0 = vel.getZ();
506
507
508 final GLONASSDate gloDate = new GLONASSDate(
509 state.getDate(),
510 dataContext.getTimeScales().getGLONASS());
511 final double gmst = gloDate.getGMST();
512
513 final double ti = glonassOrbit.getTime() + dt;
514
515 final double s = gmst + GLONASS_AV * (ti - 10800.);
516
517
518 final SinCos scS = FastMath.sinCos(s);
519 final double cosS = scS.cos();
520 final double sinS = scS.sin();
521
522
523 final double x = x0 * cosS + y0 * sinS;
524 final double y = -x0 * sinS + y0 * cosS;
525 final double z = z0;
526 final double vx = vx0 * cosS + vy0 * sinS + GLONASS_AV * y;
527 final double vy = -vx0 * sinS + vy0 * cosS - GLONASS_AV * x;
528 final double vz = vz0;
529
530
531 return new PVCoordinates(new Vector3D(x, y, z),
532 new Vector3D(vx, vy, vz));
533 }
534
535
536
537
538
539
540
541
542 private PVCoordinates getPVInInertial(final GLONASSDate date) {
543
544
545 final double gmst = date.getGMST();
546
547 final double time = glonassOrbit.getTime();
548 final double dt = time - 10800.;
549
550 final double s = gmst + GLONASS_AV * dt;
551
552
553 final SinCos scS = FastMath.sinCos(s);
554 final double cosS = scS.cos();
555 final double sinS = scS.sin();
556
557
558 final double x0 = glonassOrbit.getX() * cosS - glonassOrbit.getY() * sinS;
559 final double y0 = glonassOrbit.getX() * sinS + glonassOrbit.getY() * cosS;
560 final double z0 = glonassOrbit.getZ();
561 final double vx0 = glonassOrbit.getXDot() * cosS - glonassOrbit.getYDot() * sinS - GLONASS_AV * y0;
562 final double vy0 = glonassOrbit.getXDot() * sinS + glonassOrbit.getYDot() * cosS + GLONASS_AV * x0;
563 final double vz0 = glonassOrbit.getZDot();
564 return new PVCoordinates(new Vector3D(x0, y0, z0),
565 new Vector3D(vx0, vy0, vz0));
566 }
567
568 @Override
569 protected StateMapper createMapper(final AbsoluteDate referenceDate, final double mu,
570 final OrbitType orbitType, final PositionAngle positionAngleType,
571 final AttitudeProvider attitudeProvider, final Frame frame) {
572 return new Mapper(referenceDate, mu, orbitType, positionAngleType, attitudeProvider, frame);
573 }
574
575
576 private static class Mapper extends StateMapper {
577
578
579
580
581
582
583
584
585
586
587
588 Mapper(final AbsoluteDate referenceDate, final double mu,
589 final OrbitType orbitType, final PositionAngle positionAngleType,
590 final AttitudeProvider attitudeProvider, final Frame frame) {
591 super(referenceDate, mu, orbitType, positionAngleType, attitudeProvider, frame);
592 }
593
594 @Override
595 public SpacecraftState mapArrayToState(final AbsoluteDate date, final double[] y,
596 final double[] yDot, final PropagationType type) {
597
598 final double mass = y[6];
599 if (mass <= 0.0) {
600 throw new OrekitException(OrekitMessages.SPACECRAFT_MASS_BECOMES_NEGATIVE, mass);
601 }
602
603 final Orbit orbit = getOrbitType().mapArrayToOrbit(y, yDot, getPositionAngleType(), date, getMu(), getFrame());
604 final Attitude attitude = getAttitudeProvider().getAttitude(orbit, date, getFrame());
605
606 return new SpacecraftState(orbit, attitude, mass);
607 }
608
609 @Override
610 public void mapStateToArray(final SpacecraftState state, final double[] y,
611 final double[] yDot) {
612 getOrbitType().mapOrbitToArray(state.getOrbit(), getPositionAngleType(), y, yDot);
613 y[6] = state.getMass();
614 }
615
616 }
617
618 @Override
619 protected MainStateEquations getMainStateEquations(final ODEIntegrator integ) {
620 return new Main();
621 }
622
623
624 private class Main implements MainStateEquations {
625
626
627 private final double[] yDot;
628
629
630
631
632 Main() {
633 yDot = new double[7];
634 }
635
636 @Override
637 public double[] computeDerivatives(final SpacecraftState state) {
638
639
640 final GLONASSDate gloDate = new GLONASSDate(
641 state.getDate(),
642 dataContext.getTimeScales().getGLONASS());
643
644
645 final Vector3D vel = state.getPVCoordinates().getVelocity();
646 final Vector3D pos = state.getPVCoordinates().getPosition();
647
648 Arrays.fill(yDot, 0.0);
649
650
651 yDot[0] += vel.getX();
652 yDot[1] += vel.getY();
653 yDot[2] += vel.getZ();
654
655
656 final double x0 = pos.getX();
657 final double y0 = pos.getY();
658 final double z0 = pos.getZ();
659
660
661 final double r = pos.getNorm();
662 final double r2 = r * r;
663 final double oor = 1. / r;
664 final double oor2 = 1. / r2;
665 final double x = x0 * oor;
666 final double y = y0 * oor;
667 final double z = z0 * oor;
668 final double g = GNSSConstants.GLONASS_MU * oor2;
669 final double ro = GLONASS_EARTH_EQUATORIAL_RADIUS * oor;
670
671 yDot[3] += x * (-g + (-1.5 * GLONASS_J20 * g * ro * ro * (1. - 5. * z * z)));
672 yDot[4] += y * (-g + (-1.5 * GLONASS_J20 * g * ro * ro * (1. - 5. * z * z)));
673 yDot[5] += z * (-g + (-1.5 * GLONASS_J20 * g * ro * ro * (3. - 5. * z * z)));
674
675
676 final Vector3D acc;
677 if (isAccAvailable) {
678 acc = getLuniSolarPerturbations(gloDate);
679 } else {
680 final Vector3D accMoon = computeLuniSolarPerturbations(
681 state, moonElements[0], moonElements[1], moonElements[2],
682 moonElements[3],
683 dataContext.getCelestialBodies().getMoon().getGM());
684 final Vector3D accSun = computeLuniSolarPerturbations(
685 state,
686 sunElements[0], sunElements[1], sunElements[2],
687 sunElements[3],
688 dataContext.getCelestialBodies().getSun().getGM());
689 acc = accMoon.add(accSun);
690 }
691
692 yDot[3] += acc.getX();
693 yDot[4] += acc.getY();
694 yDot[5] += acc.getZ();
695
696 return yDot.clone();
697 }
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712 private Vector3D computeLuniSolarPerturbations(final SpacecraftState state, final double eps,
713 final double eta, final double psi,
714 final double r, final double g) {
715
716
717 final PVCoordinates pv = state.getPVCoordinates();
718
719 final double oor = 1. / r;
720 final double oor2 = oor * oor;
721
722
723 final double x = pv.getPosition().getX() * oor;
724 final double y = pv.getPosition().getY() * oor;
725 final double z = pv.getPosition().getZ() * oor;
726 final double gm = g * oor2;
727
728 final double epsmX = eps - x;
729 final double etamY = eta - y;
730 final double psimZ = psi - z;
731 final Vector3D vector = new Vector3D(epsmX, etamY, psimZ);
732 final double d2 = vector.getNormSq();
733 final double deltaM = FastMath.sqrt(d2) * d2;
734
735
736 final double accX = gm * ((epsmX / deltaM) - eps);
737 final double accY = gm * ((etamY / deltaM) - eta);
738 final double accZ = gm * ((psimZ / deltaM) - psi);
739
740 return new Vector3D(accX, accY, accZ);
741 }
742
743
744
745
746
747
748
749
750
751
752
753
754
755 private Vector3D getLuniSolarPerturbations(final GLONASSDate date) {
756
757
758 final double gmst = date.getGMST();
759
760 final double time = glonassOrbit.getTime();
761 final double dt = time - 10800.;
762
763 final double s = gmst + GLONASS_AV * dt;
764
765
766 final SinCos scS = FastMath.sinCos(s);
767 final double cosS = scS.cos();
768 final double sinS = scS.sin();
769
770
771 final double accX = glonassOrbit.getXDotDot() * cosS - glonassOrbit.getYDotDot() * sinS;
772 final double accY = glonassOrbit.getXDotDot() * sinS + glonassOrbit.getYDotDot() * cosS;
773 final double accZ = glonassOrbit.getZDotDot();
774
775 return new Vector3D(accX, accY, accZ);
776 }
777
778 }
779
780 }