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 E0 = FastMath.atan2(eSE, eCE);
225 final T M0 = E0.subtract(eSE);
226
227 final T e = eCE.square().add(eSE.square()).sqrt();
228 final T ePlusOne = e.add(1);
229 final T oneMinusE = e.negate().add(1);
230 final T sqrt = ePlusOne.divide(oneMinusE).sqrt();
231
232
233 final T v0 = sqrt.multiply((E0.divide(2)).tan()).atan().multiply(2);
234 final FieldRotation<T> rotation = new FieldRotation<>(pvM, v0, RotationConvention.FRAME_TRANSFORM);
235 final FieldVector3D<T> p = rotation.applyTo(position).normalize();
236 final FieldVector3D<T> q = pvM.crossProduct(p).normalize();
237
238
239 final T sqrtRatio = (a.reciprocal().multiply(mu)).sqrt();
240 final T meanMotion = sqrtRatio.divide(a);
241 final T M1 = M0.add(meanMotion.multiply(dt));
242 final T E1 = FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(e, M1);
243
244
245 final FieldSinCos<T> scE = FastMath.sinCos(E1);
246 final T cE = scE.cos();
247 final T sE = scE.sin();
248 final T sE2m1 = oneMinusE.multiply(ePlusOne).sqrt();
249
250
251 final T x = a.multiply(cE.subtract(e));
252 final T y = a.multiply(sE2m1).multiply(sE);
253 final T factor = sqrtRatio.divide(e.multiply(cE).negate().add(1));
254 final T xDot = factor.multiply(sE).negate();
255 final T yDot = factor.multiply(sE2m1).multiply(cE);
256
257 final FieldVector3D<T> predictedPosition = new FieldVector3D<>(x, p, y, q);
258 final FieldVector3D<T> predictedVelocity = new FieldVector3D<>(xDot, p, yDot, q);
259 return new FieldPVCoordinates<>(predictedPosition, predictedVelocity);
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273 private static <T extends CalculusFieldElement<T>> FieldPVCoordinates<T> predictPVHyperbolic(final T dt,
274 final FieldVector3D<T> position,
275 final FieldVector3D<T> velocity,
276 final T mu, final T a,
277 final T r) {
278
279 final FieldVector3D<T> pvM = position.crossProduct(velocity);
280 final T muA = a.multiply(mu);
281 final T e = a.newInstance(1.).subtract(pvM.getNormSq().divide(muA)).sqrt();
282 final T ePlusOne = e.add(1);
283 final T eMinusOne = e.subtract(1);
284 final T sqrt = ePlusOne.divide(eMinusOne).sqrt();
285
286
287 final T eSH = position.dotProduct(velocity).divide(muA.negate().sqrt());
288 final T eCH = r.divide(a).negate().add(1);
289 final T H0 = eCH.add(eSH).divide(eCH.subtract(eSH)).log().divide(2);
290 final T M0 = e.multiply(H0.sinh()).subtract(H0);
291
292
293 final T v0 = sqrt.multiply(H0.divide(2).tanh()).atan().multiply(2);
294 final FieldRotation<T> rotation = new FieldRotation<>(pvM, v0, RotationConvention.FRAME_TRANSFORM);
295 final FieldVector3D<T> p = rotation.applyTo(position).normalize();
296 final FieldVector3D<T> q = pvM.crossProduct(p).normalize();
297
298
299 final T sqrtRatio = (a.reciprocal().negate().multiply(mu)).sqrt();
300 final T meanMotion = sqrtRatio.divide(a).negate();
301 final T M1 = M0.add(meanMotion.multiply(dt));
302 final T H1 = FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(e, M1);
303
304
305 final T cH = H1.cosh();
306 final T sH = H1.sinh();
307 final T sE2m1 = eMinusOne.multiply(ePlusOne).sqrt();
308
309
310 final T x = a.multiply(cH.subtract(e));
311 final T y = a.negate().multiply(sE2m1).multiply(sH);
312 final T factor = sqrtRatio.divide(e.multiply(cH).subtract(1));
313 final T xDot = factor.negate().multiply(sH);
314 final T yDot = factor.multiply(sE2m1).multiply(cH);
315
316 final FieldVector3D<T> predictedPosition = new FieldVector3D<>(x, p, y, q);
317 final FieldVector3D<T> predictedVelocity = new FieldVector3D<>(xDot, p, yDot, q);
318 return new FieldPVCoordinates<>(predictedPosition, predictedVelocity);
319 }
320 }