Skip to Content

orbitforge target

Synopsis

orbitforge target --plan <PATH> --problem <PATH> [OPTIONS]

Description

Solves the inverse of maneuver. Instead of stating burn magnitudes and seeing where you end up, you state where you want to end up and the corrector adjusts the burns until you get there.

It uses the classic Vary and Achieve formulation: nominate free variables to adjust, nominate goals to hit, and let a differential corrector iterate.

The Jacobian is built by finite differences: each free variable is perturbed by its stated amount, the plan is re-propagated, and the change in each goal is measured. That is why the perturbation size is a parameter you supply.

Options

ParameterTypeUnitDefaultRequiredDescription
--planpathn/a—YesMission-plan JSON used as the initial guess. Same schema as `maneuver`.
--problempathn/a—YesTargeting-problem JSON: vary, achieve, and max_iterations.
--duration-hoursfloath6NoPropagation duration, which is also the goal-evaluation window.
--step-secondsfloats60NoOutput sampling step.
--coaststringn/atwo-bodyNoCoast-arc force model: `two-body`, `j2`, `j4`, or `egm96[:DxO]`.
--solved-planpathn/a—NoWrite the solved mission plan, with the varies applied.
--czmlpathn/a—NoWrite CZML of the solved trajectory.
--jsonpathn/a—NoWrite the full solution: plan, residuals, and result.

Problem schema

{ "vary": [ { "burn": 0, "component": "dv1", "perturbation": 0.1 }, { "burn": 1, "component": "dv1", "perturbation": 0.1 } ], "achieve": [ { "goal": "apoapsis_km", "value": 7100.0, "tolerance": 0.5 }, { "goal": "periapsis_km", "value": 7080.0, "tolerance": 0.5 } ], "max_iterations": 25 }

Vary

FieldMeaning
burnZero-based index into the plan’s burn list
componentdv0, dv1, dv2 for delta-v components in the burn’s frame, or time_s for firing time
perturbationFinite-difference step used to build the Jacobian, in the variable’s own units

Selecting time_s rewrites that burn’s trigger to an elapsed-time trigger, since the solver needs a continuous variable to adjust.

Achieve

goalUnit
sma_kmkm
eccdimensionless
inc_degdeg
raan_degdeg
arg_perigee_degdeg
apoapsis_kmkm, radius as a(1+e)a(1+e)
periapsis_kmkm, radius as a(1−e)a(1-e)

Count your variables and goals. Two free variables and two goals is a square system with a unique solution. More goals than variables is over-constrained and generally has no exact solution; more variables than goals is under-constrained, and the corrector will find one of many.

The example below is deliberately square: two burns, one component each, two goals.

Worked example

Taking the two-burn plan from maneuver and solving for a near-circular orbit at roughly 7090 km:

orbitforge target \ --plan plan.json \ --problem problem.json \ --duration-hours 4 --step-seconds 60 \ --solved-plan solved.json
Converged in 2 iterations: 2 varies, 2 goals. goal ApoapsisKm: target 7100.0000, residual +0.0002 (tol 0.5000) [ok] goal PeriapsisKm: target 7080.0000, residual +0.0002 (tol 0.5000) [ok] Solved mission: total delta-v 114.67 m/s, propellant 14.493 kg, final mass 265.507 kg. Wrote solved plan -> solved.json

Reading the output

FigureValueMeaning
Iterations2Corrections applied before convergence
Residual+0.0002 kmDistance from the goal, against a 0.5 km tolerance
Total delta-v114.67 m/sCost of the solved plan

Two iterations is the expected behavior

The initial guess asked for 30 and 29 m/s and reached a lower orbit than the goals required; the solver raised both burns to a total of 114.67 m/s. It took two iterations because the problem is close to linear over this range: the Jacobian computed at the first step predicted the correction almost exactly, and the second iteration confirmed convergence.

A problem needing many iterations is telling you it is strongly non-linear, and one that reaches max_iterations has not solved at all.

Residuals are far tighter than the tolerance

Both residuals came in at 0.0002 km against a 0.5 km tolerance, roughly 2500 times better than requested. That is normal for a well-conditioned square system: the corrector does not stop at the tolerance, it converges and the tolerance merely defines success.

Tight residuals describe the model, not reality. A solved plan achieves its goals under the coast force model you selected, which defaults to two-body. Under J2 the same burns produce a different orbit, and a real execution adds pointing and magnitude error on top.

Re-run the solved plan through maneuver at higher coast fidelity before treating it as a burn specification.

Choosing the perturbation

The perturbation sets the finite-difference step for the Jacobian, and both extremes fail:

Too smallToo large
The goal change is lost in numerical noise, and the Jacobian is garbageThe linear approximation breaks down, and the predicted correction overshoots

A useful starting point is a value that changes the goal by appreciably more than its tolerance but stays small compared with the variable itself. The 0.1 m/s above, against burns of tens of m/s, is a reasonable ratio.

See also

  • maneuver to propagate a plan directly, and to re-verify a solved plan at higher fidelity.
  • transfer lambert for a closed-form two-body transfer, which makes a good initial guess.
Question? Give us feedbackDocuments Varaha Constellation Designer main (pre-release)
Last updated on