1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.orbits;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
21 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22 import org.hipparchus.geometry.euclidean.threed.Rotation;
23 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
24 import org.hipparchus.geometry.euclidean.threed.Vector3D;
25 import org.hipparchus.util.FastMath;
26 import org.hipparchus.util.FieldSinCos;
27 import org.hipparchus.util.SinCos;
28 import org.orekit.utils.FieldPVCoordinates;
29 import org.orekit.utils.PVCoordinates;
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public class KeplerianMotionCartesianUtility {
44
45 private KeplerianMotionCartesianUtility() {
46
47 }
48
49
50
51
52
53
54
55
56
57
58 public static PVCoordinates predictPositionVelocity(final double dt, final Vector3D position, final Vector3D velocity,
59 final double mu) {
60 final double r = position.getNorm();
61 final double a = r / (2 - r * velocity.getNormSq() / mu);
62 if (a >= 0.) {
63 return predictPVElliptic(dt, position, velocity, mu, a, r);
64 } else {
65 return predictPVHyperbolic(dt, position, velocity, mu, a, r);
66 }
67 }
68
69
70
71
72
73
74
75
76
77
78
79 private static PVCoordinates predictPVElliptic(final double dt, final Vector3D position, final Vector3D velocity,
80 final double mu, final double a, final double r) {
81
82 final Vector3D pvM = position.crossProduct(velocity);
83 final double muA = mu * a;
84
85
86 final double eSE = position.dotProduct(velocity) / FastMath.sqrt(muA);
87 final double eCE = 1. - r / a;
88 final double E0 = FastMath.atan2(eSE, eCE);
89 final double M0 = E0 - eSE;
90
91 final double e = FastMath.sqrt(eCE * eCE + eSE * eSE);
92 final double sqrt = FastMath.sqrt((1 + e) / (1 - e));
93
94
95 final double v0 = 2 * FastMath.atan(sqrt * FastMath.tan(E0 / 2));
96 final Rotation rotation = new Rotation(pvM, v0, RotationConvention.FRAME_TRANSFORM);
97 final Vector3D p = rotation.applyTo(position).normalize();
98 final Vector3D q = pvM.crossProduct(p).normalize();
99
100
101 final double sqrtRatio = FastMath.sqrt(mu / a);
102 final double meanMotion = sqrtRatio / a;
103 final double M1 = M0 + meanMotion * dt;
104 final double E1 = KeplerianAnomalyUtility.ellipticMeanToEccentric(e, M1);
105
106
107 final SinCos scE = FastMath.sinCos(E1);
108 final double cE = scE.cos();
109 final double sE = scE.sin();
110 final double sE2m1 = FastMath.sqrt((1 - e) * (1 + e));
111
112
113 final double x = a * (cE - e);
114 final double y = a * sE2m1 * sE;
115 final double factor = sqrtRatio / (1 - e * cE);
116 final double xDot = -factor * sE;
117 final double yDot = factor * sE2m1 * cE;
118
119 final Vector3D predictedPosition = new Vector3D(x, p, y, q);
120 final Vector3D predictedVelocity = new Vector3D(xDot, p, yDot, q);
121 return new PVCoordinates(predictedPosition, predictedVelocity);
122 }
123
124
125
126
127
128
129
130
131
132
133
134 private static PVCoordinates predictPVHyperbolic(final double dt, final Vector3D position, final Vector3D velocity,
135 final double mu, final double a, final double r) {
136
137 final Vector3D pvM = position.crossProduct(velocity);
138 final double muA = mu * a;
139 final double e = FastMath.sqrt(1 - pvM.getNormSq() / muA);
140 final double sqrt = FastMath.sqrt((e + 1) / (e - 1));
141
142
143 final double eSH = position.dotProduct(velocity) / FastMath.sqrt(-muA);
144 final double eCH = 1. - r / a;
145 final double H0 = FastMath.log((eCH + eSH) / (eCH - eSH)) / 2;
146 final double M0 = e * FastMath.sinh(H0) - H0;
147
148
149 final double v0 = 2 * FastMath.atan(sqrt * FastMath.tanh(H0 / 2));
150 final Rotation rotation = new Rotation(pvM, v0, RotationConvention.FRAME_TRANSFORM);
151 final Vector3D p = rotation.applyTo(position).normalize();
152 final Vector3D q = pvM.crossProduct(p).normalize();
153
154
155 final double absA = FastMath.abs(a);
156 final double sqrtRatio = FastMath.sqrt(mu / absA);
157 final double meanMotion = sqrtRatio / absA;
158 final double M1 = M0 + meanMotion * dt;
159 final double H1 = KeplerianAnomalyUtility.hyperbolicMeanToEccentric(e, M1);
160
161
162 final double cH = FastMath.cosh(H1);
163 final double sH = FastMath.sinh(H1);
164 final double sE2m1 = FastMath.sqrt((e - 1) * (e + 1));
165
166
167 final double x = a * (cH - e);
168 final double y = -a * sE2m1 * sH;
169 final double factor = sqrtRatio / (e * cH - 1);
170 final double xDot = -factor * sH;
171 final double yDot = factor * sE2m1 * cH;
172
173 final Vector3D predictedPosition = new Vector3D(x, p, y, q);
174 final Vector3D predictedVelocity = new Vector3D(xDot, p, yDot, q);
175 return new PVCoordinates(predictedPosition, predictedVelocity);
176 }
177
178
179
180
181
182
183
184
185
186
187
188 public static <T extends CalculusFieldElement<T>> FieldPVCoordinates<T> predictPositionVelocity(final T dt,
189 final FieldVector3D<T> position,
190 final FieldVector3D<T> velocity,
191 final T mu) {
192 final T r = position.getNorm();
193 final T a = r.divide(r.multiply(velocity.getNormSq()).divide(mu).negate().add(2));
194 if (a.getReal() >= 0.) {
195 return predictPVElliptic(dt, position, velocity, mu, a, r);
196 } else {
197 return predictPVHyperbolic(dt, position, velocity, mu, a, r);
198 }
199 }
200
201
202
203
204
205
206
207
208
209
210
211
212 private static <T extends CalculusFieldElement<T>> FieldPVCoordinates<T> predictPVElliptic(final T dt,
213 final FieldVector3D<T> position,
214 final FieldVector3D<T> velocity,
215 final T mu, final T a,
216 final T r) {
217
218 final FieldVector3D<T> pvM = position.crossProduct(velocity);
219 final T muA = mu.multiply(a);
220
221
222 final T eSE = position.dotProduct(velocity).divide(muA.sqrt());
223 final T eCE = r.divide(a).negate().add(1);
224 final T e = eCE.square().add(eSE.square()).sqrt();
225 if (e.getReal() < 1e-8) {
226
227 final T meanMotion = mu.divide(a.square().multiply(a)).sqrt();
228 final T deltaM = meanMotion.multiply(dt);
229 final T sqrtA = a.sqrt();
230 final T sigma = eSE.multiply(sqrtA);
231 final FieldSinCos<T> sinCosDeltaM = FastMath.sinCos(deltaM);
232 final T deltaE = deltaM.add((r.divide(a).negate().add(1)).multiply(sinCosDeltaM.sin())).add(sigma.divide(sqrtA).multiply(sinCosDeltaM.cos().subtract(1)));
233
234 final FieldSinCos<T> sinCosDeltaE = FastMath.sinCos(deltaE);
235 final T sqrtMu = mu.sqrt();
236 final T f = (a.divide(r)).multiply(sinCosDeltaE.cos().subtract(1)).add(1);
237 final T g = a.multiply(sigma).divide(sqrtMu).multiply(sinCosDeltaE.cos().negate().add(1)).add(r.multiply(sqrtA.divide(sqrtMu)).multiply(sinCosDeltaE.sin()));
238 final T shiftedR = a.add(r.subtract(a).multiply(sinCosDeltaE.cos())).add(sigma.multiply(sqrtA).multiply(sinCosDeltaE.sin()));
239 final T fDot = sqrtMu.multiply(sqrtA).divide(r.multiply(shiftedR)).multiply(sinCosDeltaE.sin()).negate();
240 final T gDot = (a.divide(shiftedR)).multiply(sinCosDeltaE.cos().subtract(1)).add(1);
241
242 final FieldVector3D<T> shiftedPosition = new FieldVector3D<>(f, position, g, velocity);
243 final FieldVector3D<T> shiftedVelocity = new FieldVector3D<>(fDot, position, gDot, velocity);
244 return new FieldPVCoordinates<>(shiftedPosition, shiftedVelocity);
245 }
246
247 final T E0 = FastMath.atan2(eSE, eCE);
248 final T M0 = E0.subtract(eSE);
249 final T ePlusOne = e.add(1);
250 final T oneMinusE = e.negate().add(1);
251 final T sqrt = ePlusOne.divide(oneMinusE).sqrt();
252
253
254 final T v0 = sqrt.multiply((E0.divide(2)).tan()).atan().multiply(2);
255 final FieldRotation<T> rotation = new FieldRotation<>(pvM, v0, RotationConvention.FRAME_TRANSFORM);
256 final FieldVector3D<T> p = rotation.applyTo(position).normalize();
257 final FieldVector3D<T> q = pvM.crossProduct(p).normalize();
258
259
260 final T sqrtRatio = (a.reciprocal().multiply(mu)).sqrt();
261 final T meanMotion = sqrtRatio.divide(a);
262 final T M1 = M0.add(meanMotion.multiply(dt));
263 final T E1 = FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(e, M1);
264
265
266 final FieldSinCos<T> scE = FastMath.sinCos(E1);
267 final T cE = scE.cos();
268 final T sE = scE.sin();
269 final T sE2m1 = oneMinusE.multiply(ePlusOne).sqrt();
270
271
272 final T x = a.multiply(cE.subtract(e));
273 final T y = a.multiply(sE2m1).multiply(sE);
274 final T factor = sqrtRatio.divide(e.multiply(cE).negate().add(1));
275 final T xDot = factor.multiply(sE).negate();
276 final T yDot = factor.multiply(sE2m1).multiply(cE);
277
278 final FieldVector3D<T> predictedPosition = new FieldVector3D<>(x, p, y, q);
279 final FieldVector3D<T> predictedVelocity = new FieldVector3D<>(xDot, p, yDot, q);
280 return new FieldPVCoordinates<>(predictedPosition, predictedVelocity);
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294 private static <T extends CalculusFieldElement<T>> FieldPVCoordinates<T> predictPVHyperbolic(final T dt,
295 final FieldVector3D<T> position,
296 final FieldVector3D<T> velocity,
297 final T mu, final T a,
298 final T r) {
299
300 final FieldVector3D<T> pvM = position.crossProduct(velocity);
301 final T muA = a.multiply(mu);
302 final T e = a.newInstance(1.).subtract(pvM.getNormSq().divide(muA)).sqrt();
303 final T ePlusOne = e.add(1);
304 final T eMinusOne = e.subtract(1);
305 final T sqrt = ePlusOne.divide(eMinusOne).sqrt();
306
307
308 final T eSH = position.dotProduct(velocity).divide(muA.negate().sqrt());
309 final T eCH = r.divide(a).negate().add(1);
310 final T H0 = eCH.add(eSH).divide(eCH.subtract(eSH)).log().divide(2);
311 final T M0 = e.multiply(H0.sinh()).subtract(H0);
312
313
314 final T v0 = sqrt.multiply(H0.divide(2).tanh()).atan().multiply(2);
315 final FieldRotation<T> rotation = new FieldRotation<>(pvM, v0, RotationConvention.FRAME_TRANSFORM);
316 final FieldVector3D<T> p = rotation.applyTo(position).normalize();
317 final FieldVector3D<T> q = pvM.crossProduct(p).normalize();
318
319
320 final T sqrtRatio = (a.reciprocal().negate().multiply(mu)).sqrt();
321 final T meanMotion = sqrtRatio.divide(a).negate();
322 final T M1 = M0.add(meanMotion.multiply(dt));
323 final T H1 = FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(e, M1);
324
325
326 final T cH = H1.cosh();
327 final T sH = H1.sinh();
328 final T sE2m1 = eMinusOne.multiply(ePlusOne).sqrt();
329
330
331 final T x = a.multiply(cH.subtract(e));
332 final T y = a.negate().multiply(sE2m1).multiply(sH);
333 final T factor = sqrtRatio.divide(e.multiply(cH).subtract(1));
334 final T xDot = factor.negate().multiply(sH);
335 final T yDot = factor.multiply(sE2m1).multiply(cH);
336
337 final FieldVector3D<T> predictedPosition = new FieldVector3D<>(x, p, y, q);
338 final FieldVector3D<T> predictedVelocity = new FieldVector3D<>(xDot, p, yDot, q);
339 return new FieldPVCoordinates<>(predictedPosition, predictedVelocity);
340 }
341 }