|
|
|
|
@ -1,4 +1,5 @@
|
|
|
|
|
#include <catch2/catch_test_macros.hpp> |
|
|
|
|
#include <catch2/matchers/catch_matchers_floating_point.hpp> |
|
|
|
|
#include "../src/physics.h" |
|
|
|
|
#include "../src/simulation.h" |
|
|
|
|
#include "../src/orbital_objects.h" |
|
|
|
|
@ -6,6 +7,8 @@
|
|
|
|
|
#include "../src/config_loader.h" |
|
|
|
|
#include <cmath> |
|
|
|
|
|
|
|
|
|
using Catch::Matchers::WithinAbs; |
|
|
|
|
|
|
|
|
|
TEST_CASE("Maneuver loading from config", "[maneuver][config]") { |
|
|
|
|
const double TIME_STEP = 60.0; |
|
|
|
|
|
|
|
|
|
@ -143,3 +146,131 @@ TEST_CASE("Duplicate maneuver names fail config load", "[maneuver][config][error
|
|
|
|
|
|
|
|
|
|
destroy_simulation(sim); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_CASE("Time-triggered burn executes at step boundary", "[maneuver][timing][quantization]") { |
|
|
|
|
const double DT = 10.0; |
|
|
|
|
|
|
|
|
|
SimulationState* sim = create_simulation(10, 10, 100, DT); |
|
|
|
|
REQUIRE(load_system_config(sim, "tests/test_maneuver_planning.toml")); |
|
|
|
|
initialize_orbital_objects(sim); |
|
|
|
|
|
|
|
|
|
// Trigger at t=305.0, steps are at 0, 10, 20, ..., 300, 310
|
|
|
|
|
// Should fire at t=310 (5s late)
|
|
|
|
|
const double BURN_TIME = 305.0; |
|
|
|
|
|
|
|
|
|
Maneuver burn = create_maneuver( |
|
|
|
|
"TestBurst", |
|
|
|
|
0, |
|
|
|
|
BURN_PROGRADE, |
|
|
|
|
10.0, |
|
|
|
|
TRIGGER_TIME, |
|
|
|
|
BURN_TIME |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
int idx = add_maneuver_to_simulation(sim, &burn); |
|
|
|
|
REQUIRE(idx >= 0); |
|
|
|
|
|
|
|
|
|
int steps = 0; |
|
|
|
|
const int MAX_STEPS = 1000; |
|
|
|
|
while (!sim->maneuvers[idx].executed && steps < MAX_STEPS) { |
|
|
|
|
update_simulation(sim); |
|
|
|
|
steps++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
REQUIRE(sim->maneuvers[idx].executed); |
|
|
|
|
INFO("Trigger time: " << BURN_TIME); |
|
|
|
|
INFO("Executed at: " << sim->maneuvers[idx].executed_time); |
|
|
|
|
INFO("Steps taken: " << steps); |
|
|
|
|
INFO("Quantization error: " << (sim->maneuvers[idx].executed_time - BURN_TIME) << " s"); |
|
|
|
|
|
|
|
|
|
double expected_step = std::ceil(BURN_TIME / DT) * DT; |
|
|
|
|
INFO("Expected step: " << expected_step); |
|
|
|
|
REQUIRE(sim->maneuvers[idx].executed_time == expected_step); |
|
|
|
|
REQUIRE_THAT(sim->maneuvers[idx].executed_time - BURN_TIME, WithinAbs(5.0, 0.01)); |
|
|
|
|
|
|
|
|
|
destroy_simulation(sim); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_CASE("Time-triggered burn on exact step boundary", "[maneuver][timing][quantization]") { |
|
|
|
|
const double DT = 10.0; |
|
|
|
|
|
|
|
|
|
SimulationState* sim = create_simulation(10, 10, 100, DT); |
|
|
|
|
REQUIRE(load_system_config(sim, "tests/test_maneuver_planning.toml")); |
|
|
|
|
initialize_orbital_objects(sim); |
|
|
|
|
|
|
|
|
|
// Trigger at exact step boundary
|
|
|
|
|
const double BURN_TIME = 300.0; |
|
|
|
|
|
|
|
|
|
Maneuver burn = create_maneuver( |
|
|
|
|
"TestBurst", |
|
|
|
|
0, |
|
|
|
|
BURN_PROGRADE, |
|
|
|
|
10.0, |
|
|
|
|
TRIGGER_TIME, |
|
|
|
|
BURN_TIME |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
int idx = add_maneuver_to_simulation(sim, &burn); |
|
|
|
|
REQUIRE(idx >= 0); |
|
|
|
|
|
|
|
|
|
int steps = 0; |
|
|
|
|
const int MAX_STEPS = 1000; |
|
|
|
|
while (!sim->maneuvers[idx].executed && steps < MAX_STEPS) { |
|
|
|
|
update_simulation(sim); |
|
|
|
|
steps++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
REQUIRE(sim->maneuvers[idx].executed); |
|
|
|
|
INFO("Trigger time: " << BURN_TIME); |
|
|
|
|
INFO("Executed at: " << sim->maneuvers[idx].executed_time); |
|
|
|
|
INFO("Steps taken: " << steps); |
|
|
|
|
INFO("Quantization error: " << (sim->maneuvers[idx].executed_time - BURN_TIME) << " s"); |
|
|
|
|
|
|
|
|
|
REQUIRE(sim->maneuvers[idx].executed_time == BURN_TIME); |
|
|
|
|
|
|
|
|
|
destroy_simulation(sim); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_CASE("Time-triggered burn quantization error accumulates over long sim", "[maneuver][timing][quantization]") { |
|
|
|
|
const double DT = 10.0; |
|
|
|
|
|
|
|
|
|
SimulationState* sim = create_simulation(10, 10, 100, DT); |
|
|
|
|
REQUIRE(load_system_config(sim, "tests/test_maneuver_planning.toml")); |
|
|
|
|
initialize_orbital_objects(sim); |
|
|
|
|
|
|
|
|
|
// Trigger at a time that's 7s after a step boundary
|
|
|
|
|
const double BURN_TIME = 62807.0; |
|
|
|
|
double expected_step = std::ceil(BURN_TIME / DT) * DT; // 62810
|
|
|
|
|
double quantization_error = expected_step - BURN_TIME; // 3s
|
|
|
|
|
|
|
|
|
|
Maneuver burn = create_maneuver( |
|
|
|
|
"TestBurst", |
|
|
|
|
0, |
|
|
|
|
BURN_PROGRADE, |
|
|
|
|
10.0, |
|
|
|
|
TRIGGER_TIME, |
|
|
|
|
BURN_TIME |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
int idx = add_maneuver_to_simulation(sim, &burn); |
|
|
|
|
REQUIRE(idx >= 0); |
|
|
|
|
|
|
|
|
|
int steps = 0; |
|
|
|
|
const int MAX_STEPS = 10000; |
|
|
|
|
while (!sim->maneuvers[idx].executed && steps < MAX_STEPS) { |
|
|
|
|
update_simulation(sim); |
|
|
|
|
steps++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
REQUIRE(sim->maneuvers[idx].executed); |
|
|
|
|
INFO("Trigger time: " << BURN_TIME); |
|
|
|
|
INFO("Executed at: " << sim->maneuvers[idx].executed_time); |
|
|
|
|
INFO("Steps taken: " << steps); |
|
|
|
|
INFO("Quantization error: " << (sim->maneuvers[idx].executed_time - BURN_TIME) << " s"); |
|
|
|
|
INFO("Expected quantization error: " << quantization_error << " s"); |
|
|
|
|
|
|
|
|
|
REQUIRE(sim->maneuvers[idx].executed_time == expected_step); |
|
|
|
|
REQUIRE_THAT(sim->maneuvers[idx].executed_time - BURN_TIME, WithinAbs(quantization_error, 0.01)); |
|
|
|
|
|
|
|
|
|
destroy_simulation(sim); |
|
|
|
|
} |
|
|
|
|
|