ADCS.satellite_hardware.sensors.earth_horizon module

class ADCS.satellite_hardware.sensors.earth_horizon.EarthHorizonSensor(sample_time=0.1, bias=None, noise=None, estimate_bias=False, boresight=array([0., 0., -1.]), fov=np.float64(1.5707963267948966))[source]

Bases: Sensor

Earth horizon crossing sensor model.

This class implements a scanning horizon sensor that determines the spacecraft nadir direction by detecting transitions across the Earth’s limb. The sensor output is a unit vector pointing toward the Earth center expressed in the spacecraft body frame.

Physical principle

A horizon scanner sweeps a narrow beam across the Earth disk and records the angles at which infrared radiance transitions occur (bright Earth to cold space or vice versa). From the geometry of these limb crossings, the nadir direction is reconstructed.

In this simplified model, the reconstructed nadir direction is assumed to be the true nadir direction plus additive bias and noise, consistent with the generic sensor pipeline defined by Sensor.

Measurement model

Let

Symbol

Description

\(\mathbf{q}\)

Attitude quaternion (body -> inertial)

\(\mathbf{R}_{\mathrm{sat}}\)

Spacecraft position in ECI [km]

\(\mathbf{C}(\mathbf{q})\)

Rotation matrix (body -> inertial)

\(R_\oplus\)

Mean Earth radius (6378.137 km)

The nadir direction in the ECI frame is

\[\hat{\mathbf{n}}_{\mathrm{ECI}} = -\frac{\mathbf{R}_{\mathrm{sat}}} {\|\mathbf{R}_{\mathrm{sat}}\|}\]

and the clean measurement is the nadir direction in the body frame:

\[\mathbf{y}_{\text{clean}} = \mathbf{C}(\mathbf{q})^\top\,\hat{\mathbf{n}}_{\mathrm{ECI}}\]

The Earth subtends an angular radius

\[\rho = \arcsin\!\left(\frac{R_\oplus}{\|\mathbf{R}_{\mathrm{sat}}\|}\right)\]

which determines the measurement accuracy achievable by a real horizon scanner.

Visibility constraint

The sensor returns a valid measurement only when the nadir direction falls within the sensor field of view:

\[\arccos\!\bigl(\hat{\mathbf{b}} \cdot \mathbf{y}_{\text{clean}}\bigr) < \theta_{\mathrm{FOV}}\]

where \(\hat{\mathbf{b}}\) is the sensor boresight in the body frame and \(\theta_{\mathrm{FOV}}\) is the half-cone field of view. If this condition is not met, the sensor output is NaN.

After adding bias and noise, the output is renormalized to enforce the unit-vector constraint.

Estimator properties

  • Output dimension: 3

  • Depends on attitude quaternion (for frame rotation)

  • Uses orbital position for nadir direction (treated as known)

  • Jacobian is nonzero only w.r.t. quaternion states

  • No coupling to angular velocity or momentum states

See also

Sensor, StarTracker

basestate_jac(x, os)[source]

Jacobian of the nadir measurement w.r.t. the base state.

The measurement depends only on the attitude quaternion (the orbital position is treated as known). Therefore:

\[\frac{\partial \mathbf{y}}{\partial \boldsymbol{\omega}} = \mathbf{0}, \qquad \frac{\partial \mathbf{y}}{\partial \mathbf{q}} = D_{\mathbf{q}} \left( \mathbf{C}(\mathbf{q})^\top\,\hat{\mathbf{n}}_{\mathrm{ECI}} \right)\]

The quaternion derivative is computed using drotmatTvecdq().

Parameters:
  • x (numpy.ndarray) – Full spacecraft state vector.

  • os (Orbital_State) – Orbital state.

Returns:

Base-state Jacobian of shape (7, 3).

Return type:

numpy.ndarray

bias_jac(x, os)[source]

Jacobian of the measurement w.r.t. bias states.

If estimate_bias is True, the bias Jacobian is the identity. Otherwise, an empty Jacobian is returned.

Parameters:
  • x (numpy.ndarray) – Full spacecraft state vector (unused).

  • os (Orbital_State) – Orbital state (unused).

Returns:

Bias Jacobian.

Return type:

numpy.ndarray

clean_reading(x, os)[source]

Compute the noise-free nadir direction measurement.

The nadir direction is computed from the orbital position and rotated into the body frame using the attitude quaternion:

\[\mathbf{y}_{\text{clean}} = \mathbf{C}(\mathbf{q})^\top \left(-\frac{\mathbf{R}_{\mathrm{sat}}}{\|\mathbf{R}_{\mathrm{sat}}\|}\right)\]

A visibility check ensures the nadir direction falls within the sensor field of view.

Parameters:
  • x (numpy.ndarray) – Full spacecraft state vector.

  • os (Orbital_State) – Orbital state providing spacecraft position.

Returns:

Nadir unit vector in body frame, or NaN if Earth is outside the sensor FOV.

Return type:

numpy.ndarray

reading(x, os, dmode=None)[source]

Compute the full nadir measurement including bias and noise.

After the base class applies bias and noise, the output is renormalized to enforce the unit-vector constraint.

Parameters:
  • x (numpy.ndarray) – Full spacecraft state vector.

  • os (Orbital_State) – Orbital state.

  • dmode (ErrorMode or None) – Error mode controlling bias and noise.

Returns:

Normalized nadir direction in body frame.

Return type:

numpy.ndarray

property earth_angular_radius: float | None

Earth angular radius from the last measurement [rad].

Computed as \(\rho = \arcsin(R_\oplus / \|\mathbf{r}\|)\). Returns None if no measurement has been taken.

Return type:

float or None

output_length: int = 3
Parameters:
  • sample_time (float)

  • bias (Bias)

  • noise (Noise)

  • estimate_bias (bool)

  • boresight (ndarray)

  • fov (float)