rodyo / fex-lambert Goto Github PK
View Code? Open in Web Editor NEWLicense: Other
License: Other
On line 627 of lambert.m
, should r1vec
be listed as an argument twice? It seems like the third argument to minmax_distances
should instead be r2vec
.
extremal_distances = minmax_distances(r1vec, r1, r1vec, r2, dth, a, V1, V2, m, muC);
extremal_distances = minmax_distances(r1vec, r1, r2vec, r2, dth, a, V1, V2, m, muC);
Also, for your awareness, I've ported these functions to Julia over here. I followed the instructions in the BSD
license listed to properly show credit, etc. Please let me know if you have any questions.
Thanks!
tf > 0
(default): short way
tf < 0
: long way
same for |m| > 0
:
m > 0
(default): right-branch
m < 0
: left-branch
Email exchange:
From: Han Cai [email protected]
Sent: 17 March 2017 00:47
To: Rody Oldenhuis [email protected]
Subject: Re: A bug about the Lambert code
Hi, Rody:
Thanks for you reply. I'm not quite sure that the equations of THR2 and phr are the same. THR2 is definitely between -1 and 1 for any input according to its equation:
THR2 = DATAN2(QSQFMI, 2D0*Q)/PI.
But the equation of phr is different:
phr = mod(2atan2(1 - q^2, 2q), 2*pi);
the value of phr is between 0 to 2*pi which related its input q. I find another code (please see the attached code line 513) that use the equation below to define thr2, which is similar to Gooding's definition:
thr2 = atan2(qsqfm1, 2.0 * q) / pi;
I'm still confused after I compared Gooding's paper with your code again. The variables dth, and phr are both appeared in line 523:
x0 = x*(1 - (1 + m + (dth - 1/2)) / (1 + 0.15m)x(W/2 + 0.03x*sqrt(W))) + xM;
line 535:
W = x00 + 1.7sqrt(2(1 - phr));
and line 542:
lambda = (1 + (1 + m + 0.24*(dth - 1/2)) / (1 + 0.15m)x03(W/2 - 0.03x03*sqrt(W))).
Whereas, a same variable THR2 is used in all these three equations according to Gooding's paper. To be honest, I have no idea about the physical meaning of these three equations, but I'm just wondering if a same variable dth or phr need to be employed here for consistency?
Thanks.
Best wishes
Han Cai
On 17 March 2017 at 01:36, Rody Oldenhuis [email protected] wrote:
Hi Han Cai,
Thanks a lot for your email, know that it is very much appreciated.
I don’t think you are correct though. I’m looking at R.H. Gooding’s paper:
“A procedure for the solution of Lambert's orbital boundary-value problem” from 1990.
On page 162, the routine XLAMB is printed (Appendix B). There, he defines
THR2 = DATAN2(QSQFMI, 2D0*Q)/PI
Which is (eventually) equal to my definition of phr:
phr = mod(2atan2(1 - q^2, 2q), 2*pi);
Several lines below the definition of THR2, he computes:
W = X + C0DSQRT(2D0(ID0 - THR2))
Compare my line 535:
W = x00 + 1.7sqrt(2(1 - phr));
Now, while reading my code again, I kind of lost a few factors of 2 or π here and there, so I’ll be reviewing my code in the nearby future.
However, since his 1990 paper is newer than the one you referenced, I’m inclined to believe that my code is accurate.
…or do you have a test case as counterexample?
Thanks again! Best regards,
Rody Oldenhuis
From: Han Cai [mailto:[email protected]]
Sent: 09 March 2017 09:53
To: Rody Oldenhuis [email protected]
Subject: A bug about the Lambert code
Hi Rody:
I'm a PhD student in RMIT, Australia. I'm very appreciate for your Matlab code of Lambert solver. This code is fantastic, it helps me a lot in my study.
However, there is a small bug sometimes could result in program error. So I go back to check the reference and find that Gooding attached the fortran code in his paper: ON THE SOLUTION OF LAMBERT'S ORBITAL BOUNDARY-VALUE PROBLEM, 1988, page 44. According to his code, I think the bug located in line 535, where the variable 'phr' should be replaced by another variable 'dth' in this equation. When using 'phr', the quantity under the square root sign could be negative. Hope this can be helpful. Thanks.
Best wishes!
Han Cai
Content of attached glambert.m
:
function [vi, vf] = glambert(cbmu, sv1, sv2, tof, nrev)
% Gooding's solution of Lambert's problem
% input
% cbmu = central body gravitational constant
% sv1 = initial 6-element state vector (position + velocity)
% sv2 = final 6-element state vector (position + velocity)
% tof = time of flight (+ posigrade, - retrograde)
% nrev = number of full revolutions
% (positive for long period orbit,
% negative for short period orbit)
% output
% vi = initial velocity vector of the transfer orbit
% vf = final velocity vector of the transfer orbit
% References
% R. H. Gooding, Technical Report 88027
% On the Solution of Lambert's Orbital Boundary-Value Problem,
% Royal Aerospace Establishment, April 1988
% R. H. Gooding, Technical Memo SPACE 378
% A Procedure for the Solution of Lambert's Orbital Boundary-Value Problem
% Royal Aerospace Establishment, March 1991
% Orbital Mechanics with Matlab
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
r1mag = norm(sv1(1:3));
r2mag = norm(sv2(1:3));
ur1xv1 = cross(sv1(1:3), sv1(4:6));
ur1xv1 = ur1xv1 / norm(ur1xv1);
ux1 = sv1(1:3) / r1mag;
ux2 = sv2(1:3) / r2mag;
uz1 = cross(ux1, ux2);
uz1 = uz1 / norm(uz1);
% calculate the minimum transfer angle (radians)
theta = dot(ux1, ux2);
if (theta > 1.0)
theta = 1.0;
end
if (theta < -1.0)
theta = -1.0;
end
theta = acos(theta);
% calculate the angle between the orbit normal of the initial orbit
% and the fundamental reference plane
angle_to_on = dot(ur1xv1, uz1);
if (angle_to_on > 1.0)
angle_to_on = 1.0;
end
if (angle_to_on < -1.0)
angle_to_on = -1.0;
end
angle_to_on = acos(angle_to_on);
% if angle to orbit normal is greater than 90 degrees
% and posigrade orbit, then flip the orbit normal
% and the transfer angle
if ((angle_to_on > 0.5 * pi) && (tof > 0.0))
theta = 2.0 * pi - theta;
uz1 = -uz1;
end
if ((angle_to_on < 0.5 * pi) && (tof < 0.0))
theta = 2.0 * pi - theta;
uz1 = -uz1;
end
uz2 = uz1;
uy1 = cross(uz1, ux1);
uy1 = uy1 / norm(uy1);
uy2 = cross(uz2, ux2);
uy2 = uy2 / norm(uy2);
theta = theta + 2.0 * pi * abs(nrev);
[vr11, vr12, vr21, vr22, vt11, vt12, vt21, vt22, n] = vlamb(cbmu, r1mag, r2mag, theta, tof);
if (nrev > 0)
if (n == -1)
disp ('no tminium')
vi = 0.0;
vf = 0.0;
elseif (n == 0)
disp ('no solution time')
vi = 0.0;
vf = 0.0;
elseif (n == 1)
disp ('one solution')
else
disp ('two solutions')
end
end
% compute transfer orbit initial and final velocity vectors
if ((nrev > 0) && (n > 1))
vi = vr21 * ux1 + vt21 * uy1;
vf = vr22 * ux2 + vt22 * uy2;
else
vi = vr11 * ux1 + vt11 * uy1;
vf = vr12 * ux2 + vt12 * uy2;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [dt, d2t, d3t, t] = tlamb(m, q, qsqfm1, x, n)
% Gooding lambert support function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
lm1 = false;
l1 = false;
l2 = false;
l3 = false;
sw = 0.4;
lm1 = n == -1;
l1 = n >= 1;
l2 = n >= 2;
l3 = n == 3;
qsq = q * q;
xsq = x * x;
u = (1.0 - x) * (1.0 + x);
% needed if series, and otherwise useful when z = 0
if (~lm1)
dt = 0.0;
d2t = 0.0;
d3t = 0.0;
end
if (lm1 || m > 0 || x < 0.0 || abs(u) > sw)
% direct computation, not series
y = sqrt(abs(u));
z = sqrt(qsqfm1 + qsq * xsq);
qx = q * x;
if (qx <= 0.0)
a = z - qx;
b = q * z - x;
end
if ((qx < 0) && lm1)
aa = qsqfm1 / a;
bb = qsqfm1 * (qsq * u - xsq) / b;
end
if (qx == 0.0 && lm1 || qx > 0.0)
aa = z + qx;
bb = q * z + x;
end
if (qx > 0)
a = qsqfm1 / aa;
b = qsqfm1 * (qsq * u - xsq) / bb;
end
if (lm1)
dt = b;
d2t = bb;
d3t = aa;
else
if (qx * u >= 0.0)
g = x * z + q * u;
else
g = (xsq - qsq * u) / (x * z - q * u);
end
f = a * y;
if (x <= 1)
t = m * pi + atan2(f, g);
else
if (f > sw)
t = log(f + g);
else
fg1 = f / (g + 1.0);
term = 2.0 * fg1;
fg1sq = fg1 * fg1;
t = term;
twoi1 = 1.0;
told = 0.0;
while (t ~= told)
twoi1 = twoi1 + 2.0;
term = term * fg1sq;
told = t;
t = t + term / twoi1;
end
end
end
t = 2.0 * (t / y + b) / u;
if (l1 && z ~= 0.0)
qz = q / z;
qz2 = qz * qz;
qz = qz * qz2;
dt = (3.0 * x * t - 4.0 * (a + qx * qsqfm1) / z) / u;
if (l2)
d2t = (3.0 * t + 5.0 * x * dt + 4.0 * qz * qsqfm1) / u;
end
if (l3)
d3t = (8.0 * dt + 7.0 * x * d2t ...
- 12.0 * qz * qz2 * x * qsqfm1) / u;
end
end
end
else
% compute by series
u0i = 1.0;
if (l1)
u1i = 1.0;
end
if (l2)
u2i = 1.0;
end
if (l3)
u3i = 1.0;
end
term = 4.0;
tq = q * qsqfm1;
if (q < 0.5)
tqsum = 1.0 - q * qsq;
end
if (q >= 0.5)
tqsum = (1.0 / (1.0 + q) + q) * qsqfm1;
end
ttmold = term / 3.0;
t = ttmold * tqsum;
% start of loop
icounter = 0;
while (icounter < n || t ~= told)
icounter = icounter + 1;
p = icounter;
u0i = u0i * u;
if (l1 && icounter > 1)
u1i = u1i * u;
end
if (l2 && icounter > 2)
u2i = u2i * u;
end
if (l3 && icounter > 3)
u3i = u3i * u;
end
term = term * (p - 0.5) / p;
tq = tq * qsq;
tqsum = tqsum + tq;
told = t;
tterm = term / (2.0 * p + 3.0);
tqterm = tterm * tqsum;
t = t - u0i * ((1.5 * p + 0.25) * tqterm / (p * p - 0.25) ...
- ttmold * tq);
ttmold = tterm;
tqterm = tqterm * p;
if (l1)
dt = dt + tqterm * u1i;
end
if (l2)
d2t = d2t + tqterm * u2i * (p - 1.0);
end
if (l3)
d3t = d3t + tqterm * u3i * (p - 1.0) * (p - 2.0);
end
end
if (l3)
d3t = 8.0 * x * (1.5 * d2t - xsq * d3t);
end
if(l2)
d2t = 2.0 * (2.0 * xsq * d2t - dt);
end
if (l1)
dt = -2.0 * x * dt;
end
t = t / xsq;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [vr11, vr12, vr21, vr22, vt11, vt12, vt21, vt22, n] = vlamb(cbmu, r1, r2, thr2, tdelt)
% Gooding lambert support function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
vr21 = 0;
vr22 = 0;
vt21 = 0;
vt22 = 0;
m = 0;
while (thr2 > (2.0 * pi))
thr2 = thr2 - 2.0 * pi;
m = m + 1;
end
thr2 = thr2 / 2.0;
dr = r1 - r2;
r1r2 = r1 * r2;
r1r2th = 4.0 * r1r2 * sin(thr2)^2;
csq = dr^2 + r1r2th;
c = sqrt(csq);
s = (r1 + r2 + c) / 2.0;
gms = sqrt(cbmu * s / 2.0);
qsqfm1 = c/s;
q = sqrt(r1 * r2) * cos(thr2) / s;
if (c ~= 0.0)
rho = dr / c;
sig = r1r2th /csq;
else
rho = 0.0;
sig = 1.0;
end
t = 4.0 * gms * tdelt / s^2;
[x1, x2, n] = xlamb(m, q, qsqfm1, t);
% proceed for single solution, or a pair
for i = 1:1:n
if (i == 1)
x = x1;
else
x = x2;
end
[qzminx, qzplx, zplqx] = tlamb(m, q, qsqfm1, x, -1);
vt2 = gms * zplqx * sqrt(sig);
vr1 = gms * (qzminx - qzplx * rho) / r1;
vt1 = vt2 / r1;
vr2 = -gms * (qzminx + qzplx * rho) / r2;
vt2 = vt2 / r2;
if (i == 1)
vr11 = vr1;
vt11 = vt1;
vr12 = vr2;
vt12 = vt2;
else
vr21 = vr1;
vt21 = vt1;
vr22 = vr2;
vt22 = vt2;
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [x, xpl, n] = xlamb(m, q, qsqfm1, tin)
% Gooding lambert support function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
tol = 3.0e-7;
xpl = 0.0;
c0 = 1.7;
c1 = 0.5;
c2 = 0.03;
c3 = 0.15;
c41 = 1.0;
c42 = 0.24;
termflag = false;
thr2 = atan2(qsqfm1, 2.0 * q) / pi;
if (m == 0)
% single rev starter from t (at x = 0) & bilinear (usually)
n = 1;
[dt, d2t, d3t, t0] = tlamb(m, q, qsqfm1, 0.0, 0.0);
tdiff = tin - t0;
if (tdiff <= 0.0)
x = t0 * tdiff / (-4.0 * tin);
else
x = -tdiff / (tdiff + 4.0);
w = x + c0 * sqrt(2.0 * (1.0 - thr2));
if (w < 0.0)
x = x - sqrt(d8rt(-w)) * (x + sqrt(tdiff / (tdiff + 1.5 * t0)));
end
w = 4.0 /(4.0 + tdiff);
x = x * (1.0 + x * (c1 * w - c2 * x * sqrt(w)));
end
else
% with multirevs, first get t(min) as basis for starter
xm = 1.0 / (1.5 * (m + 0.5) * pi);
if (thr2 < 0.5)
xm = d8rt(2.0 * thr2) * xm;
end
if (thr2 > 0.5)
xm = (2.0 - d8rt(2.0 - 2.0 * thr2)) * xm;
end;
% starter for tmin
for i = 1:1:12
[dt, d2t, d3t, tmin] = tlamb(m, q, qsqfm1, xm, 3);
if (d2t == 0.0)
solnflag = true;
break
end
xmold = xm;
xm = xm - dt * d2t / (d2t * d2t - dt * d3t / 2.0);
xtest = abs(xmold / xm - 1.0);
if (xtest <= tol)
solnflag = true;
break
end
end
% break off & exit if tmin not located - should never happen
% now proceed from t(min) to full starter
if (solnflag)
tdiffm = tin - tmin;
if (tdiffm < 0.0)
n = 0;
termflag = true;
% exit if no solution with this m
elseif (tdiffm == 0)
x = xm;
n = 1;
termflag = true;
% exit if unique solution already from x(tmin)
else
n = 3;
if (d2t == 0)
d2t = 6.0 * m * pi;
end
x = sqrt(tdiffm / (d2t / 2.0 + tdiffm / (1.0 - xm)^2));
w = xm + x;
w = w * 4.0 / (4.0 + tdiffm) + (1.0 - w)^2;
x = x * (1.0 - (1.0 + m + c41 * (thr2 - 0.5)) / (1.0 + c3 * m) ...
* x * (c1 * w + c2 * x * sqrt(w))) + xm;
d2t2 = d2t / 2.0;
if (x >= 1.0)
n = 1;
[dt, d2t, d3t, t0] = tlamb(m, q, qsqfm1, 0, 0);
tdiff0 = t0 - tmin;
tdiff = tin - t0;
if (tdiff <= 0.0)
x = xm - sqrt(tdiffm / (d2t2 - tdiffm ...
* (d2t2 / tdiff0 - 1.0 / xm^2)));
else
x = -tdiff / (tdiff + 4.0);
w = x + c0 * sqrt(2.0 * (1.0 - thr2));
if (w < 0.0)
x = x - sqrt(d8rt(-w)) * (x + sqrt(tdiff / (tdiff + 1.5 * t0)));
end
w = 4.0 / (4.0 + tdiff);
x = x * (1.0 + (1.0 + m + c42 * (thr2 - 0.5)) ...
/ (1.0 + c3 * m) * x * (c1 * w - c2 * x * sqrt(w)));
if (x <= -1.0)
n = n - 1;
if (n == 1)
x = xpl;
end
end
end
end
end
else
n = -1;
termflag = true;
end
end
% now have a starter, so proceed by halley
if (termflag ~= true)
for i = 1:1:3
[dt, d2t, d3t, t] = tlamb(m, q, qsqfm1, x, 2);
t = tin - t;
if (dt ~= 0.0)
x = x + t * dt / (dt * dt + t * d2t / 2.0);
end
end
if (n ~= 3)
% exit if only one solution, normally when m = 0
return
end
n = 2;
xpl = x;
% second multi-rev starter
[dt, d2t, d3t, t0] = tlamb(m, q, qsqfm1, 0, 0);
tdiff0 = t0 - tmin;
tdiff = tin - t0;
if (tdiff <= 0.0)
x = xm - sqrt(tdiffm / (d2t2 - tdiffm * (d2t2 / tdiff0 - 1.0 / xm^2)));
else
x = -tdiff / (tdiff + 4.0);
w = x + c0 * sqrt(2.0 * (1.0 - thr2));
if (w < 0.0)
x = x - sqrt(d8rt(-w)) * (x + sqrt(tdiff / (tdiff + 1.5 * t0)));
end
w = 4.0 / (4.0 + tdiff);
x = x * (1.0 + (1.0 + m + c42 * (thr2 - 0.5)) / (1.0 + c3 * m) ...
* x *(c1 * w - c2 * x * sqrt(w)));
if (x <= -1.0)
n = n - 1;
if (n == 1)
% no finite solution for x < xm
x = xpl;
end
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%
function d8rt = d8rt(x)
% Gooding lambert support function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
d8rt = sqrt(sqrt(sqrt(x)));
As noted by Vasco Grilo:
The solver is not blinded against erroneous input. The following situations were detected :
For all these cases, the exit flag is 1
; which is supposed to indicate success, instead of -1
; which indicates that the given problem has no solution. Therefore the outputted results could be interpreted as correct, and undermine the following calculations.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.