mirage package#

Subpackages#

Submodules#

mirage.attitude module#

class mirage.attitude.AlignedAndConstrainedAttitude(v_align: ndarray, v_const: ndarray, dates: ndarray[datetime, Any], axis_order: Tuple[int] = (0, 1, 2))#

Bases: object

Attitude profile that aligns one body axis with a time-varying vector while constraining another body axis to a second time-varying vector.

basis_vectors_at_dates(dates: ndarray[datetime, Any]) → tuple[ndarray, ndarray, ndarray]#

Body basis vectors in inertial coordinates

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Dates (UTC)

Returns:

First, second, and third body basis vectors in inertial coordinates

Return type:

tuple[np.ndarray, np.ndarray, np.ndarray]

dcms_at_dates(dates_or_jds: ndarray[datetime | float]) → ndarray#

DCM from inertial to body axes

Parameters:

dates_or_jds (np.ndarray[Union[datetime.datetime, float]] [n,]) – Dates or Julian dates (UTC)

Returns:

DCM array

Return type:

np.ndarray [3,3xn]

propagate(epsecs: ndarray) → tuple[ndarray, ndarray]#

Propagates the attitude profile to an array of epoch seconds

Parameters:

epsecs (np.ndarray [n,]) – Seconds after the definition epoch

Returns:

Quaternion and angular velocity [rad/s] at each requested time

Return type:

tuple[np.ndarray [n,4], np.ndarray [n,3]]

class mirage.attitude.AttitudeRepresentation(repr_name: str, components: ndarray)#

Bases: object

Container for an attitude representation and conversions between rotation vectors, quaternions, direction cosine matrices, and modified Rodrigues parameters.

identity()#

Returns the identity element of SO3 as the current representation type, if possible

Returns:

The identity element

Return type:

AttitudeRepresentation

inverse()#

Returns the inverse of the attitude in the current representation via quaternions

Returns:

Inverse of the current attitude

Return type:

AttitudeRepresentation

to(target_repr_name: str)#

Converts the attitude in self to a new representation

Parameters:

target_repr_name (str) – Name of the target representation

Returns:

Converted attitude representation

Return type:

AttitudeRepresentation

to_upper_hemisphere()#

Transforms the attitude representation in place to the upper hemisphere of \(S^3\) via quaternions

Returns:

Upper hemisphere representation

Return type:

AttitudeRepresentation

class mirage.attitude.RbtfAttitude(w0: ndarray, q0: ndarray, itensor: ndarray)#

Bases: object

Class for rigid body torque free attitude propagation using accelerated semi-analytical solution with elliptic integrals

dcms_at_dates(dates_or_jds: ndarray[datetime | float]) → ndarray#

The direction cosine matrices for the orientation of this attitude profile at a set of datetimes or Julian dates

Parameters:

dates_or_jds (np.ndarray[Union[datetime.datetime, float]]) – Array of datetimes or Julian dates

Returns:

Stack of DCMs \(A_i\) which each transform inertial vectors into the body frame via multiplication on the left

Return type:

np.ndarray [3,3xn]

propagate(epsec_space: ndarray) → Tuple[ndarray, ndarray]#

Propagates attitude forward to all epoch seconds

Parameters:

epsec_space (np.ndarray) – Seconds after the definition epoch to propagate to

Returns:

Orientation of body over time as a quaternion and body frame angular velocity

Return type:

Tuple[np.ndarray [n,4], np.ndarray [n,3]]

class mirage.attitude.SpinStabilizedAttitude(rot_rate: float, inertial_rot_axis: ndarray, jd0: float, rot_angle0: float)#

Bases: object

Attitude profile for a body spinning at a constant rate about a fixed inertial rotation axis.

basis_vectors_at_jds(jd_eval: ndarray) → Tuple[ndarray, ndarray, ndarray]#

Returns the set of basis vectors in the inertial frame at given Julian dates, used for plotting

Parameters:

jd_eval (np.ndarray [n,]) – Julian dates to evaluate at

Returns:

Unit vector bases at each time

Return type:

Tuple[np.ndarray [n,3], np.ndarray [n,3], np.ndarray [n,3]]

dcms_at_dates(dates_or_jds: ndarray[datetime | float]) → ndarray#

DCM from inertial to body axes

Parameters:

dates_or_jds (np.ndarray[Union[datetime.datetime, float]] [n,]) – Dates or Julian dates to evaluate at (UTC)

Returns:

DCMs

Return type:

np.ndarray [3,3xn]

propagate(epsecs: ndarray) → ndarray#

Propagates the attitude profile to an array of epoch seconds

Parameters:

epsecs (np.ndarray [n,]) – Seconds after the definition epoch

Returns:

Quaternion and angular velocity [rad/s] at each requested time

Return type:

tuple[np.ndarray [n,4], np.ndarray [n,3]]

mirage.attitude.analytic_torque_free_angular_velocity(omega0: ndarray, itensor: ndarray, teval: ndarray, itensor_org_factor: int = 1) → Tuple[ndarray, float, float, float, bool]#

Analytically propagates angular velocity assuming no torque is being applied

Parameters:
  • omega0 (np.ndarray [n,3]) – Initial angular velocity in body frame [rad/s]

  • itensor (np.ndarray [3,3]) – Principal inertia tensor, reorganized internally to satisfy itensor[0,0] <= itensor[1,1] <= itensor[2,2] [kg m^2]

  • teval (np.ndarray [n,]) – Times to compute angular velocity for after initial state time [seconds]

  • itensor_org_factor (int, optional) – If inertia tensor was reorganized with an even or odd number of flips, defaults to 1

Returns:

Angular velocity [rad/s]; \(k^2\) term of elliptic integral, \(\tau_0\), \(\dot{\tau}\); short-axis model (SAM) flag

Return type:

Tuple[np.ndarray [n,3], float, float, float, bool]

mirage.attitude.analytic_torque_free_attitude(quat0: ndarray, omega: ndarray, itensor: ndarray, teval: ndarray, ksquared: float, tau0: float, tau_dot: float, is_sam: bool, itensor_org_factor: int = 1, itensor_inv_inds: list = [0, 1, 2]) → ndarray#

Analytically propagates orientation under torque-free rigid-body motion

Parameters:
  • quat0 (np.ndarray [n,4]) – Quaternion from the inertial to body frame at the initial time step

  • omega (np.ndarray [n,3]) – Body angular velocities at each point in teval [rad/s]

  • itensor (np.ndarray [3,3]) – Principal inertia tensor satisfying itensor[0,0] <= itensor[1,1] <= itensor[2,2] [kg m^2]

  • teval (np.ndarray [n,]) – Times to output attitude solution at, teval[0] corresponds to quat0 and omega[0,:]

  • ksquared (float) – \(k^2\) parameter from the angular velocity propagation

  • tau0 (float) – Initial value of :math:` au` from the angular velocity propagation

  • tau_dot (float) – Rate of change of :math:` au` from the angular velocity propagation

  • is_sam (np.ndarray [n,]) – Indicates the rotation mode. 0 = long-axis mode (LAM), 1 = short-axis mode (SAM)

  • itensor_org_factor (int, optional) – Indicates if an even or odd number of flips was required to reorganize the inertia tensor, defaults to 1

  • itensor_inv_inds (list, optional) – Inverse mapping from the user’s inertia tensor to the one used here, defaults to [0, 1, 2]

Returns:

Propagated quaternions at each time in teval

Return type:

np.ndarray [n,m,4]

mirage.attitude.davenport(rhat_body: ndarray, rhat_ref: ndarray) → ndarray#

Computes the quaternion estimate of the attitude of a body using Davenport’s q-method.

Parameters:
  • rhat_body (np.ndarray [n,3]) – The unit vectors in the body frame

  • rhat_ref (np.ndarray [n,3]) – The same unit vectors in the reference frame

Returns:

Quaternion estimate of the attitude of the body

Return type:

np.ndarray [1,4]

mirage.attitude.dcm_to_ea313(dcm: ndarray) → ndarray#

Finds the Euler angle (3-1-3) body frame sequence corresponding to the input direction cosine matrices

Parameters:

dcm (np.ndarray [3,3xn]) – DCM array

Returns:

Euler angle array

Return type:

np.ndarray [n,3]

mirage.attitude.dcm_to_mrp(c: ndarray) → ndarray#

Converts direction cosine matrices to modified Rodrigues parameters via quaternions

Parameters:

c (np.ndarray [3,3xn]) – Direction cosine matrix array

Returns:

MRP array

Return type:

np.ndarray [n,3]

mirage.attitude.dcm_to_quat(c: ndarray) → ndarray#

Converts DCMs to quaternions using Sheppard’s method

Parameters:

c (np.ndarray [3,3xn]) – Input DCM array

Returns:

Computed quaternions

Return type:

np.ndarray [n,4]

mirage.attitude.dcm_to_rv(c: ndarray) → ndarray#

Converts DCMs to rotation vectors by way of quaternions

Parameters:

c (np.ndarray [3,3xn]) – Input DCM array

Returns:

Computed rotation vectors

Return type:

np.ndarray [n,3]

mirage.attitude.ea_to_dcm(seq: Tuple[int, int, int], a1: ndarray, a2: ndarray, a3: ndarray) → ndarray#

Converts a set of Euler angle (EA) sequences (in radians) to DCMs

Parameters:
  • seq (Tuple[int, int, int]) – Axes to rotate about, ex: (1,2,3) gives 1-2-3 sequence

  • a1 (np.ndarray [n,]) – First rotation angle [rad]

  • a2 (np.ndarray [n,]) – Second rotation angle [rad]

  • a3 (np.ndarray [n,]) – Third rotation angle [rad]

Returns:

Computed DCMs

Return type:

np.ndarray [3,3xn]

mirage.attitude.gravity_gradient_torque(itensor: ndarray, rvec: ndarray, mu: float = 398600.4418) → ndarray#

Computes gravity gradient torque in the body frame

Parameters:
  • itensor (np.ndarray [3,3]) – Inertia tensor in body axes [kg m^2]

  • rvec (np.ndarray [1x3]) – Position vector of body [km]

  • mu (float, optional) – Gravitational parameter of central body, defaults to AstroConstants.earth_mu

Returns:

Gravity gradient torque in body frame [N m]

Return type:

np.ndarray [1x3]

mirage.attitude.integrate_rigid_attitude_dynamics(q0: ndarray, omega0: ndarray, itensor: ndarray, teval: ndarray, body_torque: Callable = <function <lambda>>, int_tol: float = 1e-13, method: str = 'RK45') → Tuple[ndarray, ndarray]#

Integration for rigid body rotational dynamics

Parameters:
  • q0 (np.ndarray [1x4]) – Initial quaternion from inertial to body frame

  • omega0 (np.ndarray [1x3]) – Initial angular velocity vector of body relative to inertial space [rad/s]

  • itensor (np.ndarray [3,3]) – Principal inertia tensor [kg m^2]

  • teval (np.ndarray [n,]) – Times to return integrated trajectory at [second]

  • body_torque (Callable, optional) – Body torque function f(t,y) -> [3,] [Nm], defaults to np.zeros(3)

  • int_tol (float, optional) – Integration rtol and atol for RK45, defaults to 1e-13

  • method (str, optional) – scipy.integrate.solve_ivp method keyword argument to use, defaults to ‘RK45’

Returns:

Integrated quaternions [n,4]; integrated angular velocities [n,3]

Return type:

Tuple[np.ndarray, np.ndarray]

mirage.attitude.itensor_is_symmetric(itensor: ndarray) → Tuple#

Identifies the repeated and axial principal moments of an axisymmetric inertia tensor.

Parameters:

itensor (np.ndarray [3,3]) – Inertia tensor in principal axes [kg m^2]

Returns:

Indices of the two equal principal moments and the index of the remaining axial moment, or (None, None) if the tensor is not axisymmetric

Return type:

Tuple

mirage.attitude.mrp_add(s1: ndarray, s2: ndarray) → ndarray#

Adds modified Rodrigues parameters (see quat_add)

Parameters:
  • s1 (np.ndarray [n,3]) – Modified Rodrigues parameter array

  • s2 (np.ndarray [n,3]) – Modified Rodrigues parameter array

Returns:

Modified Rodrigues parameter array

Return type:

np.ndarray [n,3]

mirage.attitude.mrp_to_dcm(s: ndarray) → ndarray#

Converts modified Rodrigues parameters to direction cosine matrices

Parameters:

s (np.ndarray [n,3]) – Modified Rodrigues parameter array

Returns:

Direction cosine matrix array

Return type:

np.ndarray [3,3xn]

mirage.attitude.mrp_to_quat(s: ndarray) → ndarray#

Converts modified Rodrigues parameters to quaternions

Parameters:

s (np.ndarray [n,3]) – Modified Rodrigues parameter array

Returns:

Quaternion array

Return type:

np.ndarray [n,4]

mirage.attitude.mrp_to_rv(s: ndarray) → ndarray#

Converts modified Rodrigues parameters to rotation vectors

Parameters:

s (np.ndarray [n,3]) – Modified Rodrigues parameter array

Returns:

Rotation vector array

Return type:

np.ndarray [n,3]

mirage.attitude.propagate_attitude_torque_free(quat0: ndarray, omega0: ndarray, itensor: ndarray, teval: ndarray) → Tuple[ndarray, ndarray]#

Computes torque-free motion for an arbitrary inertia tensor using elliptic integrals and Jacobi elliptic functions

Parameters:
  • quat0 (np.ndarray [n,4]) – Initial orientation as quaternion

  • omega0 (np.ndarray [n,3]) – Initial angular velocity [rad/s]

  • itensor (np.ndarray [3,3]) – Inertia tensor in principal axes [kg m^2]

  • teval (np.ndarray [m,]) – Times after the initial state to evaluate at [second]

Returns:

Orientation of body over time as a quaternion and body frame angular velocity [rad/s]

Return type:

Tuple[np.ndarray [n,m,4], np.ndarray [n,m,3]]

mirage.attitude.propagate_attitude_torque_free_axisymmetric(quat0: ndarray, omega0: ndarray, itensor: ndarray, teval: ndarray) → tuple[ndarray, ndarray]#

Propagates torque-free axisymmetric motion using an analytic solution to the constant spin and precession rate

Parameters:
  • quat0 (np.ndarray [n,4]) – Initial quaternion transforming from the inertial to body frames

  • omega0 (np.ndarray [n,3]) – Initial angular velocity [rad/s]

  • itensor (np.ndarray [3,3]) – Inertia tensor [kg m^2]

  • teval (np.ndarray [n,]) – Times in seconds after the definition epoch at t=0 where quat0 and omega0 are defined

Returns:

The time history of the quaternion and angular velocity (rad/s) at the requested epochs

Return type:

tuple[np.ndarray, np.ndarray]

mirage.attitude.quat_add(q1: ndarray, q2: ndarray) → ndarray#

Adds (multiplies) quaternions together such that quat_add(quat_inv(q1), q2) gives the rotation between q1 and q2

Parameters:
  • q1 (np.ndarray [n,4]) – Quaternion array

  • q2 (np.ndarray [n,4]) – Quaternion array

Returns:

Quaternion array

Return type:

np.ndarray [n,4]

mirage.attitude.quat_ang(q1: ndarray, q2: ndarray, deg: bool = False) → ndarray#

Angle between orientations expressed as quaternion arrays (makes sure they are on the same hemisphere of the hypersphere first)

Parameters:
  • q1 (np.ndarray [n,4]) – Quaternion array

  • q2 (np.ndarray [n,4]) – Quaternion array

  • deg (bool, optional) – Whether to output angular quantities in degrees instead of radians, defaults to False

Returns:

Angle between quaternion arrays [rad], or [deg] if deg is True

Return type:

np.ndarray [n,]

mirage.attitude.quat_inv(q: ndarray) → ndarray#

Finds the quaternion inverse (conjugate for unit quaternions)

Parameters:

q (np.ndarray [n,4]) – Input quaternion array

Returns:

Inverse quaternion array

Return type:

np.ndarray [n,4]

mirage.attitude.quat_inverse_kinematics(q: ndarray, qdot: ndarray) → ndarray#

Inverse kinematic differential equations, returns angular velocity [rad/s]

Parameters:
  • q (np.ndarray [n,4]) – Quaternions

  • qdot (np.ndarray [n,4]) – Quaternion derivatives

Returns:

Angular velocity of body frame [rad/s]

Return type:

np.ndarray [n,3]

mirage.attitude.quat_kinematics(q: ndarray, w: ndarray) → ndarray#

Kinematic differential equations for quaternion time evolution

Parameters:
  • q (np.ndarray [n,4]) – Current quaternion from inertial to body

  • w (np.ndarray [n,3]) – Current angular velocity in body frame [rad/s]

Returns:

Time derivative of input quaternion

Return type:

np.ndarray [n,4]

mirage.attitude.quat_lower_hemisphere(q: ndarray) → ndarray#

Transforms quaternions to the lower hemisphere of \(S^3\) such that the scalar component q[..., 3] <= 0.

Parameters:

q (np.ndarray) – Quaternion array of shape […, 4]

Returns:

Transformed quaternion array with same shape

Return type:

np.ndarray

mirage.attitude.quat_r_from_eas(hhat: ndarray, phi: ndarray, theta: ndarray, psi: ndarray, is_sam: bool) → ndarray#

Computes quaternion for attitude solution from Euler angle sequence

Parameters:
  • hhat (np.ndarray [n,3]) – Inertial angular momentum direction

  • phi (np.ndarray [n,]) – Spin angle [rad]

  • theta (np.ndarray [n,]) – Nutation angle [rad]

  • psi (np.ndarray [n,]) – Precession angle [rad]

  • is_sam (np.ndarray [n,]) – Whether the rotation is short axis mode (SAM)

Returns:

Computed quaternions

Return type:

np.ndarray [n,4]

mirage.attitude.quat_to_dcm(q: ndarray) → ndarray#

Converts quaternions to direction cosine matrices

Parameters:

q (np.ndarray [n,4]) – Quaternion array

Returns:

Direction cosine matrix array

Return type:

np.ndarray [3,3xn]

mirage.attitude.quat_to_mrp(q: ndarray) → ndarray#

Converts quaternions to modified Rodrigues parameters

Parameters:

q (np.ndarray [n,4]) – Quaternion array

Returns:

Modified Rodrigues parameter array

Return type:

np.ndarray [n,3]

mirage.attitude.quat_to_rv(q: ndarray) → ndarray#

Converts quaternions to rotation vectors

Parameters:

q (np.ndarray [n,4]) – Quaternion array

Returns:

Rotation vector array

Return type:

np.ndarray [n,3]

mirage.attitude.quat_upper_hemisphere(q: ndarray) → ndarray#

Transforms quaternions to the upper hemisphere of \(S^3\) such that the scalar component q[..., 3] >= 0.

Parameters:

q (np.ndarray) – Quaternion array of shape […, 4]

Returns:

Transformed quaternion array with same shape

Return type:

np.ndarray

mirage.attitude.r1(t: ndarray | float) → ndarray#

Rotation about the first body axis with input in radians

Parameters:

t (Union[np.ndarray, float]) – Angle t (short for theta) [rad]

Returns:

Rotation matrix(s) about the first body axis

Return type:

np.ndarray

mirage.attitude.r2(t: ndarray | float) → ndarray#

Rotation about the second body axis with input in radians

Parameters:

t (Union[np.ndarray, float]) – Angle t (short for theta) [rad]

Returns:

Rotation matrix(s) about the second body axis

Return type:

np.ndarray

mirage.attitude.r3(t: ndarray | float) → ndarray#

Rotation about the third body axis with input in radians

Parameters:

t (Union[np.ndarray, float]) – Angle t (short for theta) [rad]

Returns:

Rotation matrix(s) about the third body axis

Return type:

np.ndarray

mirage.attitude.rand_quaternions(num: int) → ndarray#

Generates uniform random vectors on \(S^3\) (interpreted as unit quaternions)

Parameters:

num (int) – Number of unit vectors to generate

Returns:

Sampled quaternions

Return type:

np.ndarray [n,4]

mirage.attitude.rigid_rotation_dynamics(t: float, w: ndarray, itensor: ndarray, torque: Callable | None = None) → ndarray#

Rigid body rotational dynamics (Euler’s equations of motion)

Parameters:
  • t (float) – Current integration time [seconds]

  • w (np.ndarray [1x3]) – Angular velocity vector of body relative to inertial space [rad/s]

  • itensor (np.ndarray [3,3]) – Inertia tensor in principal axes, should be diagonal [kg m^2]

  • torque (Callable, optional) – Torque applied to the body due to external forces [N m], defaults to None

Returns:

Angular acceleration vector [rad/s^2]

Return type:

np.ndarray [1x3]

mirage.attitude.rv_add(p1: ndarray, p2: ndarray) → ndarray#

Adds rotation vectors (see quat_add)

Parameters:
  • p1 (np.ndarray [n,3]) – Rotation vector array

  • p2 (np.ndarray [n,3]) – Rotation vector array

Returns:

Rotation vector array

Return type:

np.ndarray [n,3]

mirage.attitude.rv_to_dcm(p: ndarray) → ndarray#

Converts rotation vectors to direction cosine matrices

Parameters:

p (np.ndarray [n,3]) – Rotation vector array

Returns:

Direction cosine matrix array

Return type:

np.ndarray [3,3xn]

mirage.attitude.rv_to_mrp(p: ndarray) → ndarray#

Converts rotation vectors to modified Rodrigues parameters via quaternions

Parameters:

p (np.ndarray [n,3]) – Rotation vector array

Returns:

Modified Rodrigues parameter array

Return type:

np.ndarray [n,3]

mirage.attitude.rv_to_quat(p: ndarray) → ndarray#

Converts rotation vectors to quaternions

Parameters:

p (np.ndarray [n,3]) – Rotation vector array

Returns:

Quaternion array

Return type:

np.ndarray [n,4]

mirage.background module#

mirage.background.airglow_radiance(lambdas: ndarray) → ndarray#

Computes spectral radiances due to airglow [Daniels]:

Parameters:

lambdas (np.ndarray) – Wavelengths to interpolate [nm]

Returns:

Spectral radiances [W/m^2/nm/ster]

Return type:

np.ndarray

mirage.background.airglow_signal(dates: ndarray[datetime, Any], station, look_dirs_eci_eq: ndarray, obs_pos_eci_eq: ndarray, integration_time_s: float, is_ground_based: bool = True) → ndarray#

Signal on CCD sensor due to airglow [Kra]

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at (UTC)

  • station (Station) – The station to observe from

  • look_dirs_eci_eq (np.ndarray) – Look unit vectors in equatorial Earth-centered inertial (ECI)

  • obs_pos_eci_eq (np.ndarray) – Observer positions in equatorial Earth-centered inertial (ECI) [km]

  • integration_time_s (float) – Integration time [s]

  • is_ground_based (bool) – Whether the station taking the observation is ground or space based

Returns:

Signal on CCD [ADU/pixel]

Return type:

np.ndarray

mirage.background.atmospheric_extinction(lambdas: ndarray) → ndarray#

Calculates atmospheric extinction coefficient as described in [Kra]

Parameters:

lambdas (np.ndarray) – Wavelengths to sample [m]

Returns:

Atmospheric extinction coefficient [nondim]

Return type:

np.ndarray

mirage.background.equatorial_dir_to_ecliptic_azel(dates: ndarray[datetime, Any], look_dirs_eci_eq: ndarray, wrap_az_to_2pi: bool = False) → Tuple[ndarray, ndarray]#

Converts from equatorial to ecliptic azimuth and elevation

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at (UTC)

  • look_dirs_eci_eq (np.ndarray) – Look directions in Earth-Centered Inertial (ex. J2000), referenced to the Earth equator

  • wrap_az_to_2pi (bool, optional) – Whether to wrap the azimuth values from [-pi,pi] to [0,2pi], defaults to False

Returns:

Ecliptic-referenced azimuth and elevation, both [rad]

Return type:

Tuple[np.ndarray, np.ndarray]

mirage.background.individual_atmospheric_transmission(lambdas: ndarray, zenith_angles_rad: ndarray = 0.0, observer_altitude_km: float = 0.0)#

Computes atmospheric transmission at the given wavelengths and zenith angles using LOWTRAN.

Parameters:
  • lambdas (np.ndarray) – Wavelengths to evaluate at [nm]

  • zenith_angles_rad (np.ndarray, optional) – Zenith angles [rad], defaults to 0.0

  • observer_altitude_km (float, optional) – Observer altitude [km], defaults to 0.0

Returns:

Atmospheric transmission [nondim]

Return type:

np.ndarray

mirage.background.integrated_spectrum(station, z_obs: ndarray, lambdas: ndarray = array([330., 353.79310345, 377.5862069, 401.37931034, 425.17241379, 448.96551724, 472.75862069, 496.55172414, 520.34482759, 544.13793103, 567.93103448, 591.72413793, 615.51724138, 639.31034483, 663.10344828, 686.89655172, 710.68965517, 734.48275862, 758.27586207, 782.06896552, 805.86206897, 829.65517241, 853.44827586, 877.24137931, 901.03448276, 924.82758621, 948.62068966, 972.4137931, 996.20689655, 1020.]), spectrum: ndarray | None = None, area: float | None = None, is_ground_based: bool = True, include_atmospheric_transmission: bool = True) → ndarray#

