"""
Coarse Sun Sensor Array model.
"""
import numpy as np
from typing import Any
from opengnc.sensors.sensor import Sensor
[docs]
class CoarseSunSensorArray(Sensor):
r"""
Array of Coarse Sun Sensors (CSS).
Each CSS measures the cosine of the angle between the sun vector and its boresight.
$I = I_{max} \cos(\theta) = I_{max} (S \cdot N)$
Parameters
----------
boresights : list[np.ndarray], optional
Unit vectors representing the boresight direction of each CSS in the body frame.
Default is 6 faces of a cube.
i_max : float, optional
Maximum current/output when sun is aligned with boresight. Default is 1.0.
noise_std : float, optional
Standard deviation of measurement noise. Default is 0.01.
name : str, optional
Sensor name. Default is "CSSArray".
"""
def __init__(
self,
boresights: list[np.ndarray] | None = None,
i_max: float = 1.0,
noise_std: float = 0.01,
name: str = "CSSArray",
) -> None:
super().__init__(name)
if boresights is None:
# Default to 6 faces of a cube
boresights_list = [
np.array([1.0, 0.0, 0.0]),
np.array([-1.0, 0.0, 0.0]),
np.array([0.0, 1.0, 0.0]),
np.array([0.0, -1.0, 0.0]),
np.array([0.0, 0.0, 1.0]),
np.array([0.0, 0.0, -1.0]),
]
else:
boresights_list = boresights
self.boresights = [b / np.linalg.norm(b) for b in boresights_list]
self.i_max = i_max
self.noise_std = noise_std
[docs]
def measure(
self, true_sun_vec: np.ndarray | None = None, *args: Any, **kwargs: Any
) -> np.ndarray:
"""
Generate measurements from each CSS in the array.
Parameters
----------
true_sun_vec : np.ndarray
True sun unit vector in body frame.
**kwargs : dict
Additional parameters.
Returns
-------
np.ndarray
Array of measurements (typically current or voltage) from each CSS.
"""
if true_sun_vec is None:
if not args:
raise ValueError("true_sun_vec is required.")
true_sun_vec = np.asarray(args[0])
s = true_sun_vec / np.linalg.norm(true_sun_vec)
measurements = []
for n in self.boresights:
cos_theta = float(np.dot(s, n))
# CSS only works if sun is in front of the sensor
i_meas = self.i_max * max(0.0, cos_theta)
i_meas += np.random.normal(0, self.noise_std)
measurements.append(float(max(0.0, i_meas)))
return np.array(measurements)