planner

package
v0.5.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package planner implements trajectory prediction (predictor) and stubs for Phase 3 maneuver-library work (hohmann, lambert) that slip past v0.1.

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidOrbit = errors.New("planner: invalid orbit (r1, r2, mu must be > 0)")

ErrInvalidOrbit is returned when HohmannTransfer is asked to solve for a non-physical input (non-positive radius or mu).

View Source
var ErrNotImplemented = errors.New("planner: not implemented")

ErrNotImplemented is returned by planner entry points that are still stubbed (e.g. Lambert in v0.2).

Functions

func CaptureBurnDeltaV added in v0.3.1

func CaptureBurnDeltaV(vInfinity, muPlanet, rCapture float64) (float64, error)

CaptureBurnDeltaV mirrors EscapeBurnDeltaV for arrival: Δv to drop from a hyperbolic approach (excess speed vInfinity) into a circular orbit of radius rCapture around the destination primary. By symmetry the magnitude equals EscapeBurnDeltaV; provided as a named helper so the transfer-plan layer reads naturally.

func EscapeBurnDeltaV added in v0.3.1

func EscapeBurnDeltaV(vInfinity, muPlanet, rPark float64) (float64, error)

EscapeBurnDeltaV returns the prograde Δv that, applied at periapsis of a circular parking orbit of radius rPark around a primary with gravitational parameter muPlanet, yields a hyperbolic escape trajectory whose excess speed at infinity is vInfinity.

Patched-conic identity (vis-viva at hyperbolic periapsis):

v_peri² = v∞² + 2·µ/r_peri
Δv      = v_peri − v_circ

The result is in m/s (matching the SI used everywhere else in this repo). vInfinity is taken as a magnitude — direction is the caller's concern (typically aligned with the outbound asymptote, which the transfer-plan layer handles via Lambert).

func HohmannTransfer

func HohmannTransfer(r1, r2, mu float64) (dv1, dv2, tTransfer float64, err error)

HohmannTransfer computes the two impulsive burns and transfer time for a circular-to-circular coplanar Hohmann transfer between orbital radii r1 and r2 around a primary with standard gravitational parameter mu. All SI units: r1, r2 in meters, mu in m^3/s^2.

Returned dv1 and dv2 are magnitudes (always ≥ 0). Direction is implicit in r1 vs r2: outbound (r2 > r1) → both burns prograde; inbound → both retrograde. tTransfer is the half-period of the transfer ellipse (time between burn 1 and burn 2).

func LambertSolve

func LambertSolve(r1, r2 orbital.Vec3, dt, mu float64) (v1, v2 orbital.Vec3, err error)

LambertSolve is the single-revolution (N=0) entry point to the Lambert solver. Kept for backward-compat with v0.3.0–v0.3.2 callers; new code should prefer LambertSolveRev with an explicit N.

func LambertSolveRev added in v0.3.3

func LambertSolveRev(r1, r2 orbital.Vec3, dt, mu float64, nRev int) (v1, v2 orbital.Vec3, err error)

LambertSolveRev solves Lambert's problem for an N-revolution transfer: given two position vectors, a time of flight, and a revolution count, find the velocity vectors that connect them on a Keplerian orbit completing exactly N full revs before reaching r2.

Algorithm: Curtis "Orbital Mechanics for Engineering Students" Algorithm 5.2 — universal-variables formulation, Newton-Raphson on z. For N-rev transfers the lower bound on z shifts to (2πN)² (each rev contributes (2π)² to the universal-variable domain); the bracket sweep starts just past that lower bound.

Single branch only — at N ≥ 1 there are typically two time-of-flight solutions per N (a "long" and "short" transfer separated by the minimum-energy critical z). This solver returns whichever branch the bracket sweep lands in first, which is adequate for the porkchop grid's coarse sampling. Multi-branch selection is a v0.4 polish item if it comes up.

func PorkchopGrid added in v0.3.3

func PorkchopGrid(
	muSun float64,
	depState, arrState EphemerisFn,
	epoch0 float64,
	depDays, tofDays []float64,
	muDep, rPark float64,
	muArr, rCapture float64,
) [][]float64

PorkchopGrid evaluates a grid of Lambert transfers and returns per- cell total Δv (departure + arrival, m/s). NaN marks cells where the Lambert solver failed to converge — the TUI can render those as "impossible" pixels.

The returned slice is indexed [tofIdx][depIdx] so rendering row-by- row in the TUI naturally walks TOF vertically and departure day horizontally.

  • epoch0: sim-time in seconds at which depDays[0] is measured. The ephemeris is sampled at epoch0 + depDays[i]*86400 for departure and epoch0 + (depDays[i]+tofDays[j])*86400 for arrival.
  • depState, arrState: body ephemerides (heliocentric r, v).
  • muSun: gravitational parameter of the system primary.
  • muDep, rPark: destination body μ + parking-orbit radius (for departure Δv via the patched-conic identity).
  • muArr, rCapture: arrival body μ + capture-orbit radius.

func PorkchopMinCell added in v0.3.3

func PorkchopMinCell(grid [][]float64) (depIdx, tofIdx int, total float64, ok bool)

PorkchopMinCell scans a grid and returns the (depIdx, tofIdx, total) of the lowest-Δv non-NaN cell. ok=false if the entire grid is NaN.

