Ring Edge Fit (RingEdgeNav)

Overview

RingEdgeNav recovers a single translation from one or more ring-edge polylines by aligning each polyline against the image’s edge-distance-transform. The technique consumes every offered RING_EDGE feature, weights its vertices by the prior precision derived from the per-edge sigma, and runs the same coarse-NCC plus Tukey-reweighted Levenberg-Marquardt refinement that DT Fitting (Shared Polyline-vs-Image Fitter) describes.

When every consumed ring edge is flagged straight-line the combined Jacobian is rank- deficient — all parallel ring edges share a single ring-plane normal so the along-edge axis is unobservable. The returned covariance is honestly rank-1 in that case; the orchestrator’s ensemble combine fuses it with any orthogonal-axis result (a star, body limb, body blob) before declaring a final answer.

Feasibility passes when at least one offered RING_EDGE has a non-empty polyline. A single non-empty edge is sufficient — even an all-flat scene produces a useful rank-1 constraint. Feasibility fails when every offered RING_EDGE is empty (a ring system entirely outside the extended FOV or below the per-pixel resolution threshold).

Theory

The technique fits a per-image translation by minimising the weighted squared distance from the model ring-edge polylines to the image edges, exactly as the limb fit does — see DT Fitting (Shared Polyline-vs-Image Fitter) for the cost function, the LM mechanics, the polarity filter, and the Tukey biweight.

Rank-deficient covariance

Ring edges differ from limbs in that each ring edge is only locally observable along its radial direction (orthogonal to the edge tangent). Motion along the tangent of a single ring edge produces no DT cost change. When a single ring edge dominates the consumed set, the joint Jacobian’s null space is the along-edge tangent and the M-estimator information matrix is rank-1. The Moore-Penrose pseudoinverse used by information_matrix_to_covariance() handles this gracefully — the returned 2x2 covariance has an effectively-infinite eigenvalue along the tangent direction.

Multi-edge inputs at different orbital radii share the same ring-plane normal but sample different points around the projected ring; the joint information matrix becomes full-rank when at least two non-parallel edges contribute. The technique reports an is_rank_1 flag that the curator surfaces; downstream consumers (the ensemble combine, the operator’s per-image log) can distinguish a rank-1 ring-edge result from a full-rank one.

Restrictions and assumptions

  • The orchestrator must populate image_edge_dt_ext and image_gradient_vu_ext; in their absence the technique cannot evaluate the cost.

  • Per-vertex normals supplied by the upstream rings model are oriented so that the image gradient should point from outside the ring system inward at a bright ring edge against a dark background. Polarity-rejected vertices contribute a near-infinite synthetic residual so the Tukey biweight zeroes their weight on the first reweighting.

  • Ring edges that have collapsed to a sub-pixel radial extent are emitted by the upstream model as RING_ANNULUS templates instead, so the technique never sees them. See Ring Annulus Correlate (RingAnnulusNav).

  • The fit assumes the per-image SPICE pose is good enough that the integer NCC seed lands in the basin of attraction of the correct ring edge. When the SPICE pointing error exceeds the per-instrument search-window margin the seed lands on a wrong edge and the LM converges to a wrong local minimum.

Sources of uncertainty

The reported covariance is the Moore-Penrose pseudoinverse of the M-estimator information matrix at convergence; the rank-1 case carries an unbounded eigenvalue along the tangent direction. When the converged offset sits within the at-edge tolerance of any axis bound, or when the rotation parameter is at the configured fraction of its cap, the result is flagged at_edge.

Configuration

All numeric tunables for this technique live in techniques.RingEdgeNav.tuning in src/nav/config_files/config_510_techniques.yaml.

  • at_edge_tolerance_px — float, default 1.0 px. A converged offset whose absolute distance from any search-window axis bound falls within this tolerance is flagged at_edge. Matches the bilinear-DT half-cell width.

  • spurious_dt_rms_factor — float, default 5.0 (dimensionless). Final DT residual exceeding this many radial-sigmas marks the result spurious.

  • spurious_dt_floor_px — float, default 3.0 px. Floor of the spurious-detection threshold; the threshold is the larger of the floor and the per-feature sigma multiple.

  • spurious_min_inliers — int, default 6 (count). Below this Tukey-inlier count the M-estimator covariance is uninformative; the result is flagged spurious.

  • rotation_at_edge_fraction — float, default 0.95 (dimensionless). When fit_camera_rotation is true, the converged rotation magnitude trips at_edge once it crosses this fraction of the per-image max_rotation_deg cap.

Per-instrument overrides

The five keys above are global; per-instrument YAML files in src/nav/config_files/config_4N0_inst_*.yaml do not override any of them.

Confidence formula