Computes the count rate in [ADU / s] due to an exoatmospheric photon spectrum [Kra]

Parameters:
  • station (Station) – The station to observe from

  • z_obs (np.ndarray [mx1]) – Zenith angle of observation [rad]

  • lambdas (np.ndarray [nx1], optional) – Wavelengths to integrate over [nm], defaults to np.linspace(330, 1020, 30)

  • spectrum (Union[np.ndarray [nx1], None], optional) – Irradiance or radiance spectrum to integrate over, None defaults to the Sun spectrum [W / m^2 / nm]

  • area (Union[float, None], optional) – Area to distribute the signal over, [m^2] if the spectrum is [W / m^2 / nm]. Defaults to station.telescope.aperture_area. If the spectrum is [W / m^2 / nm / sr], area is [sr]

  • is_ground_based (bool) – Whether the station taking the observation is ground or space based

  • include_atmospheric_transmission (bool, optional) – Whether to include atmospheric transmission in the computed signal, defaults to True

Returns:

Count rate [ADU / s] that can be multiplied by integration time for counts

Return type:

np.ndarray

mirage.background.integrated_starlight_signal(station, look_dirs_eci_eq: ndarray, obs_pos_eci_eq: ndarray, integration_time_s: float, is_ground_based: bool = True, **_) → ndarray#

Computes the mean signal [ADU/pixel] on the CCD due to integrated starlight from magnitudes 16 to 21 using a patched Gaia catalog [Kra]

Parameters:
  • station (Station) – The station to observe from

  • look_dirs_eci_eq (np.ndarray) – Look unit vectors in equatorial Earth-centered inertial (ECI)

  • obs_pos_eci_eq (np.ndarray) – Observer positions in equatorial Earth-centered inertial (ECI) [km]

  • integration_time_s (float) – Integration time [s]

  • is_ground_based (bool) – Whether the station taking the observation is ground or space based

Returns:

Signal on CCD [ADU/pixel]

Return type:

np.ndarray

mirage.background.moon_phase_fraction(moon_phase_angle: ndarray) → ndarray#

Computes the brightness fraction at a given lunar phase angle [Kra]

Parameters:

moon_phase_angle (np.ndarray) – Angle between Earth and Sun from the perspective of the Moon [rad]

Returns:

Fraction of full Moon radiance at observer [nondim]

Return type:

np.ndarray

mirage.background.moonlight_signal(dates: ndarray[datetime, Any], station, look_dirs_eci_eq: ndarray, obs_pos_eci_eq: ndarray, integration_time_s: float, is_ground_based: bool = True) → ndarray#

Mean signal on image background due to scattered moonlight

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate brightness at [UTC]

  • station (Station) – The station to observe from

  • look_dirs_eci_eq (np.ndarray) – Look unit vectors in equatorial Earth-centered inertial (ECI)

  • obs_pos_eci_eq (np.ndarray) – Observer positions in equatorial Earth-centered inertial (ECI) [km]

  • integration_time_s (float) – Integration time [s]

  • is_ground_based (bool) – Whether the station taking the observation is ground or space based

Returns:

Background signal due to moonlight [ADU/pixel]

Return type:

np.ndarray

mirage.background.proof_zero_mag_stellar_spectrum(lambdas: ndarray) → ndarray#

Interpolates the spectrum of a representative zero-magnitude star

Parameters:

lambdas (np.ndarray) – Wavelengths to sample [nm]

Returns:

Interpolated spectrum [W/m^2/nm]

Return type:

np.ndarray

mirage.background.sint(station, z_obs: ndarray, lambda_lims: Tuple = (100, 1050), is_ground_based: bool = True) → ndarray#

Computes the electron rate per unit irradiance for the Sun spectrum [Kra]

Parameters:
  • station (Station) – The station to observe from

  • z_obs (np.ndarray) – Zenith angle of observation [rad]

  • lambda_lims (Tuple[float, float], optional) – Wavelength limits to integrate over [nm], defaults to (100, 1050)

  • is_ground_based (bool) – Whether the station taking the observation is ground or space based

Returns:

Count rate per unit irradiance [e- / (W / m^2 * s)] that can be multiplied by irradiance and integration time for counts

Return type:

np.ndarray

mirage.background.twilight_signal(dates: ndarray[datetime, Any], station, look_dirs_eci_eq: ndarray, obs_pos_eci_eq: ndarray, integration_time_s: float, is_ground_based: bool = True, band: str = 'V') → ndarray#

Signal on CCD sensor due to the setting or rising sun [PatatUgolnikovPostylyakov]

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at (UTC)

  • station (Station) – The station to observe from

  • look_dirs_eci_eq (np.ndarray) – Look unit vectors in equatorial Earth-centered inertial (ECI)

  • obs_pos_eci_eq (np.ndarray) – Observer positions in equatorial Earth-centered inertial (ECI) [km]

  • integration_time_s (float) – Integration time [s]

  • is_ground_based (bool) – Whether the station taking the observation is ground or space based

  • band (str, optional) – Which UBVRI band the observation is in

Returns:

Signal on CCD [ADU/pixel]

Return type:

np.ndarray

mirage.background.twilight_zenith_mpsas(gamma: ndarray, band: str = 'V') → ndarray#

Zenith brightness due to twilight [PatatUgolnikovPostylyakov]:

Parameters:
  • gamma (np.ndarray) – Zenith angle [deg]

  • band (str, optional) – Observation band (UBVRI filter), defaults to “V”

Returns:

Twilight brightness in magnitudes per square arcsecond

Return type:

np.ndarray

mirage.background.zodiacal_signal(dates: ndarray[datetime, Any], station, look_dirs_eci_eq: ndarray, obs_pos_eci_eq: ndarray, integration_time_s: float, is_ground_based: bool = True) → ndarray#

Computes signal in CCD due to zodiacal light [Kra]

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at (UTC)

  • station (Station) – The station to observe from

  • look_dirs_eci_eq (np.ndarray) – Look unit vectors in equatorial Earth-centered inertial (ECI)

  • obs_pos_eci_eq (np.ndarray) – Observer positions in equatorial Earth-centered inertial (ECI) [km]

  • integration_time_s (float) – Integration time [s]

  • is_ground_based (bool) – Whether the station taking the observation is ground or space based

Returns:

Signal on CCD [ADU/pixel]

Return type:

np.ndarray

mirage.ccd module#

class mirage.ccd.ChargeCoupledDevice(preset: str = 'pogs')#

Bases: object

Charge-coupled device model with detector noise, gain, sensor geometry, and image generation utilities.

The preset argument selects a detector configuration.

generate_ccd_image(date: datetime, integration_time_s: float, station, look_dir_eci: ndarray, tracking_rates: ndarray, lc_adu: float, catalog: StarCatalog, up_dir_eci: ndarray, noise: bool = True, sky_brightness: bool = True, add_catalog: bool = True, add_distortion: bool = True, verbose: bool = True, binning: tuple | None = None, flat_field: Callable | None = None) → ndarray#

Generates a CCD image for a set of observation conditions

Parameters:
  • date (datetime.datetime) – The midpoint of the integration time as a UTC datetime

  • integration_time_s (float) – Integration time in seconds

  • station (Station) – Station taking the observation

  • look_dir_eci (np.ndarray) – Look direction (unit vectors) in Earth-centered inertial (ECI) at the midpoint of the integration time

  • tracking_rates (np.ndarray) – The tracking rates of the telescope in RA/Dec at the midpoint of the integration time in [arcsec/s]

  • lc_adu (float) – The total brightness of the object (ADU)

  • catalog (StarCatalog) – The catalog to use for the background stars

  • up_dir_eci (np.ndarray) – The up directions of the telescope in ECI at the midpoint of the integration time

  • noise (bool, optional) – Whether to add noise to the image, defaults to True

  • sky_brightness (bool, optional) – Whether to account for the simulated sky brightness of the background, defaults to True

  • add_catalog (bool, optional) – Whether to add the catalog objects to the image, defaults to True

  • add_distortion (bool, optional) – Whether to add distortion to the image, defaults to True

  • verbose (bool, optional) – Whether to print information about catalog objects in frame, defaults to True

  • binning (Union[tuple, None], optional) – Binning to add, i.e. (2,2), defaults to None

  • flat_field (Union[Callable, None], optional) – Flat field intensity as a function of the x,y pixel locations, defaults to None (1.0 for all pixels)

Returns:

Image matrix with the dimensions of the station’s telescope’s sensor (ADU)

Return type:

np.ndarray

mean(pixels: ndarray, integration_time_s: float) → float#

Returns the mean noise signal due to the non-zero-mean dark noise terms: dark readout and dark integration noise

Parameters:
  • pixels (np.ndarray) – Number of pixels for each case

  • integration_time_s (float) – Integration time in seconds for each case

Returns:

Mean noise signal in each case

Return type:

Union[np.ndarray, float]

quantum_efficiency(lambdas: ndarray) → ndarray#

Computes quantum efficiency for a representative CCD sensor [Kra]

Parameters:

lambdas (np.ndarray) – Sample wavelengths [nm]

Returns:

Quantum efficiency [photoelectrons/photon]

Return type:

np.ndarray

sample_noise(integration_time_s: float, pixels: int, shape: tuple) → ndarray#

Samples the total noise signal in the CCD for a given number of pixels and integration time

Parameters:
  • integration_time_s (float) – Seconds of integration time

  • pixels (int) – Number of pixels being sampled

  • shape (tuple) – Shape of the output

Returns:

Sampled noise, each component independently sampled from the same noise distributions defined by the other inputs

Return type:

np.ndarray

variance(integration_time_s: ndarray | float) → ndarray | float#

The variance of the noise signal due to dark integration, dark readout, and read noise

Parameters:

integration_time_s (Union[np.ndarray, float]) – Integration time in seconds

Returns:

Variance in [e-^2/pix]

Return type:

Union[np.ndarray, float]

mirage.ccd.ccd_minus_parabolic_background(ccd_adu: ndarray) → ndarray#

Returns a copy of the CCD image with the parabolic background subtracted.

Parameters:

ccd_adu (np.ndarray) – CCD image in ADU

Returns:

CCD image with the parabolic background subtracted

Return type:

np.ndarray

mirage.ccd.convolve_with_kernel(image: ndarray, kernel: ndarray) → ndarray#

Convolves an image with a given kernel

Parameters:
  • image (np.ndarray) – The image to convolve

  • kernel (np.ndarray) – The kernel to convolve with

Returns:

The convolved image

Return type:

np.ndarray

mirage.ccd.image_background_naive(ccd_adu: ndarray, frac_cuts: tuple[float, float] = (0.0001, 0.002)) → tuple[ndarray, float]#

A naive approach to finding the constant background of a CCD image by cutting off a fraction of the brightest and dimmest pixels

Parameters:
  • ccd_adu (np.ndarray) – CCD image in ADU

  • frac_cuts (tuple[float, float], optional) – Fraction of values to cut off of the bottom and top of the sorted pixel counts, defaults to (1e-4, 2e-3)

Returns:

Boolean mask of pixels that are in the background, and the mean background ADU

Return type:

tuple[np.ndarray, float]

mirage.ccd.image_background_parabola(ccd_adu: ndarray, return_eq_str: bool = False, reduction_factor: int = 16) → ndarray#

Fits a parabola to the background of a CCD image

Parameters:
  • ccd_adu (np.ndarray) – CCD image in ADU

  • return_eq_str (bool, optional) – Whether to return the string form of the parabola equation, defaults to False

  • reduction_factor (int, optional) – Factor to reduce the image by for speed, defaults to 16

Returns:

Mean background values for each pixel in the CCD image, and optionally the string form of the parabola equation when return_eq_str is True

Return type:

Union[np.ndarray, tuple[np.ndarray, str]]

mirage.ccd.solve_star_streak_angle(img: ndarray, template_streak_length: int = 100, square_size_of_image_used: int = 500) → float#

Estimates the angle of a star streak in an image by maximizing the variance of the streaked image over candidate directions.

Parameters:
  • img (np.ndarray) – Image containing the star streak

  • template_streak_length (int, optional) – Length of the template streak kernel [pix], defaults to 100

  • square_size_of_image_used (int, optional) – Size of the central square image region used for the estimate [pix], defaults to 500

Returns:

Estimated streak angle [rad]

Return type:

float

mirage.ccd.streak_convolution(image: ndarray, direction: tuple[float, float], length: float) → ndarray#

Convolves an image with a streak kernel of a given length in a given direction

Parameters:
  • image (np.ndarray) – Image to streak

  • direction (tuple[float, float]) – Direction to streak in, in the image plane frame

  • length (float) – Length of the streak kernel [pix]

Returns:

Streaked image

Return type:

np.ndarray

mirage.ccd.streak_convolution_kernel(direction: tuple[float, float], length: float) → ndarray#

Generates the convolution kernel for a streak

Parameters:
  • direction (tuple[float, float]) – Direction to streak the image in, in the image plane frame

  • length (float) – Length of the streak kernel [pix]

Returns:

Convolution kernel

Return type:

np.ndarray

mirage.constants module#

class mirage.constants.AstroConstants#

Bases: object

Collection of astrodynamically-relevant constants

au_to_km: Final[float] = 149600000.0#
deg_to_arcsecond: Final[int] = 3600#
earth_angular_velocity: Final[float] = 7.292115e-05#
earth_f: Final[float] = 0.0033528106647474805#
earth_j2: Final[float] = 0.00108262668#
earth_mass_kg: Final[float] = 5.98e+24#
earth_mu: Final[float] = 398600.4418#
earth_r_eq: Final[float] = 6378.137#
earth_sec_in_day: Final[int] = 86400#
lunar_month_days: Final[float] = 29.530588853#
moon_f: Final[float] = 0.0012#
moon_inertial_angular_velocity: Final[float] = 2.6616995272150692e-06#
moon_mu: Final[float] = 4902.8001224453#
moon_orbit_semimajor_axis: Final[float] = 384400#
moon_r_eq: Final[float] = 1739#
moon_sidereal_period_days: Final[float] = 27.321661#
moon_sidereal_period_sec: Final[float] = 2360591.5104#
moon_solid_angle: Final[float] = 6.418e-05#
moon_synodic_period_days: Final[float] = 29.530588#
moon_synodic_period_sec: Final[float] = 2551442.8032#
permeability_free_space: Final[float] = 1.2566370614359173e-06#
planck_constant: Final[float] = 6.62607015e-34#
rad_to_arcsecond: Final[float] = np.float64(206264.80624709636)#
rev_to_arsecond: Final[int] = 1296000#
speed_of_light_vacuum: Final[float] = 299792458.0#
steradian_to_arcsecond2: Final[float] = np.float64(42545170296.15221)#
sun_irradiance_vacuum: Final[float] = 1361#
sun_luminosity: Final[float] = 3.846e+26#
sun_magnitude: Final[float] = -26.832#
sun_mu: Final[float] = 132712440041.27942#
sun_r_eq: Final[float] = 696340.0#
sun_solid_angle: Final[float] = 6.794e-05#
vega_irradiance: Final[float] = 2.518021002e-08#

mirage.constraints module#

class mirage.constraints.ElevationConstraint(min_angle_deg: float)#

Bases: ObserverConstraint

Constraint requiring a minimum elevation above the horizon.

DIFFICULTY = 0#
class mirage.constraints.MoonExclusionConstraint(min_angle_deg: float)#

Bases: ObserverConstraint

Constraint requiring a minimum angular separation from the Moon.

DIFFICULTY = 3#
class mirage.constraints.ObserverConstraint#

Bases: object

Base class for observer constraints.

class mirage.constraints.ObserverEclipseConstraint(station)#

Bases: ObserverConstraint

Constraint requiring the observer to be in Earth’s shadow.

DIFFICULTY = 2#
class mirage.constraints.SnrConstraint(min_snr: float)#

Bases: ObserverConstraint

Constraint requiring a minimum signal-to-noise ratio.

DIFFICULTY = 5#
class mirage.constraints.TargetIlluminatedConstraint#

Bases: ObserverConstraint

Constraint requiring the target to be in full sunlight.

DIFFICULTY = 2#
class mirage.constraints.VisualMagnitudeConstraint(max_visual_magnitude: float)#

Bases: ObserverConstraint

Constraint requiring the target to be brighter than a maximum visual magnitude.

DIFFICULTY = 1#

mirage.coordinates module#

class mirage.coordinates.EarthFixedFrame(home: str, to: str)#

Bases: object

Handles transformations between various Earth-centered reference frames

get_functions()#

Gets the functions required to transform between the requested frames

rotms_at_dates(dates: datetime | ndarray[datetime, Any]) → ndarray#

Transformation matrices from the home frame into the target frame at a given date(s)

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date(s) to evaluate [UTC]

Returns:

DCM from home frame to target frame

Return type:

np.ndarray [3,3,n] or [3,3]

vecs_at_dates(dates: datetime | ndarray[datetime, Any], vecs_in_home_frame: ndarray) → ndarray#

Transforms vectors in the home frame into the target frame at a given date(s)

Parameters:
  • dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date(s) to evaluate at [UTC]

  • vecs_in_home_frame (np.ndarray [1x3] or [n,3]) – Single vector evaluated at all dates, or one vector per date; must be in the home frame

Returns:

Transformed vectors in the target frame

Return type:

np.ndarray [1x3] or [n,3]

class mirage.coordinates.FrameInterpolator(frame_from, frame_to, dates, max_surface_error_km=0.001)#

Bases: object

Callable interpolator for a transformation between two supported frames.

class mirage.coordinates.SpiceInterpolator(body_name: str, dates: ndarray, atol: float = 1e-05)#

Bases: object

Cubic interpolator for solar-system body positions generated from SPICE kernels.

build()#

Builds the cubic interpolator, doubling the node count until the error tolerance is met.

mirage.coordinates.asc_node_moon(dates: datetime | ndarray[datetime, Any]) → ndarray#

Computes the ascending node longitude of the Moon’s orbit.

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date(s) to evaluate at [UTC]

Returns:

Ascending node longitude [rad]

Return type:

np.ndarray

mirage.coordinates.az_el_to_enu(az: ndarray, el: ndarray) → ndarray#

Converts from azimuth and elevation on the local viewing sphere to East North Up (ENU) vectors

Parameters:
  • az (np.ndarray [n,]) – Azimuth [rad], measured CW from the North vector

  • el (np.ndarray [n,]) – Elevation [rad], measured from the East-North plane, with positive elevations above the plane

Returns:

ENU unit vectors

Return type:

np.ndarray [n,3]

mirage.coordinates.date_to_et(dates: ndarray[datetime, Any]) → ndarray[float]#

Computes J2000 ephemeris time (ET) from a set of UTC dates

Parameters:

dates (np.ndarray[datetime.datetime, Any]) – Date array (UTC)

Returns:

Ephemeris time past J2000 epoch [sec]

Return type:

np.ndarray[float]

mirage.coordinates.date_to_gast(dates: ndarray[datetime, Any] | datetime, scale: str = 'ut1') → ndarray#

Computes Greenwich Apparent Sidereal Time (GAST)

Parameters:
  • dates (Union[np.ndarray[datetime.datetime, Any], datetime.datetime]) – Dates [UTC]

  • scale (str, optional) – Time scale to use from [‘utc’, ‘ut1’, ‘tai’, ‘tt’], defaults to ‘ut1’

Returns:

GAST in radians

Return type:

np.ndarray

mirage.coordinates.delta_psi_delta_epsilon(dates: datetime | ndarray[datetime, Any]) → Tuple[ndarray, ndarray, ndarray]#

Difference in Earth equator and equinox due to nutation

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date(s) to evaluate at [UTC]

Returns:

\(\Delta \psi\), \(\Delta \varepsilon\), \(\bar{\varepsilon}\) (mean obliquity) for each date

Return type:

Tuple[np.ndarray, np.ndarray, np.ndarray]

mirage.coordinates.ecef_to_enu(enu_origin_in_ecef: ndarray) → ndarray#

Rotation matrix from Earth-centered, Earth-fixed (ECEF) coordinates to East, North, Up (ENU) coordinates

Parameters:

enu_origin_in_ecef (np.ndarray [1x3]) – ENU origin point in ECEF coordinates [km]

Returns:

Rotation matrix at that ECEF point

Return type:

np.ndarray [3,3]

mirage.coordinates.eci_to_ra_dec(eci_dir: ndarray, deg: bool = False) → tuple[ndarray, ndarray]#

Converts from an Earth-centered inertial (ECI) direction to inertial right ascension (RA) and declination (Dec)

Parameters:
  • eci_dir (np.ndarray [n,3]) – Directions of interest in ECI

  • deg (bool, optional) – Whether to output angular quantities in degrees instead of radians, defaults to False

Returns:

Right ascension [rad] and declination [rad] angles

Return type:

tuple[np.ndarray, np.ndarray]

mirage.coordinates.eci_to_sun_ec(dates: ndarray[datetime, Any]) → ndarray#

Rotation matrix from Earth-centered inertial (ECI) to Sun-relative ECI

Parameters:

dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at (UTC)

Returns:

Stack of DCMs

Return type:

np.ndarray

mirage.coordinates.enu_to_az_el(r_enu: ndarray, deg: bool = False) → tuple[ndarray, ndarray]#

Converts topocentric East, North, Up (ENU) vectors to azimuth and elevation. Azimuth is referenced to North and proceeds clockwise.

Parameters:
  • r_enu (np.ndarray [n,3]) – ENU direction vectors

  • deg (bool, optional) – Whether to return angles in degrees, defaults to False

Returns:

Azimuth referenced to North and elevation above the horizon, in [rad] or [deg]

Return type:

tuple[np.ndarray, np.ndarray]

mirage.coordinates.enu_to_ecef(enu_origin_in_ecef: ndarray) → ndarray#

Rotation matrix from East, North, Up (ENU) coordinates to Earth-centered, Earth-fixed (ECEF) coordinates

Parameters:

enu_origin_in_ecef (np.ndarray [1x3]) – ENU origin point in ECEF coordinates [km]

Returns:

Rotation matrix at that ECEF point

Return type:

np.ndarray [3,3]

mirage.coordinates.gtod_to_itrf(dates: datetime | ndarray[datetime, Any]) → ndarray#

Rotation matrix(s) from Greenwich True of Date (GTOD) to the International Terrestrial Reference Frame (ITRF)

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date to evaluate at [UTC]

Returns:

Rotation matrix

Return type:

np.ndarray [3,3xn] or [3,3]

mirage.coordinates.itrf_to_lla(r_itrf_km: ndarray) → Tuple[ndarray, ndarray, ndarray]#

Converts from the International Terrestrial Reference Frame (ITRF) to latitude, longitude, and altitude above the WGS84 ellipsoid

Parameters:

r_itrf_km (np.ndarray [n,3]) – ITRF positions for each LLA triplet [km]

Returns:

Geodetic latitude [rad], longitude [rad], and altitude [km]

Return type:

Tuple[np.ndarray, np.ndarray, np.ndarray] each [n,]

mirage.coordinates.j2000_to_itrf(dates: ndarray[datetime, Any] | datetime) → ndarray#

Converts from Earth-centered inertial (ECI) J2000 to Earth-centered, Earth-fixed (ECEF) ITRF coordinates. Accounts for precession, nutation, and polar motion.

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date(s), assumed to be UTC

Returns:

Rotation matrix from ECI to ECEF

Return type:

np.ndarray [3,3xn] if more than one date provided, otherwise [3,3]

mirage.coordinates.j2000_to_lla(r_eci: ndarray, dates: ndarray[datetime]) → Tuple[ndarray, ndarray, ndarray]#

Converts J2000 Earth-centered inertial (ECI) positions to latitude, longitude, and altitude above the WGS84 ellipsoid.

Parameters:
  • r_eci (np.ndarray [n,3]) – ECI positions [km]

  • dates (np.ndarray[datetime.datetime]) – Dates to evaluate at [UTC]

Returns:

Geodetic latitude [rad], longitude [rad], and altitude [km]

Return type:

Tuple[np.ndarray, np.ndarray, np.ndarray] each [n,]

mirage.coordinates.j2000_to_mod(dates: datetime | ndarray[datetime, Any]) → ndarray | float#

Rotation matrix from J2000 to Mean of Date (MOD), accounts for precession

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date(s) to evaluate at [UTC]

Returns:

Rotation matrix or stack of rotation matrices

Return type:

np.ndarray [3,3xn] or [3,3]

mirage.coordinates.jupiter(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of Jupiter in equatorial J2000 using SPICE

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Jupiter from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.mars(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of Mars in equatorial J2000 using SPICE

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Mars from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.mcmf_to_j2000(dates: ndarray[datetime, Any]) → ndarray#

Rotation matrix from Moon-Centered-Moon-Fixed (MCMF) to J2000

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Date(s) to evaluate at (UTC)

Returns:

Rotation matrices from MCMF to J2000

Return type:

np.ndarray [3,3xn] if n > 1 else [3,3]

mirage.coordinates.mean_obliquity_of_ecliptic(dates: datetime | ndarray[datetime, Any]) → Tuple[ndarray | float]#

Inclination of the ecliptic plane relative to the equator [rad]

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date(s) to evaluate at [UTC]

Returns:

Inclination angle [rad]

Return type:

Union[np.ndarray, float]

>>> date = datetime.datetime(2000, 12, 9, 13, 14, 15, tzinfo=datetime.timezone.utc)
>>> i = mean_obliquity_of_ecliptic(date)
>>> 0.4090906724834187
mirage.coordinates.mercury(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of Mercury in equatorial J2000 using SPICE

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Mercury from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.mod_to_tod(dates: datetime | ndarray[datetime, Any]) → ndarray#

Rotation matrix(s) from Mean of Date (MOD) to True of Date (TOD), accounts for nutation

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date(s) to evaluate at [UTC]

Returns:

Rotation matrix

Return type:

np.ndarray [3,3xn] or [3,3]

mirage.coordinates.moon(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of the Moon in equatorial J2000 using the JPL NAIF SPICE toolkit

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Moon from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.neptune(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of Neptune in equatorial J2000 using SPICE

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Neptune from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.pluto(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of Pluto in equatorial J2000 using SPICE

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Pluto from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.ra_dec_to_eci(ra_rad: ndarray, dec_rad: ndarray) → ndarray#

Converts from ECI right ascension and declination to an inertial unit vector in the same reference system

Parameters:
  • ra_rad (np.ndarray) – Right ascensions in [rad]

  • dec_rad (np.ndarray) – Declinations in [rad]

Returns:

ECI look directions

Return type:

np.ndarray

mirage.coordinates.saturn(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of Saturn in equatorial J2000 using SPICE

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Saturn from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.sun(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of the Sun in equatorial J2000 using the JPL NAIF SPICE toolkit

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Sun from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.sun_angle_to_horizon(date: ndarray[datetime, Any], r_ecef: ndarray) → ndarray#

The angle between the Sun and a set of earth-fixed points at a given date, with positive angles meaning the Sun is above the horizon

Parameters:
  • date (np.ndarray[datetime.datetime, Any]) – UTC datetime to evaluate at

  • r_ecef (np.ndarray [n,3]) – Array of position vectors in ECEF coordinates to test

Returns:

Angle between Sun and horizon [rad]

Return type:

np.ndarray [n,]

mirage.coordinates.sun_ecliptic_longitude(dates: ndarray[datetime, Any]) → ndarray#

Longitude of the Sun projected onto the ecliptic plane

Parameters:

dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at (UTC)

Returns:

Ecliptic longitude [rad]

Return type:

np.ndarray

mirage.coordinates.sun_irradiance_fraction(dates: ndarray[datetime, Any], r_eci: ndarray) → ndarray#

Computes the fraction of the nominal Sun irradiance received at a given ECI position, taking into account the geometry of the solar penumbra

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at [UTC]

  • r_eci (np.ndarray [n,3]) – Position of interest in ECI [km]

Returns:

Irradiance fraction at given points: unshadowed -> 1.0, full shadow -> 0.0, semi-shadow lies between

Return type:

np.ndarray [n,]

mirage.coordinates.teme_to_gtod(dates: datetime | ndarray[datetime, Any]) → ndarray#

Rotation matrix(s) from True Equator Mean Equinox (TEME) to Greenwich True of Date (GTOD)

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date to evaluate at [UTC]

Returns:

Rotation matrix(s)

Return type:

np.ndarray [3,3xn] or [3,3]

mirage.coordinates.tod_to_teme(dates: datetime | ndarray[datetime, Any]) → ndarray#

Rotation matrix(s) from True of Date (TOD) to True Equator Mean Equinox (TEME)

Parameters:

dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date to evaluate at [UTC]

Returns:

Rotation matrix(s)

Return type:

np.ndarray [3,3xn] or [3,3]

mirage.coordinates.uranus(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of Uranus in equatorial J2000 using SPICE

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Uranus from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.venus(dates: ndarray[datetime, Any]) → ndarray#

Computes the position of Venus in equatorial J2000 using SPICE

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Array of UTC dates

Returns:

Vector to Venus from Earth center [km]

Return type:

np.ndarray [n,3]

mirage.coordinates.with_spice_kernels(f: Callable)#

Decorator that loads the required SPICE kernels before calling the decorated function.

Parameters:

f (Callable) – The function being decorated

Returns:

The decorated function

Return type:

Callable

mirage.dataio module#

mirage.dataio.download_data(urls_and_dirs: dict) → Callable#

Downloads data files to the given directories before calling the decorated function.

Parameters:

urls_and_dirs (dict[str, str]) – URLs to download from (keys) and directories to save to (values)

Returns:

The decorated function

Return type:

Callable

mirage.dataio.download_listing()#

Downloads a listing of all models available on the model archive

mirage.dataio.download_model_file(model_file: str)#

Downloads a model file (.obj) from the light curve models repository

Parameters:

model_file (str) – Model file name (not path) ending in .obj

mirage.dataio.get_model_path(model_name: str) → str#

Gets the path in the remote model repository to a given model

Parameters:

model_name (str) – Model name like cube.obj

Returns:

The path of the remote model

Return type:

str

mirage.dataio.load_json_data(file_name: str) → dict[str, ndarray]#

Loads a dictionary of data arrays from the MIRAGE data directory

Parameters:

file_name (str) – File name to load within os.environ['DATADIR']

Returns:

Dictionary of data arrays loaded from the file

Return type:

dict[str, np.ndarray]

mirage.dataio.local_models() → list[str]#

Returns a list of the models in the current model storage directory

mirage.dataio.online_models() → list[str]#

Returns a list of the models in the remote model repository

mirage.dataio.purge_user_secrets() → None#

Deletes the .env.secret file, which contains user credentials

mirage.dataio.save_file_from_url(url: str, directory: str, extension: str = None)#

Downloads a file from a URL into a directory, extracting ZIP archives if present.

Parameters:
  • url (str) – URL to download

  • directory (str) – Directory in which to save the downloaded file

  • extension (str, optional) – Extension to append if the URL file name has none, defaults to None

Returns:

None

Return type:

None

mirage.dataio.save_json_data(save_dict: dict[str, ndarray], file_name: str, round_digits: int = 9) → None#

Saves a given dictionary of arrays to a JSON file in the MIRAGE data directory

Parameters:
  • save_dict (dict) – Dictionary to be json-ified

  • file_name (str) – File name to save as within os.environ['DATADIR']

  • round_digits (int, optional) – Number of decimals to round data to, defaults to 9

mirage.dataio.with_earthdata(func: Callable) → Callable#

Decorator for functions that require EarthData credentials

Parameters:

func (Callable) – The function being decorated

Returns:

The decorated function

Return type:

Callable

mirage.dataio.with_spacetrack(func: Callable) → Callable#

Decorator for functions that require SpaceTrack credentials

Parameters:

func (Callable) – The function being decorated

Returns:

The decorated function

Return type:

Callable

mirage.environment module#

mirage.environment.albedo_irradiance(date: datetime, sat_pos_ecef: ndarray) → float#

Computes the total irradiance reflected from the surface of Earth at a satellite [W/m^2] The surface BRDF function used here is found in Blanc 2014

Parameters:
  • date (datetime.datetime) – Date to evaluate at (UTC)

  • sat_pos_ecef (np.ndarray) – Position of the satellite in Earth-Centered Earth-Fixed coordinates (ex. ITRF) [km]

Returns:

Total irradiance due to Earth albedo [W/m^2]

Return type:

float

mirage.environment.apparent_refacted_elevation(pressure_mbar: ndarray, temp_kelvin: ndarray, el_true_rad: ndarray) → ndarray#

Computes the apparent elevation angle of a celestial object, accounting for atmospheric refraction

Parameters:
  • pressure_mbar (np.ndarray) – Atmospheric pressure in millibars

  • temp_kelvin (np.ndarray) – Atmospheric temperature in Kelvin

  • el_true_rad (np.ndarray) – True elevation angle of an exoatmospheric object [rad]

Returns:

Apparent elevation angle of an exoatmospheric object [rad]

Return type:

np.ndarray

mirage.environment.apparent_refracted_elevation(pressure_mbar: ndarray, temp_kelvin: ndarray, el_true_rad: ndarray) → ndarray#

Computes the apparent elevation angle of a celestial object, accounting for atmospheric refraction

Parameters:
  • pressure_mbar (np.ndarray) – Atmospheric pressure in millibars

  • temp_kelvin (np.ndarray) – Atmospheric temperature in Kelvin

  • el_true_rad (np.ndarray) – True elevation angle of an exoatmospheric object [rad]

Returns:

Apparent elevation angle of an exoatmospheric object [rad]

Return type:

np.ndarray

mirage.environment.atmospheric_transmission(lambdas: ndarray, zenith_angles: ndarray, altitudes: ndarray = 0.0) → ndarray#

Computes atmospheric transmission by interpolating a precomputed dataset

Parameters:
  • lambdas (np.ndarray) – Wavelengths [nm]

  • zenith_angles (np.ndarray) – Zenith angles [rad]

  • altitudes (np.ndarray, optional) – Altitudes of the observer [km], defaults to 0.0

Returns:

Atmospheric transmissions

Return type:

np.ndarray

mirage.environment.light_time_delay(obs_pos: ndarray, obj_pos: ndarray) → ndarray#

Computes the approximate light time for an observation between a station and a space object

Parameters:
  • obs_pos (np.ndarray [n,3]) – Position of the observer

  • obj_pos (np.ndarray [n,3]) – Position of the object being observed

Returns:

Light time delay [s]

Return type:

np.ndarray

mirage.environment.relative_airmass(z_rad: ndarray, approx: bool = False) → ndarray#

Computes the cumulative airmass (relative to that at zenith) along a ray leaving the atmosphere, equation from [Pickering]

Parameters:
  • z_rad (np.ndarray) – Angle from zenith, measured in radians

  • approx (bool, optional) – Whether to approximate with \(\sec\z_{rad}\), defaults to False

Returns:

Airmasses

Return type:

np.ndarray

mirage.environment.total_solar_irradiance_at_dates(dates: ndarray[datetime, Any]) → ndarray#

Computes the total irradiance in \(\left[\frac{W}{m^2}\right]\) at the Earth’s instantaneous orbital radius

Parameters:

dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at (assumed to be UTC)

Returns:

Irradiance at Earth’s orbital radius \(\left[\frac{W}{m^2}\right]\)

Return type:

np.ndarray

mirage.fits module#

mirage.fits.approximate_background_variance(fits_info: dict) → float#

Estimates the background variance from a central section of a FITS image.

Parameters:

fits_info (dict) – Dictionary of FITS observation information

Returns:

Estimated background variance [ADU^2]

Return type:

float

mirage.fits.expected_star_centroids_in_fits(station: Station, catalog: StarCatalog, look_dir_eci: ndarray, up_dir_eci: ndarray, add_distortion: bool = True) → ndarray#

Computes expected star centroids and metadata for a FITS image.

Parameters:
  • station (Station) – Observing station

  • catalog (StarCatalog) – Star catalog

  • look_dir_eci (np.ndarray [3,]) – Telescope look direction in ECI

  • up_dir_eci (np.ndarray [3,]) – Telescope up direction in ECI

  • add_distortion (bool, optional) – Whether to include telescope distortion, defaults to True

Returns:

Array of star pixel coordinates, unit vectors, spectra, and catalog indices

Return type:

np.ndarray

mirage.fits.find_stars_in_rotated_image(img: ndarray, rotated_image_raw: ndarray, rotated_image: ndarray, theta_rad: float, total_pix_tracked: float) → list[dict]#

Finds star streak candidates in a rotated image using contour detection.

Parameters:
  • img (np.ndarray) – Original image

  • rotated_image_raw (np.ndarray) – Raw rotated image used for brightness measurements

  • rotated_image (np.ndarray) – Thresholded/processed rotated image used for contour detection

  • theta_rad (float) – Rotation angle applied to the image [rad]

  • total_pix_tracked (float) – Expected number of tracked pixels for a streak

Returns:

List of detected star dictionaries with centroids, bounding boxes, and brightness

Return type:

list[dict]

mirage.fits.generate_matched_image(info_path: str, img_ind: int, station: Station, catalog: StarCatalog, add_distortion: bool = True, add_refraction: bool = True, noise: bool = False, obj_total_brightness: float = 30000.0)#

Generates a synthetic CCD image matched to an observed FITS image.

Parameters:
  • info_path (str) – Path to the observation metadata file

  • img_ind (int) – Index of the observation in the metadata file

  • station (Station) – Observing station

  • catalog (StarCatalog) – Star catalog

  • add_distortion (bool, optional) – Whether to include telescope distortion, defaults to True

  • add_refraction (bool, optional) – Whether to include atmospheric refraction, defaults to True

  • noise (bool, optional) – Whether to add CCD noise, defaults to False

  • obj_total_brightness (float, optional) – Total object brightness, defaults to 3e4

Returns:

Dictionary containing the synthetic image, observed image, FITS information, and fit diagnostics

Return type:

dict

mirage.fits.info_from_fits(fits_path: str, telescope: Telescope = <mirage.station.Telescope object>, minimal: bool = False) → dict#

Loads a FITS file and returns a dictionary of observation information

Parameters:
  • fits_path (str) – Path to the FITS file

  • telescope (Telescope, optional) – The telescope used to take the observation

  • minimal (bool, optional) – If True, time-consuming operations will be skipped

Returns:

Dictionary of observation information

Return type:

dict

mirage.fits.load_obs_data(station, obs_mat_path: str, ind: int) → dict#

Loads a single observation from a MATLAB .mat file.

Parameters:
  • station (Station) – The station object

  • obs_mat_path (str) – Path to the ObservationData.mat file

  • ind (int) – Index of the observation in the .mat file

Returns:

Dictionary of observation information

Return type:

dict

mirage.fits.load_obs_mat(obs_mat_path: str) → dict#

Loads observation data from a MATLAB .mat file.

Parameters:

obs_mat_path (str) – Path to the observations.mat file

Returns:

dict of saved data

Return type:

dict

mirage.fits.prepare_fits_for_plotting(img_adu: ndarray, background_method: str = 'parabola') → dict#

Prepares a FITS image for plotting by subtracting a background estimate and applying a logarithmic stretch.

Parameters:
  • img_adu (np.ndarray) – CCD image in ADU

  • background_method (str, optional) – Background subtraction method, one of 'parabola', 'naive', or any other value to skip background subtraction, defaults to ‘parabola’

Returns:

Plot-ready image

Return type:

np.ndarray

mirage.fits.solve_star_centroids(fits_info: dict) → list[dict]#

Detects star streaks and estimates their centroids in a FITS observation.

Parameters:

fits_info (dict) – Dictionary of FITS observation information

Returns:

List of detected star dictionaries with centroids, bounding boxes, and brightness

Return type:

list[dict]

mirage.fits.update_refraction(station: Station, look_dir_eci: ndarray, up_dir_eci: ndarray, date: datetime, p_mbar: float, t_k: float) → ndarray#

Applies atmospheric refraction to a telescope look and up direction.

Parameters:
  • station (Station) – Observing station

  • look_dir_eci (np.ndarray [3,]) – Telescope look direction in ECI

  • up_dir_eci (np.ndarray [3,]) – Telescope up direction in ECI

  • date (datetime.datetime) – Observation date [UTC]

  • p_mbar (float) – Atmospheric pressure [mbar]

  • t_k (float) – Atmospheric temperature [K]

Returns:

Refracted look and up directions in ECI

Return type:

tuple[np.ndarray, np.ndarray]

mirage.iod module#

mirage.iod.check_admissibility(station: Station, dates: ndarray[datetime, Any], ras_rad: ndarray, decs_rad: ndarray, ras_dot_rad: ndarray, decs_dot_rad: ndarray, rhos_km: ndarray) → ndarray#

Computes admissible range-rate limits for the given observations.

Parameters:
  • station (Station) – Observing station

  • dates (np.ndarray[datetime.datetime, Any]) – Observation dates [UTC]

  • ras_rad (np.ndarray) – Right ascensions of the observations [rad]

  • decs_rad (np.ndarray) – Declinations of the observations [rad]

  • ras_dot_rad (np.ndarray) – Right ascension rates [rad/s]

  • decs_dot_rad (np.ndarray) – Declination rates [rad/s]

  • rhos_km (np.ndarray) – Ranges to the object [km]

Returns:

Lower and upper admissible range-rate limits [km/s]

Return type:

np.ndarray [2,n]

mirage.iod.gauss_iod(station: Station, dates: ndarray[datetime, Any], ras_rad: ndarray, decs_rad: ndarray) → ndarray#

Computes the position and velocity at the middle observation using Gauss’s method of initial orbit determination.

Parameters:
  • station (Station) – Observing station

  • dates (np.ndarray[datetime.datetime, Any]) – Observation dates [UTC]

  • ras_rad (np.ndarray) – Right ascensions of the observations [rad]

  • decs_rad (np.ndarray) – Declinations of the observations [rad]

Returns:

Position and velocity at the middle observation [km, km/s]

Return type:

np.ndarray [6,]

mirage.iod.gibbs_iod(r_eci_vecs: ndarray) → ndarray#

Computes the position and velocity at the middle observation using Gibbs’ method.

Parameters:

r_eci_vecs (np.ndarray [3,3]) – Three position vectors in ECI [km]

Returns:

Position and velocity at the middle observation [km, km/s]

Return type:

np.ndarray [6,]

mirage.iod.herrick_gibbs_iod(r_eci_vecs: ndarray, dates: ndarray) → ndarray#

Computes the position and velocity at the middle observation using the Herrick-Gibbs method.

Parameters:
  • r_eci_vecs (np.ndarray [3,3]) – Three position vectors in ECI [km]

  • dates (np.ndarray[datetime.datetime, Any]) – Observation dates [UTC]

Returns:

Position and velocity at the middle observation [km, km/s]

Return type:

np.ndarray [6,]

mirage.iod.laplace_iod(station: Station, dates: ndarray[datetime, Any], ras_rad: ndarray, decs_rad: ndarray) → ndarray#

Computes the position and velocity at the middle observation using Laplace’s method of initial orbit determination.

Parameters:
  • station (Station) – Observing station

  • dates (np.ndarray[datetime.datetime, Any]) – Observation dates [UTC]

  • ras_rad (np.ndarray) – Right ascensions of the observations [rad]

  • decs_rad (np.ndarray) – Declinations of the observations [rad]

Returns:

Position and velocity at the middle observation [km, km/s]

Return type:

np.ndarray [6,]

mirage.laser module#

class mirage.laser.Laser(hz: int, lam: float, pulse_energy: float, beam_divergence_half_angle: float, tracking_jitter_rad: float, beam_pointing_error_rad: float, pulse_fwhm_ns: float)#

Bases: object

Represents a laser transmitter used for satellite laser ranging.

mirage.laser.all_cubesats()#

Generates a collection of CubeSat models with various sizes and panel configurations.

Returns:

List of generated space objects and their face material mappings

Return type:

list[tuple[SpaceObject, np.ndarray]]

mirage.laser.d_for_rotation(v: ndarray, qs: ndarray, wb: ndarray, epsecs: ndarray, ovi: ndarray)#

Computes dot products between a vector and rotated observer vectors.

Parameters:
  • v (np.ndarray [3,]) – Vector to compare against

  • qs (np.ndarray [m,4]) – Initial attitude quaternions

  • wb (np.ndarray [m,3]) – Body-frame angular velocity vectors [rad/s]

  • epsecs (np.ndarray [t,]) – Elapsed times [s]

  • ovi (np.ndarray [n,3]) – Observer direction vectors

Returns:

Dot products between v and the rotated observer vectors

Return type:

np.ndarray [n,m]

mirage.laser.d_min_for_rotation(v: ndarray, qs: ndarray, wb: ndarray, epsecs: ndarray, ovi: ndarray)#

Computes the minimum dot product over rotation time for each attitude and time.

Parameters:
  • v (np.ndarray [3,]) – Vector to compare against

  • qs (np.ndarray [m,4]) – Initial attitude quaternions

  • wb (np.ndarray [m,3]) – Body-frame angular velocity vectors [rad/s]

  • epsecs (np.ndarray [t,]) – Elapsed times [s]

  • ovi (np.ndarray [n,3]) – Observer direction vectors

Returns:

Minimum dot products reshaped as [time, quaternion]

Return type:

np.ndarray [t,m]

mirage.laser.depth_after_time(obj: SpaceObject, p: ndarray, w: ndarray, epsecs: ndarray, ovi: ndarray)#

Computes object depth along observer directions after constant-rate attitude propagation.

Parameters:
  • obj (SpaceObject) – Space object

  • p (np.ndarray [3,]) – Initial attitude MRPs

  • w (np.ndarray [3,]) – Body-frame angular velocity [rad/s]

  • epsecs (np.ndarray [n,]) – Elapsed times [s]

  • ovi (np.ndarray [n,3]) – Observer direction vectors in the inertial frame

Returns:

Minimum depth along each observer direction

Return type:

np.ndarray [n,]

mirage.laser.evaluate_total_pdf(pts: ndarray, ns: ndarray, d_eval: ndarray) → ndarray#

Evaluates the total weighted PDF at depths d_eval.

Parameters:
  • pts – Triangles endpoints [N, 3, 2] (depths in col 0, probs in col 1)

  • ns – Weights for each triangle [N,]

  • d_eval – Depths to evaluate at [M,]

Returns:

Total PDF values [M,]

mirage.laser.filter_sdlr_noise(df_cal: DataFrame, br_epsecs_range: ndarray, br_range_range: ndarray, n_neighbors: int, p_tol: float, density: float = None, max_removals: int = None, no_removal_cap: bool = False) → DataFrame#

Filters noise from an SDLR residual-depth data frame using nearest-neighbor density estimates.

Parameters:
  • df_cal (pl.DataFrame) – Calibrated SDLR data frame

  • br_epsecs_range (np.ndarray, optional) – Elapsed-time range defining the signal region, or None

  • br_range_range (np.ndarray, optional) – Residual-depth range defining the signal region, or None

  • n_neighbors (int) – Number of nearest neighbors used for the density estimate

  • p_tol (float) – Probability threshold for classifying points as signal

  • density (float, optional) – Point density used when ranges are not provided, defaults to None

  • max_removals (int, optional) – Maximum number of points to remove, defaults to None

  • no_removal_cap (bool, optional) – Whether to disable the default removal cap, defaults to False

Returns:

Filtered signal and noise data frames

Return type:

tuple[pl.DataFrame, pl.DataFrame]

mirage.laser.find_sdlr_peaks(df_cal: DataFrame, peak_prominence: float = 0.5, savgol_window: int = 300, cut_first_percent: int = 2, cut_last_percent: int = 2, percentile_window: int = 300, cut_first_last: tuple = None, plot: bool = False)#

Finds leading-edge peaks and troughs in an SDLR residual-depth time series.

Parameters:
  • df_cal (pl.DataFrame) – Calibrated SDLR data frame

  • peak_prominence (float, optional) – Minimum peak prominence, defaults to 0.5

  • savgol_window (int, optional) – Savitzky-Golay filter window length, defaults to 300

  • cut_first_percent (int, optional) – Percentile used to filter the leading edge, defaults to 2

  • cut_last_percent (int, optional) – Percentile used to filter the trailing edge, defaults to 2

  • percentile_window (int, optional) – Window length for percentile filtering, defaults to 300

  • cut_first_last (tuple, optional) – Number of peaks to remove from the start and end, defaults to None

  • plot (bool, optional) – Whether to plot the filtered signal and detected peaks, defaults to False

Returns:

Data frame of detected peaks and troughs

Return type:

pl.DataFrame

mirage.laser.gen_depth_interper(obj: SpaceObject)#

Builds an interpolator for the minimum depth of a convex object over look direction.

Parameters:

obj (SpaceObject) – Space object

Returns:

Interpolator over azimuth and elevation returning minimum depth

Return type:

scipy.interpolate.RegularGridInterpolator

The classical laser ranging link equation, providing the expected number of received photons at the detector

Parameters:
  • r_obj (np.ndarray [n,3]) – Position of the object in any frame [km]

  • r_station (np.ndarray [n,3]) – Position of the station in the same frame as r_obj [km]

  • optical_cross_section (np.ndarray [n,m]) – Optical cross section of the object at each timestep in m^2 / sterad

  • atmospheric_transmission (np.ndarray) – Fraction of energy at the transmit wavelength transferred through the atmosphere at each timestamp [nondim]

  • pulse_energy (float) – Pulse energy [J]

  • transmit_wavelength (float) – Transmitted wavelength [nm]

  • beam_divergence_half_angle_rad (float) – Standard deviation of the beam divergence [rad]

  • beam_pointing_error_rad (float) – Pointing error from the object center of mass [rad]

  • receiver_area (float) – Area of the receiving telescope system [m^2]

  • transmit_optical_efficiency (float) – Efficiency (1 - loss_fraction) of the transmitting system [nondim]

  • receive_optical_efficiency (float) – Efficiency (1 - loss_fraction) of the receiving system [nondim]

  • tracking_jitter_rad (float) – Angular jitter of the transmitting telescope tracking [rad]

Returns:

Expected number of photoelectrons received, per pulse, per timestamp, per facet

Return type:

np.ndarray [n,m]

mirage.laser.marini_murray_atmosphere_correction(lambda_: float, E: ndarray, phi: float, H: float, P_H: float, T_H: float, R_H: float)#

Computes the Marini-Murray spectral correction factor.

Parameters:
  • lambda (float) – Wavelength [um]

  • E (Union[float, np.ndarray]) – Target true elevation angle [deg]

  • phi (float) – Latitude [rad]

  • H (float) – Altitude [km]

  • P_H (float) – Pressure at height [hPa]

  • T_H (float) – Temperature at height [K]

  • R_H (float) – Relative humidity at height [percent, 0-100]

Returns:

Spectral correction factor

Return type:

float

mirage.laser.max_depth_for_obj(obj: SpaceObject, ovb: ndarray) → ndarray#

Computes the maximum depth along each observer direction.

Parameters:
  • obj (SpaceObject) – Space object

  • ovb (np.ndarray [n,3]) – Unit observer direction vectors in the body frame

Returns:

Maximum depths along each observer direction

Return type:

np.ndarray [n,]

mirage.laser.min_depth_for_obj(obj: SpaceObject, ovb: ndarray) → ndarray#

Computes the minimum depth along each observer direction.

Parameters:
  • obj (SpaceObject) – Space object

  • ovb (np.ndarray [n,3]) – Unit observer direction vectors in the body frame

Returns:

Minimum depths along each observer direction

Return type:

np.ndarray [n,]

mirage.laser.min_vert_for_obj(obj: SpaceObject, ovb: ndarray) → ndarray#

Finds the nearest object vertex index along each observer direction.

Parameters:
  • obj (SpaceObject) – Space object

  • ovb (np.ndarray [n,3]) – Unit observer direction vectors in the body frame

Returns:

Indices of the nearest vertices

Return type:

np.ndarray [n,]

mirage.laser.omega_guesses(df_in: DataFrame, df_peaks: DataFrame, min_frequency_hz: float, max_frequency_hz: float, n_points: int, plot: bool = False, multiples: tuple[int] = (1, 2, 3, 4), samples_per_peak: int = 100, case_name: str = 'case_name', save_path: str = None)#

Generates candidate sidereal rotation-rate guesses from SDLR and light-curve periodograms.

Parameters:
  • df_in (pl.DataFrame) – SDLR/light-curve data frame

  • df_peaks (pl.DataFrame) – Detected leading-edge peaks and troughs

  • min_frequency_hz (float) – Minimum search frequency [Hz]

  • max_frequency_hz (float) – Maximum search frequency [Hz]

  • n_points (int) – Number of rotation-rate samples to return

  • plot (bool, optional) – Whether to plot the periodograms and sampling distribution, defaults to False

  • multiples (tuple[int], optional) – Periodogram harmonic multiples to sample, defaults to (1, 2, 3, 4)

  • samples_per_peak (int, optional) – Samples per peak for the Lomb-Scargle periodogram, defaults to 100

  • case_name (str, optional) – Case name used in plot titles, defaults to ‘case_name’

  • save_path (str, optional) – Path to save the diagnostic plot, defaults to None

Returns:

Candidate sidereal rotation rates [rad/s]

Return type:

np.ndarray

mirage.laser.parametric_blob(a: float, b: float, c: float, n1: float, n2: float)#

Builds a superquadric blob parametric space object.

Parameters:
  • a (float) – Superquadric semi-axis length along x

  • b (float) – Superquadric semi-axis length along y

  • c (float) – Superquadric semi-axis length along z

  • n1 (float) – Superquadric north-south exponent

  • n2 (float) – Superquadric east-west exponent

Returns:

Generated space object and material mapping for its faces

Return type:

tuple[SpaceObject, np.ndarray]

mirage.laser.parametric_blob_sampler()#

Samples a random blob parametric shape.

Returns:

Shape state vector and generated space object

Return type:

tuple[np.ndarray, SpaceObject]

mirage.laser.parametric_blob_state_limits() → dict#

Returns parameter limits for the blob parametric shape.

Returns:

Mapping of parameter names to dependency index and min/max limits

Return type:

dict

mirage.laser.parametric_box_wing(box_scale_x: float, box_scale_y: float, box_scale_z: float, panel_length: float, panel_width: float, panel_angle_rad: float)#

Builds a box-with-wings parametric space object.

Parameters:
  • box_scale_x (float) – Box length along the x-axis

  • box_scale_y (float) – Box length along the y-axis

  • box_scale_z (float) – Box length along the z-axis

  • panel_length (float) – Solar panel length

  • panel_width (float) – Solar panel width

  • panel_angle_rad (float) – Solar panel rotation angle [rad]

Returns:

Generated space object and material mapping for its faces

Return type:

tuple[SpaceObject, np.ndarray]

mirage.laser.parametric_box_wing_sampler()#

Samples a random box_wing parametric shape.

Returns:

Shape state vector and generated space object

Return type:

tuple[np.ndarray, SpaceObject]

mirage.laser.parametric_box_wing_state_limits() → dict#

Returns parameter limits for the box_wing parametric shape.

Returns:

Mapping of parameter names to dependency index and min/max limits

Return type:

dict

mirage.laser.parametric_rocket_body(body_height: float, body_radius: float, cone_height: float, nozzle_height: float, nozzle_radius: float, com_z_shift: float)#

Builds a rocket-body parametric space object.

Parameters:
  • body_height (float) – Cylindrical body height

  • body_radius (float) – Cylindrical body radius

  • cone_height (float) – Nose-cone height, negative values are clipped to zero

  • nozzle_height (float) – Nozzle height

  • nozzle_radius (float) – Nozzle radius

  • com_z_shift (float) – Center-of-mass shift along the z-axis

Returns:

Generated space object and material mapping for its faces

Return type:

tuple[SpaceObject, np.ndarray]

mirage.laser.parametric_rocket_body_sampler() → Tuple[SpaceObject, ndarray]#

Samples a random rocket_body parametric shape.

Returns:

Shape state vector and generated space object

Return type:

tuple[np.ndarray, SpaceObject]

mirage.laser.parametric_rocket_body_state_limits() → dict#

Returns parameter limits for the rocket_body parametric shape.

Returns:

Mapping of parameter names to dependency index and min/max limits

Return type:

dict

mirage.laser.parametric_sbox_wing(box_scale_x: float, box_scale_y: float, box_scale_z: float, panel_length: float, panel_width: float, com_x_shift: float, panel_angle_rad: float)#

Builds a shifted box-with-wings parametric space object.

Parameters:
  • box_scale_x (float) – Box length along the x-axis

  • box_scale_y (float) – Box length along the y-axis

  • box_scale_z (float) – Box length along the z-axis

  • panel_length (float) – Solar panel length

  • panel_width (float) – Solar panel width

  • com_x_shift (float) – Center-of-mass shift along the x-axis

  • panel_angle_rad (float) – Solar panel rotation angle [rad]

Returns:

Generated space object and material mapping for its faces

Return type:

tuple[SpaceObject, np.ndarray]

mirage.laser.parametric_sbox_wing_state_limits() → dict#

Returns parameter limits for the sbox_wing parametric shape.

Returns:

Mapping of parameter names to dependency index and min/max limits

Return type:

dict

mirage.laser.parametric_scyl_wing(body_length: float, body_radius: float, panel_length: float, panel_width: float, com_x_shift: float, panel_angle_rad: float)#

Builds a cylindrical-body-with-wings parametric space object.

Parameters:
  • body_length (float) – Cylindrical body length

  • body_radius (float) – Cylindrical body radius

  • panel_length (float) – Solar panel length

  • panel_width (float) – Solar panel width

  • com_x_shift (float) – Center-of-mass shift along the x-axis

  • panel_angle_rad (float) – Solar panel rotation angle [rad]

Returns:

Generated space object and material mapping for its faces

Return type:

tuple[SpaceObject, np.ndarray]

mirage.laser.parametric_scyl_wing_state_limits() → dict#

Returns parameter limits for the scyl_wing parametric shape.

Returns:

Mapping of parameter names to dependency index and min/max limits

Return type:

dict

mirage.laser.parametric_shape_hypercube(x: ndarray, shape_name: str)#

Converts unit-hypercube coordinates into a parametric shape state and object.

Parameters:
  • x (np.ndarray) – Coordinates in the unit hypercube [n,]

  • shape_name (str) – Parametric shape name

Returns:

Shape state vector and generated space object

Return type:

tuple[np.ndarray, SpaceObject]

mirage.laser.parametric_shape_state_dimension(shape_class: str) → int#

Returns the number of state parameters for a parametric shape class.

Parameters:

shape_class (str) – Parametric shape class name

Returns:

Number of state parameters

Return type:

int

mirage.laser.quats_for_rotation(qs: ndarray, wb: ndarray, epsecs: ndarray)#

Propagates attitude quaternions under constant body-frame angular velocity.

Parameters:
  • qs (np.ndarray [m,4]) – Initial attitude quaternions

  • wb (np.ndarray [m,3]) – Body-frame angular velocity vectors [rad/s]

  • epsecs (np.ndarray [t,]) – Elapsed times [s]

Returns:

Propagated quaternions

Return type:

np.ndarray [t,m,4]

mirage.laser.real_to_constrained_shape(x_samp: ndarray, shape_class: str, k: float = 0.5) → List#

Maps unconstrained samples to constrained parametric shape states and objects.

Parameters:
  • x_samp (np.ndarray) – Unconstrained samples [n,m]

  • shape_class (str) – Parametric shape class name

  • k (float, optional) – Logistic steepness parameter, defaults to 0.5

Returns:

Generated objects and constrained shape-state matrix

Return type:

tuple[list, np.ndarray]

mirage.laser.sdlr_residuals_adaptive(station: Station, obj: SpaceObject, attitude: RbtfAttitude, brdf: Brdf, laser: Laser, start_date: datetime, end_date: datetime, third_bodies: Tuple[str] = ('Jupiter', 'Moon', 'Sun'), gravity_harmonics_degree: int = 16, P_H: float = 1000.0, T_H: float = 300.0, R_H: float = 50.0, noise_counts_per_sec: int = 100, range_gate_ns: float = 100.0, depth_bin_count: int = 200, trajectory_time_resolution: timedelta = None, njsd_tol: float = 0.01, poly_deg: int = 9, min_nodes: int = 100, shgo_iters: int = 10, lc_integration_time_s: float = 0.01, pulse_n_std: int = 2, return_nodes: bool = False) → DataFrame#

Simulates an adaptive SDLR observation and estimates residual depths.

Parameters:
  • station (Station) – Observing station

  • obj (SpaceObject) – Space object being observed

  • attitude (RbtfAttitude) – Object attitude model

  • brdf (Brdf) – BRDF model for the object

  • laser (Laser) – Laser transmitter model

  • start_date (datetime.datetime) – Start of the observation [UTC]

  • end_date (datetime.datetime) – End of the observation [UTC]

  • third_bodies (Tuple[str], optional) – Third-body perturbers for orbit propagation, defaults to (‘Jupiter’, ‘Moon’, ‘Sun’)

  • gravity_harmonics_degree (int, optional) – Maximum gravity harmonics degree, defaults to 16

  • P_H (float, optional) – Pressure at height [hPa], defaults to 1000.0

  • T_H (float, optional) – Temperature at height [K], defaults to 300.0

  • R_H (float, optional) – Relative humidity at height [percent], defaults to 50.0

  • noise_counts_per_sec (int, optional) – Noise count rate [counts/s], defaults to 100

  • range_gate_ns (float, optional) – Range gate width [ns], defaults to 100.0

  • depth_bin_count (int, optional) – Number of depth bins, defaults to 200

  • trajectory_time_resolution (datetime.timedelta, optional) – Time step for the coarse trajectory, defaults to None (0.1 s)

  • njsd_tol (float, optional) – Jensen-Shannon divergence tolerance for adaptive node splitting, defaults to 1e-2

  • poly_deg (int, optional) – Degree of the polynomial used to detrend residual depths, defaults to 9

  • min_nodes (int, optional) – Minimum number of trajectory nodes, defaults to 100

  • shgo_iters (int, optional) – Number of SHGO iterations for orbit refinement, defaults to 10

  • lc_integration_time_s (float, optional) – Light-curve integration time [s], defaults to 10e-3

  • pulse_n_std (int, optional) – Pulse truncation in standard deviations, defaults to 2

  • return_nodes (bool, optional) – Whether to return the adaptive trajectory nodes with the data frame, defaults to False

Returns:

SDLR simulation data frame, optionally with trajectory nodes

Return type:

Union[pl.DataFrame, tuple[pl.DataFrame, dict]]

mirage.laser.shape_state_to_hypercube(x: ndarray, class_name: str) → ndarray#

Converts a parametric shape state into unit-hypercube coordinates.

Parameters:
  • x (np.ndarray) – Parametric shape state

  • class_name (str) – Parametric shape class name

Returns:

Coordinates in the unit hypercube

Return type:

np.ndarray

mirage.lighting module#

class mirage.lighting.Brdf(name: str, cd: float | ndarray | None = None, cs: float | ndarray | None = None, n: float | ndarray | None = None, validate: bool = True)#

Bases: object

Class for representing Bidirectional Reflectance Distribution Functions (BRDFs).

compute_reflection_matrix(sun_vectors: array, observer_vectors: array, normal_vectors: array) → ndarray#

Computes the reflection matrix for the EGI estimation stage of shape inversion (or for convex shape light curve simulation)

Parameters:
  • sun_vectors (np.array [n,3]) – Unit vector illumination directions

  • observer_vectors (np.array [n,3]) – Unit vector observation directions

  • normal_vectors (np.ndarray [m,3]) – Unit vector surface normals

Returns:

Reflection matrix, (i,j) entry is normalized irradiance per unit area for facet j at time i

Return type:

np.ndarray [n,m]

eval(L: ndarray, O: ndarray, N: ndarray, cd: float | ndarray = None, cs: float | ndarray = None, n: float | ndarray = None) → ndarray#

Evaluates the BRDF with the given observation and illumination geometry

Parameters:
  • L (np.ndarray [n,3]) – Unit vector illumination directions

  • O (np.ndarray [n,3]) – Unit vector observation directions

  • N (np.ndarray [n,3]) – Unit vector surface normals

  • cd (float or np.ndarray, defaults to None) – Coefficients of diffuse reflection, optional

  • cs (float or np.ndarray, defaults to None) – Coefficients of specular reflection, optional

  • n (float or np.ndarray, defaults to None) – Specular exponents, optional

Returns:

Fraction of incident irradiance reflected towards observer

Return type:

np.ndarray [n,]

eval_normalized_brightness(L: ndarray, O: ndarray, N: ndarray, cd: float | ndarray = None, cs: float | ndarray = None, n: float | ndarray = None) → ndarray#

Computes the observed irradiance per unit incident irradiance at a unit distance for this BRDF

Parameters:
  • L (np.ndarray [n,3]) – Unit vector illumination directions

  • O (np.ndarray [n,3]) – Unit vector observation directions

  • N (np.ndarray [n,3]) – Unit vector surface normals

  • cd (float or np.ndarray, defaults to None) – Coefficients of diffuse reflection, optional

  • cs (float or np.ndarray, defaults to None) – Coefficients of specular reflection, optional

  • n (float or np.ndarray, defaults to None) – Specular exponents, optional

Returns:

Fraction of incident irradiance reflected towards observer at unit distance

Return type:

np.ndarray [n,]

property use_mtl: bool#

Whether the BRDF should use material coefficients from an .mtl file.

validate()#

Decides if a BRDF is valid.

Raises:

ValueError – If energy conservation or other physical-plausibility checks fail

mirage.lighting.apparent_magnitude_to_irradiance(m: ndarray, band: str = None) → ndarray#

Computes irradiance [W/m^2] from apparent magnitude (assumed same spectrum as sunlight)

Parameters:
  • m (np.ndarray) – Apparent magnitude

  • band (str, optional) – Photometric passband name, defaults to None (solar spectrum)

Returns:

Irradiance [W/m^2]

Return type:

np.ndarray

mirage.lighting.brdf_ashikhmin_shirley(L: ndarray, O: ndarray, N: ndarray, cd: ndarray, cs: ndarray, n: ndarray) → ndarray#

Bidirectional Reflectance Distribution Function (BRDF) reflectance for the Ashikhmin-Shirley model

Parameters:
  • L (np.ndarray [n,3]) – Unit vector illumination directions

  • O (np.ndarray [n,3]) – Unit vector observation directions

  • N (np.ndarray [n,3]) – Unit vector surface normals

  • cd (np.ndarray [n,]) – Coefficients of diffuse reflection for each face

  • cs (np.ndarray [n,]) – Coefficients of specular reflection for each face

  • n (np.ndarray [n,]) – Specular exponents for each face

Returns:

Fraction of incident light reflected towards observer

Return type:

np.ndarray [n,]

mirage.lighting.brdf_blinn_phong(L: ndarray, O: ndarray, N: ndarray, cd: ndarray, cs: ndarray, n: ndarray) → ndarray#

Bidirectional Reflectance Distribution Function (BRDF) reflectance for the Blinn-Phong model

Parameters:
  • L (np.ndarray [n,3]) – Unit vector illumination directions

  • O (np.ndarray [n,3]) – Unit vector observation directions

  • N (np.ndarray [n,3]) – Unit vector surface normals

  • cd (np.ndarray [n,]) – Coefficients of diffuse reflection for each face

  • cs (np.ndarray [n,]) – Coefficients of specular reflection for each face

  • n (np.ndarray [n,]) – Specular exponents for each face

Returns:

Fraction of incident light reflected towards observer

Return type:

np.ndarray [n,]

mirage.lighting.brdf_cook_torrance(L: ndarray, O: ndarray, N: ndarray, cd: ndarray, cs: ndarray, a: float) → ndarray#

Bidirectional Reflectance Distribution Function (BRDF) reflectance for the Cook-Torrance model

Parameters:
  • L (np.ndarray [n,3]) – Unit vector illumination directions

  • O (np.ndarray [n,3]) – Unit vector observation directions

  • N (np.ndarray [n,3]) – Unit vector surface normals

  • cd (np.ndarray [n,]) – Coefficients of diffuse reflection for each face

  • cs (np.ndarray [n,]) – Coefficients of specular reflection for each face

  • a (float) – Surface roughness \(a \in [0,1]\)

Returns:

Fraction of incident light reflected towards observer

Return type:

np.ndarray [n,]

mirage.lighting.brdf_diffuse(cd: ndarray) → ndarray#

Bidirectional Reflectance Distribution Function (BRDF) reflectance for a diffuse surface

Parameters:

cd (np.ndarray) – Coefficients of diffuse reflection for each face

Returns:

Fraction of incident light reflected towards observer

Return type:

np.ndarray

mirage.lighting.brdf_glossy(L: ndarray, O: ndarray, N: ndarray, cs: ndarray, s: ndarray, **_) → ndarray#

Bidirectional Reflectance Distribution Function (BRDF) reflectance for the glossy model

Parameters:
  • L (np.ndarray [n,3]) – Unit vector illumination directions

  • O (np.ndarray [n,3]) – Unit vector observation directions

  • N (np.ndarray [n,3]) – Unit vector surface normals

  • cs (np.ndarray [n,]) – Coefficients of specular reflection for each face

  • s (float) – Standard deviation of the BRDF Gaussian [rad]

Returns:

Fraction of incident light reflected towards observer

Return type:

np.ndarray [n,]

mirage.lighting.brdf_oren_naymar(L: ndarray, O: ndarray, N: ndarray, cd: ndarray, s: float, **_) → ndarray#

Bidirectional Reflectance Distribution Function (BRDF) reflectance for the Oren-Nayar model

Parameters:
  • L (np.ndarray [n,3]) – Unit vector illumination directions

  • O (np.ndarray [n,3]) – Unit vector observation directions

  • N (np.ndarray [n,3]) – Unit vector surface normals

  • cd (np.ndarray [n,]) – Coefficients of diffuse reflection for each face

  • s (float) – Standard deviation of the surface-slope distribution

Returns:

Fraction of incident light reflected towards observer

Return type:

np.ndarray [n,]

mirage.lighting.brdf_phong(L: ndarray, O: ndarray, N: ndarray, cd: ndarray, cs: ndarray, n: ndarray) → ndarray#

Bidirectional Reflectance Distribution Function (BRDF) reflectance for the Phong model

Parameters:
  • L (np.ndarray [n,3]) – Unit vector illumination directions

  • O (np.ndarray [n,3]) – Unit vector observation directions

  • N (np.ndarray [n,3]) – Unit vector surface normals

  • cd (np.ndarray [n,]) – Coefficients of diffuse reflection for each face

  • cs (np.ndarray [n,]) – Coefficients of specular reflection for each face

  • n (np.ndarray [n,]) – Specular exponents for each face

Returns:

Fraction of incident light reflected towards observer

Return type:

np.ndarray [n,]

mirage.lighting.candela_to_watt_per_sr(cd: ndarray, lambdas: ndarray | float = 555.0) → ndarray#

Converts from candela (cd) to watts per steradian (W/sr)

Parameters:
  • cd (np.ndarray) – Candela value(s)

  • lambdas (Union[np.ndarray, float], optional) – Wavelength [nm] of monochromatic source, defaults to 555

Returns:

Watts per steradian [W/sr]

Return type:

np.ndarray

mirage.lighting.cook_torrance_beckmann(H: ndarray, N: ndarray, a: float) → ndarray#

Computes the Beckmann microfacet normal distribution function.

Parameters:
  • H (np.ndarray [n,3]) – Unit half-vector directions

  • N (np.ndarray [n,3]) – Unit surface normals

  • a (float) – Surface roughness

Returns:

Normal distribution density

Return type:

np.ndarray

mirage.lighting.cook_torrance_fresnel_schlick(H: ndarray, L: ndarray, cs: float) → ndarray#

Computes the Fresnel reflectance using the Schlick approximation.

Parameters:
  • H (np.ndarray [n,3]) – Unit half-vector directions

  • L (np.ndarray [n,3]) – Unit illumination directions

  • cs (float) – Coefficients of specular reflection

Returns:

Fresnel reflectance

Return type:

np.ndarray

mirage.lighting.cook_torrance_g_smith(O: ndarray, N: ndarray, L: ndarray, a: ndarray) → ndarray#

Computes the Smith geometric attenuation factor for the Cook-Torrance BRDF.

Parameters:
  • O (np.ndarray [n,3]) – Unit observation directions

  • N (np.ndarray [n,3]) – Unit surface normals

  • L (np.ndarray [n,3]) – Unit illumination directions

  • a (float) – Surface roughness

Returns:

Geometric attenuation factors

Return type:

np.ndarray

mirage.lighting.cook_torrance_ggx(M: ndarray, N: ndarray, a: float) → ndarray#

Calculates the GGX normal distribution function

Parameters:
  • M (np.ndarray [n,3]) – Microfacet surface normal direction

  • N (np.ndarray [n,3]) – Macro surface normal

  • a (float) – Surface roughness

Returns:

Normal distribution density

Return type:

np.ndarray

mirage.lighting.irradiance_to_apparent_magnitude(E: ndarray, zero_point_irradiance: float = 2.518021002e-08) → ndarray#

Computes apparent magnitude from irradiance [W/m^2] (assumed same spectrum as sunlight)

Parameters:
  • E (np.ndarray) – Irradiance [W/m^2]

  • zero_point_irradiance (float, optional) – Irradiance at the zero point, defaults to AstroConstants.vega_irradiance

Returns:

Apparent magnitude

Return type:

np.ndarray

mirage.lighting.irradiance_to_s10(e: ndarray, w: ndarray) → ndarray#

Converts irradiance \(\frac{W}{m^2}\) spread over a solid angle into surface brightness \(S_{10}\). \(S_{10}\) is defined as the number of 10th magnitude stars per square degree

Parameters:
  • e (np.ndarray) – Total irradiance [W/m^2]

  • w (np.ndarray) – Solid angle of the source in [rad^2]

Returns:

Surface brightness in \(S_{10}\)

Return type:

np.ndarray

mirage.lighting.mcd_m2_to_watt_m2_sr(mcd_per_m2: ndarray) → ndarray#

Converts from milli-candela per square meter to watts per square meter per steradian

Parameters:

mcd_per_m2 (np.ndarray) – Milli-candela per square meter value(s)

Returns:

Watts per square meter per steradian value(s)

Return type:

np.ndarray

mirage.lighting.mcd_per_m2_to_mpsas(mcd_per_m2: ndarray, lam_nm: float = 473.74960958) → ndarray#

Converts milli-candela per square meter to MPSAS

Parameters:
  • mcd_per_m2 (np.ndarray) – Milli-candela per square meter (artificial sky brightness)

  • lam_nm (float, optional) – Reference wavelength [nm], defaults to 473.74960958

Returns:

Magnitudes per square arcsecond (MPSAS)

Return type:

np.ndarray

mirage.lighting.mpsas_to_irradiance_per_steradian(mpsas: ndarray) → ndarray#

Converts surface brightness in magnitudes per arcsecond squared to irradiance per steradian

Parameters:

mpsas (np.ndarray) – Surface brightness in magnitudes per arcsecond squared

Returns:

Irradiance per steradian [W/m^2/sr]

Return type:

np.ndarray

mirage.lighting.mpsas_to_mcd_per_m2(mag_per_arcsec2: ndarray, lam_nm: float = 473.74960958) → ndarray#

Converts MPSAS to milli-candela per square meter

Parameters:
  • mag_per_arcsec2 (np.ndarray) – Magnitudes per square arcsecond (MPSAS)

  • lam_nm (float, optional) – Reference wavelength [nm], defaults to 473.74960958

Returns:

Equivalent milli-candela per square meter

Return type:

np.ndarray

mirage.lighting.normalized_light_curve_sphere(cd_sphere: float, r_sphere_m: float, phase_angle_rad: ndarray) → ndarray#

Computes a normalized light curve (irradiance at one meter from the object) for a diffuse sphere

Parameters:
  • cd_sphere (float) – Coefficient of diffuse reflection

  • r_sphere_m (float) – Radius of the sphere in [m]

  • phase_angle_rad (np.ndarray) – Angle between the object-Sun and object-Observer vectors [rad]

Returns:

Normalized light curve

Return type:

np.ndarray

mirage.lighting.query_brdf_shader_ind(brdf: Brdf) → int#

Figures out if a Brdf is known to the LightCurveEngine shaders, and if it is, returns its registry index

Parameters:

brdf (Brdf) – BRDF to check

Returns:

Index of BRDF as known by the shaders

Return type:

int

mirage.lighting.reflect(from_dir: ndarray, normal_dir: ndarray) → ndarray#

Reflects a direction vector about a surface normal.

Parameters:
  • from_dir (np.ndarray [n,3]) – Incident direction unit vector

  • normal_dir (np.ndarray [n,3]) – Surface normal unit vector

Returns:

Reflected direction unit vector

Return type:

np.ndarray [n,3]

mirage.lighting.s10_to_irradiance(b: ndarray, w: ndarray) → ndarray#

Converts surface brightness \(S_{10}\) over a solid angle into irradiance \(\frac{W}{m^2}\). \(S_{10}\) is defined as the number of 10th magnitude stars per square degree

Parameters:
  • b (np.ndarray) – Surface brightness in \(S_{10}\)

  • w (np.ndarray) – Solid angle of the source in [rad^2]

Returns:

Total irradiance [W/m^2]

Return type:

np.ndarray

mirage.lighting.watt_per_sr_to_candela(watt_per_sr: ndarray, lambdas: ndarray = 555.0) → ndarray#

Converts from watts per steradian (W/sr) to candela (cd).

Parameters:
  • watt_per_sr (np.ndarray) – Watts per steradian [W/sr]

  • lambdas (np.ndarray, optional) – Wavelength [nm] of monochromatic source, defaults to 555 [nm]

Returns:

Candela value(s) [cd]

Return type:

np.ndarray

mirage.math module#

mirage.math.acosd(x: ndarray | float | int) → ndarray | float#

Computes \(\cos^{-1}(x)\) outputting in degrees

Parameters:

x (Union[np.ndarray, float, int]) – Input

Returns:

\(\cos^{-1}(x)\) in [deg]

Return type:

Union[np.ndarray, float]

mirage.math.angle_between_deg(a1: ndarray, a2: ndarray) → ndarray#

Given two angular quantities, finds smallest angle between their unit circle vectors, ex: f(50, 40) -> 10, f(-30, 20) = 50

Parameters:
  • a1 (np.ndarray) – First angle [deg]

  • a2 (np.ndarray) – Second angle [deg]

Returns:

Smallest angle difference [deg]

Return type:

np.ndarray

mirage.math.angle_between_rad(a1: ndarray, a2: ndarray) → ndarray#

Given two angular quantities, finds smallest angle between their unit circle vectors, see angle_between_deg

Parameters:
  • a1 (np.ndarray) – First angle [rad]

  • a2 (np.ndarray) – Second angle [rad]

Returns:

Smallest angle difference [rad]

Return type:

np.ndarray

mirage.math.angle_between_vecs(v1: ndarray, v2: ndarray, deg: bool = False) → ndarray#

Computes the angle between two vectors in radians, expands one out to fit the other if sizes do not match

Parameters:
  • v1 (np.ndarray [n,3] or [1x3] if v2 is [n,3]) – First vector

  • v2 (np.ndarray [n,3] or [1x3] if v1 is [n,3]) – Second vector

  • deg (bool, optional) – Whether to output angular quantities in degrees instead of radians, defaults to False

Returns:

Angle between the pairs of vectors [rad] or [deg]

Return type:

np.ndarray

mirage.math.asind(x: ndarray | float | int) → ndarray | float#

Computes \(\sin^{-1}(x)\) outputting in degrees

Parameters:

x (Union[np.ndarray, float, int]) – Input

Returns:

\(\sin^{-1}(x)\) in [deg]

Return type:

Union[np.ndarray, float]

mirage.math.cart_to_sph(x: ndarray, y: ndarray, z: ndarray, deg: bool = False, wrap_negative_az: bool = False) → Tuple[ndarray, ndarray, ndarray]#

Converts from Cartesian (x,y,z) to spherical (azimuth, elevation, range)

Parameters:
  • x (np.ndarray) – Cartesian x

  • y (np.ndarray) – Cartesian y

  • z (np.ndarray) – Cartesian z

  • deg (bool, optional) – Whether to output angular quantities in degrees instead of radians, defaults to False

  • wrap_negative_az (bool, optional) – Whether to wrap the azimuth from [-pi,pi] or [-180,180] to [0,2pi] or [0,360], defaults to False

Returns:

(azimuth, elevation, range) angles in [rad]

Return type:

Tuple[np.ndarray, np.ndarray, np.ndarray]

mirage.math.close_egi(egi: ndarray) → ndarray#

Enforces closure condition by adding mean closure error to each row [RF]

Parameters:

egi (np.ndarray [n,3]) – Extended Gaussian Image (EGI)

Returns:

Shifted EGI such that the sum of rows is zero

Return type:

np.ndarray [n,3]

mirage.math.convolve_pdfs(pdfs_to_convolve: list[tuple[ndarray, ndarray]])#

Convolves an arbitrary number of numerical PDFs using the Fast Fourier Transform (FFT).

The function first resamples all PDFs onto a common, dense linspace before performing the convolution.

Parameters:

pdfs_to_convolve (list[tuple[np.ndarray, np.ndarray]]) – A list of tuples, where each tuple contains a numpy array for the x-linspace and a numpy array for the corresponding PDF values.

Returns:

The new linspace and convolved PDF, or an interpolator when exactly one PDF is provided

Return type:

Union[tuple[np.ndarray, np.ndarray], scipy.interpolate.interp1d]

mirage.math.cosd(x: ndarray | float | int) → ndarray | float#

Computes \(\cos(x)\) with \(x\) in degrees

Parameters:

x (Union[np.ndarray, float, int]) – Input [deg]

Returns:

\(\cos(x)\)

Return type:

Union[np.ndarray, float]

mirage.math.dms_to_rad(deg: ndarray | float | int, min: ndarray | float | int, sec: ndarray | float | int) → ndarray | float | int#

Converts from degrees, arcminutes, and arcseconds to radians

Parameters:
  • deg (Union[np.ndarray, float, int]) – Degrees

  • min (Union[np.ndarray, float, int]) – Arcminutes

  • sec (Union[np.ndarray, float, int]) – Arcseconds

Returns:

Radians

Return type:

Union[np.ndarray, float, int]

mirage.math.dot(v1: ndarray, v2: ndarray) → ndarray#

Euclidean dot product between corresponding rows of v1 and v2

Parameters:
  • v1 (np.ndarray [nxm]) – First input vector

  • v2 (np.ndarray [nxm]) – Second input vector

Returns:

Dot products of corresponding rows

Return type:

np.ndarray [n,1]

mirage.math.elliptic_pi_complete(n: ndarray, ksquared: ndarray) → ndarray#

Computes the complete elliptic integral of the third kind based on Carlson symmetric forms \(R_f, R_j\)

Parameters:
  • n (np.ndarray [mx1]) – \(n\) parameter of the integral

  • ksquared (np.ndarray [mx1]) – \(k^2\) parameter of the integral

Returns:

\(\Pi(n, k^2)\)

Return type:

np.ndarray [mx1]

mirage.math.elliptic_pi_incomplete(n: ndarray, phi: ndarray, ksquared: ndarray) → ndarray#

Computes the incomplete elliptic integral of the third kind based on Carlson symmetric forms \(R_f, R_j\)

Parameters:
  • n (np.ndarray [n,]) – \(n\) parameter of the integral

  • phi (np.ndarray [n,]) – \(\phi\)

  • ksquared (np.ndarray [n,]) – \(k^2\) parameter of the integral

Returns:

\(\Pi(n, \phi, k^2)\)

Return type:

np.ndarray [n,]

mirage.math.fit_2d_gaussian(data: ndarray, mahal_dist_tol: float = 3.0, max_iter: int = 100, return_used_inds: bool = False)#

Fits a 2D Gaussian while iteratively rejecting outliers by Mahalanobis distance.

Parameters:
  • data (np.ndarray) – Sample points [n,2]

  • mahal_dist_tol (float, optional) – Mahalanobis-distance threshold for rejecting outliers, defaults to 3.0

  • max_iter (int, optional) – Maximum number of reweighting iterations, defaults to 100

  • return_used_inds (bool, optional) – Whether to also return the mask of accepted samples, defaults to False

Returns:

Fitted multivariate normal distribution, optionally with the accepted-sample mask

Return type:

Union[scipy.stats.multivariate_normal, tuple[scipy.stats.multivariate_normal, np.ndarray]]

mirage.math.fit_poisson_process(data: ndarray) → float#

Fits a Poisson random process to the given data

Parameters:

data (np.ndarray) – Independent, identically distributed data to fit

Returns:

The optimal Poisson rate parameter \(\lambda\)

Return type:

float

mirage.math.hat(v: ndarray) → ndarray#

Normalizes input np.ndarray n,3 such that each row is unit length. If a row is [0,0,0], hat() returns it unchanged

Parameters:

v (np.ndarray [n,3]) – Input vectors

Returns:

Unit vectors

Return type:

np.ndarray [n,3]

mirage.math.hms_to_rad(hour: ndarray, min: ndarray, sec: ndarray) → ndarray#

Converts hours, minutes, and seconds of time to radians out of a 24 hour day

Parameters:
  • hour (Union[np.ndarray, float]) – Hours

  • min (Union[np.ndarray, float]) – Minutes

  • sec (Union[np.ndarray, float]) – Seconds

Returns:

Radians [rad]

Return type:

np.ndarray

mirage.math.jsd_norm(p: ndarray, q: ndarray)#

Jensen-Shannon Divergence, normalized between [0,1]

Parameters:
  • p (np.ndarray) – First probability density

  • q (np.ndarray) – Second probability density

Returns:

Normalized Jensen-Shannon divergence

Return type:

float

mirage.math.least_squares_line_intersection(p1: ndarray, p2: ndarray) → ndarray#

Least-squares intersection of \(n\) lines in \(m\)-dimensional space

Parameters:
  • p1 (np.ndarray [n, m]) – The first point on each line

  • p2 (np.ndarray [n, m]) – The second point on each line

Returns:

The intersection point [m,]

Return type:

np.ndarray [m,]

Source: https://stackoverflow.com/questions/52088966/nearest-intersection-point-to-many-lines-in-python

mirage.math.look_at_matrix(eye: ndarray, target: ndarray, up: ndarray) → ndarray#

Look matrix for a camera placed at eye, looking at target, with up vector up. Transforms from world frame coordinates to camera frame coordinates. Source

Parameters:
  • eye (np.ndarray [1x3]) – Location of camera origin in world coordinates

  • target (np.ndarray [1x3]) – Location of camera target in world coordinates

  • up (np.ndarray [1x3]) – Up vector constraining the vertical camera axis

Returns:

Look matrix \(V\) such that \(V[x \: 1]^T\) transforms the vector \(x\) into camera coordinates \(\frac{V[x \: 1]_{1:3}^T}{V[x \: 1]_{4}^T}\)

Return type:

np.ndarray [4x4]

mirage.math.mahal(pts: ndarray, mu: ndarray, cov: ndarray) → ndarray#

Computes the Mahalanobis distance from a set of points to a Gaussian distribution defined by its mean and covariance

Parameters:
  • pts (np.ndarray [nxm]) – Points to test

  • mu (np.ndarray [1xm]) – Mean of the distribution

  • cov (np.ndarray [mxm]) – Covariance matrix of the distribution

Returns:

Mahalanobis distances

Return type:

np.ndarray [n,]

mirage.math.matching_indices(x: ndarray, y: ndarray) → Tuple[ndarray, ndarray]#

Returns the indices into x and indices into y that match, x should be sorted for speed

Parameters:
  • x (np.ndarray) – Array 1, usually the much larger array (sorted if possible)

  • y (np.ndarray) – Array 2, smaller

Returns:

Indices a such that x[a[0]] == y[a[1]]

Return type:

Tuple[np.ndarray, np.ndarray]

mirage.math.merge_clusters(v: ndarray, atol: float, miter: int = 3) → ndarray#

Merges clusters of vectors in \(R^3\) within an angle tolerance by addition

Parameters:
  • v (np.ndarray [n,3]) – Array of row vectors to merge

  • atol (float) – Angle between vectors to merge by [rad]

  • miter (int, optional) – Merge iterations, defaults to 3

Returns:

Merged vectors

Return type:

np.ndarray [mx3], m <= n

mirage.math.multithreaded_gaussian(mu: ndarray, sigma: ndarray, seed: int = None, threads: int = 4) → ndarray#

Samples independent Gaussian random values in parallel.

Parameters:
  • mu (np.ndarray) – Gaussian means, with any shape

  • sigma (np.ndarray) – Gaussian standard deviations, with the same shape as mu

  • seed (int, optional) – Seed for the random-number generator, defaults to None

  • threads (int, optional) – Number of threads to use, defaults to 4

Returns:

Sampled values with the same shape as mu

Return type:

np.ndarray

mirage.math.multithreaded_poisson(lam: ndarray, seed: int = None, threads: int = 8) → ndarray#

Multithreaded Poisson random variable number generation

Parameters:
  • lam (np.ndarray) – Means (and equivalently variances) of the Poisson distributions to sample

  • seed (int, optional) – Seed value for the PRNG, defaults to None

  • threads (int, optional) – Number of threads to use, defaults to 8

Returns:

Sampled values, uint32

Return type:

np.ndarray

mirage.math.nth_pp_neighbor_cdf(d: ndarray, n: int, density: float) → ndarray#

CDF of the distance to the n-th nearest neighbor of a Poisson point process in 2D.

The CDF is

\[P(D_n \leq d) = 1 - \frac{\Gamma(n, \lambda\pi d^2)}{\Gamma(n)} = 1 - \mathrm{gammaincc}(n, \lambda\pi d^2),\]

where gammaincc is the regularized upper incomplete gamma function.

Parameters:
  • d (np.ndarray) – Distances at which to evaluate the CDF

  • n (int) – Order of the nearest-neighbor distance

  • density (float) – Point-process density \(\lambda\)

Returns:

CDF values at d

Return type:

np.ndarray

mirage.math.perspective_projection_matrix(fov_deg: float, aspect: float, near: float, far: float) → ndarray#

Transforms from camera coordinates to image plane coordinates for a perspective camera

Parameters:
  • fov_deg (float) – Field of view [deg]

  • aspect (float) – Aspect ratio of camera: the ratio of the horizontal to vertical fields of view

  • near (float) – Near plane distance from camera origin, avoid going much below 0.01 to avoid numerical issues at 0

  • far (float) – Far plane distance from camera origin

Returns:

Projection matrix \(P\) such that \(P[x \: 1]^T\) transforms the vector \(x\) into image coordinates \(\frac{P[x \: 1]_{1:3}^T}{P[x \: 1]_{4}^T}\)

Return type:

np.ndarray [4x4]

mirage.math.points_to_planes_dist(pt: ndarray, plane_n: ndarray, support: ndarray) → ndarray#

Computes the signed distance from a set of points to a set of planes

Parameters:
  • pt (np.ndarray [n,3]) – Array of points in R^3

  • plane_n (np.ndarray [n,3]) – Normal vectors of planes

  • support (np.ndarray [n,]) – Distance from each plane to the origin

Returns:

Distance from points to planes

Return type:

np.ndarray [n,]

mirage.math.r3_grid(grid_half_width: float, grid_side_count: int)#

Builds a cubic pyvista image-data grid centered at the origin.

Parameters:
  • grid_half_width (float) – Half-width of the cubic grid

  • grid_side_count (int) – Number of grid cells along each side

Returns:

Cubic image-data grid

Return type:

pyvista.ImageData

mirage.math.rad_to_dms(x: ndarray) → tuple[ndarray, ndarray, ndarray]#

Converts radians to degrees, minutes, seconds

Parameters:

x (Union[np.ndarray, float]) – Array or float in radians

Returns:

degrees, minutes, seconds

Return type:

tuple[np.ndarray, np.ndarray, np.ndarray]

mirage.math.rad_to_hms(x: ndarray) → tuple[ndarray, ndarray, ndarray]#

Converts radians to hours, minutes, seconds

Parameters:

x (Union[np.ndarray, float]) – Radians, either float or array

Returns:

Hours, minutes, seconds

Return type:

tuple[np.ndarray, np.ndarray, np.ndarray]

mirage.math.rdot(v1: ndarray, v2: ndarray, eps: float = 0.0) → ndarray#

Rectified dot product, where 0 if dot(v1,v2) < 0 else dot(v1,v2)

Parameters:
  • v1 (np.ndarray [nxm]) – First input vector

  • v2 (np.ndarray [nxm]) – Second input vector

  • eps (float, optional) – Cutoff where dot products of v1 and v2 less than eps return zero

Returns:

Positive dot product of v1 rows with v2` rows

Return type:

np.ndarray [n,1]

mirage.math.remove_zero_rows(v: ndarray) → ndarray#

Removes all rows from the 2D array v that have a norm of zero

Parameters:

v (np.ndarray [nxm]) – Array to operate on

Returns:

Copy of v with zero rows removed

Return type:

np.ndarray [n-k x m]

mirage.math.rk4(f: Callable, tspace: ndarray, y0: ndarray) → ndarray#

Integrates an ordinary differential equation with the classical fourth-order Runge-Kutta method.

Parameters:
  • f (Callable) – Right-hand-side function with signature f(t, y)

  • tspace (np.ndarray [n,]) – Uniformly spaced time values [s]

  • y0 (np.ndarray [m,]) – Initial state

Returns:

Integrated state at each time in tspace

Return type:

np.ndarray [n,m]

mirage.math.rotate_points_about_point(points: ndarray, angle: float, center: ndarray) → ndarray#

Rotates points in 2D about a center point

Parameters:
  • points (np.ndarray) – The points to rotate

  • angle (float) – The angle to rotate by [rad]

  • center (np.ndarray) – The center of rotation

Returns:

The rotated points

Return type:

np.ndarray

mirage.math.rv_to_daz_del(r: ndarray, v: ndarray) → tuple[ndarray, ndarray]#

Converts sets of position and velocity vectors to azimuth and elevation time derivatives (position and velocity must be expressed in the same units)

Parameters:
  • r (np.ndarray) – Position [nx3]

  • v (np.ndarray) – Velocity [nx3], any units as long as they match position

Returns:

Azimuth and elevation time derivatives

Return type:

tuple[np.ndarray, np.ndarray]

mirage.math.sind(x: ndarray | float | int) → ndarray | float#

Computes \(\sin(x)\) with \(x\) in degrees

Parameters:

x (Union[np.ndarray, float, int]) – Input [deg]

Returns:

\(\sin(x)\)

Return type:

Union[np.ndarray, float]

mirage.math.sph_to_cart(az: ndarray, el: ndarray, r: ndarray | None = None) → Tuple[ndarray, ndarray, ndarray]#

Converts from spherical (azimuth, elevation, range) to Cartesian (x, y, z)

Parameters:
  • az (np.ndarray) – Azimuth [rad]

  • el (np.ndarray) – Elevation [rad]

  • r (np.ndarray, optional) – Range, if not provided assumed to be 1

Returns:

Cartesian (x, y, z)

Return type:

Tuple[np.ndarray, np.ndarray, np.ndarray]

mirage.math.stack_mat_mult_mat(*matrices: Tuple[ndarray] | ndarray) → ndarray#

Multiplies each matrix in the next, page-wise

Parameters:

matrices (Union[Tuple[np.ndarray], np.ndarray], each must be [mxmxn]) – Matrix stacks to multiply together

Returns:

Multiplied product obeying result[:,:,i] = np.matmul(*mats[:,:,i])

Return type:

np.ndarray [mxmxn]

mirage.math.stack_mat_mult_vec(mats: ndarray, v: ndarray) → ndarray#

Multiplies each row in v by each page of mats

Parameters:
  • mats (np.ndarray [mxmxn]) – Matrices to multiply by

  • v (np.ndarray [nxm]) – Vectors to be multiplied

Returns:

Multiplied product obeying result[i, :] = mats[:,:,i] @ v[[i], :].T

Return type:

np.ndarray [nxm]

mirage.math.tand(x: ndarray | float | int) → ndarray | float#

Computes \(\tan(x)\) with \(x\) in degrees

Parameters:

x (Union[np.ndarray, float, int]) – Input [deg]

Returns:

\(\tan(x)\)

Return type:

Union[np.ndarray, float]

mirage.math.tilde(v: ndarray) → ndarray#

Matrix cross product operator such that \(v \times x = \left[\tilde{v}\right]x\)

Parameters:

v (np.ndarray [n,3]) – Vector to operate on

Returns:

Cross product matrices

Return type:

np.ndarray [3,3xn]

mirage.math.triangle_depth_pdf(v: ndarray, o: ndarray) → ndarray#

Probability density of a random point on a 3D triangle being at a given perpendicular distance from the origin in the direction of the 3-vector o

Parameters:
  • v (np.ndarray [3,3]) – Vertices of the triangle, as rows

  • o (np.ndarray) – Direction of interest (e.g., the incoming laser direction)

Returns:

The three points defining the PDF. Depths as the first column, probabilities as the second, linearly interpolated between for the true PDF

Return type:

np.ndarray

mirage.math.triangle_depth_pdf_vectorized(v: ndarray, o: ndarray) → ndarray#

Vectorized probability density for n triangles.

Parameters:
  • v – Vertices [n_faces, 3_vertices, 3_coords]

  • o – Direction [3,]

Returns:

Array [n_faces, 3, 2]

mirage.math.udot(v1: ndarray, v2: ndarray) → ndarray#

Unit dot product, clips the result of the dot product to [-1,1]

Parameters:
  • v1 (np.ndarray [nxm]) – First input vector

  • v2 (np.ndarray [nxm]) – Second input vector

Returns:

Dot product of v1 with v2, clipped to [-1,1]

Return type:

np.ndarray [n,1]

mirage.math.unique_rows(v: ndarray, decimals: int = 6, **kwargs) → ndarray#

Extracts unique rows from the input 2D array

Parameters:
  • v (np.ndarray [nxm]) – Input vector

  • decimals (int) – Number of decimals to compare when determining uniqueness, defaults to 6

  • **kwargs – Additional arguments to pass to np.unique

Returns:

Unique rows of v

Return type:

np.ndarray [n-k x m], \(k \geq 0\)

mirage.math.vecnorm(v: ndarray) → ndarray#

Takes the \(L_2\) norm of the rows of v

Parameters:

v (np.ndarray [nxm]) – Input vector

Returns:

Norm of each row

Return type:

np.ndarray [n,1]

mirage.math.wrap_to_180(lon: ndarray) → ndarray#

Wraps angular quantities to their remainder on [-180, 180]

Parameters:

lon (np.ndarray) – Angle to wrap [deg]

Returns:

Wrapped angle [deg]

Return type:

np.ndarray

mirage.math.wrap_to_360(lon: ndarray) → ndarray#

Wraps angular quantities to their remainder on [0, 360]

Parameters:

lon (np.ndarray) – Angle to wrap [deg]

Returns:

Wrapped angle [deg]

Return type:

np.ndarray

mirage.math.wrap_to_pi(lon: ndarray) → ndarray#

Wraps angular quantities to their remainder on [-pi, pi]

Parameters:

lon (np.ndarray) – Angle to wrap [rad]

Returns:

Wrapped angle [rad]

Return type:

np.ndarray

mirage.math.wrap_to_two_pi(lon: ndarray) → ndarray#

Wraps angular quantities to their remainder on [0, 2pi]

Parameters:

lon (np.ndarray) – Angle to wrap [rad]

Returns:

Wrapped angle [rad]

Return type:

np.ndarray

mirage.orbit module#

mirage.orbit.coe_to_rv(coe: ndarray, mu: float = 398600.4418) → ndarray#

Converts classical orbital elements to a state vector defined in the same frame.

Parameters:
  • coe (np.ndarray [nx6]) – Classical orbital elements in the form [a, e, i, Omega, omega, nu]

  • mu (float, optional) – Gravitational parameter of the central body, defaults to AstroConstants.earth_mu

Returns:

State vector in the form [r, v]

Return type:

np.ndarray [nx6]

mirage.orbit.drag_acceleration(y: ndarray, m: float, egi: ndarray, rho: float, cd: float = 2.0) → ndarray#

Acceleration due to atmospheric drag on a rotating body.

Parameters:
  • y (np.ndarray [13,]) – Stacked orbit-attitude state containing ECI position/velocity and the attitude quaternion in the form [r, v, q]

  • m (float) – Object mass [kg]

  • egi (np.ndarray [n,3]) – Area-weighted surface normal vectors in the body frame

  • rho (float) – Atmospheric density at the object [kg/m^3]

  • cd (float, optional) – Drag coefficient, defaults to 2.0

Returns:

Acceleration due to drag [km/s^2]

Return type:

np.ndarray [3,]

mirage.orbit.get_catalog_satrecs(date: datetime) → Tuple[SatrecArray, list, list]#

Gets the nearest catalog with cacheing. This function will be much faster if the date is rounded to the nearest hour or day

Parameters:

date (datetime.datetime) – Date (UTC) to query satrecs for

Returns:

sgp4.SatrecArray, satnums, and satellite names

Return type:

Tuple[SatrecArray, list, list]

mirage.orbit.integrate_orbit_and_attitude(r0: ndarray, v0: ndarray, q0: ndarray, w0: ndarray, itensor: ndarray, dates: ndarray, orbit_perturbations: Callable = <function <lambda>>, external_torque: Callable = <function <lambda>>, internal_torque: Callable = <function <lambda>>, int_tol: float = 1e-13, gravity_harmonics_degree: int = 4, third_bodies: list[str] = ()) → ndarray#

Integrates coupled orbit and rigid-body attitude dynamics.

Parameters:
  • r0 (np.ndarray [3,]) – Initial position in ECI [km]

  • v0 (np.ndarray [3,]) – Initial velocity in ECI [km/s]

  • q0 (np.ndarray [4,]) – Initial attitude quaternion

  • w0 (np.ndarray [3,]) – Initial body-frame angular velocity [rad/s]

  • itensor (np.ndarray [3,3]) – Body-frame inertia tensor [kg m^2]

  • dates (np.ndarray[datetime.datetime, Any]) – Dates to integrate over [UTC]

  • orbit_perturbations (Callable, optional) – Additional orbit-acceleration function with signature (date, t, y), defaults to zero acceleration

  • external_torque (Callable, optional) – External torque function with signature (date, t, y) [N m], defaults to zero torque

  • internal_torque (Callable, optional) – Internal torque function with signature (date, t, y) [N m], defaults to zero torque

  • int_tol (float, optional) – Relative and absolute integrator tolerance, defaults to 1e-13

  • gravity_harmonics_degree (int, optional) – Maximum gravity harmonics degree, defaults to 4

  • third_bodies (list[str], optional) – Names of third-body perturbers, defaults to empty

Returns:

Integrated positions [km], velocities [km/s], attitude quaternions, and body angular velocities [rad/s]

Return type:

tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]

mirage.orbit.integrate_orbit_dynamics(rv0: ndarray, dates: ndarray[datetime, Any], gravity_harmonics_degree: int = 16, third_bodies: list[str] | None = None, int_tol: float = 1e-13) → ndarray#

Integration for orbital dynamics with perturbations

Parameters:
  • rv0 (np.ndarray [1x6]) – Initial position and velocity state in Earth-centered inertial coordinates

  • dates (np.ndarray[datetime.datetime, Any]) – Dates to integrate over [UTC]

  • gravity_harmonics_degree (int, optional) – Maximum gravity harmonics degree, defaults to 16

  • third_bodies (Optional[list[str]], optional) – Names of third-body perturbers, defaults to None

  • int_tol (float, optional) – Relative and absolute integrator tolerance, defaults to 1e-13

Returns:

Integrated orbit state in ECI in position [km] and velocity [km/s]

Return type:

np.ndarray [nx6]

mirage.orbit.j2_acceleration(rvec: ndarray) → ndarray#

Acceleration due to the J2 perturbation (Earth oblateness)

Parameters:

rvec (np.ndarray [n,3]) – Position vector of the satellite [km]

Returns:

Acceleration due to J2 [km/s^2]

Return type:

np.ndarray [n,3]

mirage.orbit.moon_acceleration(date: datetime, rv: ndarray) → ndarray#

3rd body acceleration due to the Moon

Parameters:
  • date (datetime.datetime) – UTC date to evaluate at

  • rv (np.ndarray [n,6]) – Position and velocity state in Earth-centered inertial coordinates

Returns:

Acceleration due to the Moon [km/s^2]

Return type:

np.ndarray [n,3]

mirage.orbit.propagate_catalog_to_dates(dates: ndarray[datetime] | datetime, rmag_limit: float = 100000.0, return_satnums: bool = False, return_names: bool = False) → ndarray#

Propagates a satellite catalog to an array of dates, output in J2000 ECI [km]

Parameters:
  • dates (Union[np.ndarray[datetime.datetime], datetime.datetime]) – Array of datetimes [UTC]

  • rmag_limit (float, optional) – Remove all propagated positions with magnitudes greater than this value [km], defaults to 1e5

  • return_satnums (bool, optional) – Whether to return satnums with the positions, defaults to False

  • return_names (bool, optional) – Whether to return names with the positions, defaults to False

Returns:

Position [km] and velocity [km/s] in J2000

Return type:

Tuple[np.ndarray [n,3], np.ndarray [n,3]], optional names as 3rd tuple entry [n,]

mirage.orbit.propagate_satnum_to_dates(dates: datetime, satnum: int) → ndarray#

Propagates a satellite number to the given UTC datetimes in J2000

Parameters:
  • dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Array of datetimes [UTC]

  • satnum (int) – NORAD satellite number

Returns:

Position [km] in J2000

Return type:

np.ndarray [n,3]

mirage.orbit.rv_to_coe(rv: ndarray, mu: float = 398600.4418) → ndarray#

Converts a state vector to classical orbital elements defined in the same frame.

Parameters:
  • rv (np.ndarray [nx6]) – State vector in the form [r, v]

  • mu (float, optional) – Gravitational parameter of the central body, defaults to AstroConstants.earth_mu

Returns:

Classical orbital elements in the form [a, e, i, Omega, omega, nu]

Return type:

np.ndarray

mirage.orbit.srp_acceleration(t: datetime, y: ndarray, egi: ndarray, cd: ndarray, cs: ndarray, sun_interpolator: Callable, m: float, solar_irradiance: float = 1367.0) → ndarray#

Acceleration due to solar radiation pressure on a rotating body.

Parameters:
  • t (datetime.datetime) – Date at which to evaluate the Sun direction

  • y (np.ndarray [13,]) – Stacked orbit-attitude state containing ECI position/velocity and the attitude quaternion in the form [r, v, q]

  • egi (np.ndarray [n,3]) – Area-weighted surface normal vectors in the body frame

  • cd (np.ndarray [n,]) – Diffuse reflection coefficients for each surface

  • cs (np.ndarray [n,]) – Specular reflection coefficients for each surface

  • sun_interpolator (Callable) – Interpolator returning the Sun position in ECI at t

  • m (float) – Object mass [kg]

  • solar_irradiance (float, optional) – Solar irradiance at the object [W/m^2], defaults to 1367.0

Returns:

Acceleration due to solar radiation pressure [km/s^2]

Return type:

np.ndarray [3,]

mirage.orbit.third_body_acceleration(epsecs: ndarray, rv: ndarray, interpolator: SpiceInterpolator) → ndarray#

3rd body acceleration on a satellite due to a solar system body

Parameters:
  • epsecs (np.ndarray) – Epoch seconds to evaluate at after the initial epoch

  • rv (np.ndarray [n,6]) – Position and velocity state in Earth-centered inertial coordinates

  • interpolator (SpiceInterpolator) – SpiceInterpolator object for the body

Returns:

Acceleration due to the third body [km/s^2]

Return type:

np.ndarray [n,3]

mirage.orbit.tle_propagate_with_switching(satnum_or_tles: int | ndarray[str, str], dates: ndarray[datetime, Any], switch_strategy: str = 'interp', pad_time: timedelta = datetime.timedelta(days=17), frame: str = 'j2000', return_velocity: bool = False) → ndarray#

Propagates a satellite with SGP4 over a set of datetimes with a switching strategy

Parameters:
  • satnum_or_tles (Union[int, np.ndarray[str, str]]) – NORAD SAT ID, ex. 25544 for ISS (ZARYA), or array of TLE strings [n,2]

  • dates (np.ndarray[datetime.datetime, Any]) – Datetimes to propagate to

  • switch_strategy (str, optional) – Switching strategy, either ‘interp’, ‘newest’, or ‘closest’, defaults to ‘interp’ (which tends to have the lowest error)

  • pad_time (datetime.timedelta, optional) – Time to grab TLEs before and after the range of the input dates, defaults to 17 days

  • frame (str, optional) – Output frame, any of ‘j2000’, ‘teme’, ‘tod’, ‘mod’, ‘itrf’, defaults to ‘j2000’

  • return_velocity (bool, optional) – Whether to output velocity too, defaults to False

Returns:

Position of the satellite at the datetimes, or position and velocity if requested

Return type:

Union[np.ndarray [n,3], tuple[np.ndarray [n,3], np.ndarray [n,3]]]

mirage.orbit.two_body_dynamics(rv: ndarray) → ndarray#

Relative two-body dynamics for orbits

Parameters:

rv (np.ndarray [n,6]) – Position [:3] [km] and velocity [3:] [km/s] of the satellite

Returns:

Time derivative of position and velocity states

Return type:

np.ndarray [n,6]

mirage.profiling module#

mirage.profiling.get_profiling_results() → dict#

Returns the results of the mirage profiler.

Returns:

The results dictionary of the mirage profiler.

Return type:

dict

mirage.profiling.print_profiling_results() → None#

Prints the results of the mirage profiler.

mirage.profiling.profile_script(script_path: str) → None#

Runs the mirage profiler on a Python script file.

Parameters:

script_path (str) – Path to the Python script to be profiled.

Raises:
  • FileNotFoundError – If the script file is not found.

  • Exception – If an error occurs while executing the script.

mirage.profiling.set_profile_dt_threshold(threshold: float) → None#

Sets the threshold for the mirage profiler.

Parameters:

threshold (float) – The threshold in seconds.

mirage.profiling.tic(msg: str | None = None)#

Starts a timer, ended by toc()

Parameters:

msg (str, optional) – Message to come before the elapsed time statement, defaults to None

Raises:

Exception – If there is already an active tic

mirage.profiling.toc(return_elapsed_seconds: bool = False, do_print: bool = True) → None | float#

Ends the timer began by the most recent tic(), returns the elapsed time

Parameters:
  • return_elapsed_seconds (bool, optional) – Whether to return the time as well as printing it, defaults to False

  • do_print (bool, optional) – Whether to print the elapsed time, defaults to True

Raises:

Exception – If there’s no active tic() timer running with the given message

Returns:

The elapsed time in seconds, if requested

Return type:

Union[None, float]

mirage.profiling.with_profiler(func: Callable)#

Decorator that profiles a function with the mirage line profiler.

Parameters:

func (Callable) – Function to profile

Returns:

Wrapped function that records profiling results

Return type:

Callable

mirage.sampling module#

mirage.sampling.closest_fibonacci_index(p: ndarray, n: int) → int#

Finds the index of the Fibonacci sphere sampling closest to the given point following [Keinert et al. 2015]

Parameters:
  • p (np.ndarray [1x3]) – Point to find the closest neighbor of

  • n (int) – Number of points in the Fibonacci point set

Returns:

Index of the closest point

Return type:

int

mirage.sampling.fibonacci_sample_sphere(num: int) → ndarray#

Computes a point set of num points of the form described by Marques et al. in 2013

Parameters:

num (int) – Number of vectors to sample

Returns:

Sampled unit vectors

Return type:

np.ndarray [n,3]

mirage.sampling.quaternion_fibonacci_sample(n: int) → ndarray#

Samples the hypersphere with a fibonacci spiral [alexa2022]

Parameters:

n (int) – Number of quaternions to return

Returns:

Sampled unit quaternions

Return type:

np.ndarray

mirage.sampling.rand_cone_edge_vectors(cone_center: ndarray, half_angle: ndarray | float, size: int = None) → ndarray#

Uniformly samples vectors on the edge of a cone, as opposed to rand_cone_vectors which samples within the boundary of a cone

Parameters:
  • cone_center (np.ndarray [3,] or [n,3]) – Axis of symmetry of the cone(s)

  • half_angle (float | np.ndarray [n,]) – Half angle(s) of the cone(s), radians

  • size (int, optional) – Number of points to sample, if [3,] provided for vector inputs and half_angle is float, defaults to None

Returns:

Random uniform vectors on the boundary of the defined cone

Return type:

np.ndarray [n,3] or [size,3]

mirage.sampling.rand_cone_vectors(cone_axis: ndarray, cone_half_angle: float, num: int) → ndarray#

Uniformly samples vectors within a cone.

Parameters:
  • cone_axis (np.ndarray [3,] or [n,3]) – Axis of symmetry of the cone(s)

  • cone_half_angle (float) – Half-angle of the cone [rad]

  • num (int) – Number of vectors to sample

Returns:

Random vectors uniformly distributed within the cone

Return type:

np.ndarray [num,3]

mirage.sampling.rand_points_in_ball(r: float | ndarray, num: int) → ndarray#

Samples random points in a solid ball

Parameters:
  • r (Union[float, np.ndarray]) – Radius of the ball, or one unique radius per sample

  • num (int) – Number to sample

Raises:

ValueError – If the number of provided radii is not 1 or equal to num

Returns:

Sampled points

Return type:

np.ndarray [n,3]

mirage.sampling.rand_points_in_cube(num: int, origin: tuple = (0.0, 0.0, 0.0), scale: tuple = (1.0, 1.0, 1.0)) → ndarray#

Samples random points in a cube

Parameters:
  • num (int) – Number to sample

  • origin (tuple, optional) – Origin of the cube, defaults to (0., 0., 0.)

  • scale (tuple, optional) – Scale of the cube, defaults to (1., 1., 1.)

Returns:

Sampled points

Return type:

np.ndarray [n,3]

mirage.sampling.rand_points_in_shell(r_lims: Tuple[float, float], num: int) → ndarray#

Samples random points in a solid spherical shell defined by r_lims

Parameters:
  • r_lims (Tuple[float, float]) – Minimum and maximum shell radii

  • num (int) – Number of points to sample

Returns:

Sampled points

Return type:

np.ndarray [n,3]

mirage.sampling.rand_unit_vectors(num: int) → ndarray#

Generates uniform random vectors on the unit sphere \(S^2\)

Parameters:

num (int) – Number of unit vectors to generate

Returns:

Sampled unit vectors

Return type:

np.ndarray [n,3]

mirage.sampling.random_offset_quaternions(vi: ndarray, vb: ndarray, alpha: float | ndarray, size: int = None, boundary_only: bool = True) → ndarray#

Finds random quaternions that place vi (in the inertial frame) at an offset angle alpha in radians from the body-frame vector vb

Parameters:
  • vi (np.ndarray [3,] or [n,3]) – Inertial vector to offset from

  • vb (np.ndarray [3,] or [n,3]) – Body vector to offset from

  • alpha (float | np.ndarray) – Offset half-angle from vi [rad]

  • size (int, optional) – Number of points to sample, if [3,] provided for vector inputs and alpha is float, defaults to None

  • boundary_only (bool, optional) – Whether to sample points only on the boundary where the angle is exactly alpha, or to samples angles less than alpha as well, defaults to True

Returns:

Quaternions rotating from the inertial frame to the body frame via left multiplication, i.e. v_body = dcm(q) @ v_inertial

Return type:

np.ndarray [n,4] or [size,4]

mirage.sampling.spiral_sample_sphere(num: int) → ndarray#

Generates relatively uniform samples on the unit sphere via Fibonacci sampling

Parameters:

num (int) – Number of vectors to sample

Returns:

Sampled unit vectors

Return type:

np.ndarray [n,3]

mirage.sdf module#

class mirage.sdf.SDF(vertices: ndarray, faces: ndarray)#

Bases: object

Signed-distance-field representation of a triangular mesh.

gradient(r_query: ndarray, h: float = 0.0001) → ndarray#

Estimates the signed-distance-field gradient with finite differences.

Parameters:
  • r_query (np.ndarray [n,3]) – Query points

  • h (float, optional) – Finite-difference step length, defaults to 1e-4

Returns:

Gradient vectors at the query points

Return type:

np.ndarray [n,3]

normal_az_el_at_point(r_query: ndarray) → tuple[ndarray, ndarray]#

Computes surface-normal azimuth and elevation at query points.

Parameters:

r_query (np.ndarray [n,3]) – Query points

Returns:

Azimuth and elevation of the surface normal [rad]

Return type:

tuple[np.ndarray, np.ndarray]

query_grid(grid_half_width: float, grid_density: int, flatten: bool = False) → ndarray#

Evaluates the signed-distance field on a cubic grid.

Parameters:
  • grid_half_width (float) – Half-width of the cubic grid

  • grid_density (int) – Number of grid cells along each side

  • flatten (bool, optional) – Whether to flatten the returned grid, defaults to False

Returns:

Signed-distance values on the grid

Return type:

np.ndarray

query_points(query_pts: ndarray) → ndarray#

Evaluates the signed-distance field at query points.

Parameters:

query_pts (np.ndarray [n,3]) – Query points

Returns:

Signed-distance values

Return type:

np.ndarray [n,]

class mirage.sdf.SphericalWeight(ref_pts: ndarray, ref_weights: ndarray)#

Bases: object

Spherical weighting function interpolated from reference points and weights.

query_az_el(az: ndarray, el: ndarray, method: str = 'nearest') → ndarray#

Evaluates the weight function at azimuth/elevation coordinates.

Parameters:
  • az (np.ndarray [n,]) – Azimuth values [rad]

  • el (np.ndarray [n,]) – Elevation values [rad]

  • method (str, optional) – Interpolation method, either ‘nearest’ or ‘bilinear’, defaults to ‘nearest’

Returns:

Interpolated weights

Return type:

np.ndarray [n,]

query_points(query_pts: ndarray, method: str = 'nearest') → ndarray#

Evaluates the weight function at query points on the unit sphere.

Parameters:
  • query_pts (np.ndarray [n,3]) – Query points on the unit sphere

  • method (str, optional) – Interpolation method, either ‘nearest’ or ‘bilinear’, defaults to ‘nearest’

Returns:

Interpolated weights

Return type:

np.ndarray [n,]

mirage.spaceobject module#

class mirage.spaceobject.SpaceObject(model_file: str | None = None, vertices_and_faces: Tuple[ndarray, ndarray] | None = None, is_dual: bool = False, identifier: int | str | None = None, enforce_convex_normals: bool = False)#

Bases: object

Triangular-mesh space object with geometry, lighting, and propagation utilities.

build_properties()#

Builds all relevant object properties for shape inversion or visualization

build_pyvista_mesh()#

Builds a pyvista mesh from the object’s vertices and faces.

clean()#

Returns a cleaned copy of the mesh with duplicate or degenerate geometry removed.

Returns:

Cleaned space object

Return type:

SpaceObject

compute_center_of_mass() → ndarray#

Computes the center of mass for this triangle mesh

compute_face_areas()#

Computes the area of each face

compute_face_centroids()#

Computes the centroids of each face by averaging vertices

compute_face_normals()#

Computes the normals of each face

compute_inertia_tensor()#

Computes the body-frame inertia tensor of the object, from (MatlabCentral)

compute_supports(trunc_limit: float = 1e-07)#

Computes the support (perpendicular distance from plane containing face to origin)

Parameters:

trunc_limit (float, optional) – Minimum support value, used to avoid zero denominators, defaults to 1e-7

compute_volume()#

Computes the volume via the supports and unique areas

convex_light_curve(brdf: Brdf, svb: ndarray, ovb: ndarray, use_unique: bool = False) → ndarray#

Computes the light curve of a convex object with a given BRDF Fan [Fan]

Parameters:
  • brdf (Brdf) – BRDF to render with

  • svb (np.ndarray [n,3]) – Sun unit vectors in the body frame

  • ovb (np.ndarray [n,3]) – Observer unit vectors in the body frame

  • use_unique (bool, optional) – Use the unique normals and areas (requires BRDF coefficients of the same shape, if they are specified per face), defaults to False

Returns:

Observed irradiance at unit distance

Return type:

np.ndarray [n,]

property dual#

Dual object of this convex object, computed lazily.

flip_normals()#

For convex objects, flips any normal vectors pointing inside the object

get_dual()#

Sets the dual object

get_egi()#

Computes the Extended Gaussian Image (EGI)

get_face_vertices() → Tuple[ndarray, ndarray, ndarray]#

Reshapes face vertices into tuple of all 1st vertices, 2nd vertices, 3rd vertices

get_inner_vertices()#

Computes which vertices are within the convex hull (not contained in any faces of the convex hull)

get_sdf()#

Builds a signed-distance field from a cleaned copy of this object.

Returns:

Signed-distance field for the cleaned mesh

Return type:

SDF

introduce_concavity(displacement_direction: ndarray, internal_angle_deg: float, normal_selection_tolerance=0.8707963267948966, linear_iter: int = 5, loop_iter: int = 0)#

Creates a concave object by displacing selected faces inward.

Parameters:
  • displacement_direction (np.ndarray [3,]) – Direction in which selected vertices are displaced

  • internal_angle_deg (float) – Internal angle of the introduced concavity [deg]

  • normal_selection_tolerance (float, optional) – Angular tolerance for selecting displaced faces [rad], defaults to \(\pi/2 - 0.7\)

  • linear_iter (int, optional) – Number of linear subdivision iterations, defaults to 5

  • loop_iter (int, optional) – Number of butterfly subdivision iterations, defaults to 0

Returns:

Concave space object

Return type:

SpaceObject

is_convex(volume_tol: float = 0.001) → bool#

Determines whether the object is convex

Parameters:

volume_tol (float, optional) – Tolerance for the difference in the volume of the object and its convex hull, which is ideally zero if the object is truly convex, defaults to 1e-3

Returns:

True of the object is convex

Return type:

bool

property principal_itensor#

Principal-axis inertia tensor, computed lazily.

propagate(dates: ndarray[datetime, Any], return_velocity: bool = False)#

Propagates the object’s satellite state with TLEs.

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to propagate to [UTC]

  • return_velocity (bool, optional) – Whether to return velocity along with position, defaults to False

Returns:

Position [km], or position and velocity [km/s] if requested

Return type:

Union[np.ndarray [n,3], tuple[np.ndarray [n,3], np.ndarray [n,3]]]

rotate_by_quat(quat: ndarray) → None#

Rotates the object’s mesh by the given quaternion

Parameters:

quat (np.ndarray [1x4]) – Quaternion to apply to all vertices

sample_points(n_points: int) → ndarray#

Samples points uniformly by area over the object’s triangular faces.

Parameters:

n_points (int) – Number of points to sample

Returns:

Sampled points and the triangular-face index containing each point

Return type:

tuple[np.ndarray [n,3], np.ndarray [n,]]

shift_to_center_of_mass() → None#

Shifts the object’s vertices to the center of mass

subdivide(linear_iter: int = 1, loop_iter: int = 1)#

Returns a subdivided copy of the mesh.

Parameters:
  • linear_iter (int, optional) – Number of linear subdivision iterations, defaults to 1

  • loop_iter (int, optional) – Number of butterfly subdivision iterations, defaults to 1

Returns:

Subdivided space object

Return type:

SpaceObject

unique_areas_and_normals()#

Finds groups of unique normals and areas to save rows elsewhere

vertices_on_each_face()#

Computes a np.ndarray [3,3,n] of vertices on each face

mirage.spaceobject.build_dual(normals: ndarray, supports: ndarray) → SpaceObject#

Computes the polyhedral dual of the set of normals and supports

Parameters:
  • normals (np.ndarray [n,3]) – Outward-facing normal vectors

  • supports (np.ndarray [n,]) – Support of each face (see compute_supports())

Returns:

Dual object defined by the normals and supports

Return type:

SpaceObject

mirage.spaceobject.compute_in_sphere(p: SpaceObject) → Tuple[ndarray, float]#

Computes the largest inscribed sphere of a volume-normalized object.

Parameters:

p (SpaceObject) – Space object to analyze

Returns:

Sphere center and radius

Return type:

Tuple[np.ndarray [3,], float]

mirage.spaceobject.compute_out_sphere(p: SpaceObject) → Tuple[ndarray, float]#

Computes the smallest enclosing sphere of an object.

Parameters:

p (SpaceObject) – Space object to analyze

Returns:

Sphere center and radius

Return type:

Tuple[np.ndarray [3,], float]

mirage.spaceobject.construct_from_egi_and_supports(egi: ndarray, support: ndarray) → SpaceObject#

Constructs an object from an input Extended Gaussian Image (EGI) and support set

Parameters:
  • egi (np.ndarray [n,3]) – EGI of the object

  • support (np.ndarray [n,]) – Supports of each face in the EGI

Returns:

Resulting convex object, with potentially fewer faces than the original EGI depending on supports selected

Return type:

SpaceObject

mirage.spaceobject.construct_mesh_from_egi(egi: ndarray, implementation: str = 'fortran') → ndarray#

Constructs a space object mesh from an Extended Gaussian Image.

Parameters:
  • egi (np.ndarray [n,3]) – Extended Gaussian Image to reconstruct, which must be closed

  • implementation (str, optional) – Reconstruction implementation, either ‘fortran’ or ‘python’, defaults to ‘fortran’

Returns:

Reconstructed space object

Return type:

SpaceObject

mirage.spaceobject.delete_all_models()#

Removes all model files (.obj, .mtl) from the current model directory as well as the model listing file (.json)

mirage.spaceobject.edge_iterator(edges: ndarray)#

Iterates over consecutive edge-vertex pairs, including the closing edge.

Parameters:

edges (np.ndarray [n,2]) – Ordered polygon vertices

Returns:

Iterator over pairs of consecutive vertices

Return type:

Iterator[tuple[np.ndarray, np.ndarray]]

mirage.spaceobject.faces_and_vertices_from_egi(egi: ndarray) → tuple[ndarray, ndarray]#

Reconstructs triangular mesh vertices and faces from an Extended Gaussian Image.

Parameters:

egi (np.ndarray [n,3]) – Extended Gaussian Image to reconstruct

Returns:

Mesh vertices and triangular face indices

Return type:

tuple[np.ndarray, np.ndarray]

mirage.spaceobject.generate_superquadric(a: float = 1.0, b: float = 1.0, c: float = 1.0, n1: float = 1.0, n2: float = 1.0, resolution: int = 25) → Tuple[ndarray, ndarray]#

Generates a mesh for a superquadric (superellipsoid) shape.

The shape is defined by the generalized superellipsoid parametric equations, with semi-axes a, b, and c and exponents n1 and n2.

Parameters:
  • a (float) – Scaling factor along the x-axis.

  • b (float) – Scaling factor along the y-axis.

  • c (float) – Scaling factor along the z-axis.

  • n1 (float) – Exponent controlling the shape’s “squareness” along the z-axis. A value of 2.0 creates a cylinder-like shape.

  • n2 (float) – Exponent controlling the shape’s “squareness” in the xy-plane. A value of 2.0 creates a square cross-section.

  • resolution (int) – The number of points used to define the grid of angles. Higher values result in a smoother mesh.

Returns:

Space object containing the generated vertices and faces

Return type:

SpaceObject

mirage.spaceobject.get_volume(h: ndarray, egi: ndarray) → float#

Computes the volume of the polytope represented by the supports and EGI input

Parameters:
  • h (np.ndarray [n,]) – Support vector

  • egi (np.ndarray [n,3]) – Extended Gaussian image to reconstruct from

Returns:

Volume of the reconstructed convex polytope

Return type:

float

mirage.spaceobject.intersects_obj(origin: ndarray, stop: ndarray, obj: SpaceObject) → ndarray[bool]#

Computes whether a set of rays intersect an object

Parameters:
  • origin (np.ndarray [n,3]) – Ray origin points in world space

  • stop (np.ndarray [n,3]) – Ray stop points in world space

  • obj (SpaceObject) – Object to trace rays against

Returns:

Whether each ray intersects the object before reaching its stop point

Return type:

np.ndarray[bool] [n,]

mirage.spaceobject.is_tri_ccw(v1, v2, v3) → bool#

Checks whether a 2D triangle’s vertices are ordered counter-clockwise.

Parameters:
  • v1 (np.ndarray [2,]) – First triangle vertex

  • v2 (np.ndarray [2,]) – Second triangle vertex

  • v3 (np.ndarray [2,]) – Third triangle vertex

Returns:

Whether the vertices are counter-clockwise

Return type:

bool

mirage.spaceobject.little_fun(h: ndarray, egi: ndarray) → float#

Little’s objective function for support vector optimization Little [Lit]

Parameters:
  • h (np.ndarray [n,]) – Supports vector

  • egi (np.ndarray [n,3]) – Extended Gaussian image to reconstruct from

Returns:

Objective function value \(f=(h \cdot a)\)

Return type:

float

mirage.spaceobject.load_mtllib(mtllib_path: str) → dict#

Loads a .mtl file

Parameters:

mtllib_path (str) – Path to the .mtl file

Returns:

Dictionary of materials arranged by material name

Return type:

dict

mirage.spaceobject.load_obj(obj_path: str, n_default: float = 10.0, **obj_kwargs) → SpaceObject#

Loads a .obj file and its material properties

Parameters:
  • obj_path (str) – Path to the .obj file

  • n_default (float, optional) – Default specular exponent value, defaults to 10.0

  • **obj_kwargs – Additional keyword arguments passed to SpaceObject

Returns:

Loaded object, including per-face material coefficients when available

Return type:

SpaceObject

mirage.spaceobject.m_from_poly(poly: ndarray, n: ndarray) → ndarray#

Builds a local coordinate basis aligned with a polygon and its normal.

Parameters:
  • poly (np.ndarray [n,3]) – Ordered polygon vertices

  • n (np.ndarray [3,]) – Polygon normal vector

Returns:

Orthonormal basis matrix whose rows are the local axes

Return type:

np.ndarray [3,3]

mirage.spaceobject.merge_shapes(objs: Iterable[SpaceObject], weighting_fcns: ndarray | Iterable[Callable], grid_density: int = 100) → SpaceObject#

Merges any number of SpaceObjects using a weighted average of their signed distance fields

Parameters:
  • objs (Iterable[mr.SpaceObject]) – Set of objects to merge

  • weighting_fcns (Union[np.ndarray, Iterable[Callable]]) – Weights to use for each object, either an array of floats or callables of the form (az: np.ndarray, el: np.ndarray) -> np.ndarray [0,1]

  • grid_density (int, optional) – Grid density to use for the signed distance field, defaults to 100

Returns:

Merged object

Return type:

mr.SpaceObject

mirage.spaceobject.optimize_egi(lc: ndarray, svb: ndarray, ovb: ndarray, brdf: Brdf, num_candidates: int = 1000, merge_iter: int = 1, merge_angle: float = 0.3141592653589793, return_all: bool = False, weights: ndarray | None = None) → ndarray#

Optimizes an Extended Gaussian Image (EGI) to fit observed irradiances [RF]

Parameters:
  • lc (np.ndarray [n,]) – Unit irradiance light curve

  • svb (np.ndarray [n,3]) – Sun unit vectors in the body frame for each observation

  • ovb (np.ndarray [n,3]) – Observer unit vectors in the body frame

  • brdf (Brdf) – BRDF to use

  • num_candidates (int, optional) – Number of candidate normal vectors to fit, defaults to int(1e3)

  • merge_iter (int, optional) – Number of iterations for the merging step, defaults to 1

  • merge_angle (float, optional) – Angle between vectors to merge by, defaults to np.pi/10

  • return_all (bool, optional) – Whether to return the initial and merged EGIs, defaults to False

  • weights (np.ndarray, optional) – Weights for each observation, defaults to None

Returns:

Optimized EGI, or the initial and merged EGIs when return_all=True

Return type:

Union[np.ndarray, tuple[np.ndarray, np.ndarray]]

mirage.spaceobject.optimize_supports_little(egi: ndarray) → ndarray#

Optimizes a support vector to construct the polytope with the given Extended Gaussian Image (EGI) Little [Lit]

Parameters:

egi (np.ndarray [n,3]) – EGI to find supports for, convergence only possible if the sum of rows is zero. See close_egi()

Returns:

Optimal set of supports

Return type:

np.ndarray [n,]

mirage.spaceobject.poly_area(poly: ndarray) → float#

Computes the area of a simple 2D polygon by triangle decomposition.

Parameters:

poly (np.ndarray [n,2]) – Ordered polygon vertices

Returns:

Polygon area

Return type:

float

mirage.spaceobject.poly_on_plane(t1, t3, v) → array#

Projects a polygon onto the plane of a reference triangle along a direction.

Parameters:
  • t1 (np.ndarray [n,3]) – Vertices of the polygon to project

  • t3 (np.ndarray [3,3]) – Vertices of the reference triangle

  • v (np.ndarray [3,]) – Projection direction

Returns:

Projected polygon vertices

Return type:

np.ndarray [n,3]

mirage.spaceobject.proj_to_plane_along_dir(ps, nd, pp, np_)#

Projects points onto a plane along a specified direction.

Parameters:
  • ps (np.ndarray [n,3]) – Points to project

  • nd (np.ndarray [3,]) – Projection direction

  • pp (np.ndarray [3,]) – Point on the target plane

  • np (np.ndarray [3,]) – Normal vector of the target plane

Returns:

Projected points

Return type:

np.ndarray [n,3]

mirage.spaceobject.ray_triangle_intersection(ray_origin, ray_direction, v0, v1, v2, epsilon=1e-06)#

Computes the intersection of a ray with a triangle.

Parameters:
  • ray_origin (np.ndarray [3,]) – Ray origin

  • ray_direction (np.ndarray [3,]) – Ray direction

  • v0 (np.ndarray [3,]) – First triangle vertex

  • v1 (np.ndarray [3,]) – Second triangle vertex

  • v2 (np.ndarray [3,]) – Third triangle vertex

  • epsilon (float, optional) – Numerical tolerance, defaults to 1e-6

Returns:

Whether the ray intersects the triangle and the intersection distance along the ray

Return type:

tuple[bool, float]

mirage.spaceobject.set_model_directory(path: str) → None#

Sets the 3D model path used by all tools and methods

Parameters:

path (str) – Absolute or relative (from cwd) path to the model folder

mirage.spaceobject.spaceobject_from_pyvista_mesh(mesh)#

Builds a SpaceObject from a pyvista mesh.

Parameters:

mesh (pyvista.PolyData) – Pyvista mesh to convert

Returns:

Space object containing the mesh vertices and triangular faces

Return type:

SpaceObject

mirage.spaceobject.tri_area(v1: ndarray, v2: ndarray, v3: ndarray) → float#

Computes the signed area of a 2D triangle.

Parameters:
  • v1 (np.ndarray [2,]) – First triangle vertex

  • v2 (np.ndarray [2,]) – Second triangle vertex

  • v3 (np.ndarray [2,]) – Third triangle vertex

Returns:

Triangle area

Return type:

float

mirage.spaceobject.unshadowed_areas(obj: SpaceObject, directions: tuple[ndarray], plot: bool = False) → ndarray#

Computes the unshadowed area of each face for a set of illumination/view directions.

Parameters:
  • obj (SpaceObject) – Space object whose faces are tested

  • directions (tuple[np.ndarray]) – Illumination or viewing directions

  • plot (bool, optional) – Whether to render the shadowing geometry, defaults to False

Returns:

Unshadowed area of each face

Return type:

np.ndarray [n,]

mirage.stars module#

class mirage.stars.GaiaSpectralStarCatalog(station, date: datetime = None, aberration: bool = False)#

Bases: StarCatalog

Gaia catalog backed by precomputed stellar spectra.

load()#

Loads the Gaia spectral catalog from its parquet archive.

Returns:

Star unit vectors and spectra calibrated to Gaia G magnitudes

Return type:

tuple[np.ndarray, np.ndarray]

class mirage.stars.GaiaStarCatalog(station, date: datetime = None, aberration: bool = False)#

Bases: StarCatalog

Gaia catalog backed by the Gaia DR3 photometric archive.

load(**kwargs) → Callable#
class mirage.stars.StarCatalog#

Bases: object

Base class for star catalogs with lazy on-disk caching.

account_for_aberration()#

Computes apparent star positions including annual and daily aberration.

build_tree()#

Builds a KD-tree over the catalog’s unit vectors.

in_fov(eci_look_dir: ndarray, scope_up: ndarray, method: Literal['brute', 'tree'] = 'tree', return_inds: bool = False) → tuple[ndarray, ndarray]#

Finds stars in the field of view of a telescope

Parameters:
  • eci_look_dir (np.ndarray) – The look direction of the telescope in ECI coordinates

  • scope_up (np.ndarray) – The up direction of the telescope in ECI coordinates (orthogonal to the look direction, defining the vertical axis of the image)

  • method (Literal["brute", "tree"], optional) – The method to use for finding stars in the field of view, defaults to “tree”

  • return_inds (bool, optional) – Whether to return the in-frame indices as an additional output, defaults to False

Returns:

The unit vectors and associated values of the stars in the field of view, optionally with their catalog indices

Return type:

Union[tuple[np.ndarray, np.ndarray], tuple[np.ndarray, np.ndarray, np.ndarray]]

load_tree_lazy()#

Loads the star catalog from a file

save_tree_lazy()#

Saves the star catalog to a file

class mirage.stars.Tycho2StarCatalog(station, date: datetime = None, aberration: bool = False)#

Bases: StarCatalog

Tycho-2 star catalog with Johnson V-band magnitudes.

load(**kwargs) → Callable#
mirage.stars.adjust_spectrum_to_mag_in_band(lambdas: ndarray, spec: ndarray, mag: ndarray | float, band_name: str) → ndarray#

Adjusts a spectrum so that it has a given apparent magnitude in a passband

Parameters:
  • lambdas (np.ndarray [mx1]) – Wavelengths [nm]

  • spec (np.ndarray [mx1]) – Input spectrum, i.e. the spectrum of the Sun. Units do not matter as long as they are linear

  • mag (Union[np.ndarray, float]) – Magnitude(s) to adjust the spectrum to

  • band_name (str) – Name of the band to use, ex. ‘G’

Returns:

The adjusted spectra

Return type:

np.ndarray [nxm]

mirage.stars.apparent_magnitude_in_band(lambdas: ndarray, fluxes: ndarray, band: str | ndarray | None = None) → float#

Computes the apparent magnitude of a flux spectrum passed through a band

Parameters:
  • lambdas (np.ndarray) – Wavelengths [nm]

  • fluxes (np.ndarray) – Fluxes [W / m^2 / nm]

  • band (Union[str, np.ndarray, None], optional) – Passband name, or array of fraction of light at each wavelength that is transmitted, defaults to None

Returns:

Apparent magnitude using the Vega zero point

Return type:

Union[np.ndarray, float]

mirage.stars.apparent_star_positions(dates: ndarray[datetime, Any], obs_lat_geod_rad: float, alpha_rad: ndarray, delta_rad: ndarray) → tuple[ndarray, ndarray]#

The apparent positions of stars from an observer’s point of view at a given set of dates

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at [UTC]

  • obs_lat_geod_rad (float) – Geodetic latitude of the observer [rad]

  • alpha_rad (np.ndarray) – Right ascension at the reference epoch [rad]

  • delta_rad (np.ndarray) – Declinations at the reference epoch [rad]

Returns:

Apparent right ascensions and declinations [rad]

Return type:

tuple[np.ndarray, np.ndarray]

mirage.stars.apparent_star_positons(dates: ndarray[datetime, Any], obs_lat_geod_rad: float, alpha_rad: ndarray, delta_rad: ndarray) → tuple[ndarray, ndarray]#

The apparent positions of stars from an observer’s point of view at a given set of dates

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at [UTC]

  • obs_lat_geod_rad (float) – Geodetic latitude of the observer [rad]

  • alpha_rad (np.ndarray) – Right ascension at the reference epoch [rad]

  • delta_rad (np.ndarray) – Declinations at the reference epoch [rad]

Returns:

Apparent right ascensions and declinations [rad]

Return type:

tuple[np.ndarray, np.ndarray]

mirage.stars.irradiance_in_band(lambdas: ndarray, fluxes: ndarray, band: str | ndarray | None = None) → float#

Computes the irradiance of a flux spectrum passed through a band

Parameters:
  • lambdas (np.ndarray) – Wavelengths [nm]

  • fluxes (np.ndarray) – Fluxes [W / m^2 / nm]

  • band (Union[str, np.ndarray, None]) – Passband name, or array of fraction of light at each wavelength that is transmitted. If None, no band will be applied

Returns:

Integrated irradiance [W/m^2]

Return type:

float

mirage.stars.unit_vector_inds_in_fov(telescope, eci_look_dir: ndarray, scope_up: ndarray, uvs: ndarray) → ndarray#

Determines which unit vectors fall inside a telescope’s field of view.

Parameters:
  • telescope (Telescope) – Telescope defining the field of view and pixel scale

  • eci_look_dir (np.ndarray [3,]) – Telescope look direction in ECI

  • scope_up (np.ndarray [3,]) – Telescope up direction in ECI

  • uvs (np.ndarray [n,3]) – Unit vectors to test

Returns:

Mask indicating which vectors are inside the field of view

Return type:

np.ndarray[bool] [n,]

mirage.station module#

class mirage.station.ObservationCache#

Bases: object

Cache of light-curve and constraint results for a station observation.

class mirage.station.Station(**kwargs)#

Bases: object

Ground station with telescope, geometry, constraints, and observation utilities.

az_el_to_eci(az_rad: ndarray, el_rad: ndarray, dates: ndarray[datetime, Any] | datetime, end_frame: str = 'j2000') → ndarray#

Takes local azimuth and elevation angles to an ECI unit vector from the perspective of the station

Parameters:
  • az_rad (np.ndarray) – Azimuth angles, measured in the positive sense from North proceeding East [rad]

  • el_rad (np.ndarray) – Elevation angles, measured from the North East plane proceeding Up

  • dates (Union[np.ndarray[datetime.datetime, Any], datetime.datetime]) – Date(s) to evaluate at (UTC)

  • end_frame (str, optional) – Frame to express the ECI unit vector in, defaults to “j2000”

Returns:

ECI unit vector

Return type:

np.ndarray [n,3] or [3,]

eci_to_az_el(dates: ndarray[datetime, Any], r_eci_hat: ndarray, deg: bool = False) → tuple[ndarray, ndarray]#

Converts an ECI unit vector to local azimuth and elevation angles in radians

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to convert at (UTC)

  • r_eci_hat (np.ndarray) – Positions of target in ECI [km]

  • deg (bool, optional) – Whether to return angles in degrees, defaults to False

Returns:

Azimuth and elevation angles [rad]

Return type:

tuple[np.ndarray, np.ndarray]

eci_to_enu(dates: ndarray[datetime, Any] | datetime) → ndarray#

Rotation matrix(s) from an ECI look direction to topocentric East-North-Up

Parameters:

dates (Union[np.ndarray[datetime.datetime, Any], datetime.datetime]) – Dates to evaluate at (UTC)

Returns:

Stack of rotation matrices

Return type:

np.ndarray [3,3xn] or [3,3]

eval_constraints(evaluate_all: bool = False, **kwargs) → ndarray[bool] | tuple[ndarray[bool], ndarray[bool]]#

Evaluates station observations constraints at a set of times and inertial look directions

Parameters:
  • evaluate_all (bool, optional) – Whether to evaluate constraints in the provided order to output individual satisfaction, defaults to False. Setting to True will reduce performance significantly

  • **kwargs – Observation keyword arguments passed to each constraint evaluator

Returns:

Whether all constraints are met at each time, and whether each constraint is met at each time (if evaluate_all=True)

Return type:

Union[np.ndarray[bool], tuple[np.ndarray[bool], np.ndarray[bool]]]

j2000_at_dates(dates: ndarray[datetime, Any] | datetime, return_velocity: bool = False) → ndarray | Tuple[ndarray, ndarray]#

J2000 position of the station at a given set of dates

Parameters:
  • dates (Union[np.ndarray[datetime.datetime, Any], datetime.datetime]) – Date(s) in UTC

  • return_velocity (bool, optional) – Whether to return J2000 velocity vectors too, defaults to False

Returns:

J2000 positions of the station

Return type:

Union[np.ndarray, Tuple[np.ndarray, np.ndarray]], each ndarray is [n,3] or [3,]

lc_snr(dates: ndarray[datetime, Any], lc: ndarray, z_obs: ndarray, sat_to_station_inertial: ndarray, integration_time_s: float, return_intermediate: bool = False)#

Computes the signal-to-noise ratio for an observed light curve.

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at [UTC]

  • lc (np.ndarray) – Light-curve irradiance values [W/m^2]

  • z_obs (np.ndarray) – Zenith angles of the object [rad]

  • sat_to_station_inertial (np.ndarray [n,3]) – Satellite-to-station vectors in ECI [km]

  • integration_time_s (float) – Integration time [s]

  • return_intermediate (bool, optional) – Whether to return intermediate noise and signal quantities, defaults to False

Returns:

SNR values, or a tuple of intermediate signal, background, and sampler quantities

Return type:

Union[np.ndarray, tuple]

object_line_of_sight(obj: SpaceObject, dates: ndarray[datetime], apparent: bool = True, frame: str = 'j2000') → ndarray#

Computes unit vector lines of sight from the station to a space object

Parameters:
  • obj (SpaceObject) – Space object to observe

  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at (UTC)

  • apparent (bool, optional) – Whether to compute the apparent line of sight (accounting for atmospheric refraction and light travel time), defaults to True

  • frame (str, optional) – Output reference frame, defaults to ‘j2000’

Returns:

Line of sight vectors from the station to the object

Return type:

np.ndarray [n,3]

observe_light_curve(obj: SpaceObject, obj_attitude: RbtfAttitude, brdf: Brdf, dates: ndarray[datetime, Any], integration_time_s: float, model_scale_factor: float = 1.0, use_engine: bool = False, **engine_kwargs) → Tuple[Callable, dict[str, ndarray]]#

Observes a light curve with noise, returning results in ADU

Parameters:
  • obj (SpaceObject) – Space object to simulate, must have the identifier attribute set for SGP4 propagation

  • obj_attitude (RbtfAttitude) – Attitude profile for the space object

  • brdf (Brdf) – Bidirectional Reflectance Distribution Function for the object

  • dates (np.ndarray[datetime.datetime, Any]) – UTC dates to observe at

  • integration_time_s (float) – Integration time per light-curve sample [s]

  • model_scale_factor (float, optional) – Scale factor for the object, on top of its model file scale, defaults to 1.0

  • use_engine (bool, optional) – Whether to use the LightCurveEngine for the simulation, defaults to False

  • **engine_kwargs (dict, optional) – Additional keyword arguments to pass to the LightCurveEngine

Returns:

Anonymous function for sampling light curves [ADU], dictionary of relevant simulation time series

Return type:

Tuple[Callable, dict[str, np.ndarray]]

ra_dec_to_az_el(ras: ndarray, decs: ndarray, dates: ndarray[datetime, Any]) → Tuple[ndarray, ndarray]#

Converts from inertial right ascension (RA) and declination (Dec) to local azimuth and elevation, with azimuth referenced to North and increasing clockwise

Parameters:
  • ras (np.ndarray) – Right ascensions [rad]

  • decs (np.ndarray) – Declinations [rad]

  • dates (np.ndarray[datetime.datetime, Any]) – Dates to evaluate at (UTC)

Returns:

Azimuth [rad] and elevation [rad]

Return type:

Tuple[np.ndarray, np.ndarray]

scintillation_noise_std(theta_z: ndarray, integration_time_s: float, H: float = 8000.0, method: str = 'young', factor_of_safety: float = 1.5) → ndarray#

Computes the standard deviation of atmospheric scintillation noise.

Parameters:
  • theta_z (np.ndarray) – Zenith angles [rad]

  • integration_time_s (float) – Integration time [s]

  • H (float, optional) – Turbulence scale height [m], defaults to 8e3

  • method (str, optional) – Scintillation model, defaults to ‘young’

  • factor_of_safety (float, optional) – Multiplicative safety factor, defaults to 1.5

Returns:

Scintillation noise standard deviation

Return type:

np.ndarray

sky_brightness(dates: ndarray[datetime, Any], look_dir_eci: ndarray, integration_time_s: float, is_ground_based: bool = True, airglow: bool = True, integrated_starlight: bool = True, moonlight: bool = True, zodiac: bool = True, pollution: bool = True, twilight: bool = True) → ndarray#

Computes the mean background signal due to various sources [ADU/pix]

Parameters:
  • dates (np.ndarray[datetime.datetime, Any] [n,]) – Dates to evaluate at (UTC)

  • look_dir_eci (np.ndarray [n,3]) – Look directions in ECI

  • integration_time_s (float) – Integration time [s]

  • is_ground_based (bool, optional) – Whether the observer observing from below the atmosphere, defaults to True

  • airglow (bool, optional) – Whether to include the airglow signal, defaults to True

  • integrated_starlight (bool, optional) – Whether to include the signal due to faint background stars, defaults to True

  • moonlight (bool, optional) – Whether to include Mie and Rayleigh scattered moonlight, defaults to True

  • zodiac (bool, optional) – Whether to include zodiacal light, defaults to True

  • pollution (bool, optional) – Whether to take into account light pollution at the observer location, defaults to True

  • twilight (bool, optional) – Whether to include the background signal due to twilight, defaults to True

Returns:

Background signal mean at each date [ADU/pixel]

Return type:

np.ndarray

class mirage.station.Telescope(preset: Literal['pogs', 'zimlat', 'zimmain', 'izana', 'laf'] = 'pogs')#

Bases: object

Optical telescope model with aperture, field-of-view, and detector properties.

airy_disk_fwhm(lambdas: ndarray) → ndarray#

The full width at half maximum of a Gaussian approximation of an Airy disk at given wavelengths

Parameters:

lambdas (np.ndarray) – Wavelengths [nm]

Returns:

FWHM of the Airy disk at each wavelength [rad]

Return type:

np.ndarray

airy_disk_pattern(total_object_signal: float, theta_rad: ndarray, lambdas: float) → ndarray#

Airy disk pattern for far-field diffraction

Parameters:
  • total_object_signal (float) – Total signal of the object [e-]

  • theta_rad (np.ndarray) – Angles from the center of the Airy disk [rad]

  • lambdas (float) – Wavelengths of incoming light [nm]

Returns:

Intensity of the Airy disk at each angle

Return type:

np.ndarray

body_to_j2000(look_dir_eci: ndarray, up_dir_eci: ndarray) → ndarray#

Builds a rotation matrix from the camera body frame to J2000 ECI.

Parameters:
  • look_dir_eci (np.ndarray [3,]) – Camera look direction in ECI

  • up_dir_eci (np.ndarray [3,]) – Camera up direction in ECI

Returns:

Body-to-J2000 rotation matrix

Return type:

np.ndarray [3,3]

gaussian_diffraction_pattern(total_object_signal: float, theta_rad: ndarray) → ndarray#

Gaussian approximation of an Airy disk pattern for far-field diffraction

Parameters:
  • total_object_signal (float) – Total signal of the object [e-]

  • theta_rad (np.ndarray) – Angles from the center of the Airy disk [rad]

Returns:

Intensity of the Airy disk at each angle

Return type:

np.ndarray

gaussian_diffraction_pattern_grid(total_signal: float, n_pix: float) → ndarray#

Generates a square grid of pixels with the telescope’s Gaussian diffraction pattern

Parameters:
  • total_signal (float) – Total signal to distribute across the grid

  • n_pix (float) – Number of pixels in the grid

Returns:

The diffraction pattern grid

Return type:

np.ndarray

get_airy_disk_amplitude(s_obj: ndarray) → float#

Gets the signal amplitude of an object’s unresolved object signal as a 2D Gaussian

Parameters:

s_obj (np.ndarray) – Total signal of the object on the CCD [e-]

Returns:

Amplitude of the Gaussian [e-]

Return type:

float

get_airy_disk_pixels(lambdas: float = 550) → float#

Approximates the number of pixels contained in an object’s unresolved Airy disk

Parameters:

lambdas (float, optional) – Wavelength [nm], defaults to 550

Returns:

Pixel area covered by the Airy disk [pix]

Return type:

float

j2000_unit_vectors_to_pixels(look_dir_eci: ndarray, up_dir_eci: ndarray, uvs: ndarray, add_distortion: bool = False) → tuple[ndarray, ndarray]#

Converts a set of unit vectors in J2000 ECI coordinates to image plane pixel coordinates

Parameters:
  • look_dir_eci (np.ndarray [1x3]) – Look directions in ECI

  • up_dir_eci (np.ndarray [1x3]) – Up direction of the camera frame in ECI

  • uvs (np.ndarray) – Unit vectors in ECI

  • add_distortion (bool, optional) – Whether to apply pixel distortion, defaults to False

Returns:

Pixel coordinates in the x and y directions, on [0, sensor_pixels] in both axes with [sensor_pixels//2, sensor_pixels//2] at the center of the image

Return type:

tuple[np.ndarray, np.ndarray]

pixel_distortion(pix_x: ndarray, pix_y: ndarray, center_x: float, center_y: float, undo: bool = True) → Tuple[ndarray, ndarray]#

Applies or undoes pixel distortion for a given center.

Parameters:
  • pix_x (np.ndarray) – X pixel locations [pix], referenced to (0, 0) in the top-left corner

  • pix_y (np.ndarray) – Y pixel locations [pix], referenced to (0, 0) in the top-left corner

  • center_x (float) – X location of the center of the optical axis [pix], referenced to (0, 0) in the top-left corner

  • center_y (float) – Y location of the center of the optical axis [pix], referenced to (0, 0) in the top-left corner

  • undo (bool, optional) – Whether to undo or simply apply the distortion effect, defaults to True (undoing distortion)

Returns:

Apparent pixel locations in the x and y directions

Return type:

Tuple[np.ndarray, np.ndarray]

pixels_to_j2000_unit_vectors(look_dir_eci: ndarray, up_dir_eci: ndarray, xy: ndarray, input_is_distorted: bool = False) → ndarray#

Converts a set of pixel coordinates to unit vectors in J2000 ECI coordinates

Parameters:
  • look_dir_eci (np.ndarray [1x3]) – Look directions in ECI

  • up_dir_eci (np.ndarray [1x3]) – Up direction of the camera frame in ECI

  • xy (np.ndarray [nx2]) – Pixel coordinates in the x and y directions, on [0, sensor_pixels] in both axes with [sensor_pixels//2, sensor_pixels//2] at the center of the image

  • input_is_distorted (bool, optional) – Whether the input pixel coordinates are distorted, defaults to False

Returns:

Unit vectors in ECI

Return type:

np.ndarray [n,3]

tracked_pixels_from_rates(ra_rate_arcsec_s: float, dec_rate_arcsec_s: float, dec_look_rad: float, integration_time_s: float) → float#

The number of pixels tracked over the integration time

Parameters:
  • ra_rate_arcsec_s (float) – Right ascension tracking rate in arcseconds per second

  • dec_rate_arcsec_s (float) – Declination tracking rate in arcseconds per second

  • dec_look_rad (float) – The declination of the object being observed in radians

  • integration_time_s (float) – Integration time in seconds

Returns:

The number of pixels tracked over the integration time

Return type:

float

unit_airy_disk_volume(wavelength: float) → float#

Computes the volume of the Airy disk at a specific wavelength

Parameters:

wavelength (float) – Wavelength [nm]

Returns:

Volume of airy disk

Return type:

float

up_direction_eci(look_dirs_eci: ndarray) → ndarray#

The up direction in ECI for a set of look directions (the direction normal to the image plane, pointing “up” in the image)

Parameters:

look_dirs_eci (np.ndarray) – Look directions in ECI

Returns:

Direction of the “Up” side of the image in ECI

Return type:

np.ndarray [n,3]

mirage.station.geocentric_lat_to_geodetic(lat_geoc: ndarray) → ndarray#

Converts geocentric latitude to geodetic latitude

Parameters:

lat_geoc (np.ndarray) – Geocentric latitudes [rad]

Returns:

Geodetic latitudes [rad]

Return type:

np.ndarray

mirage.station.geodetic_lat_to_geocentric(lat_geod: ndarray) → ndarray#

Converts geodetic latitude to geocentric latitude

Parameters:

lat_geod (np.ndarray) – Geodetic latitudes [rad]

Returns:

Geocentric latitudes [rad]

Return type:

np.ndarray

mirage.station.lat_lon_cell_area(lat_lims_rad: tuple[float], lon_lims_rad: tuple[float], radius: float = 6378137.0) → float#

Area of a rectangular latitude longitude cell with ascending limits from this article

Parameters:
  • lat_lims_rad (tuple[float]) – Ascending latitude limits [rad]

  • lon_lims_rad (tuple[float]) – Ascending longitude limits [rad]

  • radius (float, optional) – The radius of the sphere, defaults to the Earth radius in [m]

Returns:

Area of the cell [m^2] when using the default radius

Return type:

float

mirage.station.probability_of_detection(fwhm_arcsec: float, pixel_scale: float, lambda_obj: ndarray, sigma_noise: ndarray, thresh_noise_sigma: float) → ndarray#

Computes the probability that an unresolved object is detected above a noise threshold.

Parameters:
  • fwhm_arcsec (float) – Seeing full width at half maximum [arcsec]

  • pixel_scale (float) – Detector pixel scale [arcsec/pix]

  • lambda_obj (np.ndarray) – Expected object counts per sample

  • sigma_noise (np.ndarray) – Noise standard deviation per pixel

  • thresh_noise_sigma (float) – Detection threshold in noise standard deviations

Returns:

Detection probability for each object count rate

Return type:

np.ndarray

mirage.station.radius_at_geodetic_lat(lat_geod: ndarray) → ndarray#

Earth’s ellipsoidal radius at the given geodetic latitude, referenced to WGS84.

Parameters:

lat_geod (np.ndarray) – Geodetic latitudes [rad]

Returns:

Earth’s ellipsoidal radius at the given geodetic latitudes [km]

Return type:

np.ndarray

mirage.station.signal_spread(width: int, fwhm: float)#

Computes a normalized Gaussian signal-spread grid for a given image width and FWHM.

Parameters:
  • width (int) – Image width and height in pixels

  • fwhm (float) – Full width at half maximum [arcsec]

Returns:

Normalized signal-spread grid

Return type:

np.ndarray [width,width]

mirage.time module#

mirage.time.beginning_of_day(dates: ndarray[datetime, Any]) → ndarray[datetime, Any]#

Finds the beginning of the day for given datetime array

Parameters:

dates (np.ndarray[datetime.datetime, Any] [n,]) – Date array (UTC)

Returns:

Beginning of day for each date (UTC)

Return type:

np.ndarray[datetime.datetime, Any] [n,]

mirage.time.date_arange(date_start: datetime, date_stop: datetime, date_step: timedelta, return_epsecs: bool = False) → Tuple[ndarray[datetime, Any], ndarray[float64]]#

Computes a range of datetime objects spaced by the same step

Parameters:
  • date_start (datetime.datetime) – Date to start at (UTC)

  • date_stop (datetime.datetime) – Date to stop at (UTC)

  • date_step (datetime.timedelta) – Step between elements, ex. date_step=datetime.timedelta(hours=3) or mr.seconds(2)

  • return_epsecs (bool, optional) – Whether to also return the EpochSecond space, defaults to False

Returns:

Sampled space of datetimes (UTC) and possibly also space of epoch seconds

Return type:

Tuple[np.ndarray[datetime.datetime, Any], np.ndarray[np.float64]]

mirage.time.date_linspace(date_start: datetime, date_stop: datetime, num: int, return_epsecs: bool = False) → Tuple[ndarray[datetime, Any], ndarray[float64]]#

Computes a linspace of datetime objects

Parameters:
  • date_start (datetime.datetime) – Date to start at (UTC)

  • date_stop (datetime.datetime) – Date to stop at (UTC)

  • num (int) – Number of samples to make

  • return_epsecs (bool, optional) – Whether to also return the EpochSecond space, defaults to False

Returns:

Sampled linspace of datetimes (UTC) and possibly a linspace of epoch seconds

Return type:

Tuple[np.ndarray[datetime.datetime, Any], np.ndarray[np.float64]]

mirage.time.date_to_epsec(dates: ndarray[datetime, Any]) → ndarray#

Converts date objects to an array of seconds after the initial date epoch (the first element of the dates array)

Parameters:

dates (np.ndarray[datetime.datetime, Any]) – Dates (UTC)

Returns:

Epoch seconds

Return type:

np.ndarray

mirage.time.date_to_gmst(dates: ndarray[datetime, Any] | datetime, use_astropy: bool = False, scale: str = 'ut1') → ndarray#

Computes Greenwich Mean Sidereal Time (GMST)

Parameters:
  • dates (Union[np.ndarray[datetime.datetime, Any], datetime.datetime]) – Dates [UTC]

  • use_astropy (bool, optional) – Whether to use astropy for the backend calculations, defaults to False

  • scale (str, optional) – Time scale to use from [‘utc’, ‘ut1’, ‘tai’, ‘tt’], defaults to ‘ut1’

Returns:

GMST in radians

Return type:

np.ndarray

mirage.time.date_to_jd(dates: ndarray[datetime, Any], use_astropy: bool = True, scale: str = 'utc') → ndarray#

Converts datetime to Julian date

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Date objects to compute the Julian date (UTC)

  • use_astropy (bool, optional) – Whether to use astropy for the backend calculation, defaults to True

  • scale (str, optional) – Time scale to use from [‘utc’, ‘ut1’, ‘tai’, ‘tt’], defaults to ‘utc’

Returns:

Julian date of input dates

Return type:

np.ndarray


mirage.time.date_to_julian_centuries(dates: datetime | ndarray[datetime, Any], scale: str = 'tt') → ndarray | float#

Julian centuries past the J2000 epoch as used in [Fru]

Parameters:
  • dates (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date to evaluate at [UTC]

  • scale (str, optional) – Time scale to use from [‘utc’, ‘ut1’, ‘tai’, ‘tt’], defaults to ‘tt’

Returns:

Julian centuries [100 yr]

Return type:

Union[np.ndarray, float]

mirage.time.date_to_sidereal(dates: ndarray[datetime, Any], use_astropy: bool = False, scale: str = 'ut1') → ndarray#

Converts an array of dates to Greenwich mean sidereal time (GMST)

Parameters:
  • dates (np.ndarray[datetime.datetime, Any]) – Date objects (UTC)

  • use_astropy (bool, optional) – Whether to use astropy for the backend calculations, defaults to False

  • scale (str, optional) – Time scale to use from [‘utc’, ‘ut1’, ‘tai’, ‘tt’], defaults to ‘ut1’

Returns:

Sidereal times [seconds]

Return type:

np.ndarray


mirage.time.date_to_ut(date: ndarray[datetime, Any] | datetime) → ndarray | float#

Converts a datetime object to Universal Time (UT)

Parameters:

date (Union[np.ndarray[datetime.datetime, Any], datetime.datetime]) – Date(s) (UTC)

Returns:

UT(s) [hr]

Return type:

Union[np.ndarray, float]

mirage.time.days(num: float | ndarray) → timedelta | ndarray[timedelta]#

Returns an array of datetime.timedelta in days

Parameters:

num (Union[float, np.ndarray]) – Number(s) of days

Raises:

NotImplementedError – If num is not a float or np.ndarray

Returns:

Single datetime.timedelta or array of datetime.timedelta

Return type:

Union[datetime.timedelta, np.ndarray[datetime.timedelta]]

mirage.time.hours(num: float | ndarray) → timedelta | ndarray[timedelta]#

Returns an array of datetime.timedelta in hours

Parameters:

num (Union[float, np.ndarray]) – Number(s) of hours

Raises:

NotImplementedError – If num is not a float or np.ndarray

Returns:

Single datetime.timedelta or array of datetime.timedelta

Return type:

Union[datetime.timedelta, np.ndarray[datetime.timedelta]]

mirage.time.jd_to_date(jds: ndarray, scale: str = 'utc') → ndarray[datetime, Any]#

Converts Julian dates to an array of datetime objects

Parameters:
  • jds (np.ndarray) – Julian dates

  • scale (str, optional) – Time scale to reference to, either “utc”, “ut1”, “tt”, or “tai”, defaults to “utc”

Returns:

Dates (UTC)

Return type:

np.ndarray[datetime.datetime, Any]

mirage.time.jd_to_epsec(jds: ndarray[float]) → ndarray[float]#

Converts Julian dates to an array of seconds after the initial JD epoch (the first element of the jds array)

Parameters:

jds (np.ndarray[float]) – Julian date (UTC)

Returns:

Epoch seconds

Return type:

np.ndarray

mirage.time.jd_to_mjd(jds: ndarray[float]) → ndarray#

Converts Julian dates to modified Julian dates

Parameters:

jds (np.ndarray[float]) – Julian dates

Returns:

Modified Julian dates

Return type:

np.ndarray

mirage.time.minutes(num: float | ndarray) → timedelta | ndarray[timedelta]#

Returns an array of datetime.timedelta in minutes

Parameters:

num (Union[float, np.ndarray]) – Number(s) of minutes

Raises:

NotImplementedError – If num is not a float or np.ndarray

Returns:

Single datetime.timedelta or array of datetime.timedelta

Return type:

Union[datetime.timedelta, np.ndarray[datetime.timedelta]]

mirage.time.mjd_to_jd(jds: ndarray[float]) → ndarray#

Converts modified Julian dates to Julian dates

Parameters:

jds (np.ndarray[float]) – Modified Julian dates

Returns:

Julian dates

Return type:

np.ndarray

mirage.time.now() → datetime#

Current datetime.datetime object

Returns:

Current UTC date object at runtime

Return type:

datetime.datetime

mirage.time.seconds(num: float | ndarray) → timedelta | ndarray[timedelta]#

Returns an array of datetime.timedelta in seconds

Parameters:

num (Union[float, np.ndarray]) – Number(s) of seconds

Raises:

NotImplementedError – If num is not a float or np.ndarray

Returns:

Single datetime.timedelta or array of datetime.timedelta

Return type:

Union[datetime.timedelta, np.ndarray[datetime.timedelta]]

mirage.time.sidereal_hour_angle(obs_lon_rad: float, date: datetime | ndarray[datetime, Any]) → float | ndarray#

Computes the GMST hour angle (the angle of the given longitude with respect to inertial \(\hat{x}\)) for a single observer over a range of dates

Parameters:
  • obs_lon_rad (float) – Longitude of the observer [rad]

  • date (Union[datetime.datetime, np.ndarray[datetime.datetime, Any]]) – Date(s) to evaluate at [UTC]

Returns:

Hour angle [rad]

Return type:

Union[float, np.ndarray]

mirage.time.tai_minus_utc(dates: ndarray[datetime, Any]) → ndarray#

Uses Astropy to calculate the offset between TAI and UTC, accounting for leap seconds

Parameters:

dates (np.ndarray[datetime.datetime, Any]) – Dates [UTC]

Returns:

Seconds to add to UTC time to get TAI

Return type:

np.ndarray

mirage.time.today() → datetime#

Beginning of today (UTC) datetime

Returns:

The UTC datetime at the beginning of today

Return type:

datetime.datetime

mirage.time.tt_minus_utc(dates: ndarray[datetime, Any]) → ndarray#

Uses Astropy to calculate the offset between TT and UTC, accounting for leap seconds

Parameters:

dates (np.ndarray[datetime.datetime, Any]) – Dates [UTC]

Returns:

Seconds to add to UTC time to get TT

Return type:

np.ndarray

mirage.time.ut1_minus_utc(dates: ndarray[datetime, Any]) → ndarray#

Uses Astropy to calculate the offset between UT1 and UTC, always less than 1 second by convention

Parameters:

dates (np.ndarray[datetime.datetime, Any]) – Dates [UTC]

Returns:

Seconds to add to UTC time to get UT1

Return type:

np.ndarray

mirage.time.utc(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0, microsecond: int = 0) → datetime#

Returns a UTC datetime

Parameters:
  • year (int) – Year

  • month (int) – Month

  • day (int) – Day

  • hour (int, optional) – Hour, defaults to 0

  • minute (int, optional) – Minute, defaults to 0

  • second (int, optional) – Second, defaults to 0

  • microsecond (int, optional) – Microsecond, defaults to 0

Returns:

UTC datetime.datetime

Return type:

datetime.datetime

mirage.time.years(num: float | ndarray) → timedelta | ndarray[timedelta]#

Returns an array of datetime.timedelta in years

Parameters:

num (Union[float, np.ndarray]) – Number(s) of years

Raises:

NotImplementedError – If num is not a float or np.ndarray

Returns:

Single datetime.timedelta or array of datetime.timedelta

Return type:

Union[datetime.timedelta, np.ndarray[datetime.timedelta]]

mirage.tle module#

class mirage.tle.SatDef(name: str, satnum: int, ides: str, launch_date: datetime, decay_date: datetime, inc_deg: float, period_min: float, apogee_km: int, perigee_km: int, object_type: str, rcs_size: str, country: str)#

Bases: object

Satellite catalog definition containing identification and orbital summary data.

class mirage.tle.SatDefArray(iter: Iterable[SatDef] | None = None)#

Bases: object

Collection of satellite catalog definitions with name/ID lookup helpers.

all_ides() → list[str]#

Returns the international designator of every satellite in the collection.

all_names() → list[str]#

Returns the lower-case name of every satellite in the collection.

all_satnums() → list[int]#

Returns the NORAD number of every satellite in the collection.

append(newsat: SatDef)#

Appends a satellite definition to the collection.

Parameters:

newsat (SatDef) – Satellite definition to append

get_ides_by_name(name: str) → int | None#

Returns an international designator from a satellite name.

Parameters:

name (str) – Satellite name

Returns:

International designator, or None if not found

Return type:

Union[int, None]

get_sat_by_ides(ides: str) → SatDef#

Finds a satellite by international designator.

Parameters:

ides (str) – International designator, with or without a dash

Returns:

Matching satellite definition

Return type:

SatDef

Raises:

ValueError – If no close match is found

get_sat_by_name(name: str) → SatDef#

Finds a satellite by name, ignoring spaces, parentheses, and case.

Parameters:

name (str) – Satellite name

Returns:

Matching satellite definition

Return type:

SatDef

Raises:

ValueError – If no close match is found

get_sat_by_norad(norad_id: int) → SatDef#

Finds a satellite by NORAD number.

Parameters:

norad_id (int) – NORAD satellite number

Returns:

Matching satellite definition, or a placeholder for IDs above 80000

Return type:

SatDef

Raises:

ValueError – If the number is not present in the catalog

get_satnum_by_ides(ides: str) → int | None#

Returns a NORAD number from an international designator.

Parameters:

ides (str) – International designator

Returns:

NORAD satellite number, or None if not found

Return type:

Union[int, None]

get_satnum_by_name(name: str) → int | None#

Returns a NORAD number from a satellite name.

Parameters:

name (str) – Satellite name

Returns:

NORAD satellite number, or None if not found

Return type:

Union[int, None]

mirage.tle.build_satdef_array() → SatDefArray#

Downloads and builds the satellite-definition collection from Space-Track.

mirage.tle.get_latest_catalog_at_date(dtime: datetime = datetime.datetime(2026, 11, 9, 19, 40, 39, 854578, tzinfo=datetime.timezone.utc), days_back: timedelta = datetime.timedelta(days=1), mode: str = 'gp', **query_kwargs) → list[list[str, str]]#

Gets the first TLE produced for a given NORAD SAT ID after the datetime provided

Parameters:
  • dtime (datetime.datetime, optional) – Datetime to query at, assumed to be UTC, defaults to now

  • days_back (datetime.timedelta, optional) – Number of previous days to collect TLEs for, defaults to 1 day

  • mode (str, optional) – Mode to use for querying, defaults to “gp”

  • query_kwargs (dict) – Extra keyword arguments passed to st.gp

Return type:

list[list[str, str]]

mirage.tle.get_tles_between(dtimes: ndarray[datetime, Any], satnum: int | None = None, method: str = 'tle') → list[tuple[str, str]]#

Gets all TLEs published in the range of datetimes passed

Parameters:
  • dtimes (np.ndarray[datetime]) – Datetimes, assumed to be UTC, in chronologically ascending order

  • satnum (int, optional) – Satellite number, ex. 25544 for ISS ZARYA, defaults to None

  • method (str, optional) – TLE source method, either ‘tle’ or ‘tl3’, defaults to ‘tle’

Raises:

ValueError – If the object decays during the timespan

Returns:

List of TLE lines 1 and 2

Return type:

list[tuple[str, str]]

mirage.tle.load_satdef_array() → SatDefArray#

Loads the cached satellite-definition collection, building it if necessary.

mirage.tle.make_sync_st_request(query, endpoint: str = 'gp_history')#

Makes a synchronous request to a Space-Track endpoint.

Parameters:
  • query (dict) – Keyword arguments passed to the Space-Track endpoint

  • endpoint (str, optional) – Space-Track client endpoint name, defaults to ‘gp_history’

Returns:

Raw endpoint response

Return type:

Any

mirage.tle.purge_tle_cache()#

Interactively removes cached TLE and satellite-definition files.

mirage.tle.satdef_from_identifier(identifier: str | int) → SatDef#

Resolves a satellite identifier into a catalog definition.

Parameters:

identifier (Union[str, int]) – NORAD number, satellite name, or international designator

Returns:

Matching satellite definition

Return type:

SatDef

mirage.tle.satname_from_identifier(identifier: str | int) → None | str#

Returns a satellite name from a NORAD number, name, or international designator.

Parameters:

identifier (Union[str, int]) – NORAD number, satellite name, or international designator

Returns:

Satellite name

Return type:

Union[None, str]

mirage.tle.satnum_from_identifier(identifier: str | int) → None | int#

Returns a NORAD number from a satellite name or international designator.

Parameters:

identifier (Union[str, int]) – Satellite name or international designator

Returns:

NORAD satellite number

Return type:

Union[None, int]

mirage.tle.save_satdef_array(satdefs: SatDefArray)#

Serializes a satellite-definition collection to the TLE cache directory.

Parameters:

satdefs (SatDefArray) – Satellite-definition collection to save

Module contents#