贡献者: addis
预备知识 Matlab 画图
,开普勒问题的运动方程
本文讨论开普勒问题中,若已知初始位置和初速度矢量,求轨道方程和动画的算法并给出 Matlab 代码。以下所有符号和定义沿用 “开普勒问题”。
图 1:在同一位置以同一初速度不同仰角发射的质点的椭圆轨道,具有相同的半长轴和不同的离心率,动画见
这里。虚线为参考圆,例如地球表面,可见除了水平发射的质点都会落回地面。若初速度很小,那么参考圆外的运动就趋近于抛体运动(足够扁的椭圆的一端趋近于抛物线)。
图 2:在同一位置以同 仰角和不同初速度发射的质点的轨道,动画见
这里。速度最大的轨道为双曲线,其他轨道为椭圆。
图 3:平方反比斥力产生的双曲线轨道,动画见
这里。这就是著名的
卢瑟福散射。
1. 轨道的计算
若 是平方反比的力(斥力为正引力为负),即
其中 为非零实常数。由于质点的运动只和初始位置、初始速度和 有关,与质点的质量无关,所以我们令 并不影响一般性。令发射位置的
极坐标为 ,初速度为 ,发射仰角为 (顺时针增量为正, 时质点延逆时针方向水平发射)。
所以质点机械能为动能加势能 ,角动量(逆时针为正)为 。于是离心率 可由式 2 计算,半通径 由式 3 计算。然后代入圆锥曲线的极坐标方程(式 1 )即可得到轨道方程。然而由于发射点已经选好,实际的轨道还需要旋转一个角度 (逆时针为正),即轨道方程变为
其中当 时 , 时 。要求 ,可以代入初始条件,即 。得
这里有两个解是因为圆锥曲线和半径为 的圆必定有两个交点。我们需要根据发射角度来判断哪个是发射点,稍作分析易得当 时上式取正号,否则取负号。
2. 运动的计算
我们使用 “开普勒问题的运动方程” 给出的方法求解三种圆锥曲线的含时运动。沿用其中的符号定义,令 时质点位于近日点, 近日点对应极角 ,令相对近日点的极角增量为 。接下来,先计算函数 ,默认逆时针旋转,然后数值求解反函数 即可。若要考虑顺时针旋转,函数值乘以 即可。易得 时质点绕中心天体逆时针运动, 时顺时针运动。
抛物线:时间 在 取值,式 4 就是 。
椭圆:时间 在 取值,周期 由式 5 计算。由于这是周期运动,其他任意时间都可以加减整数个周期后落到 中。由式 5 和式 6 计算 。
双曲线:时间 在 取值,使用式 7 到式 11 可得 和 两种情况时的 。
求出发射质点的初始时刻为 ,然后生成等间距时间格点 (),用二分法解方程得到对应的 即可。
以下 Matlab 程序支持对同一发射位置画出多组不同初速度和仰角的轨道。相比于使用解微分方程的方法(子节 1 )计算轨道和运动,该程序计算的轨道和运动都可以达到 13 位有效数字以上。然而缺点是只能计算理想的开普勒问题,无法拓展到非平方反比力,也无法拓展到三体乃至多体运动。程序会在当前目录中生成 Nt
张图片,完成后使用 “用 Matlab 制作 gif 动画” 中给出的代码可以制作成 gif 动画。
代码 1:kepler.m
function kepler
k = -1;
R = 1; alpha = 0;
v0 = 1.1;
beta = linspace(0, 4*pi/11, 6);
t_max = 8.94827; Nt = 100;
axis_param = 'auto';
N = max([numel(R), numel(alpha), numel(v0), numel(beta)]);
if isscalar(R), R = R*ones(1, N); end
if isscalar(alpha), alpha = alpha*ones(1, N); end
if isscalar(v0), v0 = v0*ones(1, N); end
if isscalar(beta), beta = beta*ones(1, N); end
if any(abs(cos(beta))<eps)
error('不支持纯径向运动!');
end
close all; figure;
if all(R(:) == R(1))
tmp = linspace(0, 2*pi, 500);
plot(R(1)*cos(tmp), R(1)*sin(tmp), 'k--'); hold on;
end
scatter(0, 0); hold on; axis equal;
xlabel x; ylabel y;
N = numel(v0); t_cell = cell(1,N); th_cell = t_cell;
p_list = zeros(1,N); e_list = p_list; th0_list = p_list;
for i = 1:N
[p_list(i), e_list(i), th0_list(i), t_cell{i}, th_cell{i}] = ...
kepler1(k, R(i), alpha(i), v0(i), beta(i), t_max, Nt); hold on;
axis(axis_param);
end
h = nan(1,N);
for it = 1:10000000
exit = true;
for i = 1:N
s = sign(k);
if it > size(th_cell{i})
h(i) = nan; continue;
end
exit = false;
th = th_cell{i}(it);
r = -s*p_list(i) / (1 + s*e_list(i)*cos(th - th0_list(i)));
if (~isnan(h(i))), delete(h(i)); end
h(i) = scatter(r*cos(th), r*sin(th), 'r^');
end
if exit
break;
end
title(['t = ' num2str(t_cell{1}(it) - t_cell{1}(1), '%.2f')]);
saveas(gcf, [num2str(it) '.png']);
end
end
function [p, e, th0, t, th_t] = kepler1(k, R, alpha, v0, beta, t_max, Nt)
E = v0^2/2 + k/R;
L = v0*cos(beta)*R;
e = sqrt(1 + 2*E*L^2/k^2);
p = L^2/abs(k);
dth = pi/1000; Nth = 500;
if e < 1
th = linspace(0, 2*pi, Nth);
elseif e == 1
th = linspace(dth, 2*pi-dth, Nth);
else
gamma = acos(1/e);
if k < 0
th = linspace(gamma+dth, 2*pi-gamma-dth, Nth);
else
th = linspace(pi-gamma+dth, pi+gamma-dth, Nth);
end
end
s = sign(k);
if e == 0
th0 = 0;
else
if sin(2*beta) >= 0
th0 = alpha + acos((-s - p/R)/e);
else
th0 = alpha - acos((-s - p/R)/e);
end
end
th0 = real(mod(real(th0)+pi, 2*pi) - pi);
scatter(R*cos(alpha), R*sin(alpha));
th = th + th0;
r = -s * p./(1 + s*e*cos(th-th0));
x = r .* cos(th); y = r .* sin(th);
plot(x, y); axis equal;
rot_dir = sign(cos(beta));
t0 = rot_dir*t_Dth(p, e, k, alpha-th0-pi);
t = linspace(t0, t0+t_max, Nt);
th_t = rot_dir*Dth_t(p, e, k, dth, t) + th0 + pi;
end
function t = t_Dth(p, e, k, Dth)
if Dth ~= pi
Dth = mod(Dth+pi, 2*pi) - pi;
end
if e == 1 && k < 0
L = sqrt(p*abs(k));
tmp = tan(Dth/2);
t = L^3/(2*k^2) * (tmp + tmp.^3/3);
elseif e < 1 && k < 0
a = p/(1-e^2);
r = p./(1 + e*cos(Dth));
psi = sign(Dth).*real(acos((1 - r/a)/e));
t = sqrt(a^3/(abs(k)))*(psi - e*sin(psi));
elseif e > 1 && k < 0
a = p/(e^2-1);
r = p./(1 + e*cos(Dth));
xi = sign(Dth).*real(acosh((1 + r/a)/e));
t = sqrt(a^3/(abs(k)))*(e*sinh(xi) - xi);
elseif e > 1 && k > 0
a = p/(e^2-1);
r = p./(1 - e*cos(Dth));
xi = sign(Dth).*acosh((-r/a-1)/e);
t = sqrt(a^3/(abs(k)))*(e*sinh(xi) + xi);
else
error('参数错误或未实现!');
end
end
function Dth = Dth_t(p, e, k, dth, t)
N = numel(t); Dth = zeros(1,N);
if e < 1
a = p/(1-e^2);
T = 2*pi*a^1.5*sqrt(1/abs(k));
t = mod(t + T/2, T) - T/2;
Dth_range = [-pi, pi];
elseif e == 1
Dth_range = [-pi+dth, pi-dth];
else
th1 = atan(sqrt(e^2-1));
if k < 0
Dth_range = [-pi+th1+dth, pi-th1-dth];
else
Dth_range = [-th1+dth, th1-dth];
end
end
for i = 1:N
fun = @(Dth) t_Dth(p, e, k, Dth) - t(i);
Dth(i) = fzero(fun, Dth_range);
end
end
运行结果见图 1 。这里给出另一组参数,计算以 仰角和不同初速度发射的情况,替换到以上代码中即可,结果见图 2 。
图 3 中卢瑟福散射的参数:
致读者: 小时百科一直以来坚持所有内容免费无广告,这导致我们处于严重的亏损状态。 长此以往很可能会最终导致我们不得不选择大量广告以及内容付费等。 因此,我们请求广大读者
热心打赏 ,使网站得以健康发展。 如果看到这条信息的每位读者能慷慨打赏 20 元,我们一周就能脱离亏损, 并在接下来的一年里向所有读者继续免费提供优质内容。 但遗憾的是只有不到 1% 的读者愿意捐款, 他们的付出帮助了 99% 的读者免费获取知识, 我们在此表示感谢。