ADCS.estimators.attitude_estimators.attitude_SRUKF module¶
1. Construct the square-root tangent-state filter
SRUKF uses the same physical state, right tangent attitude error, and
automatic actuator-noise prediction augmentation as
UKF:
The defining difference is the covariance representation. Instead of
storing \(\mathbf{P}\) directly, Covariance
stores an upper factor \(\mathbf{S}\) such that
The constructor converts both the state covariance and process-noise
covariance to form="sqrt" before entering the shared UKF lifecycle.
result = state.copy()
result.covariance = state.covariance.copy(form="sqrt")
result.process_noise = state.process_noise.copy(form="sqrt")
super().__init__(
satellite, result, dt=dt,
quaternion_mode=quaternion_mode,
alpha=alpha, beta=beta, kappa=kappa,
...,
)
2. Generate tangent sigma points from the square-root factor
For tangent dimension \(n=6+n_h\),
The sigma offsets are rows of the upper factor:
The mean and covariance weights are the standard unscented weights. No square-root factor is expanded into a full covariance to generate points.
points, offsets, mean_weights, covariance_weights = self._sigma_states(
prior
)
3. Propagate sigma points and form the prediction
Each sigma point is independently propagated:
As in the UKF, process noise is constructed separately and added after the propagated sigma-point deviations have been computed.
propagated_points = [
propagate_state(
point, self.satellite, control, step,
orbital_state_start, orbital_state_end,
midpoint_orbital_state=midpoint_orbital_state,
)
for point in points
]
After propagation, compute the manifold mean and square-root predicted covariance.
The predicted state is the weighted manifold mean:
With \(\mathbf{d}_{i,k}^x\) denoting the local sigma deviations, the covariance is mathematically
In SRUKF, Covariance forms its upper factor using
QR factorization and rank updates/downdates, preserving
\(\mathbf{P}=\mathbf{S}^T\mathbf{S}\) as the public representation.
predicted = self._state_mean(propagated_points, mean_weights)
transition, process_noise = discretize_process_noise(
prior, self.satellite, control, orbital_state_start, step,
final_state=predicted,
quaternion_mode=self.correction_mode,
quaternion_order="right",
unmodeled_dynamics_psd=self.unmodeled_dynamics_psd,
)
deviations = np.vstack([
point.minus(predicted,
quaternion_mode=self.correction_mode,
quaternion_order="right")
for point in propagated_points
])
predicted.covariance = prior.covariance.predicted_unscented(
deviations, covariance_weights, process_noise
)
4. Predict measurements and form their statistics
Active sigma points are passed through the measurement stack:
Additive measurements use a weighted Euclidean mean. Quaternion measurements use a weighted right-error manifold mean in the selected three-parameter chart:
sigma_measurements = [
stack.predict(point, orbital_state, active_mask=active)
for point in points
]
predicted_measurement = self._measurement_mean(
stack, sigma_measurements, active, mean_weights
)
Then form \(\mathbf{P}_{zz}\) and \(\mathbf{P}_{xz}\) from the measurement and state deviations.
Measurement deviations are expressed in residual coordinates and state deviations in tangent coordinates:
The square-root form computes the measurement covariance using QR and weighted Cholesky updates where needed; no measurement Jacobian is formed.
measurement_deviations = np.vstack([
stack.residual(
measurement, predicted_measurement, active,
quaternion_mode=self.measurement_quaternion_mode,
)
for measurement in sigma_measurements
])
measurement_noise = stack.covariance(
prior, active,
quaternion_mode=self.measurement_quaternion_mode,
)
5. Compute the square-root unscented gain and correction
The gain is obtained from the weighted cross-covariance and measurement covariance:
updated_unscented solves with the stored square-root representation and
returns the posterior covariance in square-root form.
gain, posterior_covariance = prior.covariance.updated_unscented(
state_deviations,
measurement_deviations,
covariance_weights,
measurement_noise,
)
innovation = stack.residual(
measurements, predicted_measurement, active,
quaternion_mode=self.measurement_quaternion_mode,
)
correction = gain @ innovation
6. Retract the state and preserve square-root covariance storage
The tangent correction is applied as a right multiplicative quaternion update:
The posterior covariance is transported to the new tangent origin. Because the input covariance is square-root form, the transformed result preserves the upper-factor representation:
corrected = prior.plus(
correction,
quaternion_mode=self.correction_mode,
quaternion_order="right",
)
corrected.covariance = prior.transport_covariance(
posterior_covariance,
correction,
quaternion_mode=self.correction_mode,
quaternion_order="right",
)
- class ADCS.estimators.attitude_estimators.attitude_SRUKF.SRUKF(satellite, state, *, dt, unmodeled_dynamics_psd=0.0, quaternion_mode='quaternion_vector', alpha=1.0, beta=2.0, kappa=0.0)[source]¶
Bases:
UKFUKF with square-root covariance storage.
This filter uses the same tangent-state and automatic control-noise sigma points, manifold means, and additive process and measurement noise as
UKF. Its covariance is always retained inCovariance(form="sqrt")form, so the shared unscented covariance operations use square-root QR factorizations and Cholesky updates/downdates.- Parameters:
satellite (Any)
state (EstimatorState)
dt (float)
unmodeled_dynamics_psd (Any)
quaternion_mode (str)
alpha (float)
beta (float)
kappa (float)
- reset(state)[source]¶
Reset while preserving square-root covariance storage.
- Parameters:
state (EstimatorState)
- Return type: