Source code for ADCS.satellite_factory.sensors.create_cubesat_MTM

__all__ = [
    'create_gnb_magnetometer',
    'create_isis_magnetometer',
    'create_adis16405_magnetometers',
    'create_bmx055_magnetometers',
    'create_honeywell_lightsail2_magnetometers',
    'create_hmc5883l_magnetometers',
    'create_micromag3_magnetometers',
]

import numpy as np
from typing import Optional, List

from ADCS.satellite_hardware.sensors import MTM 
from ADCS.satellite_hardware.errors import Noise, Bias
from ADCS.helpers.math_helpers import random_n_unit_vec

[docs] def create_isis_magnetometer(axes: np.ndarray = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), bias: Bias | None = None, noise: Noise | None = None, estimate_bias: bool = False) -> List[MTM]: r""" Create an ISIS magnetometer triad. Default error model provenance: The hardware identity is linked to the ISIS magnetorquer-board product listing below, but the default bias/noise values in this helper are package-level representative simulation values rather than traceable vendor or flight-calibration values. Pass explicit ``bias`` and ``noise`` objects when a source-backed model is required. Source for hardware identity: https://satsearch.co/products/isis-isis-magnetorquer-board-i-mtq """ if bias is None: e_bias = random_n_unit_vec(3)*np.random.uniform(1e-9,1e-7) std_bias = 1e-9*np.ones(3) bias = [Bias(bias=e_bias[j], std_bias=std_bias[j]) for j in range(3)] if noise is None: e_noise = np.zeros(3) std_noise = 3*1e-7*np.ones(3) noise = [Noise(noise=e_noise[j], std_noise=std_noise[j]) for j in range(3)] return [MTM(axis=axes[j], bias=bias[j], noise=noise[j], estimate_bias=estimate_bias) for j in range(3)]
[docs] def create_gnb_magnetometer( axes: np.ndarray = np.eye(3), bias: List[Bias] | None = None, noise: List[Noise] | None = None, estimate_bias: bool = False, ) -> List[MTM]: r""" Create the nominal BRITE/GNB three-axis magnetometer. The BRITE ADCS design gives magnetometer noise ``2.0e-7 T`` and worst-case bias ``4.0e-6 T``. The factory represents the latter as a bounded per-axis bias uncertainty because no fixed flight bias vector was found. The ``1.0e-9 T/sqrt(s)`` bias random walk is a conservative modeling assumption, not a source-backed BRITE/GNB calibration value. """ n_axes = len(axes) if bias is None: bias_bound = 4.0e-6 std_bias = 1.0e-9 bias = [Bias(bias=0.0, std_bias=std_bias, bounds=(-bias_bound, bias_bound)) for _ in range(n_axes)] if noise is None: noise = [Noise(noise=0.0, std_noise=2.0e-7) for _ in range(n_axes)] return [MTM(axis=axes[j], bias=bias[j], noise=noise[j], estimate_bias=estimate_bias) for j in range(n_axes)]
[docs] def create_honeywell_lightsail2_magnetometers( axes: np.ndarray | None = None, bias: List[Bias] | None = None, noise: List[Noise] | None = None, estimate_bias: bool = False, ) -> List[MTM]: r""" Create the two LightSail 2 three-axis Honeywell magnetometers. LightSail 2 had one 3-axis unit on the +X solar panel and one on the +Y solar panel. Exact sensor-to-body rotation matrices are not encoded here, so each unit is represented as an orthogonal triad in body axes. The published 1-sigma noise is ``0.2 uT``; no fixed bias is assigned. """ if axes is None: axes = np.vstack((np.eye(3), np.eye(3))) n_axes = len(axes) if bias is None: bias = [Bias() for _ in range(n_axes)] if noise is None: noise = [Noise(noise=0.0, std_noise=0.2e-6) for _ in range(n_axes)] return [MTM(axis=axes[j], bias=bias[j], noise=noise[j], estimate_bias=estimate_bias) for j in range(n_axes)]
[docs] def create_adis16405_magnetometers( axes: np.ndarray = np.eye(3), bias: List[Bias] | None = None, noise: List[Noise] | None = None, estimate_bias: bool = False, ) -> List[MTM]: r""" Create the ADIS16405 integrated magnetometer channels used on RAX. Default error model provenance: ``bias`` defaults to a Gaussian initial bias with 400 nT one-sigma component error. ``noise`` defaults to 125 nT output-noise RMS. These are ADIS16405 component characterization values reported for the RAX attitude-determination system, not a published fixed RAX flight bias vector. Source: J. C. Springmann, *Satellite Attitude Determination with Low-Cost Sensors*, Ph.D. dissertation, University of Michigan, 2013. https://deepblue.lib.umich.edu/bitstream/handle/2027.42/102312/jspringm_1.pdf?sequence=1 """ n_axes = len(axes) if bias is None: bias_std = 400e-9 e_bias = np.random.normal(0.0, bias_std, size=n_axes) bias = [Bias(bias=e_bias[j], std_bias=0.0) for j in range(n_axes)] if noise is None: std_noise = 125e-9 noise = [Noise(noise=0.0, std_noise=std_noise) for _ in range(n_axes)] return [MTM(axis=axes[j], bias=bias[j], noise=noise[j], estimate_bias=estimate_bias) for j in range(n_axes)]
[docs] def create_micromag3_magnetometers( axes: np.ndarray = np.eye(3), bias: List[Bias] | None = None, noise: List[Noise] | None = None, estimate_bias: bool = False, ) -> List[MTM]: r""" Create the PNI Sensor Corporation MicroMag3 magnetometer channels used on RAX. Default error model provenance: ``noise`` defaults to the 100 nT Gaussian magnetometer noise used in the RAX sensor-error simulations. The default constant ``bias`` is zero because the RAX flight calibration treated the embedded MicroMag3 error as scale-factor, nonorthogonality, constant-bias, and spacecraft-current-dependent terms, not as a single published fixed mission bias vector. Source: J. C. Springmann, *Satellite Attitude Determination with Low-Cost Sensors*, Ph.D. dissertation, University of Michigan, 2013. https://deepblue.lib.umich.edu/bitstream/handle/2027.42/102312/jspringm_1.pdf?sequence=1 """ n_axes = len(axes) if bias is None: bias = [Bias() for _ in range(n_axes)] if noise is None: std_noise = 100e-9 noise = [Noise(noise=0.0, std_noise=std_noise) for _ in range(n_axes)] return [MTM(axis=axes[j], bias=bias[j], noise=noise[j], estimate_bias=estimate_bias) for j in range(n_axes)]
[docs] def create_bmx055_magnetometers( axes: np.ndarray = np.eye(3), bias: List[Bias] | None = None, noise: List[Noise] | None = None, estimate_bias: bool = False, ) -> List[MTM]: r""" Create one Bosch Sensortec BMX055 magnetometer triad used on MOVE-II. The BMX055 magnetometer is represented as three one-dimensional :class:`~ADCS.satellite_hardware.sensors.MTM` channels. Default error model provenance: ``bias`` defaults to the MOVE-II HIL simulation vector ``[2.0e-6, -3.0e-6, 3.0e-6] T`` for one BMX055 triad. ``noise`` defaults to additive Gaussian white noise with ``sigma = 5.0e-7 T``. The source also models scale factor, misalignment, nonorthogonality, quantization, time sampling, and low-pass filtering; those terms are not represented directly here. Source: `Hardware-in-the-Loop Verification of the Distributed, Magnetorquer-Based ADCS of the CubeSat MOVE-II <https://mediatum.ub.tum.de/doc/1483411/document.pdf>`__ """ n_axes = len(axes) if bias is None: triad_bias = np.array([2.0e-6, -3.0e-6, 3.0e-6]) bias = [Bias(bias=triad_bias[j], std_bias=0.0) for j in range(n_axes)] if noise is None: noise = [Noise(noise=0.0, std_noise=5.0e-7) for _ in range(n_axes)] return [MTM(axis=axes[j], bias=bias[j], noise=noise[j], estimate_bias=estimate_bias) for j in range(n_axes)]
[docs] def create_hmc5883l_magnetometers( axes: np.ndarray = np.eye(3), bias: List[Bias] | None = None, noise: List[Noise] | None = None, estimate_bias: bool = False, ) -> List[MTM]: r""" Create one ESTCube-1 Honeywell HMC5883L magnetometer triad. The HMC5883L magnetometer is represented as three one-dimensional :class:`~ADCS.satellite_hardware.sensors.MTM` channels. Default error model provenance: ``bias`` defaults to a uniform initial bias over +/-2400 nT. The ESTCube-1 preflight simulator modeled magnetic-field direction noise as Gaussian 1.6 deg. Since this package's :class:`~ADCS.satellite_hardware.sensors.MTM` model uses scalar magnetic field measurements, ``noise`` approximates that 1.6 deg direction error as a transverse component error for a representative 50 microtesla field. Ground characterization also reported 0.8 deg statistical magnetic-direction uncertainty, but the simulator value is the default. Source: J. Slavinskis et al., "ESTCube-1 attitude determination system flight results," *Journal of Aerospace Engineering*, 2016. https://ascelibrary.org/doi/10.1061/%28ASCE%29AS.1943-5525.0000504 """ n_axes = len(axes) if bias is None: bias_bound = 2400e-9 e_bias = np.random.uniform(-bias_bound, bias_bound, size=n_axes) bias = [Bias(bias=e_bias[j], std_bias=0.0, bounds=(-bias_bound, bias_bound)) for j in range(n_axes)] if noise is None: representative_field = 50e-6 std_noise = representative_field * np.sin(1.6 * np.pi / 180.0) noise = [Noise(noise=0.0, std_noise=std_noise) for _ in range(n_axes)] return [MTM(axis=axes[j], bias=bias[j], noise=noise[j], estimate_bias=estimate_bias) for j in range(n_axes)]