func Predict

func Predict(start physics.StateVector, mu, totalSeconds float64, samples int) []orbital.Vec3

Predict forward-integrates a shadow StateVector using Verlet, returning a slice of inertial (primary-relative) positions sampled at regular intervals. Used by the maneuver screen for its live preview line.

- start: initial state (post-burn). - mu: gravitational parameter of the primary. - totalSeconds: total sim-time horizon. - samples: number of points to return (inclusive of start).

Types

type EphemerisFn added in v0.3.3

type EphemerisFn func(epoch float64) (r, v orbital.Vec3)

EphemerisFn returns the heliocentric (system-primary-centered) position and velocity of a body at the given sim-time epoch, in SI units (m, m/s). The planner package doesn't know about bodies/orbital elements — callers (typically sim.World) adapt their Kepler/ calculator machinery into this function type.

type TransferLeg added in v0.3.1

type TransferLeg int

TransferLeg names which end of a TransferPlan a node belongs to — helpful for HUDs and logging that want to show "departure" vs "arrival" without having to derive it from PrimaryID.

const (
	LegDeparture TransferLeg = iota
	LegArrival
)

type TransferNode added in v0.3.1

type TransferNode struct {
	Leg          TransferLeg
	PrimaryID    string        // body whose frame the burn was planned in
	DV           float64       // m/s, magnitude
	OffsetTime   time.Duration // time after PlanTransfer returns when this fires
	IsRetrograde bool          // true → retrograde mode; false → prograde
}

TransferNode is a planner-layer description of a single burn that the sim layer will turn into a sim.ManeuverNode. We keep it free of any sim-package dependencies so planner stays a pure math/algorithms surface — sim.PlanTransfer adapts these into sim.ManeuverNodes.

type TransferPlan added in v0.3.1

type TransferPlan struct {
	Departure  TransferNode
	Arrival    TransferNode
	TransferDt time.Duration // coast time (Departure → Arrival)
}

TransferPlan is the two-burn output of an auto-plant transfer. Departure fires at a parking-orbit periapsis around the origin primary; Arrival fires at the destination's SOI/circular-capture radius after the transfer ellipse coast.

func PlanHohmannTransfer added in v0.3.1

func PlanHohmannTransfer(
	muSun float64,
	rDeparture, rArrival float64,
	muDeparture, rPark float64, departureID string,
	muDestination, rCapture float64, destinationID string,
) (TransferPlan, error)

PlanHohmannTransfer constructs a Hohmann-style transfer plan from a circular parking orbit at radius rPark around a departure planet (helios distance rDeparture, gravitational parameter muDeparture) to a circular capture orbit at radius rCapture around a destination planet (helios distance rArrival, gravitational parameter muDestination), all heliocentric distances in the system primary's frame (mu = muSun).

Result Δv magnitudes are the patched-conic Hohmann values:

departure: v∞_dep = sqrt(µ_sun · (2/r_dep − 1/a_t)) − v_dep_orbit
         Δv_dep = EscapeBurnDeltaV(v∞_dep, µ_planet, r_park)
arrival:   v∞_arr = v_arr_orbit − sqrt(µ_sun · (2/r_arr − 1/a_t))
         Δv_arr = CaptureBurnDeltaV(|v∞_arr|, µ_dest, r_capture)

PrimaryIDs are set so the sim layer can render frame-aware glyphs and the planner UI can label the legs. Phasing is *not* accounted for — both burns assume the destination planet is at the right place at the right time, which the v0.3.1 sandbox doesn't enforce. A porkchop-plot screen (deferred to v0.3.2) is the natural next step.

func PlanLambertTransfer added in v0.4.1

func PlanLambertTransfer(
	muSun float64,
	rDep, vDepBody orbital.Vec3,
	rArr, vArrBody orbital.Vec3,
	tof float64,
	muDeparture, rPark float64, departureID string,
	muDestination, rCapture float64, destinationID string,
	depOffset time.Duration,
) (TransferPlan, error)

PlanLambertTransfer builds a two-burn transfer for an arbitrary (departure-time, time-of-flight) pair using a single-rev Lambert solve for the heliocentric coast. Unlike PlanHohmannTransfer which assumes 180° opposition geometry, this supports off-Hohmann launch windows — the same geometry the porkchop grid scores, so Enter-to- plant from the porkchop cursor is a direct call-through.

Inputs: heliocentric state of departure body at t_dep, heliocentric state of arrival body at t_dep + tof, transfer TOF in seconds, plus the parking / capture orbit parameters used for the patched-conic Δv identity (matching PlanHohmannTransfer + PorkchopGrid).

depOffset is the wall-clock delay from "now" (sim-time at planning) until the departure burn; it becomes the Departure node's OffsetTime. The Arrival node's OffsetTime is depOffset + tof.

Retrograde flags follow the same outbound/inbound rule as PlanHohmannTransfer: outbound (|rArr| > |rDep|) gets a prograde departure + retrograde arrival; inbound flips both. Lambert geometry varies more than Hohmann's 180° opposition, but the radius-based sign captures the common case well enough for the porkchop cursor and we can revisit if off-Hohmann arrivals need a sharper rule.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL