Spacecraft

class missiontools.Spacecraft(a, e, i, raan, arg_p, ma, epoch, propagator_type='twobody', central_body_mu=398600441800000.0, central_body_j2=1.75553e+25, central_body_radius=6378137.0)[source]

Bases: object

A spacecraft defined by its Keplerian orbital elements and propagator.

All angles in radians; distances in metres; times as datetime64[us].

Parameters:
  • a (float) – Semi-major axis (m).

  • e (float) – Eccentricity (dimensionless).

  • i (float) – Inclination (rad).

  • raan (float) – Right ascension of the ascending node (rad).

  • arg_p (float) – Argument of perigee (rad).

  • ma (float) – Mean anomaly at epoch (rad).

  • epoch (np.datetime64) – Epoch at which the elements are defined.

  • propagator_type (str, optional) – 'twobody' (default) or 'j2'.

  • central_body_mu (float, optional) – Gravitational parameter (m³ s⁻²). Defaults to Earth.

  • central_body_j2 (float, optional) – J2 perturbation coefficient (m⁵ s⁻²). Defaults to Earth.

  • central_body_radius (float, optional) – Equatorial radius (m). Defaults to Earth WGS84.

Parameters:

Notes

The dataclass-generated __eq__ compares only the declared fields (orbital elements, epoch, propagator type, and central body parameters). Two Spacecraft instances with identical orbital elements but different attached sensors or antennas will still compare as equal.

Examples

Construct directly:

import numpy as np
from missiontools import Spacecraft

sc = Spacecraft(
    a=6_771_000.0,
    e=0.0006,
    i=np.radians(51.6),
    raan=np.radians(120.0),
    arg_p=np.radians(30.0),
    ma=0.0,
    epoch=np.datetime64('2025-01-01T00:00:00', 'us'),
    propagator_type='j2',
)

Construct from sun_synchronous_orbit():

from missiontools import Spacecraft
from missiontools.orbit import sun_synchronous_orbit

params = sun_synchronous_orbit(altitude=550_000.0, local_time_at_node='10:30')
sc = Spacecraft.from_dict(params, propagator_type='j2')
a: float
e: float
i: float
raan: float
arg_p: float
ma: float
epoch: datetime64
propagator_type: str = 'twobody'
central_body_mu: float = 398600441800000.0
central_body_j2: float = 1.75553e+25
central_body_radius: float = 6378137.0
property attitude_law: AbstractAttitudeLaw

Pointing law for this spacecraft. Defaults to nadir pointing.

property sensors: list

Sensors attached to this spacecraft (read-only copy).

property solar_configs: list

Solar configs attached to this spacecraft (read-only copy).

add_solar_config(config)[source]

Attach a solar config to this spacecraft.

Sets the config’s back-reference to this spacecraft and appends it to the internal solar configs list.

Parameters:

config (AbstractSolarConfig) – The solar config to attach.

Raises:

TypeError – If config is not an AbstractSolarConfig instance.

Return type:

None

property thermal_configs: list

Thermal configs attached to this spacecraft (read-only copy).

add_thermal_config(config)[source]

Attach a thermal config to this spacecraft.

Sets the config’s back-reference to this spacecraft and appends it to the internal thermal configs list.

Parameters:

config (AbstractThermalConfig) – The thermal config to attach.

Raises:

TypeError – If config is not an AbstractThermalConfig instance.

Return type:

None

property antennas: list

Antennas attached to this spacecraft (read-only copy).

add_antenna(antenna)[source]

Attach an antenna to this spacecraft.

Sets the antenna’s back-reference to this spacecraft and appends it to the internal antennas list.

Parameters:

antenna (AbstractAntenna) – The antenna to attach.

Raises:
  • TypeError – If antenna is not an AbstractAntenna.

  • ValueError – If the antenna is already attached to a GroundStation.

Return type:

None

add_sensor(sensor)[source]

Attach a sensor to this spacecraft.

Sets the sensor’s back-reference to this spacecraft and appends it to the internal sensors list.

Parameters:

sensor (AbstractSensor) – The sensor to attach.

Raises:

TypeError – If sensor is not an AbstractSensor instance.

Return type:

None

property keplerian_params: dict

Orbital elements as a dict, compatible with propagate_analytical().

