ADCS.helpers.simresults module¶
- class ADCS.helpers.simresults.Any(*args, **kwargs)[source]¶
Bases:
objectSpecial type indicating an unconstrained type.
Any is compatible with every type.
Any assumed to have all methods.
All values assumed to be instances of Any.
Note that all the above statements are true from the point of view of static type checkers. At runtime, Any should not be used with instance checks.
- class ADCS.helpers.simresults.EstimatedSatellite(mass=1.0, COM=None, J_0=None, disturbances=[], sensors=[], actuators=[], boresight=None)[source]¶
Bases:
SatelliteSatellite model with estimator-synchronized biases and disturbance parameters.
EstimatedSatelliteextendsSatelliteby tracking additional estimator-driven quantities:actuator bias states (for actuators with
estimate_bias=True),attitude sensor bias states (for sensors with
estimate_bias=True),disturbance parameter states (for disturbances with
estimate_dist=True).
These extra states typically live in an estimator state vector, while the physical simulation maintains internal subsystem objects. This class provides a synchronization bridge between them via
match_estimate().Augmented estimator state layout
The estimator is assumed to output a stacked vector
\[\begin{split}\mathbf{x}_{\mathrm{est}} \;=\; \begin{bmatrix} \mathbf{x} \\ \mathbf{b}_{act} \\ \mathbf{b}_{sens} \\ \boldsymbol{\theta}_{dist} \end{bmatrix},\end{split}\]where
\(\mathbf{x}\in\mathbb{R}^{n_x}\) is the base satellite state used by
Satellite,\(\mathbf{b}_{act}\in\mathbb{R}^{n_{ab}}\) concatenates actuator bias parameters,
\(\mathbf{b}_{sens}\in\mathbb{R}^{n_{sb}}\) concatenates sensor bias parameters,
\(\boldsymbol{\theta}_{dist}\in\mathbb{R}^{n_{dp}}\) concatenates disturbance parameters.
The total expected estimator dimension is:
\[n_{\mathrm{tot}} \;=\; n_x + n_{ab} + n_{sb} + n_{dp}.\]Bias and parameter covariance mapping
The estimator provides a covariance \(\mathbf{P}\) and an integrated covariance \(\int \mathbf{P}\,dt\) (stored as
int_cov).match_estimate()extracts the diagonal blocks corresponding to each bias/parameter group and maps them to per-subsystem standard deviations (square roots of block diagonals).Note
During matching, noise is disabled in actuators/sensors and time variation is disabled in disturbances to ensure deterministic consistency when comparing propagation to estimation.
- Raises:
ValueError – If an estimator state vector with incompatible dimension is provided to
match_estimate().- Parameters:
mass (float)
COM (ndarray)
J_0 (ndarray)
disturbances (List[Disturbance])
sensors (List[Sensor])
actuators (List[Actuator])
boresight (dict[str, ndarray] | ndarray)
- classmethod from_satellite(sat)[source]¶
Create an EstimatedSatellite by cloning a Satellite.
- Parameters:
sat (Satellite)
- Return type:
- control_cov()[source]¶
Block-diagonal covariance of actuator input noise.
For each actuator \(j\), let its input noise covariance be \(\mathbf{R}_{u_j}\) returned by
actuator.noise.cov(). This method constructs:\[\mathbf{R}_u = \mathrm{blkdiag}\left(\mathbf{R}_{u_1}, \mathbf{R}_{u_2}, \dots, \mathbf{R}_{u_{N_u}}\right).\]This covariance is commonly used as the control-noise covariance in stochastic propagation or estimator process-noise modeling.
- Returns:
Block-diagonal actuator noise covariance matrix.
- Return type:
numpy.ndarray
- control_srcov()[source]¶
Block-diagonal square-root covariance of actuator input noise.
For each actuator \(j\), let its square-root covariance be \(\mathbf{S}_{u_j}\) returned by
actuator.noise.srcov()such that:\[\mathbf{R}_{u_j} = \mathbf{S}_{u_j}\mathbf{S}_{u_j}^\top.\]This method constructs:
\[\mathbf{S}_u = \mathrm{blkdiag}\left(\mathbf{S}_{u_1}, \mathbf{S}_{u_2}, \dots, \mathbf{S}_{u_{N_u}}\right).\]- Returns:
Block-diagonal actuator noise square-root covariance matrix.
- Return type:
numpy.ndarray
- dist_torque_hess(x, vecs)[source]¶
Hessians of total disturbance torque w.r.t. state and disturbance parameters.
This overrides
dist_torque_hess()by populating parameter–parameter and quaternion–parameter second derivatives for disturbances with estimated parameters.Let \(\boldsymbol{\tau}_d(\mathbf{x},\boldsymbol{\theta}_d)\) be the total disturbance torque. This method returns:
\[\mathbf{H}_{xx} = \frac{\partial^2 \boldsymbol{\tau}_d}{\partial \mathbf{x}^2}, \qquad \mathbf{H}_{x\theta} = \frac{\partial^2 \boldsymbol{\tau}_d}{\partial \mathbf{x}\,\partial \boldsymbol{\theta}_d}, \qquad \mathbf{H}_{\theta\theta} = \frac{\partial^2 \boldsymbol{\tau}_d}{\partial \boldsymbol{\theta}_d^2}.\]State Hessian sparsity
As in the base class, only quaternion components contribute to state second derivatives:
\[\mathbf{H}_{xx}[3:7,3:7,:] = \sum_i \frac{\partial^2 \boldsymbol{\tau}_{d,i}}{\partial \mathbf{q}^2}.\]Parameter blocks
For each estimated disturbance \(i\) with parameter vector size \(\ell_i\), the method places:
\[\mathbf{H}_{\theta\theta}[k:k+\ell_i,\,k:k+\ell_i,:] = \frac{\partial^2 \boldsymbol{\tau}_{d,i}}{\partial \boldsymbol{\theta}_{d,i}^2},\]and
\[\mathbf{H}_{x\theta}[3:7,\,k:k+\ell_i,:] = \frac{\partial^2 \boldsymbol{\tau}_{d,i}}{\partial \mathbf{q}\,\partial \boldsymbol{\theta}_{d,i}}.\]Each estimated disturbance is expected to implement:
torque_qqhess(self, vecs)→ \(\partial^2 \boldsymbol{\tau}/\partial\mathbf{q}^2\),torque_qvalhess(self, vecs)→ \(\partial^2 \boldsymbol{\tau}/\partial\mathbf{q}\partial\boldsymbol{\theta}\),torque_valvalhess(self, vecs)→ \(\partial^2 \boldsymbol{\tau}/\partial\boldsymbol{\theta}^2\).
- Parameters:
x (numpy.ndarray) – Current base spacecraft state vector, shape
(state_len,).vecs (dict[str, numpy.ndarray]) – Dictionary containing body-frame environment vectors and their derivatives.
- Returns:
Tuple
(dddist_torq__dxdx, dddist_torq__dxddmp, dddist_torq__ddmpddmp).- Return type:
tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]
Return shapes
Name
Shape
dddist_torq__dxdx(state_len, state_len, 3)dddist_torq__dxddmp(state_len, dist_param_len, 3)dddist_torq__ddmpddmp(dist_param_len, dist_param_len, 3)
- dist_torques_jacobian(x, vecs)[source]¶
Jacobians of total disturbance torque w.r.t. state and disturbance parameters.
This overrides
dist_torques_jacobian()by additionally returning the derivative of the total disturbance torque w.r.t. estimated disturbance parameters.Let the total disturbance torque be
\[\boldsymbol{\tau}_d(\mathbf{x},\boldsymbol{\theta}_d) = \sum_{i=1}^{N_d}\boldsymbol{\tau}_{d,i}(\mathbf{x},\boldsymbol{\theta}_{d,i}).\]The method returns:
\[\mathbf{J}_x = \frac{\partial \boldsymbol{\tau}_d}{\partial \mathbf{x}}, \qquad \mathbf{J}_{\theta} = \frac{\partial \boldsymbol{\tau}_d}{\partial \boldsymbol{\theta}_d}.\]State Jacobian structure
Only attitude (quaternion) affects rotated environment vectors and thus torque for the provided disturbance interface; therefore:
\[\mathbf{J}_x[3:7,:] = \sum_i \frac{\partial \boldsymbol{\tau}_{d,i}}{\partial \mathbf{q}},\qquad \mathbf{J}_x[k,:]=0\;\text{for}\;k\notin\{3,4,5,6\}.\]Parameter Jacobian assembly
If
self.dist_param_len > 0, the parameter Jacobian is formed by vertically stacking each estimated disturbance’s parameter Jacobian:\[\begin{split}\mathbf{J}_{\theta} = \begin{bmatrix} \frac{\partial \boldsymbol{\tau}_{d,i_1}}{\partial \boldsymbol{\theta}_{d,i_1}} \\ \vdots \\ \frac{\partial \boldsymbol{\tau}_{d,i_m}}{\partial \boldsymbol{\theta}_{d,i_m}} \end{bmatrix}.\end{split}\]Each estimated disturbance is expected to implement:
torque_qjac(self, vecs)→ \(\partial \boldsymbol{\tau}/\partial\mathbf{q}\),torque_valjac(self, vecs)→ \(\partial \boldsymbol{\tau}/\partial\boldsymbol{\theta}\).
- Parameters:
x (numpy.ndarray) – Current base spacecraft state vector, shape
(state_len,).vecs (dict[str, numpy.ndarray]) – Dictionary containing body-frame environment vectors and their quaternion derivatives, typically including keys like
"b","r","s","v","rho", and derivative keys like"db","dr","ds","dv".
- Returns:
Tuple
(ddist_torq__dx, ddist_torq__ddmp).- Return type:
tuple[numpy.ndarray, numpy.ndarray]
Return shapes
Name
Shape
ddist_torq__dx(state_len, 3)ddist_torq__ddmp|(dist_param_len, 3)
- dynJacCore(x, u, orbital_state)[source]¶
Jacobians of augmented dynamics w.r.t. state, inputs, and estimated parameters.
This method extends the base linearization from
dynJacCore()by additionally returning Jacobians of \(\dot{\mathbf{x}}\) w.r.t.:actuator bias vector \(\mathbf{b}_{act}\),
sensor bias vector \(\mathbf{b}_{sens}\) (typically zeros for the process model),
disturbance parameter vector \(\boldsymbol{\theta}_{dist}\).
The local first-order model is:
\[\delta\dot{\mathbf{x}} \approx \mathbf{A}\,\delta\mathbf{x} + \mathbf{B}\,\delta\mathbf{u} + \mathbf{G}_{ab}\,\delta\mathbf{b}_{act} + \mathbf{G}_{sb}\,\delta\mathbf{b}_{sens} + \mathbf{G}_{dp}\,\delta\boldsymbol{\theta}_{dist}.\]Returned blocks
The method returns a list:
\[\left[ \frac{\partial \dot{\mathbf{x}}}{\partial \mathbf{x}}, \frac{\partial \dot{\mathbf{x}}}{\partial \mathbf{u}}, \frac{\partial \dot{\mathbf{x}}}{\partial \mathbf{b}_{act}}, \frac{\partial \dot{\mathbf{x}}}{\partial \mathbf{b}_{sens}}, \frac{\partial \dot{\mathbf{x}}}{\partial \boldsymbol{\theta}_{dist}} \right].\]Where the last three blocks are assembled via actuator- and disturbance-provided derivatives:
actuators implement
dtorq__dbiasand (if wheels) storage-torque bias derivatives,disturbances provide parameter Jacobians via
dist_torques_jacobian().
Note
Sensor bias Jacobians are typically zero in the process model because sensor biases affect measurements, not rotational dynamics; therefore
dxdot__dsbis returned as zeros.- Parameters:
x (numpy.ndarray) – Current base state vector, shape
(state_len,).u (numpy.ndarray) – Current control vector, shape
(control_len,).orbital_state (
Orbital_State) – Orbital/environmental state supplying ECI vectors and scalars used by torque models.
- Returns:
List
[dxdot__dx, dxdot__du, dxdot__dab, dxdot__dsb, dxdot__ddmp].- Return type:
list[numpy.ndarray]
Return shapes
Name
Shape
dxdot__dx(state_len, state_len)dxdot__du(control_len, state_len)dxdot__dab(act_bias_len, state_len)dxdot__dsb(att_sens_bias_len, state_len)dxdot__ddmp(dist_param_len, state_len)
- dynamics_Hessians(x, u, orbital_state)[source]¶
Second-order derivatives (Hessians) of augmented dynamics.
This method computes second derivatives of the base rotational dynamics and extends them to include curvature terms w.r.t. actuator biases and disturbance parameters. The Hessians are organized as a block matrix over the stacked variable vector
\[\begin{split}\mathbf{z} = \begin{bmatrix} \mathbf{x} \\ \mathbf{u} \\ \mathbf{b}_{act} \\ \mathbf{b}_{sens} \\ \boldsymbol{\theta}_{dist} \end{bmatrix}.\end{split}\]For each state-derivative component \(\dot{x}_k\), the Hessian stores
\[\frac{\partial^2 \dot{x}_k}{\partial z_i\,\partial z_j}.\]Returned structure
If reaction wheels are present (and extended estimation terms are active), the method returns:
[ [ddxdot__dxdx, ddxdot__dxdu, ddxdot__dxdab, ddxdot__dxdsb, ddxdot__dxddmp], [ddxdot__dxdu.T, ddxdot__dudu, ddxdot__dudab, ddxdot__dudsb, ddxdot__duddmp], [0, 0, ddxdot__dabdab, ddxdot__dabdsb, ddxdot__dabddmp], [0, 0, 0, ddxdot__dsbdsb, ddxdot__dsbddmp], [0, 0, 0, 0, ddxdot__ddmpddmp] ]
If extended estimation terms are not used, it falls back to the base 2×2 structure:
[ [ddxdot__dxdx, ddxdot__dxdu], [ddxdot__dxdu.T, ddxdot__dudu] ]
Key analytic contributions
Quaternion kinematics curvature terms from \(\dot{\mathbf{q}} = \tfrac12 W(\mathbf{q})^\top\boldsymbol{\omega}\).
Rigid-body dynamics curvature from the gyroscopic term \(-\boldsymbol{\omega}\times(\mathbf{J}\boldsymbol{\omega} + \mathbf{H}_{RW})\).
Disturbance torque curvature terms from
dist_torque_hess().Actuator torque curvature terms from actuator-provided second derivatives, including bias couplings.
- Parameters:
x (numpy.ndarray) – Current base state vector, shape
(state_len,).u (numpy.ndarray) – Current control vector, shape
(control_len,).orbital_state (
Orbital_State) – Orbital/environmental state providing ECI vectors and scalars for torque models.
- Returns:
Nested list of Hessian tensors (see structure above).
- Return type:
list[list[numpy.ndarray]]
Common tensor shapes (extended case)
Tensor
Shape
ddxdot__dxdx(state_len, state_len, state_len)ddxdot__dxdu(state_len, control_len, state_len)ddxdot__dudu(control_len, control_len, state_len)ddxdot__dxdab(state_len, act_bias_len, state_len)ddxdot__dxdsb(state_len, att_sens_bias_len, state_len)ddxdot__dxddmp(state_len, dist_param_len, state_len)ddxdot__dabdab(act_bias_len, act_bias_len, state_len)ddxdot__dsbdsb(att_sens_bias_len, att_sens_bias_len, state_len)ddxdot__ddmpddmp(dist_param_len, dist_param_len, state_len)
- match_estimate(est_state, dt)[source]¶
Synchronize the satellite instance with the estimator output.
This method maps the estimator output into the simulation model by:
Extracting wheel momenta from the base state portion and updating wheel objects via
update_RWhs().Writing actuator biases into each actuator’s bias object and setting per-bias standard deviations from the corresponding covariance block.
Writing sensor biases into each attitude sensor’s bias object and setting per-bias standard deviations from the corresponding covariance block.
Writing disturbance parameters into each disturbance model (for active disturbances) and setting their parameter standard deviations from covariance blocks.
For deterministic matching, disabling: *
actuator.use_noise = Falsefor all actuators, *sensor.use_noise = Falsefor all sensors, *disturbance.time_varying = Falsefor all disturbances.
Estimator vector partition
With
\[\begin{split}\mathbf{x}_{\mathrm{est}} = \begin{bmatrix} \mathbf{x} \\ \mathbf{b}_{act} \\ \mathbf{b}_{sens} \\ \boldsymbol{\theta}_{dist} \end{bmatrix},\end{split}\]indices are:
\[\begin{split}\begin{aligned} \mathbf{x} &\in \mathbb{R}^{n_x},\\ \mathbf{b}_{act} &\in \mathbb{R}^{n_{ab}},\\ \mathbf{b}_{sens} &\in \mathbb{R}^{n_{sb}},\\ \boldsymbol{\theta}_{dist} &\in \mathbb{R}^{n_{dp}}, \end{aligned}\end{split}\]where
\[n_x=\texttt{self.state\_len},\; n_{ab}=\texttt{self.act\_bias\_len},\; n_{sb}=\texttt{self.att\_sens\_bias\_len},\; n_{dp}=\texttt{self.dist\_param\_len}.\]Covariance-to-standard-deviation mapping
For each extracted block covariance \(\mathbf{P}_{block}\), per-element standard deviations are assigned as:
\[\boldsymbol{\sigma} = \sqrt{\operatorname{diag}(\mathbf{P}_{block})}.\]In the implementation, the estimator provides an integrated covariance block (
int_cov) that may be dimension-shifted by one element in some configurations (e.g., quaternion handling). The method applies an index adjustmentadjwhenint_covis off-by-one.- Parameters:
est_state (
EstimatedArray) – Estimator output container providingval(state vector),cov(covariance), andint_cov(integrated covariance).dt (float) – Estimator propagation step (s). Used by some pipelines to normalize integrated covariance. (The current implementation partitions
int_covdirectly.)
- Returns:
None.- Return type:
None
- Raises:
ValueError – If
est_state.valdoes not have lengthself.state_len + self.act_bias_len + self.att_sens_bias_len + self.dist_param_len.
- sensor_bias_slice(att_sensor_index)[source]¶
Slice for an attitude sensor’s bias block in the full estimator state vector.
The full estimator state is assumed to be ordered as:
\[\begin{split}\mathbf{x}_{\mathrm{est}} = \begin{bmatrix} \mathbf{x} \\ \mathbf{b}_{act} \\ \mathbf{b}_{sens} \\ \boldsymbol{\theta}_{dist} \end{bmatrix},\end{split}\]where the sensor-bias block starts at offset:
\[k_0 = n_x + n_{ab} \;=\; \texttt{self.state\_len} + \texttt{self.act\_bias\_len}.\]This method returns the Python
slice(start, stop)selecting the bias elements forself.attitude_sensors[att_sensor_index]within \(\mathbf{x}_{\mathrm{est}}\). If the specified sensor does not have an estimated bias (i.e., not inatt_sens_bias_inds), the method returnsNone.- Parameters:
att_sensor_index (int) – Index into
self.attitude_sensors.- Returns:
Slice selecting the sensor’s bias portion in the estimator vector, or
None.- Return type:
slice | None
- Raises:
RuntimeError – If the sensor index is listed as bias-estimated but the slice cannot be constructed.
- sensor_cov(which_sensors)[source]¶
Block-diagonal covariance of attitude sensor noise (and wheel momentum measurement noise).
For each attitude sensor \(i\) with covariance \(\mathbf{R}_{y_i}\) (from
sensor.noise.cov()), the attitude-sensor covariance is:\[\mathbf{R}_y = \mathrm{blkdiag}\left(\mathbf{R}_{y_{i_1}}, \dots, \mathbf{R}_{y_{i_m}}\right),\]where the set \(\{i_1,\dots,i_m\}\) is selected by
which_sensors.If reaction wheels are present, each wheel contributes an additional measurement covariance for its momentum measurement model (e.g.,
rw.h_meas_noise.cov()), appended to the block diagonal.- Parameters:
which_sensors (list[bool]) – Boolean selector list of length
len(self.attitude_sensors)indicating which attitude sensors to include. IfNoneis passed in the implementation, all are included.- Returns:
Block-diagonal measurement covariance matrix. If no sensors are selected, returns a
(0,0)array.- Return type:
numpy.ndarray
- sensor_srcov(which_sensors)[source]¶
Block-diagonal square-root covariance of attitude sensor noise (and wheel momentum measurement noise).
For each attitude sensor \(i\) with square-root covariance \(\mathbf{S}_{y_i}\) (from
sensor.noise.srcov()) such that \(\mathbf{R}_{y_i}=\mathbf{S}_{y_i}\mathbf{S}_{y_i}^\top\), this method constructs\[\mathbf{S}_y = \mathrm{blkdiag}\left(\mathbf{S}_{y_{i_1}}, \dots, \mathbf{S}_{y_{i_m}}\right),\]with selection controlled by
which_sensors.If reaction wheels are present, each wheel contributes an additional square-root covariance block for its momentum measurement model (e.g.,
rw.h_meas_noise.srcov()).- Parameters:
which_sensors (list[bool]) – Boolean selector list of length
len(self.attitude_sensors)indicating which attitude sensors to include. IfNoneis passed in the implementation, all are included.- Returns:
Block-diagonal measurement square-root covariance matrix. If no sensors are selected, returns a
(0,0)array.- Return type:
numpy.ndarray
- class ADCS.helpers.simresults.Orbital_State(ephem, J2000, R, V, S=None, B=None, rho=None, density_model=None, fast=False)[source]¶
Bases:
objectComplete dynamical and environmental representation of a spacecraft orbital state.
The state is defined by inertial position and velocity in the ECI/ICRF frame at an epoch expressed in J2000 centuries. The class also stores commonly-used derived quantities and environment vectors, including Earth-fixed coordinates, Sun vector, geomagnetic field vector (IGRF), atmospheric density, and frame transforms.
Notes
The
fastargument is accepted for backward compatibility but is ignored: this implementation always computes real Sun and geomagnetic field vectors and frame transforms.- Parameters:
ephem (Ephemeris) – Ephemeris object used for Earth and Sun position queries. If
None, a newEphemerisis constructed.J2000 (float) – Epoch in Julian centuries since J2000.
R (numpy.ndarray) – Position vector in ECI frame [km].
V (numpy.ndarray) – Velocity vector in ECI frame [km/s].
S (numpy.ndarray or None) – Optional Sun position vector in ECI frame [km]. If
None, it is computed.B (numpy.ndarray or None) – Optional geomagnetic field vector in ECI frame [T]. If
None, it is computed.rho (float or None) – Optional atmospheric density [kg/m^3]. If
None, it is computed usingDensityModel.density_model (DensityModel or None) – Atmospheric density interpolation model. If
None, a newDensityModelis constructed.fast (bool) – Backward-compatible parameter (ignored). Real environment vectors are always computed.
- classmethod from_dict(d, ephem, density_model=None, fast=True)[source]¶
Construct an orbital state from a dictionary.
Notes
The
fastargument is accepted for backward compatibility but is ignored.- Parameters:
d (dict) – Dictionary containing orbital state fields.
ephem (Ephemeris) – Ephemeris object.
density_model (DensityModel or None) – Atmospheric density model.
fast (bool) – Backward-compatible parameter (ignored).
- Returns:
Reconstructed orbital state.
- Return type:
- average(orbital_state_2, ratio=0.5, fast=False)[source]¶
Linearly interpolate between two orbital states.
- Parameters:
orbital_state_2 (Orbital_State) – Second orbital state.
ratio (float) – Interpolation ratio in [0, 1].
fast (bool) – Backward-compatible parameter (ignored).
- Returns:
Interpolated orbital state.
- Return type:
- copy()[source]¶
Return a deep copy of the orbital state.
This implementation avoids recomputing environment vectors and frame transforms.
- Returns:
Independent copy of the orbital state.
- Return type:
- ecef_to_eci(vec)[source]¶
Transform a vector from ECEF to ECI coordinates.
- Parameters:
vec (numpy.ndarray) – Vector in ECEF frame.
- Returns:
Vector in ECI frame.
- Return type:
numpy.ndarray
- ecef_to_geocentric(vec)[source]¶
Transform an ECEF vector to local geocentric coordinates.
- Parameters:
vec (numpy.ndarray) – Vector in ECEF frame.
- Returns:
Vector in geocentric basis.
- Return type:
numpy.ndarray
- eci_to_ecef(vec)[source]¶
Transform a vector from ECI to ECEF coordinates.
- Parameters:
vec (numpy.ndarray) – Vector in ECI frame.
- Returns:
Vector in ECEF frame.
- Return type:
numpy.ndarray
- eci_to_enu(vec)[source]¶
Transform a vector from ECI to local ENU frame.
- Parameters:
vec (numpy.ndarray) – Vector in ECI frame.
- Returns:
Vector in ENU frame.
- Return type:
numpy.ndarray
- enu_to_eci(vec)[source]¶
Transform a vector from ENU to ECI frame.
- Parameters:
vec (numpy.ndarray) – Vector in ENU frame.
- Returns:
Vector in ECI frame.
- Return type:
numpy.ndarray
- geocentric_to_ecef(vec)[source]¶
Transform a geocentric vector to ECEF coordinates.
- Parameters:
vec (numpy.ndarray) – Vector in geocentric basis.
- Returns:
Vector in ECEF frame.
- Return type:
numpy.ndarray
- get_b_eci()[source]¶
Compute the geomagnetic field vector in the ECI frame.
- Returns:
Magnetic field vector [Tesla].
- Return type:
numpy.ndarray
- get_state_vector(x)[source]¶
Retrieve cached or updated body-frame vectors.
- Parameters:
x (numpy.ndarray or None) – Current spacecraft state vector.
- Returns:
Dictionary of vectors and derivatives.
- Return type:
dict[str, numpy.ndarray]
- get_sun_eci()[source]¶
Compute the Sun position vector in the ECI frame.
- Returns:
Sun vector in ECI coordinates [km].
- Return type:
numpy.ndarray
- is_sunlit()[source]¶
Determine whether the spacecraft is illuminated by the Sun.
- Returns:
Trueif sunlit,Falseotherwise.- Return type:
bool
- j2000_to_tai()[source]¶
Convert J2000 centuries to TAI Julian date.
- Returns:
TAI Julian date.
- Return type:
float
- orbit_dynamics(J2_perturbation_on=True)[source]¶
Compute translational orbital dynamics at the current state.
- Parameters:
J2_perturbation_on (bool) – Enable J2 perturbation.
- Returns:
Time derivatives of position and velocity.
- Return type:
tuple[numpy.ndarray, numpy.ndarray]
- orbit_dynamics_jacobians(J2_perturbation_on=True)[source]¶
Compute Jacobians of the translational dynamics.
- Parameters:
J2_perturbation_on (bool) – Enable J2 perturbation.
- Returns:
Jacobian matrices of the dynamics.
- Return type:
tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]
- propagate_jacobians(dt, J2_perturbation_on=True)[source]¶
Propagate state transition Jacobians using first-order integration.
- Parameters:
dt (float) – Time step in seconds.
J2_perturbation_on (bool) – Enable J2 perturbation.
- Returns:
State transition Jacobian blocks.
- Return type:
tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]
- propagate_jacobians_rk4(dt, J2_perturbation_on=True)[source]¶
Propagate state transition Jacobians using RK4 integration.
- Parameters:
dt (float) – Time step in seconds.
J2_perturbation_on (bool) – Enable J2 perturbation.
- Returns:
State transition Jacobian blocks.
- Return type:
tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]
- propagate_orbit(dt, J2_perturbation_on=True, fast=True)[source]¶
Propagate the orbital state forward using first-order integration.
- Parameters:
dt (float) – Time step in seconds.
J2_perturbation_on (bool) – Enable J2 perturbation.
fast (bool) – Backward-compatible parameter (ignored).
- Returns:
Propagated orbital state.
- Return type:
- propagate_orbit_rk4(dt, J2_perturbation_on=True, fast=True)[source]¶
Propagate the orbital state using fourth-order Runge–Kutta integration.
- Parameters:
dt (float) – Time step in seconds.
J2_perturbation_on (bool) – Enable J2 perturbation.
fast (bool) – Backward-compatible parameter (ignored).
- Returns:
Propagated orbital state.
- Return type:
- class ADCS.helpers.simresults.Path(*args, **kwargs)[source]¶
Bases:
PurePathPurePath subclass that can make system calls.
Path represents a filesystem path but unlike PurePath, also offers methods to do system calls on path objects. Depending on your system, instantiating a Path will return either a PosixPath or a WindowsPath object. You can also instantiate a PosixPath or WindowsPath directly, but cannot instantiate a WindowsPath on a POSIX system or vice versa.
- classmethod home()[source]¶
Return a new path pointing to the user’s home directory (as returned by os.path.expanduser(‘~’)).
- absolute()[source]¶
Return an absolute version of this path by prepending the current working directory. No normalization or symlink resolution is performed.
Use resolve() to get the canonical path to a file.
- exists(*, follow_symlinks=True)[source]¶
Whether this path exists.
This method normally follows symlinks; to check whether a symlink exists, add the argument follow_symlinks=False.
- expanduser()[source]¶
Return a new path with expanded ~ and ~user constructs (as returned by os.path.expanduser)
- glob(pattern, *, case_sensitive=None)[source]¶
Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.
- hardlink_to(target)[source]¶
Make this path a hard link pointing to the same file as target.
Note the order of arguments (self, target) is the reverse of os.link’s.
- is_file()[source]¶
Whether this path is a regular file (also True for symlinks pointing to regular files).
- iterdir()[source]¶
Yield path objects of the directory contents.
The children are yielded in arbitrary order, and the special entries ‘.’ and ‘..’ are not included.
- lchmod(mode)[source]¶
Like chmod(), except if the path points to a symlink, the symlink’s permissions are changed, rather than its target’s.
- lstat()[source]¶
Like stat(), except if the path points to a symlink, the symlink’s status information is returned, rather than its target’s.
- open(mode='r', buffering=-1, encoding=None, errors=None, newline=None)[source]¶
Open the file pointed to by this path and return a file object, as the built-in open() function does.
- read_text(encoding=None, errors=None)[source]¶
Open the file in text mode, read it, and close the file.
- rename(target)[source]¶
Rename this path to the target path.
The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.
Returns the new Path instance pointing to the target path.
- replace(target)[source]¶
Rename this path to the target path, overwriting if that path exists.
The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.
Returns the new Path instance pointing to the target path.
- resolve(strict=False)[source]¶
Make the path absolute, resolving all symlinks on the way and also normalizing it.
- rglob(pattern, *, case_sensitive=None)[source]¶
Recursively yield all existing files (of any kind, including directories) matching the given relative pattern, anywhere in this subtree.
- samefile(other_path)[source]¶
Return whether other_path is the same or not as this file (as returned by os.path.samefile()).
- stat(*, follow_symlinks=True)[source]¶
Return the result of the stat() system call on this path, like os.stat() does.
- symlink_to(target, target_is_directory=False)[source]¶
Make this path a symlink pointing to the target path. Note the order of arguments (link, target) is the reverse of os.symlink.
- touch(mode=438, exist_ok=True)[source]¶
Create this file with the given access mode, if it doesn’t exist.
- unlink(missing_ok=False)[source]¶
Remove this file or link. If the path is a directory, use rmdir() instead.
- class ADCS.helpers.simresults.RunResults(satellite: 'Satellite', est_satellite: 'Optional[EstimatedSatellite]' = None, time_J2000: 'Optional[np.ndarray]' = None, time_s: 'Optional[np.ndarray]' = None, os_hist: 'Optional[List[Orbital_State]]' = None, est_os_hist: 'Optional[List[Orbital_State]]' = None, os_cov_hist: 'Optional[List[np.ndarray]]' = None, state_hist: 'Optional[np.ndarray]' = None, est_state_hist: 'Optional[np.ndarray]' = None, state_cov_hist: 'Optional[List[np.ndarray]]' = None, sensor_bias: 'Optional[np.ndarray]' = None, est_sensor_bias: 'Optional[np.ndarray]' = None, actuator_bias: 'Optional[np.ndarray]' = None, est_actuator_bias: 'Optional[np.ndarray]' = None, target_hist: 'Optional[np.ndarray]' = None, w_target_hist: 'Optional[np.ndarray]' = None, boresight_hist: 'Optional[np.ndarray]' = None, clean_sensor_hist: 'Optional[np.ndarray]' = None, sensor_hist: 'Optional[np.ndarray]' = None, control_hist: 'Optional[np.ndarray]' = None, control_rpc_time_hist: 'Optional[np.ndarray]' = None, control_rpc_server_time_hist: 'Optional[np.ndarray]' = None, env_local_time_hist: 'Optional[np.ndarray]' = None, dynamics_time_hist: 'Optional[np.ndarray]' = None)[source]¶
Bases:
object- Parameters:
satellite (Satellite)
est_satellite (EstimatedSatellite | None)
time_J2000 (ndarray | None)
time_s (ndarray | None)
os_hist (List[Orbital_State] | None)
est_os_hist (List[Orbital_State] | None)
os_cov_hist (List[ndarray] | None)
state_hist (ndarray | None)
est_state_hist (ndarray | None)
state_cov_hist (List[ndarray] | None)
sensor_bias (ndarray | None)
est_sensor_bias (ndarray | None)
actuator_bias (ndarray | None)
est_actuator_bias (ndarray | None)
target_hist (ndarray | None)
w_target_hist (ndarray | None)
boresight_hist (ndarray | None)
clean_sensor_hist (ndarray | None)
sensor_hist (ndarray | None)
control_hist (ndarray | None)
control_rpc_time_hist (ndarray | None)
control_rpc_server_time_hist (ndarray | None)
env_local_time_hist (ndarray | None)
dynamics_time_hist (ndarray | None)
- actuator_bias: ndarray | None = None¶
- boresight_hist: ndarray | None = None¶
- clean_sensor_hist: ndarray | None = None¶
- control_hist: ndarray | None = None¶
- control_rpc_server_time_hist: ndarray | None = None¶
- control_rpc_time_hist: ndarray | None = None¶
- dynamics_time_hist: ndarray | None = None¶
- env_local_time_hist: ndarray | None = None¶
- est_actuator_bias: ndarray | None = None¶
- est_os_hist: List[Orbital_State] | None = None¶
- est_satellite: EstimatedSatellite | None = None¶
- est_sensor_bias: ndarray | None = None¶
- est_state_hist: ndarray | None = None¶
- os_cov_hist: List[ndarray] | None = None¶
- os_hist: List[Orbital_State] | None = None¶
- sensor_bias: ndarray | None = None¶
- sensor_hist: ndarray | None = None¶
- state_cov_hist: List[ndarray] | None = None¶
- state_hist: ndarray | None = None¶
- target_hist: ndarray | None = None¶
- time_J2000: ndarray | None = None¶
- time_s: ndarray | None = None¶
- w_target_hist: ndarray | None = None¶
- class ADCS.helpers.simresults.Satellite(mass=1.0, COM=None, J_0=None, disturbances=[], sensors=[], actuators=[], boresight=None)[source]¶
Bases:
objectRigid-body spacecraft model with sensors, actuators, and environmental disturbances.
This class bundles the spacecraft physical properties (mass, center of mass, inertia), a set of actuators (e.g.,
RW,MTQ), sensors (e.g.,Gyro,MTM,SunSensor,GPS), and disturbance models (e.g.,SRP_Disturbance).The rotational state is represented by body angular velocity and a unit quaternion. Reaction wheel angular momentum states may be appended.
State definition
Let the full state be
\[\begin{split}\mathbf{x} \;=\; \begin{bmatrix} \boldsymbol{\omega} \\ \mathbf{q} \\ \mathbf{h}_{\mathrm{RW}} \end{bmatrix} \in \mathbb{R}^{7+n_{\mathrm{RW}}},\end{split}\]where
\(\boldsymbol{\omega}\in\mathbb{R}^3\) is the body angular velocity (rad/s),
\(\mathbf{q}\in\mathbb{R}^4\) is a unit quaternion (Hamilton convention, body→ECI),
\(\mathbf{h}_{\mathrm{RW}}\in\mathbb{R}^{n_{\mathrm{RW}}}\) are wheel momenta.
Kinematics
Quaternion kinematics are
\[\dot{\mathbf{q}} = \frac{1}{2}\,\Omega(\boldsymbol{\omega})\,\mathbf{q},\]with an equivalent matrix form implemented via
Wmat().Dynamics (bus + wheels)
Define the total external torque
\[\boldsymbol{\tau} \;=\; \boldsymbol{\tau}_{\mathrm{dist}}(\mathbf{x}, \mathrm{os}) \;+\; \boldsymbol{\tau}_{\mathrm{act}}(\mathbf{x}, \mathbf{u}, \mathrm{os}).\]The rigid-body rotational equation is
\[\mathbf{J}\,\dot{\boldsymbol{\omega}} \;=\; -\boldsymbol{\omega}\times\Big(\mathbf{J}\boldsymbol{\omega} + \mathbf{H}_{\mathrm{RW}}\Big) \;+\; \boldsymbol{\tau},\]where \(\mathbf{H}_{\mathrm{RW}}\) is the body-frame contribution of stored wheel momentum. When wheels exist, wheel momentum dynamics follow actuator storage torques and the coupling term induced by \(\dot{\boldsymbol{\omega}}\).
Frames and environment
Environmental vectors are provided by
Orbital_Stateand rotated into the body frame viarot_mat().Inertia shifting
The inertia tensor about the center of mass is computed using the parallel axis theorem:
\[\mathbf{J}_{\mathrm{COM}} \;=\; \mathbf{J}_0 \;-\; m\left(\|\mathbf{r}_{\mathrm{COM}}\|^2\mathbf{I} \;-\;\mathbf{r}_{\mathrm{COM}}\mathbf{r}_{\mathrm{COM}}^\top\right),\]where \(\mathbf{J}_0\) is the inertia about the reference origin and \(\mathbf{r}_{\mathrm{COM}}\) is the COM offset in the same frame.
Note
Many methods accept an
ErrorModeto control bias/noise injection for Monte-Carlo simulation vs. deterministic propagation.Stored attributes (selected)
Attribute
Meaning
massTotal mass (kg)
COMCenter of mass vector (m)
J_0Inertia about reference (kg·m²)
J_COMInertia about COM (kg·m²)
J_noRWBus inertia excluding wheels
state_len7 + number_RWcontrol_lenlen(actuators)- Raises:
ValueError – If
COMis not shape(3,)orJ_0is not shape(3,3).- Parameters:
mass (float)
COM (ndarray)
J_0 (ndarray)
disturbances (List[Disturbance])
sensors (List[Sensor])
actuators (List[Actuator])
boresight (dict[str, ndarray] | ndarray)
- GPS_readings(x, os)[source]¶
Return GPS sensor readings.
GPS sensors are identified as instances of
GPS.- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).os (
Orbital_State) – Orbital/environmental state.
- Returns:
List of GPS reading arrays (model-specific shapes).
- Return type:
list[numpy.ndarray]
- RW_readings(x, os)[source]¶
Return reaction wheel momentum measurements (with wheel measurement model behavior).
Delegates to each wheel’s
measure_momentum().- Parameters:
x (numpy.ndarray) – Current state vector (unused by some wheel models but included for interface consistency).
os (
Orbital_State) – Orbital/environmental state (unused by some wheel models but included for interface consistency).
- Returns:
List of per-wheel measurement arrays.
- Return type:
list[numpy.ndarray]
- RWhs()[source]¶
Return the current reaction wheel momenta as a vector.
The returned vector is ordered according to
self.momentum_inds(indices ofRWwithinself.actuators).- Returns:
Reaction wheel momentum vector, shape
(number_RW,).- Return type:
numpy.ndarray
- RWhs_from_state(state)[source]¶
Extract the reaction wheel momenta subvector from a full state vector.
Using the state layout
\[\mathbf{x} = \begin{bmatrix} \boldsymbol{\omega} & \mathbf{q} & \mathbf{h}_{RW} \end{bmatrix}^\top,\]this returns \(\mathbf{h}_{RW} = \mathbf{x}[7:]\).
- Parameters:
state (numpy.ndarray) – Full state vector, shape
(state_len,).- Returns:
Reaction wheel momentum vector, shape
(number_RW,).- Return type:
numpy.ndarray
- act_torque(x, u, os, dmode=None)[source]¶
Compute the total actuator torque.
The total actuator torque is
\[\boldsymbol{\tau}_{act}(\mathbf{x},\mathbf{u},\mathrm{os}) \;=\;\sum_{j=1}^{N_u} \boldsymbol{\tau}_{act,j}(u_j,\mathbf{x},\mathrm{os}),\]where each actuator is a subclass of
Actuator.- Parameters:
x (numpy.ndarray) – State vector, shape
(state_len,).u (numpy.ndarray) – Control input vector, shape
(control_len,).os (
Orbital_State) – Orbital/environmental state.dmode (
ErrorMode| None) – Error/noise mode passed to actuator torque models.
- Returns:
Actuator torque vector in body frame, shape
(3,)(N·m).- Return type:
numpy.ndarray
- dist_torque_hess(x, vecs)[source]¶
Hessian tensors of total disturbance torque.
Returns second derivatives of \(\boldsymbol{\tau}_{dist}\):
\[\frac{\partial^2 \boldsymbol{\tau}_{dist}}{\partial \mathbf{x}^2}, \qquad \frac{\partial^2 \boldsymbol{\tau}_{dist}}{\partial \mathbf{x}\,\partial \boldsymbol{\theta}_d}, \qquad \frac{\partial^2 \boldsymbol{\tau}_{dist}}{\partial \boldsymbol{\theta}_d^2}.\]As with
dist_torques_jacobian(), only quaternion components contribute in the current formulation, and each disturbance must implement:torque_qqhess(self, vecs)→ \(\partial^2 \boldsymbol{\tau}/\partial \mathbf{q}^2\).
- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).vecs (dict[str, numpy.ndarray]) – Dictionary of body-frame environment vectors and their first/second quaternion derivatives.
- Returns:
Triple
(dddist_torq__dxdx, dddist_torq__dxddmp, dddist_torq__ddmpddmp).- Return type:
tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]
Return shapes
Name
Shape
dddist_torq__dxdx(state_len, state_len, 3)dddist_torq__dxddmp(state_len, dist_param_len, 3)dddist_torq__ddmpddmp(dist_param_len, dist_param_len, 3)
- dist_torques(x, os, dmode=None)[source]¶
Compute the total disturbance torque.
The total disturbance torque is the sum over all registered disturbances:
\[\boldsymbol{\tau}_{dist}(\mathbf{x},\mathrm{os}) \;=\;\sum_{i=1}^{N_d} \boldsymbol{\tau}_{dist,i}(\mathbf{x},\mathrm{os}).\]Disturbance implementations may optionally accept a
satkeyword argument; if so, the currentSatelliteinstance is provided.- Parameters:
x (numpy.ndarray) – State vector, shape
(state_len,).os (
Orbital_State) – Orbital/environmental state.dmode (
ErrorMode| None) – Optional error/noise mode (typically used inside disturbances if supported).
- Returns:
Disturbance torque vector in body frame, shape
(3,)(N·m).- Return type:
numpy.ndarray
- dist_torques_jacobian(x, vecs)[source]¶
Jacobians of total disturbance torque with respect to the state and disturbance parameters.
Let \(\boldsymbol{\tau}_{dist}(\mathbf{x})\) be the total disturbance torque. This method returns:
\[\frac{\partial \boldsymbol{\tau}_{dist}}{\partial \mathbf{x}} \in \mathbb{R}^{n_x\times 3}, \qquad \frac{\partial \boldsymbol{\tau}_{dist}}{\partial \boldsymbol{\theta}_d} \in \mathbb{R}^{n_{\theta_d}\times 3}.\]In the provided implementation, only the quaternion components affect the disturbance torque Jacobian, because environment vectors are rotated by attitude. Thus, the nonzero block is
\[\left[\frac{\partial \boldsymbol{\tau}_{dist}}{\partial \mathbf{x}}\right]_{3:7,:} = \sum_i \frac{\partial \boldsymbol{\tau}_{dist,i}}{\partial \mathbf{q}}.\]Each disturbance model must implement:
torque_qjac(self, vecs)→ \(\partial \boldsymbol{\tau}/\partial \mathbf{q}\).
- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).vecs (dict[str, numpy.ndarray]) – Dictionary of body-frame environment vectors and their quaternion derivatives, e.g.
{"b","r","s","v","rho","db","dr","ds","dv","os"}.
- Returns:
Pair
(ddist_torq__dx, ddist_torq__ddmp).- Return type:
tuple[numpy.ndarray, numpy.ndarray]
Return shapes
Name
Shape
ddist_torq__dx(state_len, 3)ddist_torq__ddmp(dist_param_len, 3)
- dynJacCore(x, u, orbital_state)[source]¶
Compute Jacobians of the dynamics with respect to state and input.
This method returns the first-order linearization
\[\delta \dot{\mathbf{x}} \approx \mathbf{A}\,\delta\mathbf{x} + \mathbf{B}\,\delta\mathbf{u},\]where
\[\mathbf{A} = \frac{\partial f}{\partial \mathbf{x}},\qquad \mathbf{B} = \frac{\partial f}{\partial \mathbf{u}}.\]Environmental vectors (magnetic field, sun vector, velocity, position) are rotated into the body frame:
\[\mathbf{v}_B(\mathbf{q}) = R(\mathbf{q})^\top \mathbf{v}_{ECI},\]and derivatives \(\partial \mathbf{v}_B/\partial \mathbf{q}\) are obtained via
drotmatTvecdq().Actuator torque derivatives are aggregated via each actuator’s methods, e.g.
dtorq__dbasestateanddtorq__du; disturbance derivatives are aggregated viadist_torques_jacobian().- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).u (numpy.ndarray) – Current control vector, shape
(control_len,).orbital_state (
Orbital_State) – Orbital/environmental state.
- Returns:
List
[dxdot__dx, dxdot__du].- Return type:
list[numpy.ndarray]
Return shapes
Name
Shape
dxdot__dx(state_len, state_len)dxdot__du(control_len, state_len)
- dynamics_Hessians(x, u, orbital_state)[source]¶
Compute second-order partial derivatives (Hessians) of the dynamics.
Returns the second derivatives of the dynamics map \(\dot{\mathbf{x}} = f(\mathbf{x},\mathbf{u},\mathrm{os})\) with respect to state and input:
\[\frac{\partial^2 f}{\partial \mathbf{x}^2}, \qquad \frac{\partial^2 f}{\partial \mathbf{x}\partial \mathbf{u}}, \qquad \frac{\partial^2 f}{\partial \mathbf{u}^2}.\]These are useful for second-order trajectory optimization methods (DDP/iLQR) and nonlinear uncertainty propagation.
Frame rotation derivatives
Environmental vectors are rotated into body frame and their first and second derivatives with respect to the quaternion are computed:
\[\mathbf{v}_B(\mathbf{q}) = R(\mathbf{q})^\top \mathbf{v}_{ECI},\quad \frac{\partial \mathbf{v}_B}{\partial \mathbf{q}},\quad \frac{\partial^2 \mathbf{v}_B}{\partial \mathbf{q}^2},\]using
drotmatTvecdq()andddrotmatTvecdqdq().Output structure
The return is a nested list representing the block Hessians:
[ [ ddxdot__dxdx, ddxdot__dxdu ], [ ddxdot__dxdu.T, ddxdot__dudu ] ]
where the final tensor index selects the component of \(\dot{\mathbf{x}}\).
- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).u (numpy.ndarray) – Current control vector, shape
(control_len,).orbital_state (
Orbital_State) – Orbital/environmental state.
- Returns:
Nested list of Hessian tensors
[[ddxdot__dxdx, ddxdot__dxdu],[ddxdot__dxdu.T, ddxdot__dudu]].- Return type:
list[list[numpy.ndarray]]
Return shapes
Name
Shape
ddxdot__dxdx(state_len, state_len, state_len)ddxdot__dxdu(state_len, control_len, state_len)ddxdot__dudu(control_len, control_len, state_len)
- dynamics_core(x, u, orbital_state, dmode=None, verbose=False)[source]¶
Continuous-time attitude dynamics \(\dot{\mathbf{x}} = f(\mathbf{x},\mathbf{u},\mathrm{os})\).
This is the primary nonlinear dynamics model used by propagation, simulation, and linearization routines.
Kinematics
Quaternion kinematics are computed as
\[\dot{\mathbf{q}} \;=\;\frac{1}{2}\,W(\mathbf{q})^\top\,\boldsymbol{\omega},\]where \(W(\mathbf{q})\) is produced by
Wmat().Torques
Disturbance and actuator torques are summed:
\[\boldsymbol{\tau}_{dist} = \sum_i \boldsymbol{\tau}_{dist,i}(\mathbf{x},\mathrm{os}), \qquad \boldsymbol{\tau}_{act} = \sum_j \boldsymbol{\tau}_{act,j}(\mathbf{x},\mathbf{u},\mathrm{os}),\]using
dist_torques()andact_torque().Rigid-body dynamics
If no reaction wheels are present:
\[\dot{\boldsymbol{\omega}} \;=\;\mathbf{J}_{noRW}^{-1}\Big( -\boldsymbol{\omega}\times(\mathbf{J}\boldsymbol{\omega}) + \boldsymbol{\tau} \Big).\]If reaction wheels are present, let \(\mathbf{A}\in\mathbb{R}^{n_{RW}\times 3}\) stack wheel spin axes as rows, and let \(\mathbf{h}\in\mathbb{R}^{n_{RW}}\) be wheel momenta. Then the coupled term uses the body-frame stored momentum \(\mathbf{H}_{RW} = \mathbf{h}^\top \mathbf{A}\) and
\[\dot{\boldsymbol{\omega}} \;=\;\mathbf{J}_{noRW}^{-1}\Big( -\boldsymbol{\omega}\times(\mathbf{J}\boldsymbol{\omega} + \mathbf{H}_{RW}) + \boldsymbol{\tau} \Big).\]Wheel momentum dynamics use the actuator storage torque commands (from each
RW) and subtract the coupling term from body acceleration:\[\dot{\mathbf{h}} \;=\;\mathbf{u}_{RW} \;-\; \mathbf{A}\,\dot{\boldsymbol{\omega}}\,\mathrm{diag}(J_{RW}),\]matching the implementation structure.
- Parameters:
x (numpy.ndarray) – State vector
[w(3), q(4), h(number_RW)], shape(state_len,).u (numpy.ndarray) – Control vector, one element per actuator, shape
(control_len,).orbital_state (
Orbital_State) – Orbital/environmental state providing vectors (e.g. magnetic field), used by torques.dmode (
ErrorMode| None) – Error/noise/bias mode used by sensors/actuators/disturbances. IfNone, a default with bias+noise enabled and updated is used.verbose (bool) – If
True, prints a detailed torque and derivative breakdown.
- Returns:
Time derivative vector \(\dot{\mathbf{x}}\), shape
(state_len,).- Return type:
numpy.ndarray
- dynamics_for_solver(t, x, u, os0, os1)[source]¶
Wrapper for ODE solvers expecting signature
f(t, x).This method interpolates the orbital/environmental state between
os0andos1using the fraction of elapsed time\[\alpha = \frac{t}{\Delta t},\qquad \Delta t = (J2000_1 - J2000_0)\cdot C_{\mathrm{cent}\to \mathrm{sec}},\]and calls
dynamics_core()with anErrorModethat does not update bias/noise so the solver uses a consistent noise sample.- Parameters:
t (float) – Time since start of the interval (s).
x (numpy.ndarray) – Current state vector, shape
(state_len,).u (numpy.ndarray) – Constant (or externally provided) control input for the interval, shape
(control_len,).os0 (
Orbital_State) – Orbital state at the interval start.os1 (
Orbital_State) – Orbital state at the interval end.
- Returns:
State derivative \(\dot{\mathbf{x}}\), shape
(state_len,).- Return type:
numpy.ndarray
- gen_dist_off(ind=None)[source]¶
Turn off general disturbances.
General disturbances correspond to
General_Disturbance.- Parameters:
ind (int | None) – Optional index to toggle only one disturbance instance.
- Returns:
None.- Return type:
None
- gen_dist_on(ind=None)[source]¶
Turn on general disturbances.
General disturbances correspond to
General_Disturbance.- Parameters:
ind (int | None) – Optional index to toggle only one disturbance instance.
- Returns:
None.- Return type:
None
- gyro_readings(x, os)[source]¶
Return readings from all gyroscopes.
Filters
self.attitude_sensorsbyGyroand returnssensor.reading(x, os)for each.- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).os (
Orbital_State) – Orbital/environmental state.
- Returns:
List of gyro measurement arrays (typically angular rate, rad/s).
- Return type:
list[numpy.ndarray]
- mtm_readings(x, os)[source]¶
Return readings from all magnetometers.
Filters
self.attitude_sensorsbyMTM.- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).os (
Orbital_State) – Orbital/environmental state.
- Returns:
List of magnetometer measurement arrays (typically magnetic field, T).
- Return type:
list[numpy.ndarray]
- noiseless_RW_readings(x, os)[source]¶
Return noiseless reaction wheel momentum measurements.
Delegates to each wheel’s
measure_momentum_noiseless()(implementation-specific).- Parameters:
x (numpy.ndarray) – Current state vector (unused by some wheel models but included for interface consistency).
os (
Orbital_State) – Orbital/environmental state (unused by some wheel models but included for interface consistency).
- Returns:
List of per-wheel measurement arrays.
- Return type:
list[numpy.ndarray]
- noiseless_rk4(x, u, dt, orbital_state0, orbital_state1, verbose=False, mid_orbital_state=None, quat_as_vec=True, give_err_est=False)[source]¶
Propagate the state forward one step using RK4 (and optional embedded error estimate).
Quaternion components are normalized at each substep to avoid drift.
RK4 update
\[\begin{split}\begin{aligned} \mathbf{k}_1 &= f(\mathbf{x}_n,\mathbf{u},\mathrm{os}_0) \\ \mathbf{k}_2 &= f(\mathbf{x}_n+\tfrac{dt}{2}\mathbf{k}_1,\mathbf{u},\mathrm{os}_{1/2}) \\ \mathbf{k}_3 &= f(\mathbf{x}_n+\tfrac{dt}{2}\mathbf{k}_2,\mathbf{u},\mathrm{os}_{1/2}) \\ \mathbf{k}_4 &= f(\mathbf{x}_n+dt\,\mathbf{k}_3,\mathbf{u},\mathrm{os}_1) \\ \mathbf{x}_{n+1} &= \mathbf{x}_n + \tfrac{dt}{6}\left(\mathbf{k}_1 + 2\mathbf{k}_2 + 2\mathbf{k}_3 + \mathbf{k}_4\right) \end{aligned}\end{split}\]where \(\mathrm{os}_{1/2}\) is the midpoint orbital state; if not provided it is computed via
average().Embedded error estimate (optional)
When
give_err_est=True, a third-order embedded estimate \(\mathbf{x}^{(3)}_{n+1}\) is computed, and the elementwise difference is returned as a local truncation error proxy.Noise/bias behavior
This routine enforces a deterministic propagation by using an
ErrorModewith all noise/bias additions disabled.- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).u (numpy.ndarray) – Control vector, shape
(control_len,).dt (float) – Integration time step (s).
orbital_state0 (
Orbital_State) – Orbital state at the start of the step.orbital_state1 (
Orbital_State) – Orbital state at the end of the step.verbose (bool) – If
True, prints intermediate RK stages.mid_orbital_state (
Orbital_State| None) – Optional precomputed midpoint orbital state.quat_as_vec (bool) – If
True, propagate quaternions using RK4 on the quaternion components with normalization. IfFalse, use a commutator-free Lie group method (CG5) for quaternion propagation.give_err_est (bool) – If
True, return(x_next, err_est)using an embedded lower-order estimate.
- Returns:
Next state, or
(next_state, error_estimate)ifgive_err_est=True.- Return type:
numpy.ndarray | tuple[numpy.ndarray, numpy.ndarray]
- Raises:
ValueError – If
give_err_est=Truewhile using the CG5 quaternion propagation variant.
- noiseless_sensor_readings(x, os)[source]¶
Compute sensor readings with noise disabled (bias may be included but not updated).
Uses an
ErrorModeconfigured as:add_bias = True
add_noise = False
update_bias = False
update_noise = False
This is useful for deterministic filtering tests where bias is treated as a fixed offset.
- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).os (
Orbital_State) – Orbital/environmental state.
- Returns:
Concatenated measurement vector.
- Return type:
numpy.ndarray
- prop_dist_off(ind=None)[source]¶
Turn off propulsion disturbances.
Propulsion disturbances correspond to
Prop_Disturbance.- Parameters:
ind (int | None) – Optional index to toggle only one disturbance instance.
- Returns:
None.- Return type:
None
- prop_dist_on(ind=None)[source]¶
Turn on propulsion disturbances.
Propulsion disturbances correspond to
Prop_Disturbance.- Parameters:
ind (int | None) – Optional index to toggle only one disturbance instance.
- Returns:
None.- Return type:
None
- sensor_readings(x, os, dmode=None)[source]¶
Compute concatenated sensor readings (attitude sensors + wheel momentum measurements).
Readings are collected from all non-GPS sensors in
self.attitude_sensorsand appended with reaction wheel momentum measurements from eachRW.Let \(\mathbf{y}\) denote the stacked measurement vector:
\[\begin{split}\mathbf{y} = \begin{bmatrix} \mathbf{y}_1 \\ \vdots \\ \mathbf{y}_{N_s} \\ \hat{\mathbf{h}}_{RW} \end{bmatrix},\end{split}\]where each \(\mathbf{y}_i\) is a sensor-specific output (possibly vector-valued).
- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).os (
Orbital_State) – Orbital/environmental state.dmode (
ErrorMode| None) – Error/noise mode controlling sensor noise/bias injection.
- Returns:
Concatenated measurement vector.
- Return type:
numpy.ndarray
- specific_dist_off(ind)[source]¶
Turn off a specific disturbance model by index.
- Parameters:
ind (int) – Index into
self.disturbances.- Returns:
None.- Return type:
None
- Raises:
IndexError – If
indis out of range.
- specific_dist_on(ind)[source]¶
Turn on a specific disturbance model by index.
- Parameters:
ind (int) – Index into
self.disturbances.- Returns:
None.- Return type:
None
- Raises:
IndexError – If
indis out of range.
- srp_dist_off()[source]¶
Turn off all Solar Radiation Pressure disturbances.
Equivalent to calling:
self._toggle_disturbance(SRP_Disturbance, on=False)
- Returns:
None.- Return type:
None
- srp_dist_on()[source]¶
Turn on all Solar Radiation Pressure disturbances.
Equivalent to calling:
self._toggle_disturbance(SRP_Disturbance, on=True)
- Returns:
None.- Return type:
None
- sunpair_readings(x, os)[source]¶
Return readings from all sun-pair sensors.
Filters
self.attitude_sensorsbySunPair.- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).os (
Orbital_State) – Orbital/environmental state.
- Returns:
List of sun-pair measurement arrays (model-specific shapes).
- Return type:
list[numpy.ndarray]
- sunsensor_readings(x, os)[source]¶
Return readings from all sun sensors.
Filters
self.attitude_sensorsbySunSensor.- Parameters:
x (numpy.ndarray) – Current state vector, shape
(state_len,).os (
Orbital_State) – Orbital/environmental state.
- Returns:
List of sun sensor measurement arrays (model-specific shapes).
- Return type:
list[numpy.ndarray]
- update_J(J_0=None, COM=None)[source]¶
Update inertia matrices and cached inverses.
This method validates the inertia tensor, enforces symmetry, checks positive definiteness, shifts the inertia to the center of mass, and computes additional derived inertias.
Validation
The inertia is required to be real, symmetric, and positive definite:
\[\mathbf{J} = \mathbf{J}^\top,\qquad \lambda_i(\mathbf{J})>0.\]Parallel axis theorem
If \(\mathbf{J}_0\) is about the reference origin and \(\mathbf{r}_{COM}\) is the COM offset, then
\[\mathbf{J}_{COM} \;=\; \mathbf{J}_0 \;-\; m\left(\|\mathbf{r}_{COM}\|^2\mathbf{I} - \mathbf{r}_{COM}\mathbf{r}_{COM}^\top\right).\]Excluding reaction wheel inertia
If wheels are present, the bus-only inertia is approximated by subtracting wheel spin-axis contributions:
\[\mathbf{J}_{noRW} \;=\; \mathbf{J}_{COM} \;-\; \sum_{k=1}^{n_{RW}} J_{RW,k}\,\hat{\mathbf{a}}_k \hat{\mathbf{a}}_k^\top,\]where \(J_{RW,k}\) and \(\hat{\mathbf{a}}_k\) are the wheel rotor inertia and spin axis.
Cached inverses are computed for efficient dynamics evaluation.
- Parameters:
J_0 (numpy.ndarray | None) – Inertia tensor about the reference origin, shape
(3,3). IfNone, usesself.J_0.COM (numpy.ndarray | None) – Center of mass offset, shape
(3,). IfNone, usesself.COM.
- Returns:
None.- Return type:
None
- Raises:
ValueError – If
J_0cannot be reshaped to(3,3), contains non-real values, is not symmetric within tolerance, or is not positive definite.
- update_RWhs(state_or_RWhs)[source]¶
Update stored wheel momentum values in each
RW.If
state_or_RWhshas lengthself.state_len, it is interpreted as the full state \(\mathbf{x}\) and wheel momenta are extracted viaRWhs_from_state(). Otherwise, it is interpreted as the wheel momentum vector directly.- Parameters:
state_or_RWhs (numpy.ndarray) – Either full state vector (shape
(state_len,)) or wheel momenta (shape(number_RW,)).- Returns:
None.- Return type:
None
- Raises:
ValueError – If the inferred wheel momentum vector length does not equal
self.number_RW.
- class ADCS.helpers.simresults.SimulationResults(runs: 'List[RunResults]', configs: 'Optional[List[Dict[str, Any]]]' = None, run_ids: 'Optional[List[int]]' = None)[source]¶
Bases:
object- Parameters:
runs (List[RunResults])
configs (List[Dict[str, Any]] | None)
run_ids (List[int] | None)
- property est_satellite: EstimatedSatellite | None¶
- run_ids: List[int] | None = None¶
- runs: List[RunResults]¶
- class ADCS.helpers.simresults.datetime(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])¶
Bases:
dateThe year, month and day arguments are required. tzinfo may be None, or an instance of a tzinfo subclass. The remaining arguments may be ints.
- classmethod combine()¶
date, time -> datetime with same date and time fields
- classmethod fromisoformat()¶
string -> datetime from a string in most ISO 8601 formats
- classmethod fromtimestamp()¶
timestamp[, tz] -> tz’s local time from POSIX timestamp.
- classmethod now(tz=None)¶
Returns new datetime object representing current time local to tz.
- tz
Timezone object.
If no tz is specified, uses local timezone.
- classmethod strptime()¶
string, format -> new datetime parsed from a string (like time.strptime()).
- classmethod utcfromtimestamp()¶
Construct a naive UTC datetime from a POSIX timestamp.
- classmethod utcnow()¶
Return a new datetime representing UTC day and time.
- astimezone()¶
tz -> convert to local time in new timezone tz
- ctime()¶
Return ctime() style string.
- date()¶
Return date object with same year, month and day.
- dst()¶
Return self.tzinfo.dst(self).
- isoformat()¶
[sep] -> string in ISO 8601 format, YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM]. sep is used to separate the year from the time, and defaults to ‘T’. The optional argument timespec specifies the number of additional terms of the time to include. Valid options are ‘auto’, ‘hours’, ‘minutes’, ‘seconds’, ‘milliseconds’ and ‘microseconds’.
- replace()¶
Return datetime with new specified fields.
- time()¶
Return time object with same time but with tzinfo=None.
- timestamp()¶
Return POSIX timestamp as float.
- timetuple()¶
Return time tuple, compatible with time.localtime().
- timetz()¶
Return time object with same time and tzinfo.
- tzname()¶
Return self.tzinfo.tzname(self).
- utcoffset()¶
Return self.tzinfo.utcoffset(self).
- utctimetuple()¶
Return UTC time tuple, compatible with time.localtime().
- fold¶
- hour¶
- max = datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)¶
- microsecond¶
- min = datetime.datetime(1, 1, 1, 0, 0)¶
- minute¶
- resolution = datetime.timedelta(microseconds=1)¶
- second¶
- tzinfo¶
- ADCS.helpers.simresults.dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False)[source]¶
Add dunder methods based on the fields defined in the class.
Examines PEP 526 __annotations__ to determine fields.
If init is true, an __init__() method is added to the class. If repr is true, a __repr__() method is added. If order is true, rich comparison dunder methods are added. If unsafe_hash is true, a __hash__() method is added. If frozen is true, fields may not be assigned to after instance creation. If match_args is true, the __match_args__ tuple is added. If kw_only is true, then by default all fields are keyword-only. If slots is true, a new class with a __slots__ attribute is returned.