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(),
214 stateInInertial.getAdditionalStatesValues(),
215 stateInInertial.getAdditionalStatesDerivatives());
216
217 return transformedState;
218 }
219
220
221
222
223
224
225
226
227 private void setInitialState() {
228
229
230 final PVCoordinates pvInInertial = getPVInInertial(initDate);
231
232
233 final Orbit orbit = new CartesianOrbit(pvInInertial,
234 eci, initDate.getDate(),
235 GNSSConstants.GLONASS_MU);
236
237
238 resetInitialState(new SpacecraftState(orbit, mass));
239 }
240
241
242
243
244
245
246
247 private void computeMoonElements(final GLONASSDate date) {
248
249 moonElements = new double[4];
250
251
252
253 final double am = 3.84385243e8;
254
255 final double em = 0.054900489;
256
257 final double im = 0.0898041080;
258
259
260
261 final double dtoJD = (glonassOrbit.getTime() - 10800.) / Constants.JULIAN_DAY;
262 final double t = (date.getJD0() + dtoJD - 2451545.0) / 36525;
263 final double t2 = t * t;
264
265 final double eps = 0.4090926006 - 0.0002270711 * t;
266
267 final double gammaM = 1.4547885346 + 71.0176852437 * t - 0.0001801481 * t2;
268
269 final double omegaM = 2.1824391966 - 33.7570459536 * t + 0.0000362262 * t2;
270
271 final double qm = 2.3555557435 + 8328.6914257190 * t + 0.0001545547 * t2;
272
273
274 final SinCos scOm = FastMath.sinCos(omegaM);
275 final SinCos scIm = FastMath.sinCos(im);
276 final SinCos scEs = FastMath.sinCos(eps);
277 final SinCos scGm = FastMath.sinCos(gammaM);
278 final double cosOm = scOm.cos();
279 final double sinOm = scOm.sin();
280 final double cosIm = scIm.cos();
281 final double sinIm = scIm.sin();
282 final double cosEs = scEs.cos();
283 final double sinEs = scEs.sin();
284 final double cosGm = scGm.cos();
285 final double sinGm = scGm.sin();
286
287
288 final double psiStar = cosOm * sinIm;
289 final double etaStar = sinOm * sinIm;
290 final double epsStar = 1. - cosOm * cosOm * (1. - cosIm);
291 final double eps11 = sinOm * cosOm * (1. - cosIm);
292 final double eps12 = 1. - sinOm * sinOm * (1. - cosIm);
293 final double eta11 = epsStar * cosEs - psiStar * sinEs;
294 final double eta12 = eps11 * cosEs + etaStar * sinEs;
295 final double psi11 = epsStar * sinEs + psiStar * cosEs;
296 final double psi12 = eps11 * sinEs - etaStar * cosEs;
297
298
299 final double ek = getEccentricAnomaly(qm, em);
300
301
302 final double vk = getTrueAnomaly(ek, em);
303 final SinCos scVk = FastMath.sinCos(vk);
304 final double sinVk = scVk.sin();
305 final double cosVk = scVk.cos();
306
307
308 final double epsM = eps11 * (sinVk * cosGm + cosVk * sinGm) + eps12 * (cosVk * cosGm - sinVk * sinGm);
309 final double etaM = eta11 * (sinVk * cosGm + cosVk * sinGm) + eta12 * (cosVk * cosGm - sinVk * sinGm);
310 final double psiM = psi11 * (sinVk * cosGm + cosVk * sinGm) + psi12 * (cosVk * cosGm - sinVk * sinGm);
311
312
313 final double rm = am * (1. - em * FastMath.cos(ek));
314
315 moonElements[0] = epsM;
316 moonElements[1] = etaM;
317 moonElements[2] = psiM;
318 moonElements[3] = rm;
319
320 }
321
322
323
324
325
326
327
328 private void computeSunElements(final GLONASSDate date) {
329
330 sunElements = new double[4];
331
332
333
334 final double as = 1.49598e11;
335
336 final double es = 0.016719;
337
338
339
340 final double dtoJD = (glonassOrbit.getTime() - 10800.) / Constants.JULIAN_DAY;
341 final double t = (date.getJD0() + dtoJD - 2451545.0) / 36525;
342 final double t2 = t * t;
343
344 final double eps = 0.4090926006 - 0.0002270711 * t;
345
346 final double ws = -7.6281824375 + 0.0300101976 * t + 0.0000079741 * t2;
347
348 final double qs = 6.2400601269 + 628.3019551714 * t - 0.0000026820 * t2;
349
350
351 final double ek = getEccentricAnomaly(qs, es);
352
353
354 final double vk = getTrueAnomaly(ek, es);
355 final SinCos scVk = FastMath.sinCos(vk);
356 final double sinVk = scVk.sin();
357 final double cosVk = scVk.cos();
358
359
360 final SinCos scWs = FastMath.sinCos(ws);
361 final SinCos scEs = FastMath.sinCos(eps);
362 final double cosWs = scWs.cos();
363 final double sinWs = scWs.sin();
364 final double cosEs = scEs.cos();
365 final double sinEs = scEs.sin();
366
367
368 final double epsS = cosVk * cosWs - sinVk * sinWs;
369 final double etaS = cosEs * (sinVk * cosWs + cosVk * sinWs);
370 final double psiS = sinEs * (sinVk * cosWs + cosVk * sinWs);
371
372
373 final double rs = as * (1. - es * FastMath.cos(ek));
374
375 sunElements[0] = epsS;
376 sunElements[1] = etaS;
377 sunElements[2] = psiS;
378 sunElements[3] = rs;
379
380 }
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395 private double getEccentricAnomaly(final double M, final double e) {
396
397
398 final double reducedM = MathUtils.normalizeAngle(M, 0.0);
399
400
401 double E;
402 if (FastMath.abs(reducedM) < 1.0 / 6.0) {
403 E = reducedM + e * (FastMath.cbrt(6 * reducedM) - reducedM);
404 } else {
405 if (reducedM < 0) {
406 final double w = FastMath.PI + reducedM;
407 E = reducedM + e * (A * w / (B - w) - FastMath.PI - reducedM);
408 } else {
409 final double w = FastMath.PI - reducedM;
410 E = reducedM + e * (FastMath.PI - A * w / (B - w) - reducedM);
411 }
412 }
413
414 final double e1 = 1 - e;
415 final boolean noCancellationRisk = (e1 + E * E / 6) >= 0.1;
416
417
418 for (int j = 0; j < 2; ++j) {
419 final double f;
420 double fd;
421 final SinCos scE = FastMath.sinCos(E);
422 final double fdd = e * scE.sin();
423 final double fddd = e * scE.cos();
424 if (noCancellationRisk) {
425 f = (E - fdd) - reducedM;
426 fd = 1 - fddd;
427 } else {
428 f = eMeSinE(E, e) - reducedM;
429 final double s = FastMath.sin(0.5 * E);
430 fd = e1 + 2 * e * s * s;
431 }
432 final double dee = f * fd / (0.5 * f * fdd - fd * fd);
433
434
435 final double w = fd + 0.5 * dee * (fdd + dee * fddd / 3);
436 fd += dee * (fdd + 0.5 * dee * fddd);
437 E -= (f - dee * (fd - w)) / fd;
438
439 }
440
441
442 E += M - reducedM;
443
444 return E;
445
446 }
447
448
449
450
451
452
453
454
455 private static double eMeSinE(final double E, final double e) {
456 double x = (1 - e) * FastMath.sin(E);
457 final double mE2 = -E * E;
458 double term = E;
459 double d = 0;
460
461 for (double x0 = Double.NaN; !Double.valueOf(x).equals(Double.valueOf(x0));) {
462 d += 2;
463 term *= mE2 / (d * (d + 1));
464 x0 = x;
465 x = x - term;
466 }
467 return x;
468 }
469
470
471
472
473
474
475
476
477 private double getTrueAnomaly(final double ek, final double ecc) {
478 final SinCos scek = FastMath.sinCos(ek);
479 final double svk = FastMath.sqrt(1. - ecc * ecc) * scek.sin();
480 final double cvk = scek.cos() - ecc;
481 return FastMath.atan2(svk, cvk);
482 }
483
484
485
486
487
488
489
490
491 private PVCoordinates getPVInPZ90(final SpacecraftState state) {
492
493
494 final double dt = state.getDate().durationFrom(initDate.getDate());
495
496
497 final PVCoordinates pv = state.getPVCoordinates();
498 final Vector3D pos = pv.getPosition();
499 final Vector3D vel = pv.getVelocity();
500
501
502 final double x0 = pos.getX();
503 final double y0 = pos.getY();
504 final double z0 = pos.getZ();
505 final double vx0 = vel.getX();
506 final double vy0 = vel.getY();
507 final double vz0 = vel.getZ();
508
509
510 final GLONASSDate gloDate = new GLONASSDate(
511 state.getDate(),
512 dataContext.getTimeScales().getGLONASS());
513 final double gmst = gloDate.getGMST();
514
515 final double ti = glonassOrbit.getTime() + dt;
516
517 final double s = gmst + GLONASS_AV * (ti - 10800.);
518
519
520 final SinCos scS = FastMath.sinCos(s);
521 final double cosS = scS.cos();
522 final double sinS = scS.sin();
523
524
525 final double x = x0 * cosS + y0 * sinS;
526 final double y = -x0 * sinS + y0 * cosS;
527 final double z = z0;
528 final double vx = vx0 * cosS + vy0 * sinS + GLONASS_AV * y;
529 final double vy = -vx0 * sinS + vy0 * cosS - GLONASS_AV * x;
530 final double vz = vz0;
531
532
533 return new PVCoordinates(new Vector3D(x, y, z),
534 new Vector3D(vx, vy, vz));
535 }
536
537
538
539
540
541
542
543
544 private PVCoordinates getPVInInertial(final GLONASSDate date) {
545
546
547 final double gmst = date.getGMST();
548
549 final double time = glonassOrbit.getTime();
550 final double dt = time - 10800.;
551
552 final double s = gmst + GLONASS_AV * dt;
553
554
555 final SinCos scS = FastMath.sinCos(s);
556 final double cosS = scS.cos();
557 final double sinS = scS.sin();
558
559
560 final double x0 = glonassOrbit.getX() * cosS - glonassOrbit.getY() * sinS;
561 final double y0 = glonassOrbit.getX() * sinS + glonassOrbit.getY() * cosS;
562 final double z0 = glonassOrbit.getZ();
563 final double vx0 = glonassOrbit.getXDot() * cosS - glonassOrbit.getYDot() * sinS - GLONASS_AV * y0;
564 final double vy0 = glonassOrbit.getXDot() * sinS + glonassOrbit.getYDot() * cosS + GLONASS_AV * x0;
565 final double vz0 = glonassOrbit.getZDot();
566 return new PVCoordinates(new Vector3D(x0, y0, z0),
567 new Vector3D(vx0, vy0, vz0));
568 }
569
570 @Override
571 protected StateMapper createMapper(final AbsoluteDate referenceDate, final double mu,
572 final OrbitType orbitType, final PositionAngle positionAngleType,
573 final AttitudeProvider attitudeProvider, final Frame frame) {
574 return new Mapper(referenceDate, mu, orbitType, positionAngleType, attitudeProvider, frame);
575 }
576
577
578 private static class Mapper extends StateMapper {
579
580
581
582
583
584
585
586
587
588
589
590 Mapper(final AbsoluteDate referenceDate, final double mu,
591 final OrbitType orbitType, final PositionAngle positionAngleType,
592 final AttitudeProvider attitudeProvider, final Frame frame) {
593 super(referenceDate, mu, orbitType, positionAngleType, attitudeProvider, frame);
594 }
595
596 @Override
597 public SpacecraftState mapArrayToState(final AbsoluteDate date, final double[] y,
598 final double[] yDot, final PropagationType type) {
599
600 final double mass = y[6];
601 if (mass <= 0.0) {
602 throw new OrekitException(OrekitMessages.SPACECRAFT_MASS_BECOMES_NEGATIVE, mass);
603 }
604
605 final Orbit orbit = getOrbitType().mapArrayToOrbit(y, yDot, getPositionAngleType(), date, getMu(), getFrame());
606 final Attitude attitude = getAttitudeProvider().getAttitude(orbit, date, getFrame());
607
608 return new SpacecraftState(orbit, attitude, mass);
609 }
610
611 @Override
612 public void mapStateToArray(final SpacecraftState state, final double[] y,
613 final double[] yDot) {
614 getOrbitType().mapOrbitToArray(state.getOrbit(), getPositionAngleType(), y, yDot);
615 y[6] = state.getMass();
616 }
617
618 }
619
620 @Override
621 protected MainStateEquations getMainStateEquations(final ODEIntegrator integ) {
622 return new Main();
623 }
624
625
626 private class Main implements MainStateEquations {
627
628
629 private final double[] yDot;
630
631
632
633
634 Main() {
635 yDot = new double[7];
636 }
637
638 @Override
639 public double[] computeDerivatives(final SpacecraftState state) {
640
641
642 final GLONASSDate gloDate = new GLONASSDate(
643 state.getDate(),
644 dataContext.getTimeScales().getGLONASS());
645
646
647 final Vector3D vel = state.getPVCoordinates().getVelocity();
648 final Vector3D pos = state.getPVCoordinates().getPosition();
649
650 Arrays.fill(yDot, 0.0);
651
652
653 yDot[0] += vel.getX();
654 yDot[1] += vel.getY();
655 yDot[2] += vel.getZ();
656
657
658 final double x0 = pos.getX();
659 final double y0 = pos.getY();
660 final double z0 = pos.getZ();
661
662
663 final double r = pos.getNorm();
664 final double r2 = r * r;
665 final double oor = 1. / r;
666 final double oor2 = 1. / r2;
667 final double x = x0 * oor;
668 final double y = y0 * oor;
669 final double z = z0 * oor;
670 final double g = GNSSConstants.GLONASS_MU * oor2;
671 final double ro = GLONASS_EARTH_EQUATORIAL_RADIUS * oor;
672
673 yDot[3] += x * (-g + (-1.5 * GLONASS_J20 * g * ro * ro * (1. - 5. * z * z)));
674 yDot[4] += y * (-g + (-1.5 * GLONASS_J20 * g * ro * ro * (1. - 5. * z * z)));
675 yDot[5] += z * (-g + (-1.5 * GLONASS_J20 * g * ro * ro * (3. - 5. * z * z)));
676
677
678 final Vector3D acc;
679 if (isAccAvailable) {
680 acc = getLuniSolarPerturbations(gloDate);
681 } else {
682 final Vector3D accMoon = computeLuniSolarPerturbations(
683 state, moonElements[0], moonElements[1], moonElements[2],
684 moonElements[3],
685 dataContext.getCelestialBodies().getMoon().getGM());
686 final Vector3D accSun = computeLuniSolarPerturbations(
687 state,
688 sunElements[0], sunElements[1], sunElements[2],
689 sunElements[3],
690 dataContext.getCelestialBodies().getSun().getGM());
691 acc = accMoon.add(accSun);
692 }
693
694 yDot[3] += acc.getX();
695 yDot[4] += acc.getY();
696 yDot[5] += acc.getZ();
697
698 return yDot.clone();
699 }
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714 private Vector3D computeLuniSolarPerturbations(final SpacecraftState state, final double eps,
715 final double eta, final double psi,
716 final double r, final double g) {
717
718
719 final PVCoordinates pv = state.getPVCoordinates();
720
721 final double oor = 1. / r;
722 final double oor2 = oor * oor;
723
724
725 final double x = pv.getPosition().getX() * oor;
726 final double y = pv.getPosition().getY() * oor;
727 final double z = pv.getPosition().getZ() * oor;
728 final double gm = g * oor2;
729
730 final double epsmX = eps - x;
731 final double etamY = eta - y;
732 final double psimZ = psi - z;
733 final Vector3D vector = new Vector3D(epsmX, etamY, psimZ);
734 final double d2 = vector.getNormSq();
735 final double deltaM = FastMath.sqrt(d2) * d2;
736
737
738 final double accX = gm * ((epsmX / deltaM) - eps);
739 final double accY = gm * ((etamY / deltaM) - eta);
740 final double accZ = gm * ((psimZ / deltaM) - psi);
741
742 return new Vector3D(accX, accY, accZ);
743 }
744
745
746
747
748
749
750
751
752
753
754
755
756
757 private Vector3D getLuniSolarPerturbations(final GLONASSDate date) {
758
759
760 final double gmst = date.getGMST();
761
762 final double time = glonassOrbit.getTime();
763 final double dt = time - 10800.;
764
765 final double s = gmst + GLONASS_AV * dt;
766
767
768 final SinCos scS = FastMath.sinCos(s);
769 final double cosS = scS.cos();
770 final double sinS = scS.sin();
771
772
773 final double accX = glonassOrbit.getXDotDot() * cosS - glonassOrbit.getYDotDot() * sinS;
774 final double accY = glonassOrbit.getXDotDot() * sinS + glonassOrbit.getYDotDot() * cosS;
775 final double accZ = glonassOrbit.getZDotDot();
776
777 return new Vector3D(accX, accY, accZ);
778 }
779
780 }
781
782 }