orbitforge maneuver
Synopsis
orbitforge maneuver --plan <PATH> [OPTIONS]Description
Propagates a spacecraft through a sequence of burns and coast arcs, reporting what each burn cost in delta-v, propellant, and mass.
This executes a plan you supply. To solve for burn parameters that achieve a
target, use target, which wraps this in a differential
corrector.
Options
| Parameter | Type | Unit | Default | Required | Description |
|---|---|---|---|---|---|
--plan | path | n/a | — | Yes | Mission-plan JSON: epoch, initial orbit, thruster, tank, and burns. See the schema below. |
--duration-hours | float | h | 6 | No | Total propagation duration. |
--step-seconds | float | s | 60 | No | Output sampling step. |
--coast | string | n/a | two-body | No | Coast-arc force model: `two-body`, `j2`, `j4`, or `egm96[:DxO]` for embedded spherical harmonics. |
--czml | path | n/a | — | No | Write CZML with orbit and burn markers. |
--oem | path | n/a | — | No | Write the trajectory as a CCSDS OEM (KVN) file. |
--json | path | n/a | — | No | Write the full mission result: samples and burn events. |
Mission plan schema
{
"epoch": "2026-01-01T00:00:00Z",
"initial_orbit": {
"semi_major_axis_km": 6878.0,
"eccentricity": 0.0,
"inclination_deg": 51.6,
"raan_deg": 0.0,
"argument_of_perigee_deg": 0.0,
"true_anomaly_deg": 0.0
},
"thruster": { "isp_s": 220.0, "max_thrust_n": 22.0 },
"tank": { "fuel_kg": 40.0, "dry_mass_kg": 240.0 },
"burns": [
{
"type": "impulsive",
"trigger": { "kind": "at_elapsed", "seconds": 600.0 },
"frame": "ric",
"dv_mps": [0.0, 30.0, 0.0]
},
{
"type": "impulsive",
"trigger": { "kind": "at_apoapsis", "orbit": 1 },
"frame": "ric",
"dv_mps": [0.0, 29.0, 0.0]
}
]
}| Section | Fields | Units |
|---|---|---|
initial_orbit | Osculating Keplerian elements at the epoch | km, deg |
thruster | isp_s, max_thrust_n | s, N |
tank | fuel_kg, dry_mass_kg | kg |
burns | Ordered, non-overlapping, time-ordered | see below |
Burn triggers
kind | Fires |
|---|---|
at_epoch | At an absolute epoch within the window |
at_elapsed | seconds after the mission epoch |
at_apoapsis | At the orbit-th apoapsis after the previous burn |
at_periapsis | At the orbit-th periapsis after the previous burn |
Time triggers are absolute along the mission timeline. Orbit-event triggers are resolved relative to the state left by the previous burn, counted 1-based and strictly after that point.
That relative behavior is what makes a multi-burn sequence composable: the second burn of a transfer fires at the apoapsis the first burn created, without you having to compute when that occurs.
Burn types
type | Fields | Models |
|---|---|---|
impulsive | frame, dv_mps as a 3-vector | An instantaneous velocity change |
finite | frame, direction, thrust_n, duration_s | Constant thrust over a real duration |
Impulsive burns are the right model when the burn is short compared with the orbital period. Finite burns matter for low-thrust systems, where the spacecraft moves substantially during the burn and the impulsive approximation overstates what the burn achieves.
Worked example
A two-burn raise, in the style of a Hohmann transfer:
orbitforge maneuver \
--plan plan.json \
--duration-hours 4 --step-seconds 60 \
--json mission.jsonPropagated 2 burns over 4.0 h: total delta-v 59.00 m/s, propellant 7.553 kg, final mass 272.447 kg.
burn 0 (impulsive, ric): t=600.0 s, dv=30.00 m/s, propellant=3.867 kg, mass_after=276.133 kg
burn 1 (impulsive, ric): t=3472.4 s, dv=29.00 m/s, propellant=3.687 kg, mass_after=272.447 kgReading the output
| Figure | Value | Meaning |
|---|---|---|
| Total delta-v | 59.00 m/s | Sum of both burns |
| Propellant | 7.553 kg | Total consumed, via the rocket equation |
| Final mass | 272.447 kg | 280 kg wet mass less propellant burned |
| Burn 0 | t=600.0 s | Fired exactly when the at_elapsed trigger asked |
| Burn 1 | t=3472.4 s | Resolved from the at_apoapsis trigger |
The apoapsis trigger did the work
Burn 1 was never given a time. It was told to fire at the first apoapsis after burn 0, and the propagator resolved that to 3472.4 seconds.
That figure is itself a check on the physics: burn 0 raised apoapsis at 600 s, and half an orbital period later the spacecraft arrives there. The 2872-second gap is consistent with roughly half the period of the transfer ellipse created by the first burn.
Propellant falls per burn, for a real reason
Burn 0 consumed 3.867 kg for 30 m/s; burn 1 consumed 3.687 kg for 29 m/s. The second burn is not simply cheaper because it is smaller. Propellant per unit delta-v scales with current mass, and the vehicle is lighter after burn 0:
At 276.133 kg rather than 280 kg, the same delta-v costs proportionally less propellant. This is why delta-v, not propellant mass, is the currency of mission design: delta-v is a property of the trajectory, while propellant depends on the mass you happen to be carrying at the time.
Coast-arc fidelity
--coast sets the force model between burns, and it defaults to two-body.
| Setting | Use |
|---|---|
two-body | Short missions, first-order checks |
j2 or j4 | Anything spanning more than a few orbits |
egm96[:DxO] | High-fidelity work with embedded spherical harmonics |
A two-body coast arc is a poor model for a plan spanning many orbits. J2 causes the
orbit plane to regress and the line of apsides to rotate, so an at_apoapsis trigger
many orbits out will fire at a different place than two-body predicts. Raise the coast
fidelity before trusting long sequences.
See also
targetto solve for burn parameters instead of specifying them.stationkeepfor long-horizon delta-v budgets.
main (pre-release)