ADCS.estimators.attitude_estimators.attitude_UKF module¶
1. Construct the non-augmented tangent-state filter
The UKF estimates only the physical state. Its nominal quaternion remains a four-element unit quaternion, while the uncertainty is represented in the right tangent coordinates
Process, sensor-bias, actuator-bias, and disturbance variables are not
appended to the sigma-point state. When actuator input noise is nonzero,
its non-perfect command channels are appended only for prediction. The
covariance is owned by
Covariance in tangent coordinates. The chart is
selected by quaternion_mode and is quaternion_vector by default.
super().__init__(
satellite, state, dt=dt,
covariance_coordinates="tangent",
correction_mode=quaternion_mode,
measurement_quaternion_mode=quaternion_mode,
...,
)
2. Generate tangent sigma points and weights
For covariance dimension \(n=6+n_h\), define
With \(\mathbf{S}\) such that \(\mathbf{P}=\mathbf{S}^T\mathbf{S}\), the sigma offsets are
The mean and covariance weights are
points, offsets, mean_weights, covariance_weights = self._sigma_states(
prior
)
3. Propagate sigma points and form the prediction
Each sigma state is propagated through the nonlinear spacecraft model. If actuator input noise is configured, control-noise sigma points use a perturbed command; otherwise every point uses the nominal control:
There is no state Jacobian in this step. The nonlinear model is evaluated at every sigma point, and model-generated plus caller-supplied discrete additive process noise is added after the propagated-point statistics have been formed.
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 state mean and predicted covariance.
The predicted mean is the weighted manifold mean, found by a safeguarded Newton solve until the weighted chart residual vanishes. Solver steps use rotation vectors, while residuals and covariance retain the selected chart:
The sigma deviations and discretized process noise then give
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
The active sources are selected first. Each state sigma point is then passed through the measurement models:
Additive measurements use a weighted Euclidean mean. Quaternion measurements use the same right-error manifold mean as the state:
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.
The UKF forms measurement deviations in the residual coordinates and state deviations in the tangent coordinates:
This is the unscented equivalent of constructing a measurement Jacobian; the UKF does not calculate an explicit \(\mathbf{H}\).
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 unscented gain and correction
The Covariance operation
updated_unscented() solves the measurement
covariance and cross-covariance system:
The posterior covariance before moving the tangent origin is the weighted state covariance returned by the same operation.
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 nominal state and reset the covariance
The correction is applied in the selected right-error chart:
Since the local tangent origin has moved, the posterior covariance is transported by the chart-specific reset Jacobian:
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_UKF.UKF(satellite, state, *, dt, unmodeled_dynamics_psd=0.0, quaternion_mode='quaternion_vector', alpha=1.0, beta=2.0, kappa=0.0)[source]¶
Bases:
AttitudeEstimatorRight-error unscented Kalman attitude estimator.
Sigma points always span the tangent state covariance. When an actuator has nonzero input-noise covariance, prediction additionally augments the sigma points with that actuator-input error and propagates each point with
control + control_error. Perfect actuator channels are omitted from the augmented dimension. Continuous state/process noise remains additive after propagation, as do measurement-noise covariances.Attitude means solve for a zero weighted residual in the selected chart, using bounded rotation-vector Newton steps and backtracking. Charts still describe local distributions: Cayley is singular at 180 degrees, and a broad or multimodal attitude prior need not have a unique local mean. Chart-coordinate variances are not interchangeable between modes (only
quaternion_vectorandrotation_vectoragree to first order in radians).- Parameters:
satellite (Any)
state (EstimatorState)
dt (float)
unmodeled_dynamics_psd (Any)
quaternion_mode (str)
alpha (float)
beta (float)
kappa (float)
- correct(measurements, orbital_state, *, enabled=None, time_s=None, epoch_s=0.0)[source]¶
Apply the unscented measurement update.
- Parameters:
measurements (Any)
orbital_state (Any)
enabled (Any | None)
time_s (float | None)
epoch_s (float)
- Return type:
- predict(control, orbital_state_start, orbital_state_end, *, dt=None, midpoint_orbital_state=None)[source]¶
Propagate tangent-state sigma points and add discretized process noise.
- Parameters:
control (Any)
orbital_state_start (Any)
orbital_state_end (Any)
dt (float | None)
midpoint_orbital_state (Any | None)
- Return type: