Skip to content

High-Precision Orbit Propagator

API reference for the numerical (force-model) propagator: satkit.propagate integrates a Cartesian state under a configurable force model (gravity field, Sun/Moon, drag, radiation pressure, tides, relativity). It is one of three ways to move a satellite forward in time in satkit — pick by what you have and how accurate you need to be:

you have use what it does
a Cartesian state and a force model this page — satkit.propagate / satstate.propagate numerical integration, the most accurate; needs the ephemeris and EOP data files
a TLE / OMM element set satkit.sgp4 the analytic SGP4/SDP4 theory the elements were fitted with; km-level accuracy for days; no data files
classical elements and an unperturbed (two-body) model satkit.kepler.propagate advances the anomaly only; instantaneous, no data files; see the Keplerian Elements guide

For background on the numerical propagator, see:

propagate(state=None, begin=None, end=None, *, pos=None, vel=None, duration=None, duration_secs=None, duration_days=None, output_phi=False, propsettings=None, satproperties=None)

High-precision orbit propagator

Propagate orbits with high-precision force modeling via adaptive Runge-Kutta methods (default is order 9/8).

Parameters:

Name Type Description Default
state ArrayLike | None

6-element numpy array representing satellite GCRF position and velocity in meters and meters/second. Required unless pos and vel are given

None
begin time | None

Time at which satellite is at input state. Required (TypeError if omitted); its None default only lets state be omitted in favour of pos and vel

None

Other Parameters:

Name Type Description
end time | None

Time at which new position and velocity will be computed

duration duration | None

Duration from begin at which new position & velocity will be computed

duration_secs float | None

Duration in seconds from begin at which new position and velocity will be computed

duration_days float | None

Duration in days from begin at which new position and velocity will be computed

output_phi bool

Output 6x6 state transition matrix between begin and end times. Default is False

propsettings propsettings | None

Settings for the propagation; if omitted, defaults are used

satproperties satproperties | None

Drag and radiation pressure susceptibility of satellite

pos ArrayLike | None

GCRF position in meters; replaces the first three elements of state, or stands in for state together with vel

vel ArrayLike | None

GCRF velocity in meters/second; replaces the last three elements of state

Returns:

Name Type Description
propresult propresult

Propagation result object holding state outputs, statistics, and dense output if requested

Notes

Propagates satellite ephemeris (position, velocity in GCRF & time) to new time and outputs new position and velocity via Runge-Kutta integration. Inputs and outputs are all in the Geocentric Celestial Reference Frame (GCRF).

Included forces:

  • Earth gravity with higher-order spherical-harmonic terms
  • Sun, Moon gravity
  • Solid Earth tides (IERS 2010 Step 1 by default; propsettings.tide_model selects tidemodel.solid_step1, tidemodel.solid_full or tidemodel.none)
  • General relativity (IERS 2010 Eq. 10.12; propsettings.use_relativistic_correction)
  • Radiation pressure
  • Atmospheric drag: NRL-MSISE 2000 density model, with option to include space weather effects

An end time is required: pass end or one of duration, duration_secs, duration_days (TypeError if none is given; ValueError for a NaN or infinite duration_secs / duration_days).

For future propagation (beyond available data files):

  • Earth orientation parameters use the last available values (constant extrapolation)
  • Space weather past the observed record comes from the NOAA/SWPC 45-day forecast and then NASA's MSAFE monthly forecast, which carries a climatological Ap. With no space-weather table at all, F10.7 = F10.7A = 150 and Ap = 4.
Example
import numpy as np

# Define initial state in GCRF (position in meters, velocity in m/s)
state = np.array([6.781e6, 0, 0, 0, 7.5e3, 0])
t0 = satkit.time(2024, 1, 1)

# Propagate forward by 1 day
result = satkit.propagate(state, t0, duration_days=1.0)
print(f"End position: {result.pos} m")
print(f"End velocity: {result.vel} m/s")

# Interpolate at intermediate time
t_mid = t0 + satkit.duration(hours=12)
mid_state = result.interp(t_mid)

propresult

Results of a satellite propagation