Use this to pass the spacecraft’s orbit to the functional API:

r, v = propagate_analytical(t, **sc.keplerian_params)
coverage_fraction(lat, lon, sc.keplerian_params, t_start, t_end,
                  propagator_type=sc.propagator_type)
classmethod from_dict(params, propagator_type='twobody')[source]

Construct from a keplerian_params dict.

Accepts dicts produced by sun_synchronous_orbit() and similar helpers. Optional central-body keys fall back to Earth defaults if absent.

Parameters:
  • params (dict) – Must contain 'a', 'e', 'i', 'raan', 'arg_p', 'ma', 'epoch'. May optionally contain 'central_body_mu', 'central_body_j2', 'central_body_radius'.

  • propagator_type (str, optional) – 'twobody' (default) or 'j2'.

Parameters:
  • params (dict)

  • propagator_type (str)

Return type:

Spacecraft

propagate(t_start, t_end, step)[source]

Propagate the orbit and return ECI state vectors.

Parameters:
  • t_start (np.datetime64) – Start of the propagation window.

  • t_end (np.datetime64) – End of the propagation window (inclusive).

  • step (np.timedelta64) – Time step between samples.

Returns:

dictt : (N,) datetime64[us] — sample timestamps.

r : (N, 3) float — ECI position vectors (m).

v : (N, 3) float — ECI velocity vectors (m s⁻¹).

Parameters:
Return type:

dict

classmethod sunsync(altitude_km, node_solar_time, node_type='ascending', epoch=None, ma_deg=0.0)[source]

Create a circular sun-synchronous orbit spacecraft.

Delegates to sun_synchronous_orbit() for element computation and always uses the 'j2' propagator, since J2 is what drives the RAAN precession that maintains sun-synchronicity.

Parameters:
  • altitude_km (float) – Orbit altitude above the WGS84 equatorial surface (km).

  • node_solar_time (str) – Local solar time at the node crossing ('HH:MM' or 'HH:MM:SS', 24-hour clock).

  • node_type (str, optional) – 'ascending' (default) or 'descending'.

  • epoch (np.datetime64 | None, optional) – Reference epoch. Defaults to J2000.0.

  • ma_deg (float, optional) – Mean anomaly at epoch (deg). Defaults to 0 (spacecraft at the ascending or descending node at epoch).

Returns:

Spacecraft – With propagator_type='j2'.

Parameters:
Return type:

Spacecraft

classmethod geostationary(longitude_deg, epoch=None, propagator='twobody')[source]

Create a geostationary orbit spacecraft.

Delegates to geostationary_orbit(). The satellite is placed at longitude_deg geographic longitude exactly at the epoch.

Parameters:
  • longitude_deg (float) – Sub-satellite longitude at epoch (deg). Any value is accepted; values outside [-180, 180] are wrapped automatically.

  • epoch (np.datetime64 | None, optional) – Reference epoch. Defaults to J2000.0.

  • propagator (str, optional) – 'twobody' (default) or 'j2'.

Returns:

Spacecraft – Equatorial, circular orbit with i=0, e=0.

Parameters:
Return type:

Spacecraft

classmethod heo(period_s, e, epoch, apogee_solar_time, apogee_longitude_deg, arg_p_deg=270.0, propagator='twobody')[source]

Create a critically inclined highly elliptical orbit spacecraft.

Delegates to highly_elliptical_orbit(). The inclination is set automatically to the critical inclination (63.435° for northern-hemisphere apogee, 116.565° for southern) so the apsidal line does not drift under J2.

Parameters:
  • period_s (float) – Orbital period (s).

  • e (float) – Eccentricity (0 < e < 1).

  • epoch (np.datetime64) – Reference epoch for the orbital elements.

  • apogee_solar_time (str) – Local mean solar time at the apogee sub-satellite point ('HH:MM' or 'HH:MM:SS', 24-hour clock).

  • apogee_longitude_deg (float) – Geographic longitude of the apogee sub-satellite point (deg).

  • arg_p_deg (float, optional) – Argument of perigee (deg). 270° (default) places the apogee in the northern hemisphere; 90° places it in the southern hemisphere.

  • propagator (str, optional) – 'twobody' (default) or 'j2'.

Returns:

Spacecraft

Parameters:
Return type:

Spacecraft