@ -6,6 +6,7 @@
# include "../src/orbital_objects.h"
# include "../src/rendezvous_hohmann.h"
# include "../src/config_loader.h"
# include "../src/test_utilities.h"
# include <cmath>
# include <cstring>
@ -17,8 +18,6 @@ using Catch::Matchers::WithinAbs;
// Helper Functions
// ============================================================================
// TODO: Add find_spacecraft_by_name() to simulation.h interface
// FIXME: This helper should be part of the public simulation API for testability
static int find_spacecraft_by_name ( SimulationState * sim , const char * name ) {
for ( int i = 0 ; i < sim - > craft_count ; i + + ) {
if ( strcmp ( sim - > spacecraft [ i ] . name , name ) = = 0 ) {
@ -48,21 +47,13 @@ TEST_CASE("Config loading for Hohmann transfer", "[rendezvous_hohmann][config]")
REQUIRE ( sim - > spacecraft [ 1 ] . parent_index = = 0 ) ;
REQUIRE ( sim - > spacecraft [ 2 ] . parent_index = = 0 ) ;
// Verify initial orbits
REQUIRE_THAT ( sim - > spacecraft [ 0 ] . orbit . semi_major_axis ,
WithinAbs ( 6.771e6 , 1.0 ) ) ; // 400 km altitude
REQUIRE_THAT ( sim - > spacecraft [ 1 ] . orbit . semi_major_axis ,
WithinAbs ( 6.671e6 , 1.0 ) ) ; // 300 km altitude
REQUIRE_THAT ( sim - > spacecraft [ 2 ] . orbit . semi_major_axis ,
WithinAbs ( 6.871e6 , 1.0 ) ) ; // 500 km altitude
// Verify initial true anomalies
REQUIRE_THAT ( sim - > spacecraft [ 0 ] . orbit . true_anomaly ,
WithinAbs ( 0.0 , 0.001 ) ) ;
REQUIRE_THAT ( sim - > spacecraft [ 1 ] . orbit . true_anomaly ,
WithinAbs ( 4.71238898038469 , 0.001 ) ) ; // 270° = 3π/2
REQUIRE_THAT ( sim - > spacecraft [ 2 ] . orbit . true_anomaly ,
WithinAbs ( 1.5707963267948966 , 0.001 ) ) ; // 90° = π/2
REQUIRE_THAT ( sim - > spacecraft [ 0 ] . orbit . semi_major_axis , WithinAbs ( 6.771e6 , 1.0 ) ) ;
REQUIRE_THAT ( sim - > spacecraft [ 1 ] . orbit . semi_major_axis , WithinAbs ( 6.671e6 , 1.0 ) ) ;
REQUIRE_THAT ( sim - > spacecraft [ 2 ] . orbit . semi_major_axis , WithinAbs ( 6.871e6 , 1.0 ) ) ;
REQUIRE_THAT ( sim - > spacecraft [ 0 ] . orbit . true_anomaly , WithinAbs ( 0.0 , 0.001 ) ) ;
REQUIRE_THAT ( sim - > spacecraft [ 1 ] . orbit . true_anomaly , WithinAbs ( 4.71238898038469 , 0.001 ) ) ;
REQUIRE_THAT ( sim - > spacecraft [ 2 ] . orbit . true_anomaly , WithinAbs ( 1.5707963267948966 , 0.001 ) ) ;
destroy_simulation ( sim ) ;
}
@ -90,33 +81,33 @@ TEST_CASE("Calculate wait time for Hohmann transfer (lower to higher)", "[rendez
double r2 = vec3_magnitude ( target - > local_position ) ;
SECTION ( " Zero angular separation - immediate transfer not possible " ) {
// If chaser is directly behind target, need to wait for target to move ahead
double angular_separation = 0.0 ;
double wait_time = calculate_wait_time_for_hohmann ( r1 , r2 , angular_separation , earth - > mass ) ;
INFO ( " Wait time: " < < wait_time < < " s " ) ;
// Since lower orbit is faster, chaser will catch up, so wait time should be positive
REQUIRE_THAT ( wait_time , WithinAbs ( 1358.16 , 1.0 ) ) ;
// At 0 separation, chaser is faster and needs to be behind target
// Wait time is negative (should have burned already)
REQUIRE_THAT ( wait_time , WithinAbs ( - 1358.16 , 1.0 ) ) ;
}
SECTION ( " Small angular separation " ) {
double angular_separation = 0.5 ; // ~29 degrees
double angular_separation = 0.5 ;
double wait_time = calculate_wait_time_for_hohmann ( r1 , r2 , angular_separation , earth - > mass ) ;
INFO ( " Angular separation: " < < angular_separation < < " rad " ) ;
INFO ( " Wait time: " < < wait_time < < " s " ) ;
REQUIRE_THAT ( wait_time , WithinAbs ( - 18192.7 , 1.0 ) ) ;
REQUIRE_THAT ( wait_time , WithinAbs ( - 20909.0 , 1.0 ) ) ;
}
SECTION ( " Large angular separation (near 2π ) " ) {
double angular_separation = 6.0 ; // ~344 degrees
SECTION ( " Large angular separation (near 2pi ) " ) {
double angular_separation = 6.0 ;
double wait_time = calculate_wait_time_for_hohmann ( r1 , r2 , angular_separation , earth - > mass ) ;
INFO ( " Angular separation: " < < angular_separation < < " rad " ) ;
INFO ( " Wait time: " < < wait_time < < " s " ) ;
REQUIRE_THAT ( wait_time , WithinAbs ( 12431.2 , 1.0 ) ) ;
REQUIRE_THAT ( wait_time , WithinAbs ( 9714.9 , 1.0 ) ) ;
}
destroy_simulation ( sim ) ;
@ -145,22 +136,22 @@ TEST_CASE("Calculate wait time for Hohmann transfer (higher to lower)", "[rendez
double r2 = vec3_magnitude ( target - > local_position ) ;
SECTION ( " Zero angular separation - target must catch up " ) {
// Higher orbit is slower, so target must catch up
double angular_separation = 0.0 ;
double wait_time = calculate_wait_time_for_hohmann ( r1 , r2 , angular_separation , earth - > mass ) ;
INFO ( " Wait time: " < < wait_time < < " s " ) ;
REQUIRE_THAT ( wait_time , WithinAbs ( 1414.46 , 1.0 ) ) ;
// Higher orbit case: chaser is slower, needs to be ahead of target
REQUIRE_THAT ( wait_time , WithinAbs ( - 1414.46 , 1.0 ) ) ;
}
SECTION ( " Small angular separation " ) {
double angular_separation = 0.3 ; // ~17 degrees
double angular_separation = 0.3 ;
double wait_time = calculate_wait_time_for_hohmann ( r1 , r2 , angular_separation , earth - > mass ) ;
INFO ( " Angular separation: " < < angular_separation < < " rad " ) ;
INFO ( " Wait time: " < < wait_time < < " s " ) ;
REQUIRE_THAT ( wait_time , WithinAbs ( 13586.2 , 1.0 ) ) ;
REQUIRE_THAT ( wait_time , WithinAbs ( 10757.3 , 1.0 ) ) ;
}
destroy_simulation ( sim ) ;
@ -196,18 +187,18 @@ TEST_CASE("Calculate required separation for Hohmann transfer", "[rendezvous_hoh
double required_separation = calculate_required_separation_for_hohmann ( r_lower , r_target , earth - > mass ) ;
INFO ( " Required separation: " < < required_separation < < " rad " ) ;
INFO ( " Required separation (deg): " < < required_separation * 180.0 / M_PI < < " ° " ) ;
INFO ( " Required separation (deg): " < < required_separation * 180.0 / M_PI < < " deg " ) ;
REQUIRE_THAT ( required_separation , WithinAbs ( 0.034734 , 0.001 ) ) ;
REQUIRE_THAT ( required_separation , WithinAbs ( - 0.034734 , 0.001 ) ) ; // Chaser faster, needs to be behind
}
SECTION ( " Higher to lower transfer " ) {
double required_separation = calculate_required_separation_for_hohmann ( r_higher , r_target , earth - > mass ) ;
INFO ( " Required separation: " < < required_separation < < " rad " ) ;
INFO ( " Required separation (deg): " < < required_separation * 180.0 / M_PI < < " ° " ) ;
INFO ( " Required separation (deg): " < < required_separation * 180.0 / M_PI < < " deg " ) ;
REQUIRE_THAT ( required_separation , WithinAbs ( - 0.0348625 , 0.001 ) ) ;
REQUIRE_THAT ( required_separation , WithinAbs ( 0.0348625 , 0.001 ) ) ; // Chaser slower, needs to be ahead
}
SECTION ( " Equal radii - no transfer needed " ) {
@ -221,71 +212,363 @@ TEST_CASE("Calculate required separation for Hohmann transfer", "[rendezvous_hoh
destroy_simulation ( sim ) ;
}
SCENARIO ( " Complete Hohmann transfer phasing workflow " , " [rendezvous_hohmann][workflow] " ) {
const double TIME_STEP = 10.0 ;
// ============================================================================
// New Test Cases for Validation and Next Wait Time
// ============================================================================
SimulationState * sim = create_simulation ( 3 , 5 , 10 , TIME_STEP ) ;
TEST_CASE ( " Validate Hohmann transfer parameters " , " [rendezvous_hohmann][validation] " ) {
const double TIME_STEP = 30.0 ;
SimulationState * sim = create_simulation ( 3 , 5 , 10 , TIME_STEP ) ;
REQUIRE ( load_system_config ( sim , " tests/test_rendezvous_hohmann.toml " ) ) ;
initialize_orbital_objects ( sim ) ;
int target_idx = find_spacecraft_by_name ( sim , " Target_Satellite " ) ;
int chaser_lower_idx = find_spacecraft_by_name ( sim , " Chaser_Lower " ) ;
Spacecraft * chaser_lower = & sim - > spacecraft [ 1 ] ;
Spacecraft * chaser_higher = & sim - > spacecraft [ 2 ] ;
Spacecraft * target = & sim - > spacecraft [ 0 ] ;
CelestialBody * earth = & sim - > bodies [ 0 ] ;
REQUIRE ( target_idx > = 0 ) ;
REQUIRE ( chaser_lower_idx > = 0 ) ;
double r_lower = vec3_magnitude ( chaser_lower - > local_position ) ;
double r_higher = vec3_magnitude ( chaser_higher - > local_position ) ;
double r_target = vec3_magnitude ( target - > local_position ) ;
Spacecraft * target = & sim - > spacecraft [ target_idx ] ;
Spacecraft * chaser = & sim - > spacecraft [ chaser_lower_idx ] ;
SECTION ( " Valid lower to higher transfer " ) {
bool valid = validate_hohmann_transfer_parameters ( r_lower , r_target , earth - > mass ) ;
INFO ( " Valid lower to higher: " < < ( valid ? " true " : " false " ) ) ;
REQUIRE ( valid = = true ) ;
}
SECTION ( " Valid higher to lower transfer " ) {
bool valid = validate_hohmann_transfer_parameters ( r_higher , r_target , earth - > mass ) ;
INFO ( " Valid higher to lower: " < < ( valid ? " true " : " false " ) ) ;
REQUIRE ( valid = = true ) ;
}
SECTION ( " Equal radii - invalid (no relative motion) " ) {
bool valid = validate_hohmann_transfer_parameters ( r_target , r_target , earth - > mass ) ;
INFO ( " Equal radii valid: " < < ( valid ? " true " : " false " ) ) ;
REQUIRE ( valid = = false ) ;
}
SECTION ( " Negative initial radius - invalid " ) {
bool valid = validate_hohmann_transfer_parameters ( - 1000.0 , r_target , earth - > mass ) ;
INFO ( " Negative radius valid: " < < ( valid ? " true " : " false " ) ) ;
REQUIRE ( valid = = false ) ;
}
SECTION ( " Negative target radius - invalid " ) {
bool valid = validate_hohmann_transfer_parameters ( r_lower , - 1000.0 , earth - > mass ) ;
INFO ( " Negative target radius valid: " < < ( valid ? " true " : " false " ) ) ;
REQUIRE ( valid = = false ) ;
}
SECTION ( " Zero central mass - invalid " ) {
bool valid = validate_hohmann_transfer_parameters ( r_lower , r_target , 0.0 ) ;
INFO ( " Zero mass valid: " < < ( valid ? " true " : " false " ) ) ;
REQUIRE ( valid = = false ) ;
}
SECTION ( " Negative central mass - invalid " ) {
bool valid = validate_hohmann_transfer_parameters ( r_lower , r_target , - 1.0 ) ;
INFO ( " Negative mass valid: " < < ( valid ? " true " : " false " ) ) ;
REQUIRE ( valid = = false ) ;
}
destroy_simulation ( sim ) ;
}
TEST_CASE ( " Calculate relative orbit period " , " [rendezvous_hohmann][phasing] " ) {
const double TIME_STEP = 30.0 ;
SimulationState * sim = create_simulation ( 3 , 5 , 10 , TIME_STEP ) ;
REQUIRE ( load_system_config ( sim , " tests/test_rendezvous_hohmann.toml " ) ) ;
initialize_orbital_objects ( sim ) ;
Spacecraft * chaser_lower = & sim - > spacecraft [ 1 ] ;
Spacecraft * chaser_higher = & sim - > spacecraft [ 2 ] ;
Spacecraft * target = & sim - > spacecraft [ 0 ] ;
CelestialBody * earth = & sim - > bodies [ 0 ] ;
double r_lower = vec3_magnitude ( chaser_lower - > local_position ) ;
double r_higher = vec3_magnitude ( chaser_higher - > local_position ) ;
double r_target = vec3_magnitude ( target - > local_position ) ;
SECTION ( " Lower to higher transfer " ) {
double rel_period = calculate_relative_orbit_period ( r_lower , r_target , earth - > mass ) ;
INFO ( " Relative orbit period: " < < rel_period < < " s " ) ;
INFO ( " Relative orbit period: " < < rel_period / 3600.0 < < " h " ) ;
REQUIRE ( rel_period > 0.0 ) ;
REQUIRE_THAT ( rel_period , WithinAbs ( 245683.24 , 1.0 ) ) ;
}
SECTION ( " Higher to lower transfer " ) {
double rel_period = calculate_relative_orbit_period ( r_higher , r_target , earth - > mass ) ;
INFO ( " Relative orbit period: " < < rel_period < < " s " ) ;
INFO ( " Relative orbit period: " < < rel_period / 3600.0 < < " h " ) ;
REQUIRE ( rel_period > 0.0 ) ;
REQUIRE_THAT ( rel_period , WithinAbs ( 254924.71 , 1.0 ) ) ;
}
SECTION ( " Very small radius difference - long period " ) {
double r1 = 6770000.0 ;
double r2 = 6771000.0 ;
double rel_period = calculate_relative_orbit_period ( r1 , r2 , earth - > mass ) ;
INFO ( " Relative orbit period: " < < rel_period < < " s " ) ;
INFO ( " Relative orbit period: " < < rel_period / 3600.0 / 24.0 < < " days " ) ;
REQUIRE ( rel_period > 0.0 ) ;
REQUIRE_THAT ( rel_period , WithinAbs ( 25025208.27 , 1.0 ) ) ;
}
SECTION ( " Large radius difference - short period " ) {
double r1 = 6571000.0 ;
double r2 = 7071000.0 ;
double rel_period = calculate_relative_orbit_period ( r1 , r2 , earth - > mass ) ;
INFO ( " Relative orbit period: " < < rel_period < < " s " ) ;
INFO ( " Relative orbit period: " < < rel_period / 3600.0 < < " h " ) ;
REQUIRE ( rel_period > 0.0 ) ;
REQUIRE_THAT ( rel_period , WithinAbs ( 50889.08 , 1.0 ) ) ;
}
destroy_simulation ( sim ) ;
}
TEST_CASE ( " Calculate next valid wait time for Hohmann transfer " , " [rendezvous_hohmann][phasing] " ) {
const double TIME_STEP = 30.0 ;
SimulationState * sim = create_simulation ( 3 , 5 , 10 , TIME_STEP ) ;
REQUIRE ( load_system_config ( sim , " tests/test_rendezvous_hohmann.toml " ) ) ;
initialize_orbital_objects ( sim ) ;
SECTION ( " Calculate and verify phasing for lower-to-higher transfer " ) {
double r1 = vec3_magnitude ( chaser - > local_position ) ;
double r2 = vec3_magnitude ( target - > local_position ) ;
Spacecraft * chaser_lower = & sim - > spacecraft [ 1 ] ;
Spacecraft * chaser_higher = & sim - > spacecraft [ 2 ] ;
Spacecraft * target = & sim - > spacecraft [ 0 ] ;
CelestialBody * earth = & sim - > bodies [ 0 ] ;
INFO ( " Chaser orbit radius: " < < r1 < < " m " ) ;
INFO ( " Target orbit radius: " < < r2 < < " m " ) ;
double r_lower = vec3_magnitude ( chaser_lower - > local_position ) ;
double r_higher = vec3_magnitude ( chaser_higher - > local_position ) ;
double r_target = vec3_magnitude ( target - > local_position ) ;
// Calculate current angular separation
double current_sep = angular_distance ( chaser - > orbit . true_anomaly , target - > orbit . true_anomaly ) ;
SECTION ( " Lower to higher - positive wait time " ) {
double angular_separation = 0.0 ;
double next_wait = calculate_next_hohmann_wait_time ( r_lower , r_target , angular_separation , earth - > mass , TIME_STEP ) ;
INFO ( " Current angular separation: " < < current_sep < < " rad " ) ;
INFO ( " Current angular separation (deg): " < < current_sep * 180.0 / M_PI < < " ° " ) ;
INFO ( " Angular separation: " < < angular_separation < < " rad " ) ;
INFO ( " Next wait time: " < < next_wait < < " s " ) ;
INFO ( " Next wait time: " < < next_wait / 3600.0 < < " h " ) ;
// Calculate required separation for Hohmann
double required_sep = calculate_required_separation_for_hohmann ( r1 , r2 , earth - > mass ) ;
REQUIRE ( next_wait > = TIME_STEP ) ;
REQUIRE_THAT ( next_wait , WithinAbs ( 244325.08 , 1.0 ) ) ;
}
INFO ( " Required separation: " < < required_sep < < " rad " ) ;
INFO ( " Required separation (deg): " < < required_sep * 180.0 / M_PI < < " ° " ) ;
SECTION ( " Higher to lower - negative wait time becomes next cycle " ) {
double angular_separation = 0.0 ;
double next_wait = calculate_next_hohmann_wait_time ( r_higher , r_target , angular_separation , earth - > mass , TIME_STEP ) ;
// Calculate wait time
double wait_time = calculate_wait_time_for_hohmann ( r1 , r2 , current_sep , earth - > mass ) ;
INFO ( " Angular separation: " < < angular_separation < < " rad " ) ;
INFO ( " Next wait time: " < < next_wait < < " s " ) ;
INFO ( " Next wait time: " < < next_wait / 3600.0 < < " h " ) ;
INFO ( " Wait time: " < < wait_time < < " s " ) ;
REQUIRE ( next_wait > = TIME_STEP ) ;
REQUIRE_THAT ( next_wait , WithinAbs ( 253510.25 , 1.0 ) ) ;
}
REQUIRE_THAT ( wait_time , WithinAbs ( - 60062.651728 , 0.1 ) ) ;
SECTION ( " Higher to lower - positive wait time (no adjustment needed) " ) {
double angular_separation = 0.3 ;
double next_wait = calculate_next_hohmann_wait_time ( r_higher , r_target , angular_separation , earth - > mass , TIME_STEP ) ;
// Verify orbits are circular
REQUIRE_THAT ( chaser - > orbit . eccentricity , WithinAbs ( 0.0 , 0.001 ) ) ;
REQUIRE_THAT ( target - > orbit . eccentricity , WithinAbs ( 0.0 , 0.001 ) ) ;
INFO ( " Angular separation: " < < angular_separation < < " rad " ) ;
INFO ( " Next wait time: " < < next_wait < < " s " ) ;
REQUIRE ( next_wait > = TIME_STEP ) ;
REQUIRE_THAT ( next_wait , WithinAbs ( 10757.30 , 1.0 ) ) ;
}
SECTION ( " Calculate Hohmann transfer parameters " ) {
SECTION ( " At required separation - forced to next cycle by min_wait " ) {
double req_sep = calculate_required_separation_for_hohmann ( r_lower , r_target , earth - > mass ) ;
double next_wait = calculate_next_hohmann_wait_time ( r_lower , r_target , req_sep , earth - > mass , TIME_STEP ) ;
INFO ( " Required separation: " < < req_sep < < " rad " ) ;
INFO ( " Next wait time: " < < next_wait < < " s " ) ;
INFO ( " Next wait time: " < < next_wait / 3600.0 < < " h " ) ;
REQUIRE ( next_wait > = TIME_STEP ) ;
REQUIRE_THAT ( next_wait , WithinAbs ( 245683.24 , 1.0 ) ) ;
}
SECTION ( " Force skip to next cycle with large min_wait " ) {
double angular_separation = 0.5 ;
double min_wait = 30000.0 ;
double next_wait = calculate_next_hohmann_wait_time ( r_lower , r_target , angular_separation , earth - > mass , min_wait ) ;
INFO ( " Angular separation: " < < angular_separation < < " rad " ) ;
INFO ( " Min wait: " < < min_wait < < " s " ) ;
INFO ( " Next wait time: " < < next_wait < < " s " ) ;
REQUIRE ( next_wait > = min_wait ) ;
REQUIRE_THAT ( next_wait , WithinAbs ( 224774.23 , 1.0 ) ) ;
}
SECTION ( " Zero min_wait allows immediate transfer " ) {
double angular_separation = 0.3 ;
double next_wait = calculate_next_hohmann_wait_time ( r_higher , r_target , angular_separation , earth - > mass , 0.0 ) ;
INFO ( " Angular separation: " < < angular_separation < < " rad " ) ;
INFO ( " Next wait time: " < < next_wait < < " s " ) ;
REQUIRE ( next_wait > = 0.0 ) ;
REQUIRE_THAT ( next_wait , WithinAbs ( 10757.30 , 1.0 ) ) ;
}
destroy_simulation ( sim ) ;
}
SCENARIO ( " Hohmann transfer rendezvous with validation " , " [rendezvous_hohmann][integration] " ) {
const double TIME_STEP = 0.1 ;
SimulationState * sim = create_simulation ( 3 , 5 , 10 , TIME_STEP ) ;
REQUIRE ( load_system_config ( sim , " tests/test_rendezvous_hohmann.toml " ) ) ;
int target_idx = find_spacecraft_by_name ( sim , " Target_Satellite " ) ;
int chaser_lower_idx = find_spacecraft_by_name ( sim , " Chaser_Lower " ) ;
REQUIRE ( target_idx > = 0 ) ;
REQUIRE ( chaser_lower_idx > = 0 ) ;
Spacecraft * target = & sim - > spacecraft [ target_idx ] ;
Spacecraft * chaser = & sim - > spacecraft [ chaser_lower_idx ] ;
CelestialBody * earth = & sim - > bodies [ 0 ] ;
initialize_orbital_objects ( sim ) ;
SECTION ( " Execute validated Hohmann transfer and verify rendezvous " ) {
double r1 = vec3_magnitude ( chaser - > local_position ) ;
double r2 = vec3_magnitude ( target - > local_position ) ;
// Use existing calculate_hohmann_transfer from maneuver.h
HohmannTransfer hohmann = calculate_hohmann_transfer ( r1 , r2 , earth - > mass ) ;
INFO ( " \n === HOHMANN TRANSFER RENDZVOUS TEST === " ) ;
INFO ( " Initial state: " ) ;
INFO ( " Chaser: r= " < < r1 < < " m, nu= " < < chaser - > orbit . true_anomaly < < " rad " ) ;
INFO ( " Target: r= " < < r2 < < " m, nu= " < < target - > orbit . true_anomaly < < " rad " ) ;
INFO ( " First burn delta-v: " < < hohmann . dv1 < < " m/s " ) ;
INFO ( " Second burn delta-v: " < < hohmann . dv2 < < " m/s " ) ;
INFO ( " Transfer time: " < < hohmann . transfer_time < < " s " ) ;
INFO ( " Target true anomaly: " < < hohmann . true_anomaly_2 < < " rad " ) ;
// Calculate angular separation
double angular_separation = chaser - > orbit . true_anomaly - target - > orbit . true_anomaly ;
while ( angular_separation > M_PI ) angular_separation - = 2.0 * M_PI ;
while ( angular_separation < - M_PI ) angular_separation + = 2.0 * M_PI ;
INFO ( " Angular separation: " < < angular_separation < < " rad " ) ;
REQUIRE_THAT ( hohmann . dv1 , WithinAbs ( 28.699077 , 0.01 ) ) ;
REQUIRE_THAT ( hohmann . dv2 , WithinAbs ( 28.592521 , 0.01 ) ) ;
REQUIRE_THAT ( hohmann . transfer_time , WithinAbs ( 2741.813778 , 0.1 ) ) ;
// Validate parameters before proceeding
REQUIRE ( validate_hohmann_transfer_parameters ( r1 , r2 , earth - > mass ) ) ;
INFO ( " Validation passed " ) ;
// Calculate Hohmann transfer parameters
HohmannTransfer hohmann = calculate_hohmann_transfer ( r1 , r2 , earth - > mass ) ;
double wait_time = calculate_next_hohmann_wait_time ( r1 , r2 , angular_separation , earth - > mass , TIME_STEP ) ;
double arrival_time = wait_time + hohmann . transfer_time ;
INFO ( " \n Transfer parameters: " ) ;
INFO ( " Transfer time: " < < hohmann . transfer_time < < " s " ) ;
INFO ( " DV1 (departure): " < < hohmann . dv1 < < " m/s " ) ;
INFO ( " DV2 (arrival): " < < hohmann . dv2 < < " m/s " ) ;
INFO ( " Wait time: " < < wait_time < < " s " ) ;
INFO ( " Arrival time: " < < arrival_time < < " s " ) ;
// Create departure maneuver
Maneuver departure = create_maneuver (
" Departure_Burn " ,
chaser_lower_idx ,
BURN_PROGRADE ,
hohmann . dv1 ,
TRIGGER_TIME ,
wait_time
) ;
int dep_idx = add_maneuver_to_simulation ( sim , & departure ) ;
REQUIRE ( dep_idx > = 0 ) ;
// Create arrival maneuver
Maneuver arrival = create_maneuver (
" Circularization_Burn " ,
chaser_lower_idx ,
BURN_PROGRADE ,
hohmann . dv2 ,
TRIGGER_TIME ,
arrival_time
) ;
int arr_idx = add_maneuver_to_simulation ( sim , & arrival ) ;
REQUIRE ( arr_idx > = 0 ) ;
// Dump initial state
dump_simulation_state ( sim , " INITIAL STATE " ) ;
// Run simulation
double sim_time = 0.0 ;
const double DT = 1.0 ;
const int MAX_STEPS = 700000 ;
bool transfer_complete = false ;
for ( int i = 0 ; i < MAX_STEPS ; i + + ) {
update_simulation ( sim ) ;
sim_time + = DT ;
// Dump state at key milestones
if ( i = = 0 ) {
dump_simulation_state ( sim , " T=0 (initial) " ) ;
}
if ( i = = int ( wait_time / DT ) ) {
dump_simulation_state ( sim , " JUST BEFORE DEPARTURE " ) ;
}
if ( i = = int ( wait_time / DT ) + 1 ) {
dump_simulation_state ( sim , " AFTER DEPARTURE BURN " ) ;
}
if ( i = = int ( arrival_time / DT ) ) {
dump_simulation_state ( sim , " JUST BEFORE ARRIVAL " ) ;
}
if ( sim - > maneuvers [ arr_idx ] . executed & & ! transfer_complete ) {
dump_simulation_state ( sim , " AFTER ARRIVAL BURN " ) ;
transfer_complete = true ;
break ;
}
}
INFO ( " \n === FINAL STATE === " ) ;
INFO ( " Final time: " < < sim_time < < " s " ) ;
INFO ( " Departure executed: " < < sim - > maneuvers [ dep_idx ] . executed ) ;
INFO ( " Arrival executed: " < < sim - > maneuvers [ arr_idx ] . executed ) ;
dump_simulation_state ( sim , " FINAL STATE " ) ;
// Verify maneuvers executed
REQUIRE ( sim - > maneuvers [ dep_idx ] . executed ) ;
REQUIRE ( sim - > maneuvers [ arr_idx ] . executed ) ;
// Verify rendezvous quality
double final_radius = vec3_magnitude ( chaser - > local_position ) ;
double radius_error = fabs ( final_radius - r2 ) ;
INFO ( " \n Verification: " ) ;
INFO ( " Radius error: " < < radius_error < < " m " ) ;
INFO ( " Chaser eccentricity: " < < chaser - > orbit . eccentricity ) ;
Vec3 chaser_vel = chaser - > local_velocity ;
Vec3 target_vel = target - > local_velocity ;
double chaser_speed = vec3_magnitude ( chaser_vel ) ;
double target_speed = vec3_magnitude ( target_vel ) ;
Vec3 separation = vec3_sub ( chaser - > local_position , target - > local_position ) ;
double separation_distance = vec3_magnitude ( separation ) ;
double relative_velocity = vec3_magnitude ( vec3_sub ( chaser_vel , target_vel ) ) ;
INFO ( " Chaser speed: " < < chaser_speed < < " m/s " ) ;
INFO ( " Target speed: " < < target_speed < < " m/s " ) ;
INFO ( " Separation: " < < separation_distance < < " m " ) ;
INFO ( " Relative velocity: " < < relative_velocity < < " m/s " ) ;
REQUIRE_THAT ( radius_error , WithinAbs ( 10.0 , 10.0 ) ) ;
REQUIRE_THAT ( chaser - > orbit . eccentricity , WithinAbs ( 0.0 , 0.001 ) ) ;
REQUIRE_THAT ( chaser_speed , WithinAbs ( target_speed , 1.0 ) ) ;
REQUIRE_THAT ( separation_distance , WithinAbs ( 0.0 , 100.0 ) ) ;
}
destroy_simulation ( sim ) ;