1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.analytical.gnss;
18
19 import java.util.List;
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.hipparchus.Field;
23 import org.hipparchus.analysis.differentiation.FieldGradient;
24 import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2;
25 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26 import org.hipparchus.geometry.euclidean.threed.Vector3D;
27 import org.hipparchus.linear.FieldMatrix;
28 import org.hipparchus.linear.FieldQRDecomposition;
29 import org.hipparchus.linear.FieldVector;
30 import org.hipparchus.linear.MatrixUtils;
31 import org.hipparchus.util.FastMath;
32 import org.hipparchus.util.FieldSinCos;
33 import org.orekit.attitudes.AttitudeProvider;
34 import org.orekit.attitudes.FieldAttitude;
35 import org.orekit.attitudes.FrameAlignedProvider;
36 import org.orekit.frames.Frame;
37 import org.orekit.orbits.FieldKeplerianAnomalyUtility;
38 import org.orekit.orbits.FieldKeplerianOrbit;
39 import org.orekit.orbits.FieldKeplerianParameters;
40 import org.orekit.orbits.FieldOrbit;
41 import org.orekit.orbits.PositionAngleType;
42 import org.orekit.propagation.FieldSpacecraftState;
43 import org.orekit.propagation.Propagator;
44 import org.orekit.propagation.analytical.FieldAbstractAnalyticalPropagator;
45 import org.orekit.propagation.analytical.gnss.data.FieldGnssOrbitalElements;
46 import org.orekit.propagation.analytical.gnss.data.GNSSOrbitalElements;
47 import org.orekit.propagation.analytical.gnss.data.GNSSOrbitalElementsFactory;
48 import org.orekit.propagation.analytical.gnss.data.NonKeplerianDriversFactory;
49 import org.orekit.time.FieldAbsoluteDate;
50 import org.orekit.utils.FieldPVCoordinates;
51 import org.orekit.utils.ParameterDriver;
52
53
54
55
56
57
58
59
60
61
62
63
64 public class FieldGnssPropagator<T extends CalculusFieldElement<T>, O extends GNSSOrbitalElements<O>>
65 extends FieldAbstractAnalyticalPropagator<T> {
66
67
68 private static final int MAX_ITER = 100;
69
70
71 private static final double TOL_P = 1.0e-6;
72
73
74 private static final double TOL_V = 1.0e-9;
75
76
77 private static final int FREE_PARAMETERS = 6;
78
79
80 private static final double EPS = 1.0e-12;
81
82
83 private FieldGnssOrbitalElements<T, O> orbitalElements;
84
85
86
87
88 private final NonKeplerianDriversFactory driversFactory;
89
90
91 private final Frame eci;
92
93
94 private final Frame ecef;
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 public FieldGnssPropagator(final Field<T> field, final GNSSOrbitalElementsFactory<O> factory) {
111 this(factory.createFromDrivers().toField(field),
112 factory.getInertial(), factory.getBodyFixed(),
113 FrameAlignedProvider.of(factory.getInertial()),
114 field.getZero().newInstance(Propagator.DEFAULT_MASS));
115 }
116
117
118
119
120
121
122
123
124
125 public FieldGnssPropagator(final FieldGnssOrbitalElements<T, O> orbitalElements,
126 final Frame eci, final Frame ecef,
127 final AttitudeProvider provider, final T mass) {
128 super(orbitalElements.getDate().getField(), provider);
129
130 this.orbitalElements = orbitalElements;
131 this.driversFactory = new NonKeplerianDriversFactory();
132 driversFactory.reset(orbitalElements);
133
134 this.eci = eci;
135
136 this.ecef = ecef;
137
138 final FieldOrbit<T> orbit = propagateOrbit(orbitalElements.getDate(),
139 getParameters(orbitalElements.getDate().getField()));
140 final FieldAttitude<T> attitude = provider.getAttitude(orbit, orbit.getDate(), orbit.getFrame());
141
142
143 super.resetInitialState(new FieldSpacecraftState<>(orbit, attitude).withMass(mass));
144
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160 public FieldGnssPropagator(final FieldSpacecraftState<T> initialState,
161 final FieldGnssOrbitalElements<T, O> nonKeplerianElements,
162 final Frame ecef, final AttitudeProvider provider, final T mass) {
163 this(buildOrbitalElements(initialState, nonKeplerianElements, new NonKeplerianDriversFactory(),
164 ecef, provider, mass),
165 initialState.getFrame(), ecef, provider, initialState.getMass());
166 }
167
168
169 @Override
170 public List<ParameterDriver> getParametersDrivers() {
171 return driversFactory.getParametersDrivers();
172 }
173
174
175
176
177
178
179 public Frame getECI() {
180 return eci;
181 }
182
183
184
185
186
187
188
189 public Frame getECEF() {
190 return ecef;
191 }
192
193
194
195
196
197
198 public T getMU() {
199 return orbitalElements.getOrbit().getMu();
200 }
201
202
203
204
205
206 public FieldGnssOrbitalElements<T, O> getOrbitalElements() {
207 return orbitalElements;
208 }
209
210
211 @Override
212 public FieldOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date, final T[] parameters) {
213
214 final FieldPVCoordinates<T> pvaInECEF = propagateInEcef(date, parameters);
215
216 final FieldPVCoordinates<T> pvaInECI = ecef.getTransformTo(eci, date).transformPVCoordinates(pvaInECEF);
217
218 return new FieldKeplerianOrbit<>(pvaInECI, eci, date, getMU());
219 }
220
221
222
223
224
225
226
227
228
229
230
231 public FieldPVCoordinates<T> propagateInEcef(final FieldAbsoluteDate<T> date, final T[] parameters) {
232
233 final FieldKeplerianOrbit<T> orbit = orbitalElements.getOrbit();
234
235
236 final FieldUnivariateDerivative2<T> tk = new FieldUnivariateDerivative2<>(getTk(date),
237 date.getField().getOne(),
238 date.getField().getZero());
239
240
241 final FieldUnivariateDerivative2<T> ak = tk.multiply(parameters[NonKeplerianDriversFactory.A_DOT_INDEX]).
242 add(orbit.getA());
243
244 final FieldUnivariateDerivative2<T> nA = tk.multiply(parameters[NonKeplerianDriversFactory.DELTA_N0_DOT_INDEX].multiply(0.5)).
245 add(parameters[NonKeplerianDriversFactory.DELTA_N0_INDEX]).
246 add(orbit.getKeplerianMeanMotion());
247
248 final FieldUnivariateDerivative2<T> mk = tk.multiply(nA).add(orbit.getMeanAnomaly());
249
250 final FieldUnivariateDerivative2<T> e = tk.newInstance(orbit.getE());
251 final FieldUnivariateDerivative2<T> ek = FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(e, mk);
252
253 final FieldUnivariateDerivative2<T> vk = FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(e, ek);
254
255 final FieldUnivariateDerivative2<T> phik = vk.add(orbit.getPeriapsisArgument());
256 final FieldSinCos<FieldUnivariateDerivative2<T>> cs2phi = FastMath.sinCos(phik.multiply(2));
257
258 final FieldUnivariateDerivative2<T> dphik = cs2phi.cos().multiply(parameters[NonKeplerianDriversFactory.CUC_INDEX]).
259 add(cs2phi.sin().multiply(parameters[NonKeplerianDriversFactory.CUS_INDEX]));
260
261 final FieldUnivariateDerivative2<T> drk = cs2phi.cos().multiply(parameters[NonKeplerianDriversFactory.CRC_INDEX]).
262 add(cs2phi.sin().multiply(parameters[NonKeplerianDriversFactory.CRS_INDEX]));
263
264 final FieldUnivariateDerivative2<T> dik = cs2phi.cos().multiply(parameters[NonKeplerianDriversFactory.CIC_INDEX]).
265 add(cs2phi.sin().multiply(parameters[NonKeplerianDriversFactory.CIS_INDEX]));
266
267 final FieldSinCos<FieldUnivariateDerivative2<T>> csuk = FastMath.sinCos(phik.add(dphik));
268
269 final FieldUnivariateDerivative2<T> rk = ek.cos().multiply(e.negate()).add(1).multiply(ak).add(drk);
270
271 final FieldUnivariateDerivative2<T> ik = tk.multiply(parameters[NonKeplerianDriversFactory.I_DOT_INDEX]).
272 add(orbit.getI()).add(dik);
273 final FieldSinCos<FieldUnivariateDerivative2<T>> csik = FastMath.sinCos(ik);
274
275 final FieldUnivariateDerivative2<T> xk = csuk.cos().multiply(rk);
276 final FieldUnivariateDerivative2<T> yk = csuk.sin().multiply(rk);
277
278 final FieldSinCos<FieldUnivariateDerivative2<T>> csomk =
279 FastMath.sinCos(tk.multiply(parameters[NonKeplerianDriversFactory.OMEGA_DOT_INDEX].
280 subtract(orbitalElements.getAngularVelocity())).
281 add(orbit.getRightAscensionOfAscendingNode().
282 subtract(parameters[NonKeplerianDriversFactory.TIME_INDEX].multiply(orbitalElements.getAngularVelocity()))));
283
284 final FieldVector3D<FieldUnivariateDerivative2<T>> positionWithDerivatives =
285 new FieldVector3D<>(xk.multiply(csomk.cos()).subtract(yk.multiply(csomk.sin()).multiply(csik.cos())),
286 xk.multiply(csomk.sin()).add(yk.multiply(csomk.cos()).multiply(csik.cos())),
287 yk.multiply(csik.sin()));
288 return new FieldPVCoordinates<>(positionWithDerivatives);
289
290 }
291
292
293
294
295
296
297
298 private T getTk(final FieldAbsoluteDate<T> date) {
299
300 T tk = date.durationFrom(orbitalElements.getTimeOfEphemeris());
301
302 while (tk.getReal() > 0.5 * orbitalElements.getCycleDuration()) {
303 tk = tk.subtract(orbitalElements.getCycleDuration());
304 }
305 while (tk.getReal() < -0.5 * orbitalElements.getCycleDuration()) {
306 tk = tk.add(orbitalElements.getCycleDuration());
307 }
308
309 return tk;
310 }
311
312
313 @Override
314 public Frame getFrame() {
315 return eci;
316 }
317
318
319 @Override
320 protected T getMass(final FieldAbsoluteDate<T> date) {
321 return getInitialState().getMass();
322 }
323
324
325 @Override
326 public void resetInitialState(final FieldSpacecraftState<T> state) {
327 orbitalElements = buildOrbitalElements(state, orbitalElements, driversFactory,
328 ecef, getAttitudeProvider(), state.getMass());
329 final FieldOrbit<T> orbit = propagateOrbit(orbitalElements.getDate(),
330 getParameters(orbitalElements.getDate().getField()));
331 final FieldAttitude<T> attitude = getAttitudeProvider().getAttitude(orbit, orbit.getDate(), orbit.getFrame());
332 super.resetInitialState(new FieldSpacecraftState<>(orbit, attitude).withMass(state.getMass()));
333 }
334
335
336 @Override
337 protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
338 resetInitialState(state);
339 }
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358 public static <T extends CalculusFieldElement<T>,
359 O extends GNSSOrbitalElements<O>>
360 FieldGnssOrbitalElements<T, O> buildOrbitalElements(final FieldSpacecraftState<T> initialState,
361 final FieldGnssOrbitalElements<T, O> nonKeplerianElements,
362 final NonKeplerianDriversFactory driversFactory,
363 final Frame ecef, final AttitudeProvider provider,
364 final T mass) {
365
366 final Field<T> field = initialState.getDate().getField();
367
368
369 final Frame frozenEcef = ecef.getFrozenFrame(initialState.getFrame(),
370 initialState.getDate().toAbsoluteDate(),
371 GNSSOrbitalElementsFactory.FROZEN + ecef.getName());
372 final FieldKeplerianOrbit<T> orbit = approximateInitialOrbit(initialState, nonKeplerianElements, frozenEcef);
373 driversFactory.reset(nonKeplerianElements);
374
375
376 final FieldPVCoordinates<T> targetPV = initialState.getPVCoordinates(frozenEcef);
377 FieldGnssOrbitalElements<FieldGradient<T>, O> gElements = toGradient(nonKeplerianElements, orbit, driversFactory);
378 for (int i = 0; i < MAX_ITER; ++i) {
379
380
381 final FieldGnssPropagator<FieldGradient<T>, O> gPropagator =
382 new FieldGnssPropagator<>(gElements, frozenEcef, ecef, provider,
383 gElements.getOrbit().getMu().newInstance(mass));
384 final FieldPVCoordinates<FieldGradient<T>> gPV = gPropagator.getInitialState().getPVCoordinates();
385
386
387 final FieldMatrix<T> jacobian = MatrixUtils.createFieldMatrix(field, FREE_PARAMETERS, FREE_PARAMETERS);
388 jacobian.setRow(0, gPV.getPosition().getX().getGradient());
389 jacobian.setRow(1, gPV.getPosition().getY().getGradient());
390 jacobian.setRow(2, gPV.getPosition().getZ().getGradient());
391 jacobian.setRow(3, gPV.getVelocity().getX().getGradient());
392 jacobian.setRow(4, gPV.getVelocity().getY().getGradient());
393 jacobian.setRow(5, gPV.getVelocity().getZ().getGradient());
394
395
396 final FieldVector<T> residuals = MatrixUtils.createFieldVector(field, FREE_PARAMETERS);
397 residuals.setEntry(0, targetPV.getPosition().getX().subtract(gPV.getPosition().getX().getValue()));
398 residuals.setEntry(1, targetPV.getPosition().getY().subtract(gPV.getPosition().getY().getValue()));
399 residuals.setEntry(2, targetPV.getPosition().getZ().subtract(gPV.getPosition().getZ().getValue()));
400 residuals.setEntry(3, targetPV.getVelocity().getX().subtract(gPV.getVelocity().getX().getValue()));
401 residuals.setEntry(4, targetPV.getVelocity().getY().subtract(gPV.getVelocity().getY().getValue()));
402 residuals.setEntry(5, targetPV.getVelocity().getZ().subtract(gPV.getVelocity().getZ().getValue()));
403 final FieldVector<T> correction = new FieldQRDecomposition<>(jacobian, field.getZero().newInstance(EPS)).
404 getSolver().
405 solve(residuals);
406
407
408 final FieldKeplerianOrbit<FieldGradient<T>> previous = gElements.getOrbit();
409 T updatedA;
410 T updatedE;
411 double factor = 2;
412 do {
413
414 factor *= 0.5;
415 updatedA = previous.getA().getValue().add(correction.getEntry(0).multiply(factor));
416 updatedE = previous.getE().getValue().add(correction.getEntry(1).multiply(factor));
417 } while (updatedA.getReal() < 0 || updatedE.getReal() < 0 || updatedE.getReal() >= 1);
418
419
420 final FieldKeplerianOrbit<T> updated =
421 new FieldKeplerianOrbit<>(new FieldKeplerianParameters<>(updatedA,
422 updatedE,
423 previous.getI().getValue().add(correction.getEntry(2).multiply(factor)),
424 previous.getPeriapsisArgument().getValue().add(correction.getEntry(3).multiply(factor)),
425 previous.getRightAscensionOfAscendingNode().getValue().add(correction.getEntry(4).multiply(factor)),
426 previous.getMeanAnomaly().getValue().add(correction.getEntry(5).multiply(factor)),
427 PositionAngleType.MEAN),
428 previous.getFrame(),
429 new FieldAbsoluteDate<>(previous.getMu().getValue().getField(),
430 previous.getDate().toAbsoluteDate()),
431 previous.getMu().getValue());
432 gElements = toGradient(nonKeplerianElements, updated, driversFactory);
433
434 final double deltaP = FastMath.sqrt(residuals.getEntry(0).getReal() * residuals.getEntry(0).getReal() +
435 residuals.getEntry(1).getReal() * residuals.getEntry(1).getReal() +
436 residuals.getEntry(2).getReal() * residuals.getEntry(2).getReal());
437 final double deltaV = FastMath.sqrt(residuals.getEntry(3).getReal() * residuals.getEntry(3).getReal() +
438 residuals.getEntry(4).getReal() * residuals.getEntry(4).getReal() +
439 residuals.getEntry(5).getReal() * residuals.getEntry(5).getReal());
440
441 if (deltaP < TOL_P && deltaV < TOL_V) {
442 break;
443 }
444
445 }
446
447 final FieldKeplerianOrbit<FieldGradient<T>> initialOrbit = gElements.getOrbit();
448 return gElements.toField(new FieldKeplerianOrbit<>(new FieldKeplerianParameters<>(initialOrbit.getA().getValue(),
449 initialOrbit.getE().getValue(),
450 initialOrbit.getI().getValue(),
451 initialOrbit.getPeriapsisArgument().getValue(),
452 initialOrbit.getRightAscensionOfAscendingNode().getValue(),
453 initialOrbit.getMeanAnomaly().getValue(),
454 PositionAngleType.MEAN),
455 initialOrbit.getFrame(),
456 new FieldAbsoluteDate<>(initialOrbit.getMu().getValue().getField(),
457 initialOrbit.getDate().toAbsoluteDate()),
458 initialOrbit.getMu().getValue()),
459 nonKeplerianElements.toArray(),
460 FieldGradient::getValue);
461
462 }
463
464
465
466
467
468
469
470
471 private static <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T>
472 approximateInitialOrbit(final FieldSpacecraftState<T> initialState,
473 final FieldGnssOrbitalElements<T, ?> nonKeplerianElements,
474 final Frame frozenEcef) {
475
476
477
478 final FieldPVCoordinates<T> pv = initialState.getPVCoordinates(frozenEcef);
479 final FieldVector3D<T> p = pv.getPosition();
480 final FieldVector3D<T> v = pv.getVelocity();
481
482
483 final T rk = p.getNorm();
484
485
486 final FieldVector3D<T> normal = pv.getMomentum().normalize();
487 final T cosIk = normal.getZ();
488 final T ik = FieldVector3D.angle(normal, Vector3D.PLUS_K);
489
490
491 final T q = FastMath.hypot(normal.getX(), normal.getY());
492 final T cos = normal.getY().negate().divide(q);
493 final T sin = normal.getX().divide(q);
494 final T xk = p.getX().multiply(cos).add(p.getY().multiply(sin));
495 final T yk = p.getY().multiply(cos).subtract(p.getX().multiply(sin)).divide(cosIk);
496
497
498 final T uk = FastMath.atan2(yk, xk);
499
500
501 T phi = uk;
502 for (int i = 0; i < MAX_ITER; ++i) {
503 final T previous = phi;
504 final FieldSinCos<T> cs2Phi = FastMath.sinCos(phi.multiply(2));
505 phi = uk.subtract(cs2Phi.cos().multiply(nonKeplerianElements.getCuc()).add(cs2Phi.sin().multiply(nonKeplerianElements.getCus())));
506 if (FastMath.abs(phi.subtract(previous).getReal()) <= EPS) {
507 break;
508 }
509 }
510 final FieldSinCos<T> cs2phi = FastMath.sinCos(phi.multiply(2));
511
512
513
514 final T i0 = ik.subtract(cs2phi.cos().multiply(nonKeplerianElements.getCic()).add(cs2phi.sin().multiply(nonKeplerianElements.getCis())));
515 final double toe = nonKeplerianElements.getTimeOfEphemeris().getGnssDate().getSecondsInWeek();
516 final T om0 = FastMath.atan2(sin, cos).
517 add(nonKeplerianElements.getAngularVelocity() * toe);
518
519
520 final T mu = initialState.getOrbit().getMu();
521 final T rV2OMu = rk.multiply(v.getNorm2Sq()).divide(mu);
522 final T sma = rk.divide(rV2OMu.negate().add(2));
523 final T eCosE = rV2OMu.subtract(1);
524 final T eSinE = FieldVector3D.dotProduct(p, v).divide(FastMath.sqrt(mu.multiply(sma)));
525 final T e = FastMath.hypot(eCosE, eSinE);
526 final T eccentricAnomaly = FastMath.atan2(eSinE, eCosE);
527 final T aop = phi.subtract(eccentricAnomaly);
528 final T meanAnomaly = FieldKeplerianAnomalyUtility.ellipticEccentricToMean(e, eccentricAnomaly);
529
530 return new FieldKeplerianOrbit<>(sma, e, i0, aop, om0, meanAnomaly, PositionAngleType.MEAN,
531 frozenEcef, initialState.getDate(), mu);
532
533 }
534
535
536
537
538
539
540
541
542
543 private static <T extends CalculusFieldElement<T>, O extends GNSSOrbitalElements<O>>
544 FieldGnssOrbitalElements<FieldGradient<T>, O> toGradient(final FieldGnssOrbitalElements<T, O> elements,
545 final FieldKeplerianOrbit<T> orbit,
546 final NonKeplerianDriversFactory driversFactory) {
547
548 final FieldGradient<T> aG = FieldGradient.variable(FREE_PARAMETERS, 0, orbit.getA());
549 final FieldGradient<T> eG = FieldGradient.variable(FREE_PARAMETERS, 1, orbit.getE());
550 final FieldGradient<T> iG = FieldGradient.variable(FREE_PARAMETERS, 2, orbit.getI());
551 final FieldGradient<T> paG = FieldGradient.variable(FREE_PARAMETERS, 3, orbit.getPeriapsisArgument());
552 final FieldGradient<T> raanG = FieldGradient.variable(FREE_PARAMETERS, 4, orbit.getRightAscensionOfAscendingNode());
553 final FieldGradient<T> mG = FieldGradient.variable(FREE_PARAMETERS, 5, orbit.getMeanAnomaly());
554 final FieldKeplerianOrbit<FieldGradient<T>> orbitG =
555 new FieldKeplerianOrbit<>(new FieldKeplerianParameters<>(aG, eG, iG, paG, raanG, mG,
556 PositionAngleType.MEAN),
557 orbit.getFrame(),
558 new FieldAbsoluteDate<>(FieldGradient.constant(FREE_PARAMETERS, orbit.getMu()).
559 getField(),
560 orbit.getDate().toAbsoluteDate()),
561 FieldGradient.constant(FREE_PARAMETERS, orbit.getMu()));
562
563
564 return elements.toField(orbitG,
565 driversFactory.toGradients(orbit.getMu().getField(), FREE_PARAMETERS),
566 d -> FieldGradient.constant(FREE_PARAMETERS, d));
567 }
568
569 }