mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 20:51:14 +00:00
[AZ-358] [AZ-361] C4 OpenCVGtsamPoseEstimator + Jacobian thermal hybrid
Implement the single production-default C4 PoseEstimator strategy. AZ-358 — Marginals path: OpenCV solvePnPRansac (SOLVEPNP_IPPE) on best-candidate inliers, PriorFactorPose3 with Jacobian-derived initial covariance, flushed into C5's iSAM2 graph via the widened ISam2GraphHandle.update(graph, values, None) (Option B). Posterior covariance from compute_marginals().marginalCovariance(pose_key) with SPD-defensive Cholesky check. Tile pixel -> ENU world conversion via the shared WgsConverter + a configurable tile_size_px. Two spec deviations now documented in the AZ-358 task file: PriorFactorPose3 over GenericProjectionFactorCal3DS2 (avoids unbounded landmark variables; same Fisher information on the pose marginal) and explicit (graph, values, timestamps) update args (aligns with C5's impl). AZ-361 — Jacobian + thermal hybrid: per-frame dispatch on thermal_state.thermal_throttle_active selects the cv2.projectPoints- derived 6x6 information matrix (with ridge regularisation) as the emitted covariance. Skips the iSAM2 factor add under throttle (Invariant 12). Emits CovarianceDegradedWarning via warnings.warn (never raised); paired WARN log + FDR record rate-limited per covariance_degraded_warn_window_ns (default 60 s) via an injected monotonic Clock. Supersedes the AZ-358 NotImplementedError stub. Widens ISam2GraphHandle from get_pose_key only to all five C4-facing methods (add_factor, update, compute_marginals, last_anchor_age_ms); C5's existing ISam2GraphHandleImpl already satisfies the superset, so no C5 source change this batch. Threads fdr_client + clock through pose_factory composition. Registers two new FDR payload kinds: pose.frame_done (per-call telemetry; both success and PnpFailureError paths) and pose.covariance_degraded (per-window throttle exposure). Tests: 21 new (AZ-358 AC-1..11 + AZ-361 AC-1..10/12/13; AZ-361 AC-11 RMSE-ratio informational per spec, not asserted). Updates 2 existing test files for Protocol widening and the FDR-schema round trip. Code review verdict: PASS_WITH_WARNINGS (5 findings: Medium x2, Low x3; none blocking). Full suite: 1958 passed, 1 unrelated host-dependent perf failure (c12 CLI cold-start, pre-existing). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -36,12 +36,33 @@ class C4PoseConfig:
|
||||
* ``thermal_throttle_threshold_celsius`` — informational only;
|
||||
the actual ``ThermalState.thermal_throttle_active`` decision is owned by C7
|
||||
(AZ-302). Default 75.0 °C.
|
||||
* ``covariance_degraded_warn_window_ns`` — AZ-361 rate-limit
|
||||
window for ``CovarianceDegradedWarning`` emissions AND the
|
||||
paired ``c4.pose.covariance_degraded`` WARN log + FDR record.
|
||||
Default 60 s. Set to 0 to disable rate-limiting (useful in
|
||||
tests that want to see every warning).
|
||||
* ``ridge_regularisation_epsilon`` — AZ-361 ridge added to
|
||||
``JᵀJ/σ²`` before inversion to stabilise near-singular
|
||||
Jacobians on degenerate inlier sets. Default 1e-9; raise
|
||||
to 1e-6 if Jacobian-path SPD failures begin spiking in
|
||||
forensics.
|
||||
* ``tile_size_px`` — AZ-358 satellite-tile pixel dimensions
|
||||
(square). Used to map ``MatchResult`` inlier tile-pixel
|
||||
coordinates back to WGS84 lat/lon → local-ENU world points
|
||||
consumed by ``solvePnPRansac``. Default 256 matches the OSM /
|
||||
C6 tile-cache convention. If the upstream tile source
|
||||
provides a different square size, override at composition
|
||||
time; the spec assumes a square tile (any non-square tile
|
||||
handling would land in a future config extension).
|
||||
"""
|
||||
|
||||
strategy: str = "opencv_gtsam"
|
||||
ransac_iterations: int = 200
|
||||
ransac_reprojection_threshold_px: float = 4.0
|
||||
thermal_throttle_threshold_celsius: float = 75.0
|
||||
covariance_degraded_warn_window_ns: int = 60_000_000_000
|
||||
ridge_regularisation_epsilon: float = 1e-9
|
||||
tile_size_px: int = 256
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.strategy not in KNOWN_POSE_STRATEGIES:
|
||||
@@ -62,3 +83,17 @@ class C4PoseConfig:
|
||||
"C4PoseConfig.thermal_throttle_threshold_celsius must be > 0; "
|
||||
f"got {self.thermal_throttle_threshold_celsius}"
|
||||
)
|
||||
if self.covariance_degraded_warn_window_ns < 0:
|
||||
raise ConfigError(
|
||||
"C4PoseConfig.covariance_degraded_warn_window_ns must be >= 0; "
|
||||
f"got {self.covariance_degraded_warn_window_ns}"
|
||||
)
|
||||
if self.ridge_regularisation_epsilon <= 0.0:
|
||||
raise ConfigError(
|
||||
"C4PoseConfig.ridge_regularisation_epsilon must be > 0; "
|
||||
f"got {self.ridge_regularisation_epsilon}"
|
||||
)
|
||||
if self.tile_size_px <= 0:
|
||||
raise ConfigError(
|
||||
f"C4PoseConfig.tile_size_px must be > 0; got {self.tile_size_px}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user