Gravity Gradient Tether with Tidal Pumping (#961)
Problem
Stations in orbits around moons experience tidal energy drift from the parent planet’s gravity gradient. At Io (orbiting Jupiter at 17.3 km/s), this drift is ~0.03-0.05%/orbit, eventually causing orbit decay and surface impact. The Encke integration (#960) reduces numerical drift but cannot eliminate the physical tidal perturbation.
Solution
A gravity gradient tether provides two functions:
- Attitude stabilization — the tidal torque on an extended mass aligns the station radially (gravity gradient stabilization)
- Orbital correction — oscillating the tether length in phase with the orbital period exchanges energy with the tidal field (tidal pumping), counteracting secular drift
Physics
Gravity gradient attitude
A tether of length L with tip mass m_tip in a gravity field creates a restoring torque that aligns the tether along the local vertical (radial direction from the parent body). The station’s attitude quaternion is set kinematically each tick — no angular velocity dynamics needed.
Tidal pumping
The station records its target semi-major axis a₀ at spawn. Each tick, the controller:
-
Computes current specific orbital energy: E = ½v² - μ/r (relative to parent body)
-
Computes target energy: E₀ = -μ/(2a₀)
-
Computes energy error: δE = E - E₀
-
Applies a radial velocity correction: δv = clamp(-K × δE, ±δv_max)
where K is a proportional gain and δv_max is the tether’s physical capability per tick.
Tether capability
The maximum correction per tick comes from the tidal force differential across the tether:
F_tidal = m_tip × (2μ/r³) × (L/2)
δv_max = F_tidal / m_station × dt
where 2μ/r³ is the tidal gradient from the parent body at the station’s orbital radius r.
Auto-sizing
At spawn, tether parameters are computed from the local environment:
- Length: L = clamp(0.01 × r_orbit, 100m, 10km)
- Tip mass: m_tip = 0.05 × m_station (per tip)
- Target SMA: a₀ = r_orbit (circular orbit at spawn)
Design
Scope
- Stations only (not jump gates or ships)
- Orbital force correction only (no attitude dynamics — kinematic radial alignment each tick)
- Telemetry visible in station info panel
Station model fields
- tether_length (float, meters, set at spawn)
- tether_tip_mass (float, kg, set at spawn)
- target_sma (float, meters, set at spawn)
- tether_energy_error (float, J/kg, updated each tick)
- tether_correction_dv (float, m/s, updated each tick)
Integration
In update_station(), after leapfrog integration:
- Find parent body from station.parent_body
- Apply tidal pumping correction (proportional controller)
- Orient attitude to local vertical
Rendering
- Station mesh oriented along radial (gravity gradient alignment)
- Tether rendered as a billboarded mesh ribbon (16 segments × 2 vertices each = triangle strip) with transverse standing-wave oscillation perpendicular to the tether axis, simulating real tether dynamics.
THREE.Linewas replaced because it renders as 1px on Chrome’s ANGLE backend — invisible on HiDPI displays (#1007).- Ribbon half-width: 3m (6m total physical width)
- Ribbon orientation: perpendicular to camera each frame via
cross(tetherAxis, viewDirection) - Two superimposed sine modes at different frequencies for organic, non-repeating motion
- Amplitude = 1.5% of tether half-length
DoubleSiderendering,frustumCulled: false
- Tension color: base orange (0xff8844) shifts toward cyan (0x44ddff) proportional to |tether_energy_error|, showing when tidal pumping is actively correcting. Lerp factor = clamp(|error| / 100, 0, 1).
- Structure mesh loader retries failed GLB loads every 5 seconds (up to 3 attempts). Without retry, a transient mesh-service failure leaves the station as a permanent placeholder with no tether (#1007).
- Docking tether also rendered as catenary (16 segments) with sag toward the parent body (scene origin); sag magnitude = 8% of tether distance
- Telemetry in station info panel: tether length, energy error, correction delta-v
Config
- tether_pumping_gain: 1e-6 (m/s)/(J/kg)
- tether_max_correction_per_tick: 0.001 m/s
Files
- models.py — tether fields on Station
- nbody.py — apply_tether_tidal_pumping(), attitude in update_station()
- spawning.py — auto-size tether, compute target SMA
- redis_state.py — serialize tether fields
- config.py — tether constants
- grpc_server.py, physics.proto — new proto fields
- ws_state_broadcast.py — include tether in broadcast
- cockpitExtrapolation.js — tether line rendering