madlib package

Submodules

madlib._maneuver module

class madlib._maneuver.ContinuousManeuver(f: Callable, time_range: Tuple[float, float])[source]

Bases: object

ContinuousManeuver class holds a continuous maneuver definition, which includes the acceleration function defining the maneuver, and the time range over which the maneuver occurs.

_accel_func: Callable
_time_range: Tuple[float, float]
class madlib._maneuver.ImpulsiveManeuver(time: float, dv: ndarray[Any, dtype[float64]])[source]

Bases: object

ImpulseManeuver class holds an impulse maneuver definition, which includes the time of the maneuver, and the impulsive delta-v.

Properties

timefloat

Timestamp of the maneuver (MJD, UTC)

dvNDArray[np.float64]

3D Array of the impulsive delta-v (RSW frame)

_dv: ndarray[Any, dtype[float64]]
_time: float
property dv: ndarray[Any, dtype[float64]]
property time: float

madlib._observation module

class madlib._observation.Observation(*, mjd: float, ra: float | None = None, dec: float | None = None, az: float | None = None, el: float | None = None, range_: float | None = None, range_rate: float | None = None, lat: float | None = None, lon: float | None = None, sun_el: float | None = None, sun_separation: float | None = None, sensor_id: str | None = None)[source]

Bases: object

Class for holding observables. All angles are in degrees.

Parameters:
  • mjd (float) – Timestamp of the observation, described as a MJD in UTC

  • ra (float | None) – Topocentric right ascension angle, by default None

  • dec (float | None) – Topocentric declination angle, by default None

  • az (float | None) – Azimuth angle, by default None

  • el (float | None) – Elevation angle, by default None

  • range (float | None) – Distance between sensor and target, by default None

  • range_rate (float | None) – Time rate of change of the distance between the sensor and target, by default None

  • lat (float | None) – Geodetic latitude, by default None

  • lon (float | None) – Geodetic longitude, by default None

  • sun_el (float | None) – Elevation angle of sun, by default None

  • sun_separation (float | None) – Separation angle between target and sun, by default None

  • sensor_id (str | None) – Unique Sensor ID, by default None

_keys = ['ra', 'dec', 'az', 'el', 'range_', 'range_rate', 'lat', 'lon', 'sun_el', 'sun_separation']
asarray() ndarray[Any, dtype[float64]][source]

Convert this observation to a flat 1-D array

az: float | None = None
dec: float | None = None
el: float | None = None
lat: float | None = None
lon: float | None = None
mjd: float
ra: float | None = None
range_: float | None = None
range_rate: float | None = None
sensor_id: str | None = None
sun_el: float | None = None
sun_separation: float | None = None
class madlib._observation.ObservationCollection(*, pos_observed: ndarray[Observation, dtype[float64]], pos_truth: ndarray[Observation, dtype[float64]], pos_expected: ndarray[Observation, dtype[float64]])[source]

Bases: object

Class for holding observed and true positions of satellites.

Parameters:
  • pos_observed (np.ndarray[Observation, np.dtype[np.float64]]) – Realistic observations of a satellite given sensor noise parameters

  • pos_truth (np.ndarray[Observation, np.dtype[np.float64]]) – True observations of a satellite ignoring all noise sources

  • pos_expected (np.ndarray[Observation, np.dtype[np.float64]]) – Observations expected if no noise or maneuvers occur

Raises:

MadlibException – Can only add two ObservationCollection objects

count_valid_observations()[source]
pos_expected: ndarray[Observation, dtype[float64]]
pos_observed: ndarray[Observation, dtype[float64]]
pos_truth: ndarray[Observation, dtype[float64]]
class madlib._observation.ObservationResidual(*, mjd: float, ra: float | None = None, dec: float | None = None, az: float | None = None, el: float | None = None, range_: float | None = None, range_rate: float | None = None, lat: float | None = None, lon: float | None = None)[source]

Bases: object

Class for holding the difference between two observables.

Parameters:
  • mjd (float) – Timestamp of the observation, described as a MJD in UTC

  • ra (float | None) – Topocentric right ascension angle difference, by default None

  • dec (float | None) – Topocentric declination angle difference, by default None

  • az (float | None) – Azimuth angle difference, by default None

  • el (float | None) – Elevation angle difference, by default None

  • range (float | None) – Distance between sensor and target difference, by default None

  • range_rate (float | None) – Time rate of change of the distance between the sensor and target difference, by default None

  • lat (float | None) – Geodetic latitude difference, by default None

  • lon (float | None) – Geodetic longitude difference, by default None

asarray() ndarray[Any, dtype[float64]][source]

Convert this observation to a flat 1-D array

az: float | None = None
dec: float | None = None
el: float | None = None
lat: float | None = None
lon: float | None = None
mjd: float
ra: float | None = None
range_: float | None = None
range_rate: float | None = None
madlib._observation.combineObsCollections(collectionList: List[ObservationCollection]) ObservationCollection[source]

Given observations of a satellite from multiple sensors, combine them into a single object.

Parameters:

collectionList (List[ObservationCollection]) – List of observations from multiple sensors of a single satellite.

Returns:

Combined collection of observations from all sensors.

Return type:

ObservationCollection

madlib._satellite module

Implementation of the Satellite class, which models the propagation of a satellite (with or without a maneuver).

class madlib._satellite.ContinuousThrustSatellite(epoch: float, pos: ndarray[Any, dtype[float64]], vel: ndarray[Any, dtype[float64]], acc: ndarray[Any, dtype[float64]] = array([0., 0., 0.]), maneuver_info: ContinuousManeuver | None = None, epoch_true: float | None = None, pos_true: ndarray[Any, dtype[float64]] | None = None, vel_true: ndarray[Any, dtype[float64]] | None = None, acc_true: ndarray[Any, dtype[float64]] | None = None, **kwargs)[source]

Bases: Satellite

Satellite subclass for propagating an orbit that uses continuous thrust (i.e. ContinuousManeuver)

_setup_propfun()[source]
propagate(times: float | ndarray[Any, dtype[float64]], ignore_maneuvers: bool = False, use_true_orbit: bool = False) tuple[ndarray[Any, dtype[float64]], ndarray[Any, dtype[float64]]][source]

Top level continuous thrust propagate method. Propagates the satellite to the time(s) given.

Parameters:
  • times (float | NDArray[np.float64]) – Timestamp(s) for evaluating the satellite propagation (MJD, UTC)

  • ignore_maneuvers (bool) – If True, propagate without applying any maneuvers, by default False.

  • use_true_orbit (bool) – If True, and if input values were given for <epoch_true>, <pos_true>, <vel_true>, or <aa_true>, use these values for the true orbit to propagate instead of the reported values (<epoch>, <pos>, <vel>, <aa>)

Returns:

First element of tuple is X : (N,3), position vector(s) at the time(s) requested. Coordinate system is TETED. Units are km. Second element of tuple is V : (N,3), velocity vector(s) at the time(s) requested, Coordinate system is TETED. Units are km/s.

Return type:

tuple[NDArray[np.float64], NDArray[np.float64]]

class madlib._satellite.Satellite(epoch: float, pos: ndarray[Any, dtype[float64]], vel: ndarray[Any, dtype[float64]], acc: ndarray[Any, dtype[float64]] = array([0., 0., 0.]), maneuver_info: ImpulsiveManeuver | None | ContinuousManeuver = None, epoch_true: float | None = None, pos_true: ndarray[Any, dtype[float64]] | None = None, vel_true: ndarray[Any, dtype[float64]] | None = None, acc_true: ndarray[Any, dtype[float64]] | None = None, **kwargs)[source]

Bases: object

Satellite class for propagating a satellite (either with or without a maneuver).

_aa: ndarray[Any, dtype[float64]]
_aa_true: ndarray[Any, dtype[float64]]
_epoch: float
_epoch_true: float
_maneuver: ImpulsiveManeuver | None | ContinuousManeuver = None
_vv: ndarray[Any, dtype[float64]]
_vv_true: ndarray[Any, dtype[float64]]
_xx: ndarray[Any, dtype[float64]]
_xx_true: ndarray[Any, dtype[float64]]
property acc: ndarray[Any, dtype[float64]]
property acc_true: ndarray[Any, dtype[float64]]
copy() Self[source]
create_cross_tag(cross_mjd: float, delta_pos_km: ndarray[Any, dtype[float64]], delta_vel_kms: ndarray[Any, dtype[float64]])[source]

Create a satellite that will cross nearby this satellite, potentially creating a series of misattribution events.

Parameters:
  • cross_mjd – float A time (in MJD) at which the two objects will be nearby

  • delta_pos_km – NDArray[np.float64] A vector representing the distance between the two satellites at time <cross_mjd> (ECI, km)

  • delta_vel_kms – NDArray[np.float64] A vector representing the difference in the two satellites’ velocities at time <cross_mjd> (ECI, km/s)

Returns:

Satellite

The Satellite object for the crossing satellite, with epoch set at <cross_mjd>

property does_maneuver: bool
property epoch: float
property epoch_true: float
classmethod from_GEO_longitude(lon: float, epoch: float) Self[source]

Create a Satellite in GEO at the given longitude

Parameters:
  • lon (float) – Longitude of the GEO satellite (deg)

  • epoch (float) – Timestamp (MJD, UTC) indicating the time at which this orbital state is defined

Returns:

Instance of the Satellite class

Return type:

Self

classmethod from_keplerian(epoch: float, inclination_rad: float, raan_rad: float, argp_rad: float, ecc: float, semi_major_axis_km: float, mean_anomaly_rad: float, GM: float = 398600.4418) Self[source]

Create a Satellite from Keplerian elements

Parameters:
  • epoch (float) – Timestamp (MJD, UTC) indicating the time at which this orbital state is defined

  • inclination_rad (float) – Orbital inclination in radians

  • raan_rad (float) – Right ascension of the ascending node in radians

  • argp_rad (float) – Argument of pericenter in radians

  • ecc (float) – Eccentricity, a number between 0 and 1

  • semi_major_axis_km (float) – Semi-major axis in km

  • mean_anomaly_rad (float) – Mean anomaly in radians

  • GM (float, optional) – Standard gravitational parameter (the product of the gravitational constant and the mass of a given astronomical body such as the Sun or Earth) in km^3/s^2. Earth’s standard gravitational parameter by default (398600.4418 km^3/s^2)

Returns:

Instance of the Satellite class

Return type:

Self

property maneuver: ImpulsiveManeuver | ContinuousManeuver | None
propagate(times: float | ndarray[Any, dtype[float64]], ignore_maneuvers: bool = False, use_true_orbit: bool = False) tuple[ndarray[Any, dtype[float64]], ndarray[Any, dtype[float64]]][source]

Propagates the satellite to the time(s) given.

Parameters:
  • times (float | NDArray[np.float64]) – Timestamp(s) for evaluating the satellite propagation (MJD, UTC)

  • ignore_maneuvers (bool) – If True, propagate without applying any maneuvers, by default False.

  • use_true_orbit (bool) – If True, and if input values were given for <epoch_true>, <pos_true>, <vel_true>, or <aa_true>, use these values for the true orbit to propagate instead of the reported values (<epoch>, <pos>, <vel>, <aa>)

Returns:

First element of tuple is X : (N,3), position vector(s) at the time(s) requested. Coordinate system is TETED. Units are km. Second element of tuple is V : (N,3), velocity vector(s) at the time(s) requested, Coordinate system is TETED. Units are km/s.

Return type:

tuple[NDArray[np.float64], NDArray[np.float64]]

Raises:

ValueError – One of the propagation times is the exact same time as the maneuver.

static rv2rsw(r: ndarray[Any, dtype[float64]], v: ndarray[Any, dtype[float64]]) ndarray[Any, dtype[float64]][source]

Compute rotation matrix from ECI frame to RSW frame.

Parameters:
  • r (NDArray[np.float64]) – Position vector (ECI, km)

  • v (NDArray[np.float64]) – Velocity vector (ECI, km/s)

Returns:

Rotation matrix from ECI frame to RSW frame

Return type:

NDArray[np.float64]

property v: ndarray[Any, dtype[float64]]
property v_true: ndarray[Any, dtype[float64]]
validate_input_vector(input_vector, input_name)[source]
property x: ndarray[Any, dtype[float64]]
property x_true: ndarray[Any, dtype[float64]] | None

madlib._sensor module

class madlib._sensor.GroundOpticalSensor(lat: float, lon: float, alt: float, dra: float, ddec: float, collect_gap_mean: float, obs_limits: dict | None = None, collect_gap_std: float = 0.0, obs_per_collect: int | tuple[int, int] = 1, obs_time_spacing: float = 1.0, id: str | None = None, lat_truth: float | None = None, lon_truth: float | None = None, alt_truth: float | None = None, cross_tag: Satellite | None = None, cross_tag_limit_arcsec: float = 100.0, **extras)[source]

Bases: _OpticalSensor

Class for modeling the observing of a satellite with an optical sensor

_abc_impl = <_abc._abc_data object>
_eci_to_az_el(x: ndarray[Any, dtype[float64]], mjd: ndarray[Any, dtype[float64]]) tuple[ndarray[Any, dtype[float64]], ndarray[Any, dtype[float64]]][source]

Convert TETED positions to Az/El from the site.

Parameters:
  • x (NDArray[np.float64]) – TETED positions

  • mjd (NDArray[np.float64]) – timestamps (mjd)

Returns:

Az/El results

Return type:

tuple[NDArray[np.float64], NDArray[np.float64]]

_is_protocol = False
_site_loc_TETED(times: ndarray[Any, dtype[float64]], use_true_location: bool = False) tuple[ndarray[Any, dtype[float64]], ndarray[Any, dtype[float64]]][source]

Rotate the site location to TETED for a given set of times.

Parameters:
  • times (NDArray[np.float64]) – timestamps at which to compute the site location

  • use_true_location (bool, optional) – If True, use the sensor’s true position (as opposed to reported) in the calculation. By default False.

Returns:

site locations for timestamps

Return type:

tuple[NDArray[np.float64], NDArray[np.float64]]

_site_reported_itrs: ndarray[Any, dtype[float64]]
alt: float
collect_gap_mean: float
collect_gap_std: float
ddec: float
dra: float
lat: float
lon: float
obs_limits: dict | None
obs_per_collect: int | tuple[int, int]
observe(target_satellite: Satellite, times: float | ndarray[Any, dtype[float64]] | Tuple[float, float]) ObservationCollection[source]

Observe a satellite with this sensor model at the times given. Observations are computed in three forms:

  • truth: Measurements that would be returned if there were no random or

    systematic errors and knowledge of the orbit and maneuvers was perfect. These are the observations you would see in a perfect world.

  • expected: Measurements without random noise, but also without maneuver knowledge

    and with any systematic errors on sensor position and/or satellite orbit. These are the observations that you THINK you should get, given your actual knowledge of the system.

  • measured: The actual output of the simulated system, including all random and

    systematic sources of error and following the target satellite’s full trajectory. This can also contain cross-tag events.

Parameters:
  • target_satellite (Satellite) – madlib.Satellite object to observe

  • times (float | NDArray[np.float64] | Tuple[float, float]) –

    Time(s) to observe the satellite. Specified as MJD in the UTC system.
    • If a single float is given, observation will be made at just that time.

    • If a numpy array is given, observations will be made at each time in the array.

    • If a tuple of two floats is given, they will represent the start and end of observations, and observation times will be generated accordingly

Returns:

A container object holding a realistic observation of the satellite given the sensor noise parameters and the “true” observation that excludes all noise sources.

Return type:

ObservationCollection

class madlib._sensor.SpaceOpticalSensor(sensor_satellite: Satellite, dra: float, ddec: float, collect_gap_mean: float, sensor_satellite_truth: Satellite | None = None, obs_limits: dict | None = None, collect_gap_std: float = 0.0, obs_per_collect: int | tuple[int, int] = 1, obs_time_spacing: float = 1.0, id: str | None = None, cross_tag: Satellite | None = None, cross_tag_limit_arcsec: float = 100.0, **extras)[source]

Bases: _OpticalSensor

Class for modeling observations with an optical sensor in Earth orbit.

_abc_impl = <_abc._abc_data object>
_is_protocol = False
collect_gap_mean: float
collect_gap_std: float
ddec: float
dra: float
obs_limits: dict | None
obs_per_collect: int | tuple[int, int]
observe(target_satellite: Satellite, times: float | ndarray[Any, dtype[float64]] | Tuple[float, float])[source]

Observe a satellite with this sensor model at the times given. Observations are computed in three forms:

  • truth: Measurements that would be returned if there were no random or

    systematic errors and knowledge of the target’s orbit and maneuvers was perfect. These are the observations you would see in a perfect world.

  • expected: Measurements without random noise, but also without maneuver knowledge

    and with any systematic errors on sensor position and/or satellite orbit. These are the observations that you THINK you should get, given your actual knowledge of the system.

  • measured: The actual output of the simulated system, including all random and

    systematic sources of error and following the target satellite’s full trajectory. This can also contain cross-tag events.

Parameters:
  • target_satellite (Satellite) – madlib.Satellite object to observe

  • times (float | NDArray[np.float64] | Tuple[float, float]) –

    Time(s) to observe the satellite. Specified as MJD in the UTC system.
    • If a single float is given, observation will be made at just that time.

    • If a numpy array is given, observations will be made at each time in the array.

    • If a tuple of two floats is given, they will represent the start and end of observations, and observation times will be generated accordingly

Returns:

A container object holding a realistic observation of the satellite given the sensor noise parameters and the “true” observation that excludes all noise sources.

Return type:

ObservationCollection

class madlib._sensor._OpticalSensor(dra: float, ddec: float, collect_gap_mean: float, obs_limits: dict | None = None, collect_gap_std: float = 0.0, obs_per_collect: int | tuple[int, int] = 1, obs_time_spacing: float = 1.0, students_dof: int | None = None, id: str | None = None, cross_tag: Satellite | None = None, cross_tag_limit_arcsec: float = 100.0)[source]

Bases: _Sensor

Generic class for optical sensors

_abc_impl = <_abc._abc_data object>
_is_protocol = False
collect_gap_mean: float
collect_gap_std: float
ddec: float
dra: float
generate_obs_timing(start: float, end: float) ndarray[Any, dtype[float64]][source]

Randomly generate a realistic time sampling of observations.

Parameters:
  • start (float) – Timestamp (MJD) corresponding to the beginning of the observing period

  • end (float) – Timestamp (MJD) corresponding to the end of the observing period

Returns:

Array of MJD timestamps corresponding to typical observing times on a satellite

Return type:

NDArray[np.float64]

Raises:

ValueError – Start timestamp must be before end timestamp

id: str | None
obs_limits: dict | None
obs_per_collect: int | tuple[int, int]
obs_time_spacing: float
validate_limits(obs: Observation) bool[source]

Determine whether Observation is possible based on the sensor limits.

Parameters:

obs (Observation) – madlib.Observation class for holding observables

Returns:

Whether or not the Observation is possible

Return type:

bool

class madlib._sensor._Sensor(*args, **kwargs)[source]

Bases: Protocol

Class is not yet implemented

