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