本文针对兰伯特方程给出具体的算法,并不打算给出详细的过程。各位读者可参照此算法及相应的代码进行编程计算。
介绍
见下图,仅考虑中心天体C的万有引力,飞行器从P1点飞行到P2点,飞行时间为Δt。起点P1的地心距为r1,终点P2的地心距为r2,飞行路径所对应的地心角为θ。
兰伯特首先发现此两点轨道转移所需要的时间仅与始末的几何构型以及轨道半长径有关,而与其它轨道参数无关,其数学表述为:
μΔt=F(a,r1+r2,c)
拉格朗日和高斯曾经都研究过这个问题,并给出相应的表达式,有兴趣的读者可直接参考相关教科书,此处不再详述。
下面介绍比较高效的求解算法,主要由R.H.Gooding在1990年的数篇文献中给出。想要详细了解,可参考他的两篇文献:
- A procedure for the solution of Lambert’s orbital boundary-value problem
- On the Solution of Lambert’s Orbital Boundary-Value Problem
本文基于上述两篇文献,直接给出算法。
初始化
由上图兰伯特转移轨道的几何构型,初始输入参数如下:
- r1,转移轨道起点P1到引力中心C的距离 (m);
- r2,转移轨道起点P2到引力中心C的距离(m) ;
- θ, 转移轨道的地心夹角,不超过360°;
- Δt,转移轨道的飞行时间(s);
- m,椭圆轨道时,转移轨道的飞行圈数,m=0时,表示转移轨道的地心角 θ不超过360°;m>0时,仅表示椭圆转移轨道,指转移轨道的地心角超过了360°。
-
μ,中心天体的引力常数;
由初始输入参数,可得部分参数: - c=(r1−r2)2+4r1r2sin2(θ/2);
- s=(r1+r2+c)/2 ;
- q=r1r2cos(θ/2)/s;
- 1−q2=c/s,为了避免计算中有效位数的损失,此参数单独计算;
- T=8μ/s3Δt: 无量纲飞行时间;
转移时间T及其导数的求解
输入:
- m
- q
- 1−q2
- n,n=0表示仅计算时间T,n=1表示计算一阶导数,n=2表示计算到二阶导数,n=3表示计算到三阶导数。
输出:T,T′,T′′,T′′′
T的导数(T′,T′′,T′′′)指T对x的1-3阶导数。
无量纲转移时间T可表达成如下形式:
T(m,q,x)(1)
其中,q与转移轨道几何构型相关,自变量x与轨道半长轴a相关,有:x2=1−s/(2a)
根据参数m,q,x的初值,T的计算有两种方式:直接计算与级数计算。下面分别阐述。
直接计算方式
当下式成立时,,采用直接计算方式。
m>0或x<0或∣u∣>0.4(2)
其中
u=1−x2
因此,针对x的具体范围为:x<0.6或x>1.4,即x的范围不在1附近(抛物线轨道)
定义
z=1−q2+q2x2
当qx≤0时,
{α=z−qxβ=qz−x
当qx>0时,
{α=z+qx1−q2β=qz+x(1−q2)(q2u−x2)
令
{y=∣u∣f=αy
且令
g={xz+qu,xz−qux2−q2u,if qxu≥0if qxu<0
则参数d为
d={mπ+arctan2(f,g)tanh−1(f/g)=ln(f+g)if x≤1if x>1
上式中,arctan2(f,g)为反正切函数tan−1(f/g)的扩充,由f,g 的符号决定了返回值的正确象限。
当x>1且f<0.4时,文献中使用级数方式计算ln(f+g),经测试,误差不超过10−15,因此此处仅使用ln(f+g)。
最后,直接给出 T及其导数的计算公式:
⎩⎪⎪⎪⎨⎪⎪⎪⎧T=2(d/y+β)/uT′=(3xT+4q3x/z−4)/uT′′=(3T+5xT′+4(q/z)3(1−q2))/uT′′′=(8T′+7xT′′−12x(q/z)5(1−q2))/u(3)
注意,上式中, 参数u不可能为0;但参数z有可能为0,因此当z=0时,不计算T的导数(T′,T′′,T′′′),直接赋值为0。
级数计算方式
当直接计算方式的条件(式2)不成立时,则采用级数计算方式。此时x在1附近,接近抛物线。
此时无量纲时间 T的级数表达式为:
T=n=0∑∞Anbnun(4)
其中
{An=22n−2(n!)2(2n+3)(2n)!bn=1−q2n+3
在实际求解时,式(4)变为下式:
Tx2=n=0∑∞Cnun(5)
其中
Cn=−4n2−16n+1Anbn+An−1(bn−bn−1)
上式中,An的递推公式为:
An=2n+3anan=2n2n−1an−1
bn的递推公式为:
bn=bn−1+q2n+1(1−q2)
初值为:
C0=A0b0
其中,A0=4/3,b0则由下式给出
b0={1−q3(q+1/(1+q))(1−q2)if q<0.5if q≥0.5
最后,直接给出 T的导数计算公式:
⎩⎪⎨⎪⎧T′=−2xTu′T′′=−2Tu′+4x2Tu′′T′′′=12xTu′′−8x3Tu′′′(6)
也就是说,T对x的导数(T′,T′′,T′′′)依赖T对u的导数(Tu′,Tu′′,Tu′′′)
T对u的导数(Tu′,Tu′′,Tu′′′)可由(4)式推导,得到:
Tu′=n=0∑∞Anbnnun−1Tu′′=n=0∑∞Anbnn(n−1)un−2Tu′′′=n=0∑∞Anbnn(n−1)(n−2)un−3(7)
上式1-3阶导数的求和过程可与式(5)的求和过程同步。
下图给出了转移时间T(无量纲)的图像。横坐标为x,其范围为:x∈(−1,∞),图中只画到1.5。
x∈(−1,1)时,为椭圆轨道;
x=1时,为抛物线轨道;
x∈(1,∞)时,为双曲轨道;
此外,图中仅画出了m=0,1的图像。
源码(C#)
// Lambert 方程的无量纲时间 (R.H.Gooding 方法)
//--------------------------------------------------------------------
// 1 t=sqrt(8u/s^3)*Δt= 2*pi*m/(1-x*x)^1.5+
// 4/3*(F[3,1;2.5;0.5*(1-x)]-q^3*F[3,1;2.5;0.5*(1-y)])
// 其中: y=sqrt(1-q*q+q^2*x^2)=sqrt(qsqfm1+q^2*x^2)
// 2 此算法根据不同情况,用直接计算法和级数法来计算
// *与文献中的算法不同之处:f<0.4时(q接近1,x>1.2),未采用级数循环计算,而直接采用
// log(f+g)计算,经测试,误差小于1e-15。
// 3 算法引用的文献为:
// 1 Gooding,R.H.:: 1988a,'On the Solution of Lambert's Orbital
// Boundary-Value Problem',RAE Technical Report 88027
// 2 Gooding,R.H.:: 1989, 'A Procedure for the Solution of Lambert's
// Orbital Boundary
// 4 主要由子程序XLamb调用进行迭代寻根使用
/// <summary>
/// Lambert 方程的无量纲时间 (R.H.Gooding 方法)
/// <para>主要由子程序XLamb调用进行迭代寻根使用</para>
/// </summary>
/// <param name="m">飞行的圈数(0 for 0-2pi)</param>
/// <param name="q">q=sqrt(r1*r2)/s*cos(0.5*theta)</param>
/// <param name="qsqfm1">(1-q*q): c/s</param>
/// <param name="x">自变量(x*x=1-am/a)</param>
/// <param name="n">0仅计算t; 2计算到d2t; 3计算到d3t</param>
/// <param name="t">out:无量纲时间(T=sqrt(8u/s^3)*Δt)</param>
/// <param name="dt">out:T对x的1阶导数</param>
/// <param name="d2t">out:T对x的2阶导数</param>
/// <param name="d3t">out:T对x的3阶导数</param>
public static void TLAMB2(int m, double q, double qsqfm1, double x, int n, out double t, out double dt, out double d2t, out double d3t)
{
// 缺省值
t = dt = d2t = d3t = 0.0;
// 初值
double sw = 0.4;
// 导数计算的判断标志
bool l1 = (n >= 1);
bool l2 = (n >= 2);
bool l3 = (n == 3);
double qsq = q * q; //q^2
double xsq = x * x; //x^2
double u = (1 - x) * (1 + x); //u=1-x^2
#region 直接计算(非级数计算)
if (m > 0 || x < 0 || Math.Abs(u) > sw)
{
double y = Math.Sqrt(Math.Abs(u));
double z = Math.Sqrt(qsqfm1 + qsq * xsq);
double qx = q * x;
// alpha,beta
double a = 0;
double b = 0;
if (qx <= 0)
{
a = z - qx;
b = q * z - x;
}
else
{
a = qsqfm1 / (z + qx);
b = qsqfm1 * (qsq * u - xsq) / (q * z + x);
}
double g = 0;
if (qx * u >= 0)
g = x * z + q * u;
else
g = (xsq - qsq * u) / (x * z - q * u);
double f = a * y;
// 椭圆情形
if (x <= 1.0)
t = m * Math.PI + Math.Atan2(f, g);
// 双曲线情形
else
t = Math.Log(f + g);
// 无量纲时间
t = 2.0 * (t / y + b) / u;
// 1-3阶导数
if (l1 && z != 0)
{
double qz = q / z;
double qz2 = qz * qz;
double qz3 = qz2 * qz;
dt = (3.0 * x * t - 4.0 * (a + qx * qsqfm1) / z) / u;
if (l2)
d2t = (3.0 * t + 5.0 * x * dt + 4.0 * qz3 * qsqfm1) / u;
if (l3)
d3t = (8.0 * dt + 7.0 * x * d2t - 12.0 * qz3 * qz2 * x * qsqfm1) / u;
}
}
#endregion
#region 级数计算( T*x^2=Sum(Cn*u^n) n=0,1,2...)
else
{
// 求解T时级数中u的n次方
double u0i = 1.0;
// 求解T的1-3阶导数时级数中u的n次方
double u1i = 0;
double u2i = 0;
double u3i = 0;
if (l1) u1i = 1.0;
if (l2) u2i = 1.0;
if (l3) u3i = 1.0;
double term = 4.0; //a0
double tq = q * qsqfm1; //q*(1-q^2)
double tqsum = 0.0; //b0
if (q < 0.5) tqsum = 1.0 - q * qsq;
if (q >= 0.5) tqsum = (1.0 / (1.0 + q) + q) * qsqfm1;
double ttmold = term / 3.0; //A0
t = ttmold * tqsum; //A0*b0: T*x^2的级数的0次方
double told = t - 1.0; //T*x^2的级数前一值,force t ~= told to get one pass through
int i = 0;
double tterm, tqterm; //An,An*bn
while (i < n || t != told)
{
i = i + 1;
u0i = u0i * u; //u^n
if (l1 && i > 1) u1i = u1i * u;
if (l2 && i > 2) u2i = u2i * u;
if (l3 && i > 3) u3i = u3i * u;
term = term * (i - 0.5) / i; //an
tq = tq * qsq; //bn-b(n-1)
tqsum = tqsum + tq; //bn=b(n-1)+q^(2n)*q*(1-q^2)
told = t; //保留T*x^2级数的当前值
tterm = term / (2.0 * i + 3.0); //An=an/(2n+3)
tqterm = tterm * tqsum; //An*bn
// T*x^2的级数: +当前的Cn*u^n
t = t - u0i * ((1.5 * i + 0.25) * tqterm / (i * i - 0.25) - ttmold * tq);
ttmold = tterm; //保留当前的An
tqterm = tqterm * i; //An*bn*n
// T对u的1-3阶级数:+当前的An*bn*n*..
if (l1) dt = dt + tqterm * u1i;
if (l2) d2t = d2t + tqterm * u2i * (i - 1.0);
if (l3) d3t = d3t + tqterm * u3i * (i - 1.0) * (i - 2.0);
}
// T对x的1-3阶导数
if (l3) d3t = 8.0 * x * (1.5 * d2t - xsq * d3t);
if (l2) d2t = 2.0 * (2.0 * xsq * d2t - dt);
if (l1) dt = -2.0 * x * dt;
// T:最后求得的级数需要除以x^2
t = t / xsq;
}
#endregion
}
云上飞47636962
发布了32 篇原创文章 · 获赞 50 · 访问量 7万+
私信
关注