vibe coding an orbital mechanics simulation to try out claude code
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.
 
 
 
 
 

8.5 KiB

Orbital Mechanics Simulation - Conceptual Reference

Overview

N-body orbital mechanics simulator using analytical propagation for precise Keplerian trajectories. Supports elliptical, parabolic, and hyperbolic orbits with dynamic Sphere of Influence (SOI) transitions, impulsive burns, and 3D visualization via Raylib.

Architecture

Modular C-style C++ (structs/functions, no classes). Module dependencies:

Main → Simulation → Orbital Mechanics → Physics
      → Maneuver
      → Config Loader

Renderer and UI Renderer depend on Config Loader for display data. Test Utilities are standalone.

Coordinate Frame System

Local Frame: Position/velocity relative to parent body. Primary system for orbital mechanics calculations. Maintains double-precision accuracy for small orbits (LEO, lunar).

Global Frame: Position/velocity from simulation origin (Sun at 0,0,0). Computed as global = parent.global + local. Used for SOI distance calculations and rendering.

Conversion: Simple vector addition/subtraction. All bodies and spacecraft store both local and global coordinates.

Core Data Structures

Vec3

3D vector (x, y, z). Operations: add, sub, cross, scale, magnitude, distance, normalize, dot.

Mat3

3x3 row-major matrix. Used for orbital plane rotations (z-x-z Euler angles).

OrbitalElements

Keplerian elements with union for parabolic/hyperbolic distinction:

struct OrbitalElements {
    union {
        double semi_major_axis;       // elliptical (e<1), hyperbolic (e>1)
        double semi_latus_rectum;     // parabolic (e≈1)
    };
    double eccentricity;
    double true_anomaly;
    double inclination;
    double longitude_of_ascending_node;
    double argument_of_periapsis;
};

CelestialBody

Planet/moon with mass, radius, parent_index, color, orbital elements, local/global coordinates, SOI radius.

Spacecraft

Similar to CelestialBody but without radius or SOI. Supports standalone (parent_index = -1) and orbiting spacecraft.

Maneuver

Impulsive burn: name, craft_index, direction, delta_v, trigger_type, trigger_value, scheduled_dt, executed flag, executed_time.

SimulationState

Top-level container: arrays of bodies/spacecraft/maneuvers (with counts and capacities), time, dt, config_name.

Orbital Propagation Algorithm

Analytical propagation solves Kepler's equations exactly (no integration error, perfect energy conservation).

Common Pattern:

  1. Compute mean motion: n = √(μ/|a|³)
  2. Convert true anomaly to appropriate anomaly form
  3. Advance mean anomaly: M_new = M + n·dt
  4. Solve Kepler's equation for new anomaly
  5. Convert back to true anomaly
  6. Update elements

Elliptical (e < 1): Newton-Raphson on E - e·sin(E) = M. Tolerance: 1e-10, max 50 iterations.

Parabolic (|e-1| < PARABOLIC_TOLERANCE): Barker's equation D + D³/3 = M with closed-form solution using cubic roots. Mean motion: n = √(μ/p³) where p = semi_latus_rectum.

Hyperbolic (e > 1): Newton-Raphson on H - e·sinh(H) = M. Mean motion: n = √(μ/(-a)³) using negative semi-major axis. Initial guess: H = log(2M/e) when e·sinh(M) > M, else H = M.

Orbital Element Reconstruction

Elements are dynamically maintained and reconstructed from Cartesian state when:

  • SOI transitions: Parent changes, local coordinates update
  • Burns: Velocity changes impulsively
  • Velocity drift: |v_local - v_expected| > 1e-6 m/s before propagation

Reconstruction uses cartesian_to_orbital_elements() which handles edge cases (near-circular e < 1e-10, near-parabolic).

Coordinate Transformations

Orbital plane orientation via z-x-z Euler rotation:

R_total = R_z(Ω) · R_x(i) · R_z(ω)

Sequence: argument_of_periapsis (ω) → inclination (i) → longitude_of_ascending_node (Ω).

Forward: orbital_elements_to_cartesian() applies rotation. Reverse: cartesian_to_orbital_elements() computes angles from angular momentum and eccentricity vectors.

Sphere of Influence Mechanics

SOI Radius: Hill sphere approximation r_soi = a × (m/M)^(2/5).

SOI Transitions:

  1. find_dominant_body() called before each physics update
  2. For non-root bodies: stay if distance < parent.soi_radius, else switch to root
  3. For root bodies: find closest body where distance < body.soi_radius
  4. On parent change:
    • Compute global position/velocity from old parent
    • Update parent_index
    • Compute new local coordinates
    • Reconstruct orbital elements

SOI in Loop: Checked for all bodies and spacecraft before physics propagation.

Maneuver System

Burn Directions

  • BURN_PROGRADE: normalized velocity vector
  • BURN_RETROGRADE: opposite velocity
  • BURN_NORMAL: normalized (position × velocity)
  • BURN_ANTINORMAL: opposite normal
  • BURN_RADIAL_IN: -normalized position
  • BURN_RADIAL_OUT: normalized position
  • BURN_CUSTOM: user-specified vector

Exact Position Execution

True anomaly triggers must execute at precise orbital position:

  1. check_maneuver_trigger() calculates scheduled_dt to target anomaly (triggers when angular distance < 0.01 rad)
  2. If scheduled_dt < sim->dt, trigger fires
  3. Propagate spacecraft by scheduled_dt to exact position
  4. Execute burn (apply delta-v, reconstruct elements)
  5. Propagate remaining time (sim->dt - scheduled_dt)
  6. Mark spacecraft as handled to skip in update_spacecraft_physics()

Wraparound handling: When current_nu > 5.0 and future_nu < 1.0, detect 2π→0 crossing at periapsis.

Simulation Loop

Initialization:

  1. create_simulation()
  2. load_system_config() - parse TOML
  3. run_all_config_validations()
  4. initialize_orbital_objects() - convert elements to Cartesian, compute globals, calculate SOI
  5. Main loop begins

Main Loop Order:

  1. update_bodies_physics() - SOI checks, drift detection, propagation
  2. compute_global_coordinates()
  3. execute_pending_maneuvers()
  4. update_spacecraft_physics()
  5. compute_spacecraft_globals()
  6. time += dt

Body Physics Per-Frame:

  • Check SOI via find_dominant_body()
  • Handle transitions (compute global, update parent, compute local, reconstruct elements)
  • Check velocity drift (> 1e-6 m/s) and reconstruct if needed
  • Propagate via propagate_orbital_elements()
  • Update local position/velocity

Orbit Types

Elliptical (e < 1): ε < 0, bound periodic motion. a = -μ/(2ε) > 0.

Parabolic (|e-1| < tolerance): ε ≈ 0, escape trajectory. p = h²/μ.

Hyperbolic (e > 1): ε > 0, unbound. a = -μ/(2ε) < 0.

All satisfy vis-viva: v² = μ(2/r - 1/a).

Configuration

TOML Format: bodies, spacecraft, maneuvers arrays.

Validation Rules:

  • Parent index ordering (parents before children)
  • Orbital element consistency (e ≥ 0, parabolic p > 0, etc.)
  • True anomaly ranges for hyperbolic orbits
  • Mass ratios (MIN_MASS_RATIO = 1000.0 for large-radius bodies)
  • SOI overlap (siblings must not overlap)
  • Nested orbits (grandchild semi-major axis ≤ 5× parent SOI)
  • Initial positions (no overlap with parent)

Testing Utilities

OrbitalMetrics: kinetic_energy, potential_energy, total_energy, orbital_radius, velocity_magnitude, angular_position.

OrbitTracker: Tracks orbit completion via quadrant transitions and total rotation. 3D mode uses orbital elements for inclined orbits.

Energy Functions:

  • KE = 0.5 × m × v²
  • PE = -G × m1 × m2 / r (min distance clamped to 1.0)
  • Total = ΣKE + ΣPE_pairs

Visualization

Renderer (Raylib):

  • XY simulation plane → XZ render plane (90° rotation around X)
  • Scale: 1e-9 (1 unit = 1 billion meters)
  • Relative rendering when body selected
  • Orbit paths with appropriate segment counts
  • Wireframe spheres, child indicators

UI Renderer (raygui):

  • Bottom-left: Sim time, body count, FPS, controls, config
  • Top-left: Objects list with selection
  • Top-right: Selected object details
  • Below info: Maneuver list

Build System

Targets: make, make all, make raylib, make run, make test, make test-build, make clean, make rebuild.

Dependencies: g++ (C++14), raylib (git submodule), raygui (header-only), tomlc17, Catch2 (tests only).

Testing:

make test                    # Run all tests
./orbit_test '[config_name]' # Run specific config
./orbit_test -s '[config]'   # With debug output

Use WithinAbs(expected, tolerance) for floating-point comparisons (NOT Approx()).

Hybrid Documentation Strategy

This document provides high-level concepts and architecture. Per-module summary files (src/*.summary.md) contain detailed function documentation including signatures, parameters, formulas, and edge cases. Use both: this for the big picture, summaries for implementation details.