This class lets the user access results of the satellite propagation

Notes

If enable_interp is set to True in the propagation settings, the propresult object can be used to interpolate solutions at any time between the begin and end times of the propagation via the interp method.

pos property

GCRF position of satellite, meters

Returns:

Type Description
NDArray[float64]

3-element numpy array representing GCRF position (meters) at end of propagation

vel property

GCRF velocity of satellite, meters/second

Returns:

Type Description
NDArray[float64]

3-element numpy array representing GCRF velocity in meters/second at end of propagation

state property

6-element end state (pos + vel) of satellite in meters & meters/second

Returns:

Type Description
NDArray[float64]

6-element numpy array representing state of satellite in meters & meters/second

state_end property

6-element state (pos + vel) of satellite in meters & meters/second at end of propagation

Notes: - This is the same as the "state" property

Returns:

Type Description
NDArray[float64]

6-element numpy array representing state of satellite in meters & meters/second

state_begin property

6-element state (pos + vel) of satellite in meters & meters/second at begin of propagation Returns: 6-element numpy array representing state of satellite in meters & meters/second at begin of propagation

time property

Time at which state is valid

Returns:

Type Description
_Time

Time at which state is valid

time_end property

Time at which state is valid

Notes: - This is identical to "time" property

Returns:

Type Description
_Time

Time at which state is valid

time_begin property

Time at which state_begin is valid

Returns:

Type Description
_Time

Time at which state_begin is valid

stats property

Statistics of propagation

Returns:

Name Type Description
propstats propstats

Object containing statistics of propagation

next_step_secs property

Step the integrator would take next, seconds: its working stride at time_end (the controller's last unclamped proposal for the adaptive integrators, the fixed step for integrator.gauss_jackson8, 0 for a zero-duration propagation). Signed like the propagation direction. Pass it as propsettings.initial_step_secs to continue this arc without the start-up ramp.

can_interp property

Whether this result supports interpolation

Returns:

Type Description
bool

True if dense output is available for interpolation

phi property

State transition matrix

Returns:

Type Description
NDArray[float64] | None

6x6 numpy array representing state transition matrix or None if not computed. Maps a perturbation of the begin state (meters, m/s) to the end state (meters, m/s), so blocks are unitless, seconds, 1/seconds, unitless.

interp(time, output_phi)

interp(time: TimeScalar, output_phi: typing.Literal[False] = False) -> npt.NDArray[np.float64]
interp(time: TimeScalar, output_phi: typing.Literal[True]) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]
interp(time: TimeArrayLike, output_phi: typing.Literal[False] = False) -> npt.NDArray[np.float64]
interp(time: TimeArrayLike, output_phi: typing.Literal[True]) -> list[tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]]
interp(time: TimeInput, output_phi: bool) -> npt.NDArray[np.float64] | tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]] | list[tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]]

Interpolate the GCRF state at one or more times between the begin and end times

Parameters:

Name Type Description Default
time TimeInput

time(s) at which to interpolate: a single time, or a list or 1-D array of times

required
output_phi bool

also return the 6x6 state transition matrix. Default False

required

Returns:

Type Description
NDArray[float64] | tuple[NDArray[float64], NDArray[float64]] | list[tuple[NDArray[float64], NDArray[float64]]]

npt.NDArray[np.float64] | tuple | list[tuple]: 6-element state [x, y, z, vx, vy, vz] in meters and m/s for a single time; for a list or array of N times, one (N, 6) array ((0, 6) for an empty list). With output_phi=True, a (state, phi) tuple, where phi is the 6x6 state transition matrix, or a list of them for a list of times

Raises:

Type Description
ValueError

if output_phi is True but the propagation did not compute the state transition matrix (propagate with output_phi=True), or a time is outside the interpolation range

propsettings

This class contains settings used in the high-precision orbit propagator part of the "satkit" python toolbox

Notes
  • Default settings:
    • abs_error: 1e-8
    • rel_error: 1e-8
    • gravity_degree: 4
    • gravity_order: 4
    • gravity_model: gravmodel.egm2008
    • use_spaceweather: True
    • use_sun_gravity: True
    • use_moon_gravity: True
    • tide_model: tidemodel.solid_step1
    • use_relativistic_correction: True
    • enable_interp: True
    • integrator: integrator.rkv98
    • gj_step_seconds: 60.0
    • max_steps: 1_000_000
  • enable_interp enables high-precision interpolation of state between begin and end times via the returned function, it is enabled by default. There is a small increase in computational efficiency if set to false

abs_error property writable

Maximum absolute value of error for any element in propagated state following ODE integration

Returns:

Type Description
float

Maximum absolute value of error for any element in propagated state following ODE integration, in the units of the state (meters for position elements, m/s for velocity elements); default is 1e-8

rel_error property writable

Maximum relative error of any element in propagated state following ODE integration

Returns:

Type Description
float

Maximum relative error of any element in propagated state following ODE integration, unitless; default is 1e-8

gravity_degree property writable

Maximum degree of spherical harmonic gravity model

Returns:

Type Description
int

Maximum degree of spherical harmonic gravity model, default is 4

gravity_order property writable

Maximum order of spherical harmonic gravity model

Returns:

Type Description
int

Maximum order of spherical harmonic gravity model, default is same as gravity_degree

use_sun_gravity property writable

Include sun third-body gravitational perturbation

Returns:

Type Description
bool

Whether sun gravity is enabled, default is True

use_moon_gravity property writable

Include moon third-body gravitational perturbation

Returns:

Type Description
bool

Whether moon gravity is enabled, default is True

use_spaceweather property writable

Use space weather data when computing atmospheric density for drag forces

Notes:

  • Space weather data can have a large effect on the density of the atmosphere
  • This can be important for accurate drag force calculations
  • Space weather data is updated every 3 hours. Most-recent data can be downloaded with satkit.utils.update_datafiles()
  • Default value is True

Returns:

Type Description
bool

Indicate whether or not space weather data should be used when computing atmospheric density for drag forces

tide_model property writable

Solid Earth tide model fidelity.

Default is tidemodel.solid_step1 (IERS 2010 §6.2.1 frequency-independent Love-number response). Set to tidemodel.none to disable.

use_relativistic_correction property writable

Include the general-relativistic acceleration of IERS 2010 §10.3 Eq. 10.12 (PPN β = γ = 1): the Schwarzschild term, geodesic (de Sitter) precession 2 (Ω × v) from the Earth's heliocentric motion, and Lense–Thirring frame dragging from the Earth's spin. Default is True.

The Schwarzschild term dominates below GEO (omitting it costs ~1 m/day at GPS altitude); the geodesic term dominates beyond ~100,000 km (~1 m over 7 days at 200,000 km). Computational cost is negligible. Matches GMAT's RelativisticCorrection.

require_eop_coverage property writable

Raise RuntimeError from propagate if the span is not inside the loaded Earth-orientation-parameter (EOP) table: past its end (instead of holding the last EOP row constant) or before its start, 1973-01-02 (instead of using zero EOP, UT1 = UTC), each otherwise with a one-time warning. Default False.

Polar motion and UT1−UTC drift by ~0.1 arcsec / ~10 ms over a few months — metres at LEO — and zero EOP is off by up to ~12 arcsec (hundreds of metres at LEO), so set this for precision work and refresh the data files with satkit.utils.update_datafiles() when it trips past the end. See satkit.frametransform.eop_coverage and eop_status.

initial_step_secs property writable

First step (seconds) the adaptive integrators attempt, or None for the default, derived from the initial state, the tolerances and the integrator order as 1.5 * |r|/|v| * tol**(1/(p+1)) with tol = rel_error + abs_error/|r| (about 170 s for rkv98 at 1e-9 in LEO; within a factor of ~2.5 of the settled stride, which the step controller closes within a step or two).

Set it to a previous propresult.next_step_secs to warm-start a follow-on arc at full stride. A magnitude: backward propagation applies the sign, and a value longer than the arc is clamped to it. Ignored by integrator.gauss_jackson8. Zero or non-finite raises RuntimeError from propagate.

enable_interp property writable

Store intermediate data that allows for fast high-precision interpolation of state between begin and end times.

When False, no dense output is stored and integrator.rkv98 runs its 16-stage no-interpolant tableau (same order and error control, 24% fewer force evaluations per step).

gravity_model property writable

Gravity model used for Earth gravity computation

Returns:

Name Type Description
gravmodel gravmodel

The gravity model, default is gravmodel.egm2008

integrator property writable

ODE integrator used for orbit propagation

Returns:

Name Type Description
integrator integrator

The integrator, default is integrator.rkv98

gj_step_seconds property writable

Fixed step size (seconds) used by integrator.gauss_jackson8.

Ignored by adaptive integrators. Typical values: 30-120 s for LEO, 60-300 s for MEO, 300-600 s for GEO.

Returns:

Type Description
float

Fixed step size in seconds, default is 60.0

max_steps property writable

Maximum number of integrator steps before the propagator aborts.

Applies to all integrators (adaptive Runge-Kutta, Rosenbrock, and Gauss-Jackson 8). Increase for very long propagation arcs or tight tolerances.

Returns:

Type Description
int

Maximum steps, default is 1_000_000

__init__(*, abs_error=1e-08, rel_error=1e-08, gravity_degree=4, gravity_order=None, gravity_model=..., use_spaceweather=True, use_sun_gravity=True, use_moon_gravity=True, tide_model=..., use_relativistic_correction=True, enable_interp=True, integrator=..., gj_step_seconds=60.0, max_steps=1000000, require_eop_coverage=False, initial_step_secs=None)

Create propagation settings object used to configure high-precision orbit propagator

Parameters:

Name Type Description Default
abs_error float

Maximum absolute value of error for any element in propagated state following ODE integration, in the units of the state (meters for position elements, m/s for velocity elements). Default is 1e-8

1e-08
rel_error float

Maximum relative error of any element in propagated state following ODE integration, unitless. Default is 1e-8

1e-08
gravity_degree int

Maximum degree of spherical harmonic gravity model, at most 70 (ValueError above that). Default is 4

4
gravity_order int | None

Maximum order of spherical harmonic gravity model. Must be <= gravity_degree (and so at most 70; ValueError otherwise). Default is same as gravity_degree

None
gravity_model gravmodel

Gravity model to use. Default is gravmodel.egm2008

...
use_spaceweather bool

Use space weather data when computing atmospheric density for drag forces. Default is True

True
use_sun_gravity bool

Include sun third-body gravitational perturbation. Default is True

True
use_moon_gravity bool

Include moon third-body gravitational perturbation. Default is True

True
tide_model tidemodel

Solid Earth tide model. Default is tidemodel.solid_step1 (IERS 2010 §6.2.1 frequency-independent Love-number response). Use tidemodel.none to disable (e.g., for reproducibility with pre-tide releases).

...
use_relativistic_correction bool

Include the general-relativistic acceleration of IERS 2010 §10.3 Eq. 10.12 (β=γ=1): Schwarzschild + geodesic (de Sitter) precession + Lense-Thirring. Default is True. Its position effect depends on the orbit, propagation arc, and fitted parameters (~1 m/day at GPS altitude if omitted; the geodesic term dominates beyond ~100,000 km); cost is negligible.

True
enable_interp bool

Store intermediate data that allows for fast high-precision interpolation of state between begin and end times. Default is True. When False, no dense output is stored and integrator.rkv98 runs its 16-stage no-interpolant tableau (same order and error control, 24% fewer force evaluations per step).

True
integrator integrator

ODE integrator to use. Default is integrator.rkv98

...
gj_step_seconds float

Fixed step size (seconds) used by integrator.gauss_jackson8. Ignored by adaptive integrators. Typical values: 30-120 s for LEO, 60-300 s for MEO, 300-600 s for GEO. Default is 60.0.

60.0
max_steps int

Maximum number of integrator steps before the propagator aborts with a max-steps error. Applies to all integrators (adaptive Runge-Kutta, Rosenbrock, and Gauss-Jackson 8). Default is 1_000_000, which covers very long propagation arcs with plenty of headroom. Lower for a tighter runaway-propagation safeguard.

1000000
require_eop_coverage bool

Raise RuntimeError if the propagation span is not inside the loaded Earth-orientation-parameter (EOP) table: past its end (instead of holding the last EOP row constant) or before its start, 1973-01-02 (instead of using zero EOP), each otherwise with a one-time warning. Default is False. See satkit.frametransform.eop_coverage / eop_status.

False
initial_step_secs float | None

First step (seconds) the adaptive integrators attempt. Default None: derived from the initial state, the tolerances and the integrator order as 1.5 * |r|/|v| * tol**(1/(p+1)) with tol = rel_error + abs_error/|r| (about 170 s for rkv98 at 1e-9 in LEO; within a factor of ~2.5 of the settled stride). Set it to a previous propresult.next_step_secs to warm-start a follow-on arc at full stride. Ignored by integrator.gauss_jackson8.

None

Returns:

Name Type Description
propsettings None

New propsettings object with default settings

Example
settings = satkit.propsettings(
    gravity_degree=16,
    abs_error=1e-10,
    rel_error=1e-10,
    gravity_model=satkit.gravmodel.egm96,
    integrator=satkit.integrator.rkts54,
)

precompute_terms(begin, end, step=None)

Precompute terms for fast interpolation of state between begin and end times

This can be used, for example, to compute sun and moon positions only once if propagating many satellites over the same time period

Parameters:

Name Type Description Default
begin time

Begin time of propagation

required
end time

End time of propagation

required
step duration | float | timedelta

Step size for interpolation. Default = 60 seconds. float is interpreted as seconds.

None

integrator

Choice of ODE integrator for orbit propagation

Available integrators, from highest to lowest order:

  • rkv98 - Verner 9(8) with 8th-degree dense output, 21 stages (default)
  • rkv98_nointerp - Verner 9(8) without interpolation, 16 stages
  • rkv87 - Verner 8(7) with 7th-degree dense output, 17 stages
  • rkv65 - Verner 6(5) with 6th-degree dense output, 10 stages
  • rkts54 - Tsitouras 5(4) with FSAL, 7 stages
  • rodas4 - RODAS4 L-stable Rosenbrock 4(3), 6 stages. For stiff problems.
  • gauss_jackson8 - Gauss-Jackson 8, fixed-step multistep predictor-corrector. For high-precision long-duration orbit propagation (days to months).

Higher-order integrators can take larger time steps for the same accuracy, so despite having more stages per step, they often require fewer total function evaluations. For typical orbit propagation, rkv98 (the default) is recommended. For faster but lower-accuracy propagation, rkts54 or rkv65 can be used. For stiff problems (re-entry, very low perigee), rodas4 is recommended. For long-duration high-precision propagation of smooth orbits, gauss_jackson8 typically uses 3-10× fewer force evaluations than rkv98 at comparable accuracy — but it requires a user-chosen fixed step size (gj_step_seconds), does not handle discontinuities such as impulsive maneuvers, and needs ≥9 steps of startup, so it's unsuitable for very short propagations.

rkv98 class-attribute

Verner 9(8) with 8th-degree dense output, 21 stages (default)

Highest accuracy integrator. Recommended for precision orbit propagation.

rkv98_nointerp class-attribute

Verner 9(8) without interpolation, 16 stages

Same stepping accuracy as rkv98 but skips interpolation stages. Slightly faster when dense output is not needed (enable_interp=False).

rkv87 class-attribute

Verner 8(7) with 7th-degree dense output, 17 stages

rkv65 class-attribute

Verner 6(5) with 6th-degree dense output, 10 stages

rkts54 class-attribute

Tsitouras 5(4) with FSAL, 7 stages

Fastest integrator. Good for quick propagations where high accuracy is not critical.

rodas4 class-attribute

RODAS4 — L-stable Rosenbrock 4(3), 6 stages

Implicit solver for stiff problems such as re-entry or very low perigee orbits. Uses analytical Jacobian. Does not support dense output interpolation or state transition matrix (output_phi) propagation.

gauss_jackson8 class-attribute

Gauss-Jackson 8 — 8th-order fixed-step multistep predictor-corrector

Specialised for 2nd-order ODEs (r'' = f(t, r, v)). The dominant integrator in high-precision astrodynamics codes (GMAT, STK, ODTK). Typically uses 3-10× fewer force evaluations than rkv98 at comparable accuracy on smooth long-duration orbit propagation.

Uses a fixed step size set via propsettings.gj_step_seconds. Supports dense output interpolation (quintic Hermite, 5th-order). Does not support state transition matrix (output_phi) propagation. Not recommended for highly eccentric orbits or integration across discontinuities (eclipse boundaries, impulsive maneuvers).

tidemodel

Solid Earth tide model fidelity for high-precision orbit propagation.

Solid Earth tides deform the Earth under lunar and solar gravitational attraction, perturbing the gravity field. The effect is small (~0.3 m position drift over half a day at GEO; ~1 m/day at GPS altitude) but matters for sub-meter-class propagation accuracy.

Implements IERS Conventions 2010, Chapter 6.

Available models:

  • none — no solid Earth tide correction
  • solid_step1 — IERS §6.2.1 Step 1, frequency-independent Love-number response (default). ≈99% of the total signal.
  • solid_full — Step 1 + §6.2.2 Step 2 frequency-dependent corrections. Step 2 is not yet implemented; currently behaves as solid_step1.

none class-attribute

No solid Earth tide correction.

solid_step1 class-attribute

IERS 2010 §6.2.1 Step 1 — frequency-independent Love-number response. Accounts for ≈99% of the solid-tide signal at ~5% per-ydot overhead. Default.

solid_full class-attribute

IERS 2010 Step 1 + Step 2 (frequency-dependent corrections). Step 2 is not yet implemented; currently behaves as solid_step1.

propstats

Statistics of a satellite propagation

num_eval property

Number of function evaluations

num_accept property

Number of accepted steps in adaptive RK integrator

num_reject property

Number of rejected steps in adaptive RK integrator

satproperties

Satellite properties relevant for drag, radiation pressure, and thrust

This class lets the satellite radiation pressure, drag, and thrust parameters be set for duration of propagation.

Attributes:

Name Type Description
cdaoverm float

Coefficient of drag times area over mass in m^2/kg

craoverm float

Coefficient of radiation pressure times area over mass in m^2/kg

thrusts list[thrust]

List of continuous thrust arcs

ecom ecomparams | None

ECOM empirical solar-radiation-pressure coefficients, added to the cannonball term (use craoverm=0 for a pure ECOM model). See :class:ecomparams for the conventions and the "ECOM Solar Radiation Pressure" tutorial for a fit against IGS GPS orbits.

cdaoverm property writable

Coefficient of drag times area over mass. Units are m^2/kg

craoverm property writable

Coefficient of radiation pressure times area over mass. Units are m^2/kg

thrusts property writable

List of continuous thrust arcs

ecom property writable

ECOM solar-radiation-pressure coefficients, or None

When set, the ECOM acceleration (see :class:ecomparams for the DYB frame, sign and eclipse conventions) is added to the cannonball term craoverm; use craoverm=0 for a pure ECOM model. The "ECOM Solar Radiation Pressure" tutorial shows how to fit the coefficients to IGS GPS orbits.

__init__(*, cdaoverm=0, craoverm=0, thrusts=None, ecom=None)

Create a satproperties object

All arguments are keyword-only; a positional call raises TypeError. (Earlier releases read positional arguments as (craoverm, cdaoverm), the reverse of the documented order, so scripts that passed them positionally had drag and radiation pressure swapped.)

Other Parameters:

Name Type Description
cdaoverm float

Coefficient of drag times area over mass in m^2/kg

craoverm float

Coefficient of radiation pressure times area over mass in m^2/kg

thrusts list[thrust]

List of continuous thrust arcs

ecom ecomparams

ECOM solar-radiation-pressure coefficients

Example:

import satkit as sk

t0 = sk.time(2024, 1, 1)
t1 = t0 + sk.duration.from_hours(2)

props = sk.satproperties(
    cdaoverm=0.01,
    thrusts=[sk.thrust.constant([0, 1e-4, 0], t0, t1, frame=sk.frame.RTN)]
)

# GNSS-style empirical SRP instead of the cannonball
props = sk.satproperties(craoverm=0.0, ecom=sk.ecomparams.reduced(-1e-7, 0, 0, 0, 0))

ecomparams

Empirical CODE Orbit Model (ECOM) solar-radiation-pressure coefficients

ECOM expresses the non-gravitational acceleration of a (nominally yaw-steering) satellite in a Sun-oriented frame with constant and harmonic terms. The coefficients are normally estimated in orbit determination; satkit propagates with the values you supply.

Coefficients (all accelerations in m/s² at 1 AU; typical GPS sizes in nm/s²):

d0        e_D (toward Sun), constant, all models      -80 to -110 (negative)
y0        e_Y (solar-panel axis), constant, all       ~1  (attitude/thermal Y-bias)
b0        e_B, constant, all                          ~1-5, varies with beta
dc, ds    e_D, cos/sin phi, ECOM1 (phi = u)           <~1
yc, ys    e_Y, cos/sin phi, ECOM1                     <~1
bc, bs    e_B, cos/sin phi; reduced/ECOM1 (phi = u), ECOM2's B1c/B1s (phi = du)  <~2
d2c, d2s  e_D, cos/sin 2*du, ECOM2                    few (eclipse seasons)
d4c, d4s  e_D, cos/sin 4*du, ECOM2                    few (eclipse seasons)

Experimental: this interface is new and may be reshaped in a minor release; the physics and conventions are stable.

Frame (GCRF), with r the satellite position and s the Sun position:

  • e_D = unit(s - r) — satellite → Sun
  • e_Y = unit(e_D × r̂) — solar-panel rotation axis
  • e_B = e_D × e_Y

Model::

a = ν · (AU / d)² · [ D(φ)·e_D + Y(φ)·e_Y + B(φ)·e_B ]
D(φ) = d0 + dc cos φ + ds sin φ + d2c cos 2φ + d2s sin 2φ + d4c cos 4φ + d4s sin 4φ
Y(φ) = y0 + yc cos φ + ys sin φ
B(φ) = b0 + bc cos φ + bs sin φ

where ν is the Earth-shadow factor applied to all three axes (the CODE/Bernese convention: the whole ECOM acceleration is switched off in umbra), d is the satellite-Sun distance, and φ is the argument of latitude u when sun_relative is False (ECOM1) or Δu, measured from orbit noon, when True (ECOM2).

Because e_D points at the Sun, the physical d0 is negative: about -1e-7 m/s² for a GPS satellite; y0 and the B terms are ~1e-9. All coefficients are in m/s² referred to 1 AU and scaled by (AU / d)² like the cannonball pressure, so d0 = -consts.solar_pressure_1au * craoverm reproduces the cannonball term. Coefficients estimated with software that applies them unscaled convert by multiplying by (d / AU)² at the arc epoch. satkit 0.23.1 and earlier applied them unscaled.

Attach to a propagation via satproperties(ecom=...). The ECOM acceleration is added to the cannonball term, so use craoverm=0 for a pure ECOM model.

Example:

import satkit as sk

ecom = sk.ecomparams.reduced(d0=-1.0e-7, y0=1e-9, b0=0, bc=2e-9, bs=-1e-9)
props = sk.satproperties(craoverm=0.0, ecom=ecom)
res = sk.propagate(state, t0, t1, propsettings=settings, satproperties=props)

d0 instance-attribute

Constant D (Sun-direction) term, m/s². Physically negative.

y0 instance-attribute

Constant Y term, m/s² (along the solar-panel axis).

b0 instance-attribute

Constant B term, m/s².

dc instance-attribute

D cos φ coefficient, m/s².

ds instance-attribute

D sin φ coefficient, m/s².

yc instance-attribute

Y cos φ coefficient, m/s².