The technique reports a calibrated confidence in \([0, 1]\) produced by the shared sigmoid combination; see Confidence Calibration (Shared Sigmoid-of-Linear Combination). The formula spec is techniques.RingEdgeNav and consumes attributes off RingEdgeDiagnostics plus at_edge.

  • total_edge_length_px — alpha = 1.0, offset = 0.0, divisor = 200.0, cap at 1.0. Cumulative pixel length of all surviving ring-edge polylines. More polyline earns confidence up to a 200-pixel saturation point.

  • per_edge_dt_rms_summed — alpha = -2.0, offset = 0.0, divisor = 1.0, no cap. Sum of per-edge final DT RMS values. Larger residuals pull confidence down.

Hard-zero gate: at_edge firing forces confidence to zero. The constant baseline is \(\alpha_{0} = -1.0\). No post-sigmoid hard_cap is applied.

Implementation

Source files:

Public class RingEdgeNav, base NavTechnique. Self-registers via __init_subclass__.

Class attributes:

Public methods (autodocumented at nav.nav_technique): is_feasible() and navigate().

Diagnostics

RingEdgeDiagnostics:

  • total_edge_length_px — cumulative pixel length of all surviving ring-edge polylines. Consumed by the confidence formula.

  • per_edge_dt_rms_summed — sum of per-edge final DT RMS values. Consumed by the confidence formula.

  • edge_count — number of RING_EDGE features fused.

  • is_rank_1 — True when every consumed ring-edge feature was straight-line and the combined covariance is rank-1.

Call path

Call path traced through navigate():

  1. Open a logged section. Fail fast (RuntimeError) if either image_edge_dt_ext or image_gradient_vu_ext is missing.

  2. Filter the offered features to RING_EDGE entries with non-empty polylines and concatenate the per-feature vertex / normal / sigma arrays.

  3. Build the binary polyline mask and pull the search-window margin off the observation via search_window_for_obs(). Run coarse_ncc_search() for the integer seed.

  4. Read fit_camera_rotation and set the rotation pivot to the centroid of the concatenated vertices when rotation is fit.

  5. Call lm_subpixel_refine() and capture the converged LMRefineResult.

  6. Detect the rank-1 condition: every consumed RING_EDGE flagged is_straight_line collapses the joint Jacobian to rank-1. The flag is recorded in is_rank_1 so downstream consumers can branch on it.

  7. Result-shape branches on fit_camera_rotation:

    • No rotation fit. covariance_px2 is the (2, 2) translation block returned by lm_subpixel_refine() (rank-1 when every edge is straight; full-rank otherwise).

    • Rotation fit. covariance_px2 is the (3, 3) translation + rotation information matrix.

  8. Apply the at-edge tests and the spurious tests on RMS / inlier-count.

  9. Build a RingEdgeDiagnostics, evaluate the confidence spec, log the breakdown, and assemble the NavTechniqueResult.

Examples

ring_only_curved (Cassini ISS NAC, image N1447064164_1)

A curved Saturn-ring scene with no body in FOV. The rings model emits multiple RING_EDGE polylines (the F ring, the A-ring outer edge, etc.) at different orbital radii; the curvature gives the joint Jacobian non-degenerate column rank. RingEdgeNav converges to a 2-D translation against the operator-verified offset \((\Delta v, \Delta u) = (5.85, 3.55)\) px. The is_rank_1 flag is False on this scene (the curvature lifts the rank-deficiency) and the orchestrator’s ensemble combine fuses the result without needing an orthogonal-axis cross-check.

ring_only_curved (Cassini ISS NAC, image N1492091163_1)

A high-curvature single-edge scene with no other ring features in the FOV. The rings model emits one RING_EDGE polyline whose curvature lifts the rank-1 degeneracy. RingEdgeNav converges to \((\Delta v, \Delta u) \approx (5.00, -25.00)\) px against an operator-verified ground truth of (4.92, -24.32) px — sub-pixel agreement on a single curved edge. The technique reports a sub-pixel final DT residual; the is_rank_1 flag is False because the per-edge curvature exceeds FLAT_CURVATURE_THRESHOLD_PX.

ring_only_flat (Saturn ansa scene class, no body in FOV)

An edge-on or extreme-grazing ring view in which every surviving polyline is flagged is_straight_line. The joint-Jacobian column rank collapses to 1 along the shared radial direction; the technique returns the rank-1 pseudo-inverse covariance described in the Theory section, sets is_rank_1 True, and reports a calibrated confidence drawn down by the missing along-edge constraint. The orchestrator’s ensemble combine treats the result as a one-axis observation and relies on a cross-feature (a body limb arc, a star prediction) to constrain the orthogonal axis. When no cross-feature is available the orchestrator surfaces the rank-1 result with confidence capped by the rank-1 confidence formula.