1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.control.heuristics.lambert;
18
19 import org.hipparchus.analysis.differentiation.Gradient;
20 import org.hipparchus.exception.MathIllegalStateException;
21 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22 import org.hipparchus.geometry.euclidean.threed.Vector3D;
23 import org.hipparchus.geometry.euclidean.twod.Vector2D;
24 import org.hipparchus.linear.DecompositionSolver;
25 import org.hipparchus.linear.LUDecomposition;
26 import org.hipparchus.linear.MatrixUtils;
27 import org.hipparchus.linear.RealMatrix;
28 import org.hipparchus.util.FastMath;
29 import org.orekit.orbits.KeplerianMotionCartesianUtility;
30 import org.orekit.utils.FieldPVCoordinates;
31 import org.orekit.utils.PVCoordinates;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class LambertSolver {
50
51
52 private final double mu;
53
54
55
56
57
58 public LambertSolver(final double mu) {
59 this.mu = mu;
60 }
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 public LambertBoundaryVelocities solve(final boolean posigrade, final int nRev,
95 final LambertBoundaryConditions boundaryConditions) {
96 final Vector3D p1 = boundaryConditions.getInitialPosition();
97 final Vector3D p2 = boundaryConditions.getTerminalPosition();
98 final double r1 = p1.getNorm();
99 final double r2 = p2.getNorm();
100 final double tau = boundaryConditions.getTerminalDate().durationFrom(boundaryConditions.getInitialDate());
101
102
103 if (tau < 0.0) {
104 final LambertBoundaryConditions backwardConditions = new LambertBoundaryConditions(boundaryConditions.getTerminalDate(),
105 boundaryConditions.getTerminalPosition(), boundaryConditions.getInitialDate(), boundaryConditions.getInitialPosition(),
106 boundaryConditions.getReferenceFrame());
107 final LambertBoundaryVelocities solutionForward = solve(posigrade, nRev, backwardConditions);
108 if (solutionForward != null) {
109 return new LambertBoundaryVelocities(solutionForward.getTerminalVelocity(),
110 solutionForward.getInitialVelocity());
111 } else {
112 return null;
113 }
114 }
115
116
117 final double R = FastMath.max(r1, r2);
118 final double V = FastMath.sqrt(mu / R);
119 final double T = R / V;
120
121
122 double dth = Vector3D.angle(p1, p2);
123
124 if (!posigrade) {
125 dth = 2 * FastMath.PI - dth;
126 }
127
128
129 final Vector2D vDep = solveNormalized2D(r1 / R, r2 / R, dth, tau / T, nRev);
130
131 if (vDep != Vector2D.NaN) {
132 final double[] Vdep = vDep.toArray();
133
134
135 final Vector3D Pn = p1.crossProduct(p2);
136
137 final Vector3D Pt = Pn.crossProduct(p1);
138
139
140 double RT = Pt.getNorm();
141 if (!posigrade) {
142 RT = -RT;
143 }
144
145
146 final Vector3D Vel1 = new Vector3D(V * Vdep[0] / r1, p1, V * Vdep[1] / RT, Pt);
147
148
149 Vector3D terminalVelocity;
150 try {
151 final PVCoordinates pv2 = KeplerianMotionCartesianUtility.predictPositionVelocity(tau, p1, Vel1, mu);
152 terminalVelocity = pv2.getVelocity();
153 } catch (final MathIllegalStateException exception) {
154 terminalVelocity = Vector3D.NaN;
155 }
156
157
158 return new LambertBoundaryVelocities(Vel1, terminalVelocity);
159 }
160
161 return null;
162 }
163
164
165
166
167
168
169
170
171
172
173
174 public static Vector2D solveNormalized2D(final double r1, final double r2, final double dth, final double tau,
175 final int mRev) {
176
177
178 final boolean leftbranch = dth < FastMath.PI;
179 int longway = 1;
180 if (dth > FastMath.PI) {
181 longway = -1;
182 }
183
184 final int m = FastMath.abs(mRev);
185 final double rtof = FastMath.abs(tau);
186
187
188 final double chord = FastMath.sqrt(r1 * r1 + r2 * r2 - 2 * r1 * r2 * FastMath.cos(dth));
189
190
191 final double speri = 0.5 * (r1 + r2 + chord);
192
193
194 final double minSma = speri / 2.;
195
196
197 final double lambda = longway * FastMath.sqrt(1 - chord / speri);
198
199
200 final double logt = FastMath.log(rtof);
201
202
203
204
205
206
207 final double in1;
208 final double in2;
209 double x1;
210 double x2;
211 if (m == 0) {
212
213 in1 = -0.6523333;
214 in2 = 0.6523333;
215 x1 = FastMath.log(1 + in1);
216 x2 = FastMath.log(1 + in2);
217 } else {
218
219 if (!leftbranch) {
220 in1 = -0.523334;
221 in2 = -0.223334;
222 } else {
223 in1 = 0.723334;
224 in2 = 0.523334;
225 }
226 x1 = FastMath.tan(in1 * 0.5 * FastMath.PI);
227 x2 = FastMath.tan(in2 * 0.5 * FastMath.PI);
228 }
229
230
231 final double tof1 = timeOfFlight(in1, longway, m, minSma, speri, chord);
232 final double tof2 = timeOfFlight(in2, longway, m, minSma, speri, chord);
233
234
235 double y1;
236 double y2;
237 if (m == 0) {
238 y1 = FastMath.log(tof1) - logt;
239 y2 = FastMath.log(tof2) - logt;
240 } else {
241 y1 = tof1 - rtof;
242 y2 = tof2 - rtof;
243 }
244
245
246 double err = 1e20;
247 int iterations = 0;
248 final double tol = 1e-13;
249 final int maxiter = 50;
250 double xnew = 0;
251 while (err > tol && iterations < maxiter) {
252
253 xnew = (x1 * y2 - y1 * x2) / (y2 - y1);
254
255
256 final double x;
257 if (m == 0) {
258 x = FastMath.exp(xnew) - 1;
259 } else {
260 x = FastMath.atan(xnew) * 2 / FastMath.PI;
261 }
262
263 final double tof = timeOfFlight(x, longway, m, minSma, speri, chord);
264
265
266 final double ynew;
267 if (m == 0) {
268 ynew = FastMath.log(tof) - logt;
269 } else {
270 ynew = tof - rtof;
271 }
272
273
274 x1 = x2;
275 x2 = xnew;
276 y1 = y2;
277 y2 = ynew;
278
279
280 err = FastMath.abs(x1 - xnew);
281
282
283 ++iterations;
284 }
285
286
287 if (err > tol) {
288 return Vector2D.NaN;
289 }
290
291
292 final double x;
293 if (m == 0) {
294 x = FastMath.exp(xnew) - 1;
295 } else {
296 x = FastMath.atan(xnew) * 2 / FastMath.PI;
297 }
298
299
300 final double sma = minSma / (1 - x * x);
301
302
303 final double eta;
304 if (x < 1) {
305
306 final double alfa = 2 * FastMath.acos(x);
307 final double beta = longway * 2 * FastMath.asin(FastMath.sqrt((speri - chord) / (2. * sma)));
308 final double psi = (alfa - beta) / 2;
309
310 final double sinPsi = FastMath.sin(psi);
311 final double etaSq = 2 * sma * sinPsi * sinPsi / speri;
312 eta = FastMath.sqrt(etaSq);
313 } else {
314
315 final double gamma = 2 * FastMath.acosh(x);
316 final double delta = longway * 2 * FastMath.asinh(FastMath.sqrt((chord - speri) / (2 * sma)));
317
318 final double psi = (gamma - delta) / 2.;
319 final double sinhPsi = FastMath.sinh(psi);
320 final double etaSq = -2 * sma * sinhPsi * sinhPsi / speri;
321 eta = FastMath.sqrt(etaSq);
322 }
323
324
325 final double VR1 = (1. / eta) * FastMath.sqrt(1. / minSma) * (2 * lambda * minSma / r1 - (lambda + x * eta));
326 final double VT1 = (1. / eta) * FastMath.sqrt(1. / minSma) * FastMath.sqrt(r2 / r1) * FastMath.sin(dth / 2);
327 return new Vector2D(VR1, VT1);
328 }
329
330
331
332
333
334
335
336
337
338
339
340
341 private static double timeOfFlight(final double x, final int longway, final int mrev, final double minSma,
342 final double speri, final double chord) {
343
344 final double a = minSma / (1 - x * x);
345
346 final double tof;
347 if (FastMath.abs(x) < 1) {
348
349
350 final double beta = longway * 2 * FastMath.asin(FastMath.sqrt((speri - chord) / (2. * a)));
351 final double alfa = 2 * FastMath.acos(x);
352 tof = a * FastMath.sqrt(a) * ((alfa - FastMath.sin(alfa)) - (beta - FastMath.sin(beta)) + 2 * FastMath.PI * mrev);
353 } else {
354
355 final double alfa = 2 * FastMath.acosh(x);
356 final double beta = longway * 2 * FastMath.asinh(FastMath.sqrt((speri - chord) / (-2. * a)));
357 tof = -a * FastMath.sqrt(-a) * ((FastMath.sinh(alfa) - alfa) - (FastMath.sinh(beta) - beta));
358 }
359
360 return tof;
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 public RealMatrix computeJacobian(final boolean posigrade, final int nRev,
379 final LambertBoundaryConditions boundaryConditions) {
380 final LambertBoundaryVelocities velocities = solve(posigrade, nRev, boundaryConditions);
381 if (velocities != null) {
382 return computeNonTrivialCase(boundaryConditions, velocities);
383 } else {
384 final RealMatrix nanMatrix = MatrixUtils.createRealMatrix(8, 8);
385 for (int i = 0; i < nanMatrix.getRowDimension(); i++) {
386 for (int j = 0; j < nanMatrix.getColumnDimension(); j++) {
387 nanMatrix.setEntry(i, j, Double.NaN);
388 }
389 }
390 return nanMatrix;
391 }
392 }
393
394
395
396
397
398
399
400 private RealMatrix computeNonTrivialCase(final LambertBoundaryConditions boundaryConditions,
401 final LambertBoundaryVelocities velocities) {
402
403 final int freeParameters = 8;
404 final Vector3D nominalInitialPosition = boundaryConditions.getInitialPosition();
405 final FieldVector3D<Gradient> initialPosition = new FieldVector3D<>(Gradient.variable(freeParameters, 5, nominalInitialPosition.getX()),
406 Gradient.variable(freeParameters, 6, nominalInitialPosition.getY()),
407 Gradient.variable(freeParameters, 7, nominalInitialPosition.getZ()));
408 final Vector3D nominalInitialVelocity = velocities.getInitialVelocity();
409 final FieldVector3D<Gradient> initialVelocity = new FieldVector3D<>(Gradient.variable(freeParameters, 1, nominalInitialVelocity.getX()),
410 Gradient.variable(freeParameters, 2, nominalInitialVelocity.getY()),
411 Gradient.variable(freeParameters, 3, nominalInitialVelocity.getZ()));
412 final double dt = boundaryConditions.getTerminalDate().durationFrom(boundaryConditions.getInitialDate());
413 final Gradient fieldDt = Gradient.variable(freeParameters, 4, dt).subtract(Gradient.variable(freeParameters, 0, 0));
414 final FieldPVCoordinates<Gradient> terminalPV = KeplerianMotionCartesianUtility.predictPositionVelocity(fieldDt,
415 initialPosition, initialVelocity, fieldDt.newInstance(mu));
416
417 final RealMatrix intermediate = MatrixUtils.createRealMatrix(6, freeParameters);
418 final FieldVector3D<Gradient> terminalVelocity = terminalPV.getVelocity();
419 intermediate.setRow(0, initialVelocity.getX().getGradient());
420 intermediate.setRow(1, initialVelocity.getY().getGradient());
421 intermediate.setRow(2, initialVelocity.getZ().getGradient());
422 intermediate.setRow(3, terminalVelocity.getX().getGradient());
423 intermediate.setRow(4, terminalVelocity.getY().getGradient());
424 intermediate.setRow(5, terminalVelocity.getZ().getGradient());
425
426 final RealMatrix matrixToInvert = MatrixUtils.createRealIdentityMatrix(freeParameters);
427 matrixToInvert.setRow(1, initialPosition.getX().getGradient());
428 matrixToInvert.setRow(2, initialPosition.getY().getGradient());
429 matrixToInvert.setRow(3, initialPosition.getZ().getGradient());
430 final FieldVector3D<Gradient> terminalPosition = terminalPV.getPosition();
431 matrixToInvert.setRow(5, terminalPosition.getX().getGradient());
432 matrixToInvert.setRow(6, terminalPosition.getY().getGradient());
433 matrixToInvert.setRow(7, terminalPosition.getZ().getGradient());
434 final DecompositionSolver solver = new LUDecomposition(matrixToInvert).getSolver();
435 final RealMatrix inverse = solver.getInverse();
436 return intermediate.multiply(inverse);
437 }
438 }