_abc_impl = <_abc._abc_data object>
_is_protocol = True
abstract generate_obs_timing(start: float, end: float) ndarray[Any, dtype[float64]][source]

Given a start time and an end time (in MJD) as well as the sensor’s defined parameters, generate an array of observation times (also in MJD).

Parameters:
  • start (float) – Earliest possible observation timestamp (in MJD)

  • end (float) – Latest possible observation timestamp (in MJD)

Returns:

An array of times (in MJD) at which an observation will be made.

Return type:

NDArray[np.float64]

Raises:

NotImplementedError

abstract observe(sat: Satellite, times: float | ndarray[Any, dtype[float64]])[source]

Observe a given satellite with this sensor at the times given.

Parameters:
  • sat (Satellite) – Satellite object to observe

  • times (float | NDArray[np.float64]) – Time(s) to observe the satellite. Specified as MJD in the UTC system.

Raises:

NotImplementedError

madlib._sensor.pos_to_lat_lon(pos: ndarray[Any, dtype[float64]], times: ndarray[Any, dtype[float64]]) tuple[ndarray[Any, dtype[float64]], ndarray[Any, dtype[float64]]][source]

Compute latitude & longitude for given position(s) and time(s).

Parameters:
  • pos (NDArray[np.float64]) – position vector

  • times (NDArray[np.float64]) – array of timestamps

Returns:

computed latitudes and longitudes

Return type:

tuple[NDArray[np.float64], NDArray[np.float64]]

Raises:

ValueError – The number of positions and times must be equal (for now)

madlib._sensor.spherical_to_cartesian(ra: float, dec: float) ndarray[Any, dtype[float64]][source]

Convert spherical coordinates (ra, dec) to cartesian coordinates.

Parameters:
  • ra (float) – Right Ascension

  • dec (float) – Declination

Returns:

Cartesian coordinates

Return type:

NDArray[np.float64]

madlib._sensor_collection module

class madlib._sensor_collection.SensorCollection(sensorList: Sequence[_Sensor])[source]

Bases: object

Class containing multiple sensor objects that can generate a comprehensive observing schedule and collate observations.

add_sensor(sensor: _Sensor)[source]

Add a new sensor to the existing collection, provided the sensor timing has not already been generated.

Parameters:

sensor (_Sensor) – The sensor object to add to the collection

classmethod fromYAML(yaml_file: str)[source]

Instantiate a SensorCollection object from a YAML file

Parameters:

yaml_file (str) – Path to YAML file defining the sensors in the collection

generate_obs_timing(start: float, end: float)[source]

Given a start time and an end time (in MJD), generate an array of observation times (also in MJD) based on the sensors’ defined parameters.

Parameters:
  • start (float) – Earliest possible observation timestamp (MJD)

  • end (float) – Latest possible observation (MJD)

Raises:

SensorException – The observation schedule has already been generated.

observe(target_satellite: Satellite) ObservationCollection[source]

Given a madlib.Satellite, generate an ObservationCollection

Parameters:

target_satellite (Satellite) – madlib.Satellite is a class for propagating a satellite

Returns:

Observations of a satellite from multiple sensors, combined into a single object.

Return type:

ObservationCollection

Raises:

SensorException – The observation schedule has already been generated.

static paramsFromYAML(yaml_file: str | Path)[source]

Parse a YAML into sensor parameters, returned as a list of dicts

exception madlib._sensor_collection.SensorException(message=None)[source]

Bases: Exception

SensorException class

madlib._utils module

exception madlib._utils.MadlibException[source]

Bases: Exception

MadlibException Class

madlib._utils.calc_separation_angle(v1: ndarray[Any, dtype[float64]], v2: ndarray[Any, dtype[float64]], in_deg: bool = False)[source]

Returns the angle between vectors v1 and v2, both with shapes (N, 3). Output is in radians by default, in degrees if <in_deg> is True.

Module contents

Maneuver Detection Library (MaDLib)