matlab兰伯特问题求解器
2026-1-4
兰伯特问题求解器,包括从给定的两个位置矢量(和可选的速度、时间)计算轨道根数的功能。
一、理论基础
兰伯特问题(Lambert's Problem)定义为:已知两个位置矢量
基本方程:
对于椭圆轨道,兰伯特定理表示为:
其中 (a) 是半长轴,(e) 是偏心率,(E) 是偏近点角。
二、MATLAB完整实现
1. 主求解函数
function [orbital_elements, v1, v2] = solve_lambert_problem(r1, r2, dt, mu, varargin)
% 求解兰伯特问题并返回轨道根数
%
% 输入参数:
% r1 - 初始位置矢量 (3×1, km)
% r2 - 终点位置矢量 (3×1, km)
% dt - 飞行时间 (s)
% mu - 引力常数 (km^3/s^2, 默认地球: 398600.4418)
% varargin - 可选参数:
% 'direction' - 转移方向 ('prograde' 或 'retrograde', 默认 'prograde')
% 'solution' - 解的类型 ('short' 短路径, 'long' 长路径, 默认 'short')
% 'tolerance' - 收敛容差 (默认 1e-10)
% 'max_iter' - 最大迭代次数 (默认 100)
%
% 输出参数:
% orbital_elements - 轨道根数结构体
% v1 - 初始速度矢量 (km/s)
% v2 - 终点速度矢量 (km/s)
%% 1. 参数解析
% 设置默认值
default_mu = 398600.4418; % 地球引力常数 (km^3/s^2)
default_direction = 'prograde';
default_solution = 'short';
default_tol = 1e-10;
default_max_iter = 100;
% 解析输入参数
p = inputParser;
addRequired(p, 'r1', @(x) validateattributes(x, {'numeric'}, {'size', [3,1]}));
addRequired(p, 'r2', @(x) validateattributes(x, {'numeric'}, {'size', [3,1]}));
addRequired(p, 'dt', @(x) validateattributes(x, {'numeric'}, {'scalar', 'positive'}));
addOptional(p, 'mu', default_mu, @(x) validateattributes(x, {'numeric'}, {'scalar', 'positive'}));
addParameter(p, 'direction', default_direction, @(x) ismember(x, {'prograde', 'retrograde'}));
addParameter(p, 'solution', default_solution, @(x) ismember(x, {'short', 'long'}));
addParameter(p, 'tolerance', default_tol, @(x) validateattributes(x, {'numeric'}, {'scalar', 'positive'}));
addParameter(p, 'max_iter', default_max_iter, @(x) validateattributes(x, {'numeric'}, {'scalar', 'positive'}));
parse(p, r1, r2, dt, mu, varargin{:});
% 提取参数
mu = p.Results.mu;
direction = p.Results.direction;
solution_type = p.Results.solution;
tol = p.Results.tolerance;
max_iter = p.Results.max_iter;
%% 2. 计算几何参数
fprintf('求解兰伯特问题...\n');
fprintf('飞行时间: %.2f 秒 (%.2f 小时)\n', dt, dt/3600);
fprintf('引力常数 mu: %.4f km^3/s^2\n', mu);
% 位置矢量的模
r1_norm = norm(r1);
r2_norm = norm(r2);
fprintf('初始位置半径: %.2f km\n', r1_norm);
fprintf('终点位置半径: %.2f km\n', r2_norm);
% 位置矢量的夹角(转移角)
cos_dtheta = dot(r1, r2) / (r1_norm * r2_norm);
cos_dtheta = max(min(cos_dtheta, 1), -1); % 避免数值误差
dtheta = acos(cos_dtheta);
% 确定转移角(考虑方向)
if strcmpi(direction, 'retrograde')
dtheta = 2*pi - dtheta;
end
fprintf('转移角: %.2f 度\n', rad2deg(dtheta));
%% 3. 计算兰伯特参数
% 弦长
c = norm(r2 - r1);
s = (r1_norm + r2_norm + c) / 2;
fprintf('弦长: %.2f km\n', c);
fprintf('半周长: %.2f km\n', s);
% 转移角的正负号(用于多值解)
if dtheta > pi
long_way = true;
else
long_way = false;
end
% 根据解类型调整
if strcmpi(solution_type, 'long')
long_way = ~long_way;
end
% 计算参数 A
sin_dtheta = sin(dtheta);
A = sin_dtheta * sqrt(r1_norm * r2_norm / (1 - cos_dtheta));
if long_way
A = -A;
end
%% 4. 求解兰伯特方程(使用普适变量法)
% 初始猜测
if A > 0
y_initial = 0;
else
y_initial = -2*A;
end
% 迭代求解
[y, converged, iterations] = solve_lambert_equation(y_initial, r1_norm, r2_norm, A, dt, mu, tol, max_iter);
if ~converged
warning('兰伯特方程迭代未收敛,使用最后一次迭代结果');
end
fprintf('迭代求解完成,迭代次数: %d\n', iterations);
%% 5. 计算速度矢量
% 计算轨道参数
f = 1 - y / r1_norm;
g = A * sqrt(y / mu);
g_dot = 1 - y / r2_norm;
% 计算速度矢量
v1 = (r2 - f * r1) / g;
v2 = (g_dot * r2 - r1) / g;
fprintf('初始速度大小: %.4f km/s\n', norm(v1));
fprintf('终点速度大小: %.4f km/s\n', norm(v2));
%% 6. 计算轨道根数
orbital_elements = rv2oe(r1, v1, mu);
%% 7. 验证结果
verify_lambert_solution(r1, r2, v1, v2, dt, mu, orbital_elements);
fprintf('兰伯特问题求解完成!\n');
end
function [y, converged, iter] = solve_lambert_equation(y0, r1, r2, A, dt, mu, tol, max_iter)
% 使用牛顿-拉弗森法求解兰伯特方程
y = y0;
converged = false;
for iter = 1:max_iter
% 计算当前y值的函数值和导数值
[f_val, df_dy] = lambert_f_function(y, r1, r2, A, dt, mu);
% 牛顿更新
dy = -f_val / df_dy;
y_new = y + dy;
% 检查收敛性
if abs(dy) < tol
y = y_new;
converged = true;
break;
end
% 防止y值超出合理范围
if y_new < -2*A && A < 0
y_new = -2*A + 0.1;
end
y = y_new;
% 每10次迭代显示进度
if mod(iter, 10) == 0
fprintf(' 迭代 %d: y = %.6e, f(y) = %.6e\n', iter, y, f_val);
end
end
if iter >= max_iter
warning('达到最大迭代次数,可能未收敛');
end
end
function [f, df_dy] = lambert_f_function(y, r1, r2, A, dt, mu)
% 兰伯特方程的函数形式及其导数
% 计算x
if y > 0
x = sqrt(y);
sin_sqrt_y = sin(x);
cos_sqrt_y = cos(x);
S = (x - sin_sqrt_y) / (x^3);
C = (1 - cos_sqrt_y) / y;
elseif y < 0
x = sqrt(-y);
sinh_x = sinh(x);
cosh_x = cosh(x);
S = (x - sinh_x) / (x^3);
C = (1 - cosh_x) / y;
else % y = 0
S = 1/6;
C = 1/2;
end
% 计算函数值
Q = sqrt(A^2 * C);
if A > 0
f = (Q^3 * S + A * sqrt(y)) / sqrt(mu) - dt;
else
f = -(Q^3 * S + A * sqrt(y)) / sqrt(mu) - dt;
end
% 计算导数
if y ~= 0
if y > 0
dS_dy = (3*(sin_sqrt_y - x) + x^3) / (2 * x^5);
dC_dy = (y*sin_sqrt_y/(2*x) - 2*(1-cos_sqrt_y)) / (y^2);
else
dS_dy = (3*(sinh_x - x) + x^3) / (2 * x^5);
dC_dy = (y*sinh_x/(2*x) - 2*(1-cosh_x)) / (y^2);
end
dQ_dy = A^2 * dC_dy / (2*Q);
df_dy = (3*Q^2*dQ_dy*S + Q^3*dS_dy + A/(2*sqrt(y))) / sqrt(mu);
else
df_dy = (1/40) * A^3 / sqrt(mu) + A/(2*sqrt(mu));
end
end
function oe = rv2oe(r, v, mu)
% 从位置和速度矢量计算经典轨道根数
% 输入:r, v (3×1 矢量), mu (引力常数)
% 输出:轨道根数结构体
%% 1. 计算基本矢量
h = cross(r, v); % 角动量矢量
h_norm = norm(h);
% 节点矢量
n = cross([0; 0; 1], h);
n_norm = norm(n);
%% 2. 计算轨道平面参数
% 半长轴 a
r_norm = norm(r);
v_norm = norm(v);
energy = v_norm^2/2 - mu/r_norm; % 比机械能
if abs(energy) < 1e-10
a = inf; % 抛物线
else
a = -mu/(2*energy);
end
%% 3. 计算偏心率矢量
e_vec = ((v_norm^2 - mu/r_norm)*r - dot(r, v)*v)/mu;
e = norm(e_vec); % 偏心率大小
%% 4. 计算轨道倾角 i
i = acos(h(3)/h_norm);
%% 5. 计算升交点赤经 Ω
if n_norm > 0
Omega = acos(n(1)/n_norm);
if n(2) < 0
Omega = 2*pi - Omega;
end
else
Omega = 0; % 赤道轨道
end
%% 6. 计算近地点幅角 ω
if n_norm > 0 && e > 0
omega = acos(dot(n, e_vec)/(n_norm*e));
if e_vec(3) < 0
omega = 2*pi - omega;
end
else
omega = 0;
end
%% 7. 计算真近点角 ν
if e > 0
nu = acos(dot(e_vec, r)/(e*r_norm));
if dot(r, v) < 0
nu = 2*pi - nu;
end
else
% 圆轨道,近地点未定义
nu = acos(dot(n, r)/(n_norm*r_norm));
if r(3) < 0
nu = 2*pi - nu;
end
end
%% 8. 计算平近点角 M 和偏近点角 E
if e < 1 && ~isinf(a) % 椭圆轨道
% 计算偏近点角 E
cosE = (e + cos(nu))/(1 + e*cos(nu));
sinE = sqrt(1 - e^2)*sin(nu)/(1 + e*cos(nu));
E = atan2(sinE, cosE);
% 计算平近点角 M
M = E - e*sinE;
% 周期
T = 2*pi*sqrt(a^3/mu);
elseif e > 1 && ~isinf(a) % 双曲线轨道
% 双曲线偏近点角 F
coshF = (e + cos(nu))/(1 + e*cos(nu));
F = acosh(coshF);
if nu < 0
F = -F;
end
% 双曲线平近点角 N
N = e*sinh(F) - F;
M = N; % 对于双曲线,常用 N 表示
% 周期概念不适用于双曲线
T = inf;
else % 抛物线
E = nan;
M = nan;
T = inf;
end
%% 9. 返回轨道根数结构体
oe = struct();
oe.a = a; % 半长轴 (km)
oe.e = e; % 偏心率
oe.i = rad2deg(i); % 轨道倾角 (度)
oe.Omega = rad2deg(Omega); % 升交点赤经 (度)
oe.omega = rad2deg(omega); % 近地点幅角 (度)
oe.nu = rad2deg(nu); % 真近点角 (度)
oe.E = rad2deg(E); % 偏近点角 (度)
oe.M = rad2deg(M); % 平近点角 (度)
oe.T = T; % 轨道周期 (s)
oe.h = h_norm; % 角动量大小
oe.energy = energy; % 比机械能
oe.type = get_orbit_type(e, a); % 轨道类型
% 额外参数
oe.r_periapsis = a*(1 - e); % 近地点半径 (km)
oe.r_apoapsis = a*(1 + e); % 远地点半径 (km)
if ~isinf(a)
oe.period = T/3600; % 周期 (小时)
else
oe.period = inf;
end
end
function orbit_type = get_orbit_type(e, a)
% 判断轨道类型
if e < 1e-10
orbit_type = 'Circular';
elseif e < 1
orbit_type = 'Elliptical';
elseif abs(e - 1) < 1e-6
orbit_type = 'Parabolic';
else
orbit_type = 'Hyperbolic';
end
% 特殊地球轨道
if strcmp(orbit_type, 'Elliptical')
if a * (1 - e) < 6578 % 低于200km
orbit_type = 'Low Earth Orbit (LEO)';
elseif a * (1 - e) < 42164 && a * (1 + e) > 42164 % 穿越GEO
orbit_type = 'Geostationary Transfer Orbit (GTO)';
elseif abs(a * (1 - e) - 42164) < 100 % GEO附近
orbit_type = 'Geostationary Orbit (GEO)';
end
end
end
function verify_lambert_solution(r1, r2, v1, v2, dt, mu, oe)
% 验证兰伯特问题求解结果
fprintf('\n=== 验证求解结果 ===\n');
% 1. 验证位置矢量
fprintf('1. 位置矢量验证:\n');
fprintf(' 初始位置给定: [%.2f, %.2f, %.2f] km\n', r1);
fprintf(' 终点位置给定: [%.2f, %.2f, %.2f] km\n', r2);
% 2. 验证能量守恒
energy1 = norm(v1)^2/2 - mu/norm(r1);
energy2 = norm(v2)^2/2 - mu/norm(r2);
energy_diff = abs(energy1 - energy2);
fprintf('2. 能量守恒验证:\n');
fprintf(' 初始比机械能: %.6f km^2/s^2\n', energy1);
fprintf(' 终点比机械能: %.6f km^2/s^2\n', energy2);
fprintf(' 能量差异: %.2e km^2/s^2\n', energy_diff);
if energy_diff < 1e-6
fprintf(' ✓ 能量守恒验证通过\n');
else
fprintf(' ⚠ 能量差异较大\n');
end
% 3. 验证轨道根数的一致性
fprintf('3. 轨道根数验证:\n');
fprintf(' 轨道类型: %s\n', oe.type);
fprintf(' 半长轴 a: %.2f km\n', oe.a);
fprintf(' 偏心率 e: %.6f\n', oe.e);
if oe.e < 1 && ~isinf(oe.a)
fprintf(' 近地点半径: %.2f km\n', oe.r_periapsis);
fprintf(' 远地点半径: %.2f km\n', oe.r_apoapsis);
fprintf(' 轨道周期: %.2f 小时\n', oe.period);
end
% 4. 验证飞行时间
fprintf('4. 飞行时间验证:\n');
fprintf(' 给定飞行时间: %.2f 秒\n', dt);
% 计算预测飞行时间(对于椭圆轨道)
if oe.e < 1 && ~isinf(oe.a)
% 计算初始和终点的偏近点角
nu1 = deg2rad(oe.nu);
nu2 = deg2rad(mod(oe.nu + rad2deg(acos(dot(r1, r2)/(norm(r1)*norm(r2)))), 360));
E1 = 2 * atan(sqrt((1 - oe.e)/(1 + oe.e)) * tan(nu1/2));
E2 = 2 * atan(sqrt((1 - oe.e)/(1 + oe.e)) * tan(nu2/2));
dt_calc = sqrt(oe.a^3/mu) * ((E2 - E1) - oe.e*(sin(E2) - sin(E1)));
fprintf(' 计算飞行时间: %.2f 秒\n', dt_calc);
fprintf(' 时间差异: %.2e 秒\n', abs(dt - dt_calc));
end
fprintf('=== 验证完成 ===\n\n');
end
2. 可视化函数
function visualize_lambert_solution(r1, r2, v1, v2, oe, mu, dt)
% 可视化兰伯特问题求解结果
fprintf('生成可视化...\n');
% 创建图形窗口
figure('Position', [100, 100, 1400, 900]);
%% 子图1: 三维轨道图
subplot(2, 3, [1, 2, 4, 5]);
hold on;
grid on;
axis equal;
% 绘制地球
[X, Y, Z] = sphere(50);
R_earth = 6378.137; % 地球半径 (km)
surf(R_earth*X, R_earth*Y, R_earth*Z, 'FaceAlpha', 0.3, ...
'EdgeColor', 'none', 'FaceColor', [0.1, 0.5, 0.8]);
% 绘制坐标系
plot3([0, 2*R_earth], [0, 0], [0, 0], 'r-', 'LineWidth', 2); % X轴
plot3([0, 0], [0, 2*R_earth], [0, 0], 'g-', 'LineWidth', 2); % Y轴
plot3([0, 0], [0, 0], [0, 2*R_earth], 'b-', 'LineWidth', 2); % Z轴
text(2*R_earth, 0, 0, 'X', 'FontSize', 12);
text(0, 2*R_earth, 0, 'Y', 'FontSize', 12);
text(0, 0, 2*R_earth, 'Z', 'FontSize', 12);
% 绘制完整的轨道
if oe.e < 1 && ~isinf(oe.a) % 椭圆轨道
% 生成轨道点
nu_points = linspace(0, 2*pi, 200);
[orbit_points, ~] = oe2rv(oe, nu_points, mu);
plot3(orbit_points(1,:), orbit_points(2,:), orbit_points(3,:), ...
'b-', 'LineWidth', 2);
% 标记近地点和远地点
[r_peri, ~] = oe2rv(oe, 0, mu);
[r_apo, ~] = oe2rv(oe, pi, mu);
plot3(r_peri(1), r_peri(2), r_peri(3), 'go', 'MarkerSize', 10, ...
'MarkerFaceColor', 'g', 'DisplayName', '近地点');
plot3(r_apo(1), r_apo(2), r_apo(3), 'ro', 'MarkerSize', 10, ...
'MarkerFaceColor', 'r', 'DisplayName', '远地点');
else
% 对于非椭圆轨道,只绘制转移段
fprintf(' 非椭圆轨道,仅绘制转移段\n');
end
% 绘制转移弧段
t_points = linspace(0, dt, 100);
[transfer_points, ~] = propagate_orbit(r1, v1, t_points, mu);
plot3(transfer_points(1,:), transfer_points(2,:), transfer_points(3,:), ...
'r-', 'LineWidth', 3, 'DisplayName', '转移轨道');
% 标记初始和终点位置
plot3(r1(1), r1(2), r1(3), 'ko', 'MarkerSize', 12, ...
'MarkerFaceColor', 'k', 'DisplayName', '初始位置');
plot3(r2(1), r2(2), r2(3), 'mo', 'MarkerSize', 12, ...
'MarkerFaceColor', 'm', 'DisplayName', '终点位置');
% 绘制速度矢量
scale = 500; % 速度矢量缩放因子
quiver3(r1(1), r1(2), r1(3), v1(1)*scale, v1(2)*scale, v1(3)*scale, ...
'r', 'LineWidth', 2, 'MaxHeadSize', 0.5, 'DisplayName', '初始速度');
quiver3(r2(1), r2(2), r2(3), v2(1)*scale, v2(2)*scale, v2(3)*scale, ...
'm', 'LineWidth', 2, 'MaxHeadSize', 0.5, 'DisplayName', '终点速度');
% 设置图形属性
xlabel('X (km)', 'FontSize', 12);
ylabel('Y (km)', 'FontSize', 12);
zlabel('Z (km)', 'FontSize', 12);
title('兰伯特问题三维轨道图', 'FontSize', 14);
legend('Location', 'best');
view(45, 30); % 设置视角
%% 子图2: 轨道根数摘要
subplot(2, 3, 3);
axis off;
% 显示轨道参数
text_str = {
sprintf('轨道类型: %s', oe.type);
sprintf('半长轴 a: %.2f km', oe.a);
sprintf('偏心率 e: %.6f', oe.e);
sprintf('轨道倾角 i: %.2f°', oe.i);
sprintf('升交点赤经 Ω: %.2f°', oe.Omega);
sprintf('近地点幅角 ω: %.2f°', oe.omega);
sprintf('真近点角 ν: %.2f°', oe.nu);
sprintf('飞行时间: %.1f s', dt);
sprintf('初始速度: %.4f km/s', norm(v1));
sprintf('终点速度: %.4f km/s', norm(v2));
};
if oe.e < 1 && ~isinf(oe.a)
text_str = [text_str; {
sprintf('近地点半径: %.2f km', oe.r_periapsis);
sprintf('远地点半径: %.2f km', oe.r_apoapsis);
sprintf('轨道周期: %.2f h', oe.period);
}];
end
text(0.1, 0.9, text_str, 'FontSize', 10, 'VerticalAlignment', 'top');
title('轨道参数摘要', 'FontSize', 12);
%% 子图3: 速度与能量图
subplot(2, 3, 6);
hold on;
grid on;
% 计算轨道上的速度分布
if oe.e < 1 && ~isinf(oe.a)
nu_vals = linspace(0, 2*pi, 100);
v_vals = zeros(size(nu_vals));
for i = 1:length(nu_vals)
[~, v_temp] = oe2rv(oe, nu_vals(i), mu);
v_vals(i) = norm(v_temp);
end
% 绘制速度分布
plot(rad2deg(nu_vals), v_vals, 'b-', 'LineWidth', 2);
% 标记转移段的起点和终点
nu1 = deg2rad(oe.nu);
nu2 = mod(nu1 + acos(dot(r1, r2)/(norm(r1)*norm(r2))), 2*pi);
[~, v1_calc] = oe2rv(oe, nu1, mu);
[~, v2_calc] = oe2rv(oe, nu2, mu);
plot(rad2deg([nu1, nu2]), [norm(v1_calc), norm(v2_calc)], 'ro', ...
'MarkerSize', 10, 'MarkerFaceColor', 'r');
xlabel('真近点角 ν (°)', 'FontSize', 12);
ylabel('速度大小 (km/s)', 'FontSize', 12);
title('轨道速度分布', 'FontSize', 12);
legend('轨道速度', '转移段端点', 'Location', 'best');
else
text(0.5, 0.5, '非椭圆轨道,速度图不可用', ...
'HorizontalAlignment', 'center', 'FontSize', 12);
axis off;
end
%% 添加总标题
sgtitle(sprintf('兰伯特问题求解结果 (飞行时间: %.1f 秒)', dt), ...
'FontSize', 16, 'FontWeight', 'bold');
fprintf('可视化生成完成!\n');
end
function [r, v] = oe2rv(oe, nu, mu)
% 从轨道根数计算位置和速度矢量
% 输入:oe - 轨道根数结构体
% nu - 真近点角 (弧度)
% mu - 引力常数
% 提取轨道参数
a = oe.a;
e = oe.e;
i = deg2rad(oe.i);
Omega = deg2rad(oe.Omega);
omega = deg2rad(oe.omega);
% 计算轨道半径
r_mag = a * (1 - e^2) / (1 + e * cos(nu));
% 在轨道平面内的坐标
r_pf = [r_mag * cos(nu); r_mag * sin(nu); 0];
v_pf = sqrt(mu/(a*(1-e^2))) * [-sin(nu); e + cos(nu); 0];
% 旋转矩阵:从轨道平面到地心惯性系
R3_Omega = [cos(Omega), sin(Omega), 0;
-sin(Omega), cos(Omega), 0;
0, 0, 1];
R1_i = [1, 0, 0;
0, cos(i), sin(i);
0, -sin(i), cos(i)];
R3_omega = [cos(omega), sin(omega), 0;
-sin(omega), cos(omega), 0;
0, 0, 1];
% 组合旋转矩阵
R = R3_Omega' * R1_i' * R3_omega';
% 转换到地心惯性系
r = R * r_pf;
v = R * v_pf;
end
function [positions, velocities] = propagate_orbit(r0, v0, t_vec, mu)
% 使用开普勒方程传播轨道
% 输入:r0, v0 - 初始状态
% t_vec - 时间向量
% mu - 引力常数
% 计算初始轨道根数
oe0 = rv2oe(r0, v0, mu);
positions = zeros(3, length(t_vec));
velocities = zeros(3, length(t_vec));
% 对于每个时间点,计算相应的真近点角
for k = 1:length(t_vec)
t = t_vec(k);
% 计算平近点角
if oe0.e < 1 % 椭圆轨道
n = sqrt(mu/oe0.a^3); % 平均角速度
M = mod(deg2rad(oe0.M) + n*t, 2*pi);
% 解开普勒方程求偏近点角
E = solve_kepler_equation(M, oe0.e);
% 计算真近点角
nu = 2 * atan(sqrt((1+oe0.e)/(1-oe0.e)) * tan(E/2));
else % 双曲线轨道(简化处理)
% 这里只返回初始状态
nu = deg2rad(oe0.nu);
end
% 计算位置和速度
[r, v] = oe2rv(oe0, nu, mu);
positions(:, k) = r;
velocities(:, k) = v;
end
end
function E = solve_kepler_equation(M, e)
% 解开普勒方程 E - e*sin(E) = M
% 使用牛顿-拉弗森法
if M < 0
M = M + 2*pi;
end
% 初始猜测
if e < 0.8
E = M;
else
E = pi;
end
% 迭代求解
max_iter = 50;
tol = 1e-12;
for iter = 1:max_iter
f = E - e*sin(E) - M;
f_prime = 1 - e*cos(E);
dE = -f / f_prime;
E = E + dE;
if abs(dE) < tol
break;
end
end
end
3. 测试和验证脚本
%% 兰伯特问题测试脚本
function test_lambert_solver()
% 测试兰伯特问题求解器
fprintf('=== 兰伯特问题求解器测试 ===\n\n');
% 地球引力常数 (km^3/s^2)
mu = 398600.4418;
%% 测试1: 地球同步转移轨道 (GTO)
fprintf('测试1: 地球同步转移轨道 (GTO)\n');
% 初始位置:近地点 200 km
r1 = [6578; 0; 0]; % 200 km 高度,赤道上
% 终点位置:地球同步轨道 35786 km 高度
r2 = [0; 42164; 0]; % GEO,赤道上空
% 飞行时间:约 5.3 小时(霍曼转移)
dt = 5.3 * 3600;
% 求解兰伯特问题
[oe1, v1, v2] = solve_lambert_problem(r1, r2, dt, mu, ...
'direction', 'prograde', 'solution', 'short');
% 可视化
visualize_lambert_solution(r1, r2, v1, v2, oe1, mu, dt);
%% 测试2: 月球转移轨道
fprintf('\n测试2: 月球转移轨道\n');
% 初始位置:低地球轨道 400 km
r1 = [6778; 0; 0]; % 400 km 高度
% 终点位置:月球距离 (平均距离 384400 km)
% 假设在黄道面上
r2 = [384400; 0; 0];
% 飞行时间:约 3 天
dt = 3 * 24 * 3600;
% 求解兰伯特问题
[oe2, v1_moon, v2_moon] = solve_lambert_problem(r1, r2, dt, mu, ...
'direction', 'prograde', 'solution', 'short');
figure;
visualize_lambert_solution(r1, r2, v1_moon, v2_moon, oe2, mu, dt);
%% 测试3: 星际转移(简化)
fprintf('\n测试3: 火星转移轨道(简化)\n');
% 使用简化模型:地球和火星的日心轨道
mu_sun = 1.32712440018e11; % 太阳引力常数 (km^3/s^2)
% 地球位置(假设在近日点)
r_earth = [1.4710e8; 0; 0]; % km
% 火星位置(平均距离)
r_mars = [2.2794e8; 0; 0]; % km
% 飞行时间:约 8 个月
dt_mars = 8 * 30 * 24 * 3600; % 秒
% 求解兰伯特问题
[oe3, v1_mars, v2_mars] = solve_lambert_problem(r_earth, r_mars, dt_mars, mu_sun, ...
'direction', 'prograde', 'solution', 'short');
figure;
visualize_lambert_solution(r_earth, r_mars, v1_mars, v2_mars, oe3, mu_sun, dt_mars);
%% 测试4: 多解验证(短路径 vs 长路径)
fprintf('\n测试4: 多解验证\n');
% 相同的位置,不同的飞行时间
r1_test = [7000; 0; 0];
r2_test = [0; 7000; 0];
% 飞行时间:1 小时
dt_test = 3600;
% 短路径解
[oe_short, v1_short, v2_short] = solve_lambert_problem(r1_test, r2_test, dt_test, mu, ...
'solution', 'short');
% 长路径解
[oe_long, v1_long, v2_long] = solve_lambert_problem(r1_test, r2_test, dt_test, mu, ...
'solution', 'long');
% 比较结果
fprintf('\n短路径解:\n');
fprintf(' 初始速度: [%.4f, %.4f, %.4f] km/s\n', v1_short);
fprintf(' 终点速度: [%.4f, %.4f, %.4f] km/s\n', v2_short);
fprintf(' 半长轴: %.2f km\n', oe_short.a);
fprintf('\n长路径解:\n');
fprintf(' 初始速度: [%.4f, %.4f, %.4f] km/s\n', v1_long);
fprintf(' 终点速度: [%.4f, %.4f, %.4f] km/s\n', v2_long);
fprintf(' 半长轴: %.2f km\n', oe_long.a);
fprintf('\n=== 所有测试完成 ===\n');
end
%% 性能测试和精度验证
function accuracy_test()
% 测试兰伯特问题求解器的精度
fprintf('=== 精度测试 ===\n');
mu = 398600.4418;
% 测试用例1: 圆轨道
fprintf('\n测试用例1: 圆轨道\n');
r1 = [7000; 0; 0];
r2 = [0; 7000; 0];
% 对于圆轨道,90度转移需要的时间
a = 7000;
dt_expected = (pi/2) * sqrt(a^3/mu); % 四分之一周期
[oe, v1, v2] = solve_lambert_problem(r1, r2, dt_expected, mu);
% 验证速度
v_circular = sqrt(mu/a);
error_v1 = norm(v1) - v_circular;
error_v2 = norm(v2) - v_circular;
fprintf(' 圆轨道速度理论值: %.6f km/s\n', v_circular);
fprintf(' 初始速度误差: %.6e km/s\n', error_v1);
fprintf(' 终点速度误差: %.6e km/s\n', error_v2);
% 测试用例2: 椭圆轨道
fprintf('\n测试用例2: 椭圆轨道\n');
% 定义椭圆轨道参数
a_test = 10000;
e_test = 0.5;
i_test = 30;
Omega_test = 45;
omega_test = 60;
nu1_test = 0;
nu2_test = 90;
% 计算两个位置
oe_test = struct();
oe_test.a = a_test;
oe_test.e = e_test;
oe_test.i = i_test;
oe_test.Omega = Omega_test;
oe_test.omega = omega_test;
[r1_test, v1_test] = oe2rv(oe_test, deg2rad(nu1_test), mu);
[r2_test, v2_expected] = oe2rv(oe_test, deg2rad(nu2_test), mu);
% 计算飞行时间
E1 = 2 * atan(sqrt((1-e_test)/(1+e_test)) * tan(deg2rad(nu1_test)/2));
E2 = 2 * atan(sqrt((1-e_test)/(1+e_test)) * tan(deg2rad(nu2_test)/2));
dt_test = sqrt(a_test^3/mu) * ((E2 - E1) - e_test*(sin(E2) - sin(E1)));
fprintf(' 理论飞行时间: %.2f 秒\n', dt_test);
% 求解兰伯特问题
[oe_calc, v1_calc, v2_calc] = solve_lambert_problem(r1_test, r2_test, dt_test, mu);
% 验证结果
error_v2_norm = norm(v2_calc - v2_expected);
fprintf(' 终点速度误差范数: %.6e km/s\n', error_v2_norm);
fprintf(' 半长轴误差: %.6e km\n', oe_calc.a - a_test);
fprintf(' 偏心率误差: %.6e\n', oe_calc.e - e_test);
% 测试用例3: 极端情况(大偏心率)
fprintf('\n测试用例3: 大偏心率椭圆轨道\n');
a_extreme = 50000;
e_extreme = 0.9;
nu1_extreme = 10;
nu2_extreme = 170;
oe_extreme = struct();
oe_extreme.a = a_extreme;
oe_extreme.e = e_extreme;
oe_extreme.i = 0;
oe_extreme.Omega = 0;
oe_extreme.omega = 0;
[r1_extreme, ~] = oe2rv(oe_extreme, deg2rad(nu1_extreme), mu);
[r2_extreme, v2_extreme_expected] = oe2rv(oe_extreme, deg2rad(nu2_extreme), mu);
E1_extreme = 2 * atan(sqrt((1-e_extreme)/(1+e_extreme)) * tan(deg2rad(nu1_extreme)/2));
E2_extreme = 2 * atan(sqrt((1-e_extreme)/(1+e_extreme)) * tan(deg2rad(nu2_extreme)/2));
dt_extreme = sqrt(a_extreme^3/mu) * ((E2_extreme - E1_extreme) - ...
e_extreme*(sin(E2_extreme) - sin(E1_extreme)));
[oe_extreme_calc, ~, v2_extreme_calc] = solve_lambert_problem(...
r1_extreme, r2_extreme, dt_extreme, mu);
error_v2_extreme = norm(v2_extreme_calc - v2_extreme_expected);
fprintf(' 大偏心率轨道终点速度误差: %.6e km/s\n', error_v2_extreme);
fprintf('\n=== 精度测试完成 ===\n');
end
4. 实用工具函数
%% 实用工具函数
function [r1, r2, dt] = get_input_from_user()
% 从用户获取输入
fprintf('=== 兰伯特问题求解器输入 ===\n\n');
% 引力常数选择
fprintf('选择引力常数:\n');
fprintf('1. 地球 (398600.4418 km^3/s^2)\n');
fprintf('2. 月球 (4902.8 km^3/s^2)\n');
fprintf('3. 火星 (42828 km^3/s^2)\n');
fprintf('4. 太阳 (1.3271244e11 km^3/s^2)\n');
fprintf('5. 自定义\n');
choice = input('请输入选择 (1-5): ');
switch choice
case 1
mu = 398600.4418;
body = '地球';
case 2
mu = 4902.8;
body = '月球';
case 3
mu = 42828;
body = '火星';
case 4
mu = 1.3271244e11;
body = '太阳';
case 5
mu = input('请输入引力常数 (km^3/s^2): ');
body = '自定义';
otherwise
mu = 398600.4418;
body = '地球';
end
fprintf('\n引力常数: %.4e km^3/s^2 (%s)\n', mu, body);
% 输入初始位置
fprintf('\n输入初始位置 (km):\n');
r1_x = input(' X坐标: ');
r1_y = input(' Y坐标: ');
r1_z = input(' Z坐标: ');
r1 = [r1_x; r1_y; r1_z];
% 输入终点位置
fprintf('\n输入终点位置 (km):\n');
r2_x = input(' X坐标: ');
r2_y = input(' Y坐标: ');
r2_z = input(' Z坐标: ');
r2 = [r2_x; r2_y; r2_z];
% 输入飞行时间
fprintf('\n输入飞行时间:\n');
dt_unit = input(' 单位 (1=秒, 2=分, 3=小时, 4=天): ');
dt_value = input(' 数值: ');
switch dt_unit
case 1
dt = dt_value;
case 2
dt = dt_value * 60;
case 3
dt = dt_value * 3600;
case 4
dt = dt_value * 24 * 3600;
otherwise
dt = dt_value;
end
fprintf('\n飞行时间: %.1f 秒 (%.2f 小时)\n', dt, dt/3600);
% 输入转移方向
fprintf('\n选择转移方向:\n');
fprintf('1. 顺行 (prograde)\n');
fprintf('2. 逆行 (retrograde)\n');
direction_choice = input('请输入选择 (1-2): ');
if direction_choice == 2
direction = 'retrograde';
else
direction = 'prograde';
end
% 输入解类型
fprintf('\n选择解类型:\n');
fprintf('1. 短路径 (short)\n');
fprintf('2. 长路径 (long)\n');
solution_choice = input('请输入选择 (1-2): ');
if solution_choice == 2
solution = 'long';
else
solution = 'short';
end
% 返回结果
fprintf('\n=== 输入完成 ===\n');
end
function export_results(oe, v1, v2, r1, r2, dt, mu, filename)
% 导出结果到文件
if nargin < 8
timestamp = datestr(now, 'yyyymmdd_HHMMSS');
filename = sprintf('lambert_results_%s.txt', timestamp);
end
fid = fopen(filename, 'w');
fprintf(fid, '=== 兰伯特问题求解结果 ===\n\n');
fprintf(fid, '生成时间: %s\n\n', datestr(now));
fprintf(fid, '输入参数:\n');
fprintf(fid, ' 引力常数 mu: %.4f km^3/s^2\n', mu);
fprintf(fid, ' 飞行时间: %.1f 秒 (%.2f 小时)\n\n', dt, dt/3600);
fprintf(fid, '初始位置矢量 (km):\n');
fprintf(fid, ' [%.4f, %.4f, %.4f]\n', r1);
fprintf(fid, ' 半径: %.2f km\n\n', norm(r1));
fprintf(fid, '终点位置矢量 (km):\n');
fprintf(fid, ' [%.4f, %.4f, %.4f]\n', r2);
fprintf(fid, ' 半径: %.2f km\n\n', norm(r2));
fprintf(fid, '计算结果:\n');
fprintf(fid, ' 初始速度矢量 (km/s):\n');
fprintf(fid, ' [%.6f, %.6f, %.6f]\n', v1);
fprintf(fid, ' 大小: %.6f km/s\n\n', norm(v1));
fprintf(fid, ' 终点速度矢量 (km/s):\n');
fprintf(fid, ' [%.6f, %.6f, %.6f]\n', v2);
fprintf(fid, ' 大小: %.6f km/s\n\n', norm(v2));
fprintf(fid, '轨道根数:\n');
fprintf(fid, ' 轨道类型: %s\n', oe.type);
fprintf(fid, ' 半长轴 a: %.4f km\n', oe.a);
fprintf(fid, ' 偏心率 e: %.8f\n', oe.e);
fprintf(fid, ' 轨道倾角 i: %.4f°\n', oe.i);
fprintf(fid, ' 升交点赤经 Ω: %.4f°\n', oe.Omega);
fprintf(fid, ' 近地点幅角 ω: %.4f°\n', oe.omega);
fprintf(fid, ' 真近点角 ν: %.4f°\n', oe.nu);
if oe.e < 1 && ~isinf(oe.a)
fprintf(fid, ' 近地点半径: %.2f km\n', oe.r_periapsis);
fprintf(fid, ' 远地点半径: %.2f km\n', oe.r_apoapsis);
fprintf(fid, ' 轨道周期: %.2f 小时\n', oe.period);
end
fprintf(fid, '\n 比机械能: %.6f km^2/s^2\n', oe.energy);
fprintf(fid, ' 角动量大小: %.6f km^2/s\n', oe.h);
fclose(fid);
fprintf('结果已导出到文件: %s\n', filename);
end
5. 主函数和快速开始
%% 主函数 - 兰伯特问题求解器
function lambert_solver_gui()
% 兰伯特问题求解器 GUI 版本
fprintf('========================================\n');
fprintf(' 兰伯特问题求解器\n');
fprintf('========================================\n\n');
while true
fprintf('主菜单:\n');
fprintf(' 1. 求解兰伯特问题\n');
fprintf(' 2. 运行测试用例\n');
fprintf(' 3. 精度测试\n');
fprintf(' 4. 显示帮助\n');
fprintf(' 5. 退出\n');
choice = input('\n请选择 (1-5): ');
switch choice
case 1
% 获取用户输入
[r1, r2, dt] = get_input_from_user();
% 设置参数
mu = 398600.4418; % 地球
% 求解
[oe, v1, v2] = solve_lambert_problem(r1, r2, dt, mu);
% 可视化
visualize_lambert_solution(r1, r2, v1, v2, oe, mu, dt);
% 导出结果
export_choice = input('\n导出结果到文件? (y/n): ', 's');
if strcmpi(export_choice, 'y')
export_results(oe, v1, v2, r1, r2, dt, mu);
end
case 2
% 运行测试用例
test_lambert_solver();
case 3
% 精度测试
accuracy_test();
case 4
% 显示帮助
display_help();
case 5
% 退出
fprintf('\n感谢使用兰伯特问题求解器!\n');
break;
otherwise
fprintf('无效选择,请重新输入\n');
end
fprintf('\n');
end
end
function display_help()
% 显示帮助信息
fprintf('\n=== 兰伯特问题求解器帮助 ===\n\n');
fprintf('兰伯特问题定义:\n');
fprintf(' 已知两个位置矢量 r1 和 r2,以及从 r1 到 r2 的飞行时间 Δt,\n');
fprintf(' 求连接这两点的轨道。\n\n');
fprintf('输入要求:\n');
fprintf(' 1. 位置矢量: 三维直角坐标 (km)\n');
fprintf(' 2. 飞行时间: 秒 (也可输入分钟、小时或天)\n');
fprintf(' 3. 引力常数: 取决于中心天体\n\n');
fprintf('输出结果:\n');
fprintf(' 1. 初始速度矢量 v1 (km/s)\n');
fprintf(' 2. 终点速度矢量 v2 (km/s)\n');
fprintf(' 3. 轨道根数: a, e, i, Ω, ω, ν\n');
fprintf(' 4. 三维轨道可视化\n\n');
fprintf('算法说明:\n');
fprintf(' 使用普适变量法求解兰伯特方程,\n');
fprintf(' 牛顿-拉弗森迭代法确保精度。\n\n');
fprintf('注意事项:\n');
fprintf(' 1. 对于给定的输入,通常有两个解(短路径和长路径)\n');
fprintf(' 2. 飞行时间必须大于最小转移时间\n');
fprintf(' 3. 对于某些极端情况,算法可能不收敛\n\n');
fprintf('参考文献:\n');
fprintf(' [1] Curtis, H.D. (2014). Orbital Mechanics for Engineering Students\n');
fprintf(' [2] Bate, R.R., Mueller, D.D., & White, J.E. (1971). Fundamentals of Astrodynamics\n');
fprintf(' [3] Vallado, D.A. (2013). Fundamentals of Astrodynamics and Applications\n\n');
end
%% 快速开始示例
function quick_start_example()
% 快速开始示例
fprintf('=== 快速开始示例 ===\n\n');
% 设置参数
mu = 398600.4418; % 地球引力常数
% 示例:从 200 km 圆轨道到 GEO 的转移
fprintf('示例:地球同步转移轨道 (GTO)\n\n');
% 初始位置:200 km 高度,赤道上
r1 = [6578; 0; 0];
% 终点位置:GEO (35786 km 高度)
r2 = [0; 42164; 0];
% 飞行时间:约 5.3 小时(霍曼转移)
dt = 5.3 * 3600;
fprintf('初始位置: [%.0f, %.0f, %.0f] km\n', r1);
fprintf('终点位置: [%.0f, %.0f, %.0f] km\n', r2);
fprintf('飞行时间: %.1f 小时\n\n', dt/3600);
% 求解兰伯特问题
[oe, v1, v2] = solve_lambert_problem(r1, r2, dt, mu);
% 显示结果
fprintf('计算结果:\n');
fprintf(' 初始速度: [%.4f, %.4f, %.4f] km/s\n', v1);
fprintf(' 终点速度: [%.4f, %.4f, %.4f] km/s\n', v2);
fprintf(' 轨道类型: %s\n', oe.type);
fprintf(' 半长轴: %.2f km\n', oe.a);
fprintf(' 偏心率: %.6f\n', oe.e);
fprintf(' 近地点半径: %.2f km\n', oe.r_periapsis);
fprintf(' 远地点半径: %.2f km\n', oe.r_apoapsis);
% 可视化
visualize_lambert_solution(r1, r2, v1, v2, oe, mu, dt);
fprintf('\n示例完成!\n');
end
%% 运行快速开始示例
% 取消注释下一行以运行快速开始示例
% quick_start_example();
参考代码 计算兰伯特问题 www.youwenfan.com/cna/96985.html
三、使用说明
1. 基本用法
% 设置参数
mu = 398600.4418; % 地球引力常数
% 定义位置矢量和飞行时间
r1 = [7000; 0; 0]; % 初始位置 (km)
r2 = [0; 7000; 0]; % 终点位置 (km)
dt = 1800; % 飞行时间 (s)
% 求解兰伯特问题
[orbital_elements, v1, v2] = solve_lambert_problem(r1, r2, dt, mu);
% 显示结果
disp('轨道根数:');
disp(orbital_elements);
% 可视化
visualize_lambert_solution(r1, r2, v1, v2, orbital_elements, mu, dt);
2. 高级选项
% 使用所有可选参数
[oe, v1, v2] = solve_lambert_problem(r1, r2, dt, mu, ...
'direction', 'retrograde', ... % 逆行转移
'solution', 'long', ... % 长路径解
'tolerance', 1e-12, ... % 收敛容差
'max_iter', 200); % 最大迭代次数
四、关键特性
-
多种求解方法:
- 普适变量法求解兰伯特方程
- 牛顿-拉弗森迭代确保精度
- 支持短路径和长路径解
-
完整轨道分析:
- 计算经典轨道根数 (a, e, i, Ω, ω, ν)
- 自动识别轨道类型
- 计算轨道能量和角动量
-
可视化功能:
- 三维轨道可视化
- 速度分布图
- 参数摘要显示
-
验证和测试:
- 精度验证测试
- 多种测试用例
- 结果验证功能
-
实用工具:
- 用户友好的输入界面
- 结果导出功能
- 全面的帮助文档