ys instance-attribute

Y sin φ coefficient, m/s².

bc instance-attribute

B cos φ coefficient, m/s² (B1c in ECOM2).

bs instance-attribute

B sin φ coefficient, m/s² (B1s in ECOM2).

d2c instance-attribute

D cos 2φ coefficient, m/s² (ECOM2).

d2s instance-attribute

D sin 2φ coefficient, m/s² (ECOM2).

d4c instance-attribute

D cos 4φ coefficient, m/s² (ECOM2).

d4s instance-attribute

D sin 4φ coefficient, m/s² (ECOM2).

sun_relative instance-attribute

True: harmonics in Δu from orbit noon (ECOM2); False: in the argument of latitude u (ECOM1).

__init__(*, d0=0.0, y0=0.0, b0=0.0, dc=0.0, ds=0.0, yc=0.0, ys=0.0, bc=0.0, bs=0.0, d2c=0.0, d2s=0.0, d4c=0.0, d4s=0.0, sun_relative=False)

Create ECOM coefficients (m/s² at 1 AU); all default to zero.

Parameters:

Name Type Description Default
d0, y0, b0 float

constant D, Y, B terms

required
dc, ds float

D cos φ, D sin φ

required
yc, ys float

Y cos φ, Y sin φ

required
bc, bs float

B cos φ, B sin φ

required
d2c, d2s, d4c, d4s float

even D harmonics (ECOM2)

required
sun_relative bool

False → φ = argument of latitude (ECOM1); True → φ = Δu from orbit noon (ECOM2)

False

reduced(d0, y0, b0, bc, bs) staticmethod

Reduced ECOM1: D0, Y0, B0, Bc, Bs in argument of latitude (CODE's classic GPS set)

ecom1(d0, y0, b0, dc, ds, yc, ys, bc, bs) staticmethod

Full 9-parameter ECOM1 (once-per-revolution terms on D, Y, B in argument of latitude)

ecom2(d0, y0, b0, b1c, b1s, d2c, d2s, d4c, d4s) staticmethod

ECOM2 (Arnold et al. 2015): D0, Y0, B0, B1c, B1s, D2c, D2s, D4c, D4s in Δu from orbit noon

to_dict()

Coefficients as a dict (13 floats plus sun_relative)

from_dict(d) staticmethod

Build from a dict as produced by :meth:to_dict; missing keys default to zero / False

thrust

Continuous thrust acceleration for orbit maneuvers

Represents a constant thrust acceleration over a time window, specified in GCRF (inertial), RTN (CCSDS-standard orbital frame, also known as RSW or RIC), NTW (velocity-aligned), or LVLH.

RTN components are [R, T, N] where R = radial (outward from Earth centre), T = tangential / in-track, N = normal / cross-track (along angular momentum, h = r × v).

Example:

import satkit as sk

t0 = sk.time(2024, 1, 1)
t1 = t0 + sk.duration.from_hours(2)

# In-track thrust in the RTN (a.k.a. RSW, RIC) frame
t = sk.thrust.constant([0, 1e-4, 0], t0, t1, frame=sk.frame.RTN)

# Fixed direction thrust in GCRF frame
t = sk.thrust.constant([0, 0, 1e-3], t0, t1, frame=sk.frame.GCRF)

accel property

Acceleration vector [m/s^2]

frame property

Coordinate frame

start property

Start time of thrust arc

end property

End time of thrust arc

constant(accel, start, end, frame) staticmethod

Create a constant thrust acceleration

Parameters:

Name Type Description Default
accel array - like

3-element acceleration vector [m/s^2]

required
start time

Start time of thrust arc

required
end time

End time of thrust arc

required
frame frame

Coordinate frame — required, no default (matching the Rust API). Supported values:

  • frame.GCRF — inertial Cartesian
  • frame.RTN — radial / in-track / cross-track
  • frame.NTW — normal-to-velocity / tangent / cross-track (use this for thrust along the velocity vector)
  • frame.LVLH — Local Vertical / Local Horizontal
required

Returns:

Name Type Description
thrust thrust

Thrust object