You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
7.1 KiB
195 lines
7.1 KiB
#include "mission_planning.h" |
|
#include <cstdio> |
|
#include <cmath> |
|
|
|
TransferParameters calculate_hohmann_transfer(double r_departure, double r_arrival, |
|
double central_mass) { |
|
TransferParameters params; |
|
|
|
params.periapsis = r_departure; |
|
params.apoapsis = r_arrival; |
|
params.semi_major_axis = (r_departure + r_arrival) / 2.0; |
|
params.eccentricity = (r_arrival - r_departure) / (r_arrival + r_departure); |
|
|
|
params.transfer_time = M_PI * sqrt(pow(params.semi_major_axis, 3) / (G * central_mass)); |
|
|
|
params.departure_velocity = sqrt(G * central_mass * (2.0/r_departure - 1.0/params.semi_major_axis)); |
|
params.arrival_velocity = sqrt(G * central_mass * (2.0/r_arrival - 1.0/params.semi_major_axis)); |
|
|
|
double circular_velocity = sqrt(G * central_mass / r_departure); |
|
params.delta_v_injection = params.departure_velocity - circular_velocity; |
|
|
|
params.delta_v_capture = 0.0; |
|
|
|
double arrival_period = 2.0 * M_PI * sqrt(pow(r_arrival, 3) / (G * central_mass)); |
|
params.phase_angle_deg = calculate_required_phase_angle(params.transfer_time, arrival_period); |
|
|
|
return params; |
|
} |
|
|
|
double calculate_angular_position(CelestialBody* body, CelestialBody* center) { |
|
Vec3 rel_pos = vec3_sub(body->position, center->position); |
|
|
|
double angle = atan2(rel_pos.y, rel_pos.x); |
|
|
|
if (angle < 0.0) { |
|
angle += 2.0 * M_PI; |
|
} |
|
|
|
return angle; |
|
} |
|
|
|
double calculate_required_phase_angle(double transfer_time, double arrival_period) { |
|
double omega_arrival = 2.0 * M_PI / arrival_period; |
|
|
|
double alpha_arrival = omega_arrival * transfer_time; |
|
|
|
double phase_angle_rad = M_PI - alpha_arrival; |
|
|
|
double phase_angle_deg = phase_angle_rad * 180.0 / M_PI; |
|
|
|
while (phase_angle_deg < 0.0) { |
|
phase_angle_deg += 360.0; |
|
} |
|
while (phase_angle_deg >= 360.0) { |
|
phase_angle_deg -= 360.0; |
|
} |
|
|
|
return phase_angle_deg; |
|
} |
|
|
|
bool check_launch_window(SimulationState* sim, int departure_idx, int arrival_idx, |
|
double required_phase_angle_deg, double tolerance_deg) { |
|
if (departure_idx < 0 || departure_idx >= sim->body_count) { |
|
return false; |
|
} |
|
if (arrival_idx < 0 || arrival_idx >= sim->body_count) { |
|
return false; |
|
} |
|
|
|
CelestialBody* departure = &sim->bodies[departure_idx]; |
|
CelestialBody* arrival = &sim->bodies[arrival_idx]; |
|
CelestialBody* sun = &sim->bodies[0]; |
|
|
|
double theta_depart = calculate_angular_position(departure, sun); |
|
double theta_arrival = calculate_angular_position(arrival, sun); |
|
|
|
double current_phase_rad = theta_arrival - theta_depart; |
|
if (current_phase_rad < 0.0) { |
|
current_phase_rad += 2.0 * M_PI; |
|
} |
|
|
|
double current_phase_deg = current_phase_rad * 180.0 / M_PI; |
|
|
|
double error = fabs(current_phase_deg - required_phase_angle_deg); |
|
if (error > 180.0) { |
|
error = fabs(error - 360.0); |
|
} |
|
|
|
return error <= tolerance_deg; |
|
} |
|
|
|
void wait_for_launch_window(SimulationState* sim, int departure_idx, int arrival_idx, |
|
double required_phase_angle_deg, double tolerance_deg) { |
|
const double TIME_STEP = 60.0; |
|
const int STEPS_PER_DAY = (int)(86400.0 / TIME_STEP); |
|
|
|
while (!check_launch_window(sim, departure_idx, arrival_idx, |
|
required_phase_angle_deg, tolerance_deg)) { |
|
for (int i = 0; i < STEPS_PER_DAY; i++) { |
|
update_simulation(sim); |
|
} |
|
} |
|
|
|
printf("Launch window opened at t = %.2f days\n", sim->time / 86400.0); |
|
} |
|
|
|
void initialize_spacecraft_leo(CelestialBody* spacecraft, CelestialBody* parent, |
|
double altitude_m) { |
|
|
|
double orbital_radius = parent->radius + altitude_m; |
|
|
|
Vec3 sun_to_earth = vec3_sub(parent->position, |
|
(Vec3){0.0, 0.0, 0.0}); |
|
Vec3 direction = vec3_normalize(sun_to_earth); |
|
|
|
Vec3 offset = vec3_scale(direction, orbital_radius); |
|
spacecraft->position = vec3_add(parent->position, offset); |
|
|
|
spacecraft->local_position = offset; |
|
|
|
double v_leo = sqrt(G * parent->mass / orbital_radius); |
|
|
|
Vec3 leo_tangent = (Vec3){direction.y, -direction.x, 0.0}; |
|
Vec3 leo_velocity = vec3_scale(leo_tangent, v_leo); |
|
|
|
spacecraft->velocity = vec3_add(parent->velocity, leo_velocity); |
|
spacecraft->local_velocity = leo_velocity; |
|
|
|
spacecraft->semi_major_axis = orbital_radius; |
|
|
|
printf("Spacecraft LEO initialized:\n"); |
|
printf(" Altitude: %.2f km\n", altitude_m / 1000.0); |
|
printf(" Orbital radius: %.2e m\n", orbital_radius); |
|
printf(" LEO velocity: %.2f m/s\n", v_leo); |
|
printf(" Parent: %s\n", parent->name); |
|
} |
|
|
|
// DEPRECATED: This function is no longer needed. Spacecraft positions and velocities |
|
// are now set via TOML config files with semi_major_axis parameter. Use config-based |
|
// initialization instead. This function is kept for reference only and will be |
|
// removed in a future cleanup. |
|
|
|
void apply_transfer_burn(SimulationState* sim, int spacecraft_idx, |
|
int departure_idx, TransferParameters* params) { |
|
CelestialBody* spacecraft = &sim->bodies[spacecraft_idx]; |
|
CelestialBody* departure = &sim->bodies[departure_idx]; |
|
CelestialBody* sun = &sim->bodies[0]; |
|
|
|
Vec3 sun_to_departure = vec3_sub(departure->position, sun->position); |
|
Vec3 sun_to_departure_norm = vec3_normalize(sun_to_departure); |
|
|
|
Vec3 transfer_dir = (Vec3){-sun_to_departure_norm.y, sun_to_departure_norm.x, 0.0}; |
|
Vec3 v_transfer_helio = vec3_scale(transfer_dir, params->departure_velocity); |
|
|
|
Vec3 old_helio = spacecraft->velocity; |
|
Vec3 old_local = spacecraft->local_velocity; |
|
|
|
Vec3 v_transfer_local = vec3_sub(v_transfer_helio, departure->velocity); |
|
|
|
spacecraft->local_velocity = v_transfer_local; |
|
spacecraft->velocity = vec3_add(departure->velocity, spacecraft->local_velocity); |
|
|
|
Vec3 delta_v_local = vec3_sub(spacecraft->local_velocity, old_local); |
|
Vec3 delta_v_helio = vec3_sub(spacecraft->velocity, old_helio); |
|
|
|
printf("Transfer burn applied:\n"); |
|
printf(" Current heliocentric velocity: (%.2f, %.2f, %.2f) m/s\n", |
|
old_helio.x, old_helio.y, old_helio.z); |
|
printf(" Target heliocentric velocity: (%.2f, %.2f, %.2f) m/s\n", |
|
v_transfer_helio.x, v_transfer_helio.y, v_transfer_helio.z); |
|
printf(" Delta-v (local): (%.2f, %.2f, %.2f) m/s\n", |
|
delta_v_local.x, delta_v_local.y, delta_v_local.z); |
|
printf(" Delta-v magnitude: %.2f m/s (%.3f km/s)\n", |
|
vec3_magnitude(delta_v_helio), vec3_magnitude(delta_v_helio) / 1000.0); |
|
} |
|
|
|
double calculate_phase_angle(SimulationState* sim, int departure_idx, int arrival_idx) { |
|
CelestialBody* departure = &sim->bodies[departure_idx]; |
|
CelestialBody* arrival = &sim->bodies[arrival_idx]; |
|
CelestialBody* sun = &sim->bodies[0]; |
|
|
|
double theta_depart = calculate_angular_position(departure, sun); |
|
double theta_arrival = calculate_angular_position(arrival, sun); |
|
|
|
double phase_rad = theta_arrival - theta_depart; |
|
|
|
while (phase_rad < 0.0) { |
|
phase_rad += 2.0 * M_PI; |
|
} |
|
while (phase_rad >= 2.0 * M_PI) { |
|
phase_rad -= 2.0 * M_PI; |
|
} |
|
|
|
return phase_rad * 180.0 / M_PI; |
|
}
|
|
|