Body Disc Correlate (BodyDiscCorrelateNav)

Overview

BodyDiscCorrelateNav recovers a single translation by full-disc normalised cross-correlation against a composite template fused from every offered BODY_DISC feature. Per-body templates are Z-buffer painted into a single postage stamp (the closer body’s pixels overwrite the farther body’s), the result is run through the shared pyramid-NCC machinery in nav.support.correlate, and the chosen peak is returned with a Cramer-Rao-lower-bound covariance derived from the local correlation curvature. Multi-body composites improve the peak’s signal-to-noise as roughly \(\sqrt{N}\) for N bodies and remove the “swap moon assignments” mode-failure that plagues per-body solo correlation.

Feasibility passes when at least one offered BODY_DISC feature carries a template payload; feasibility fails when no offered feature has one (a body model that emitted only LIMB_ARC / BODY_BLOB without an accompanying disc).

Theory

The technique fits a per-image translation by maximising the normalised cross-correlation between the composite template and the observed image. It supports an optional in-plane rotation parameter that runs an outer NCC pyramid over a rotation schedule.

Composite template construction

When more than one body emits a BODY_DISC feature, the per-body templates are fused into a single composite by Z-buffer paint: at each pixel covered by more than one body’s bounding box, the closer body’s template value (and the closer body’s mask True) overwrite the farther body’s, so an in-front body occludes an in-behind body in the composite. The fused template carries one combined bounding box, one fused brightness image, and one fused mask; the orchestrator’s compose_template_features() helper does the work.

Cost function

Let \(T\) be the composite template image and \(M\) the composite template mask. Let \(I\) be the observed image (or a mode-selected gradient of it; see below). The technique maximises the normalised cross-correlation

\[\mathrm{NCC}(\Delta v, \Delta u) = \frac{\langle T, I_{\Delta v, \Delta u} \rangle_{M}} {\sqrt{\langle T, T \rangle_{M} \cdot \langle I_{\Delta v, \Delta u}, I_{\Delta v, \Delta u} \rangle_{M}}}\]

over the integer offsets \((\Delta v, \Delta u)\) in the per-instrument search window, where \(\langle \cdot, \cdot \rangle_{M}\) denotes the masked inner product (only pixels where \(M = \mathrm{True}\) contribute). Sub-pixel refinement comes from a localized upsampled-DFT (Guizar-Sicairos) of the cross-power spectrum around the integer peak, reaching a 1/128 px resolution. The refinement is evaluated on the raw-intensity surfaces even when the integer peak was chosen on the gradient surfaces, so a gradient-mode peak does not carry the gradient-magnitude rectification bias (the magnitude rectifies the signal, making the cross-power peak non-smooth at its apex) into the reported offset; the correlation-surface curvature provides the Cramer-Rao lower bound covariance.

Sub-pixel refinement band-limit (refine_lowpass_sigma_px)

Before the cross-power spectrum is formed, the full-resolution refinement low-passes both surfaces – the image and the (already mask-multiplied) template – with a Gaussian of refine_lowpass_sigma_px (default 1.0 px).

Why. The template is an oversampled but otherwise sharp Lambert silhouette, and a real or simulated body has an equally sharp (PSF-aside) limb whose edge profile does not match the template’s. Cross-correlating two sharp surfaces with differing edge profiles aliases the cross-power peak: the high-frequency edge content beats against the sampling grid and shifts the peak by an amount that depends on the sub-pixel phase. The result is an odd S-curve in the recovered offset – zero at integer and half-pixel offsets, growing to a peak near the quarter-pixel – which is per-axis separable (a pure-v offset biases v only). The matched low-pass removes the high-frequency mismatch that drives the aliasing, so the peak lands on the true shift. The localized upsampled DFT still resolves the smoothed peak to 1/128 px, so the band-limit costs no usable resolution.

What happens if you don’t (set it to 0). The disc carries a sub-pixel-phase-dependent residual of roughly ±0.03 px on a single axis, rising to ~0.1 px at the worst two-axis phase, independent of SNR (it is a deterministic correlation artifact, not noise). Because the simulator’s body and the navigator’s template are both sharp, a round-number planted offset (0, 0.5) lands on the bias null and hides it entirely – which is why the per-technique characterization plants an off-grid offset. With the default 1.0 px low-pass the residual drops to ~0.01 px across every sub-pixel phase. The band-limit is applied only to the final full-resolution refine; the coarse pyramid levels keep their sharp surfaces so integer-peak selection is unaffected. It must low-pass the mask-multiplied template, not the bare template – low-passing before the mask multiply lets the hard mask edge re-sharpen the model and makes the bias worse, not better.

Alternative considered and rejected: a render-time PSF. Since the bias comes from sharp edges, an obvious idea is to convolve the simulated body (and, to match, the template) with the instrument point-spread function so the edges are realistically soft. This does not work as a fix. Blurring only the rendered image at the camera’s own ~0.54 px sigma leaves it mismatched against the still-sharp template – a soft image against a sharp template is a worse mismatch than two matched sharp surfaces – and it destabilizes the integer-peak choice at some phases; a larger blur is monotonically worse. It is also the wrong layer: the bias is in the navigator’s correlation, which applies to real PSF-blurred images too, so it must be fixed in the correlator (the band-limit above) rather than in the simulator. The band-limit removes the bias for both simulated and real images and changes neither the rendered image nor the template.

Mode selection (auto / raw / gradient)

The shared NCC pyramid evaluates the correlation in two modes — raw image vs. raw template, and gradient image vs. gradient template — and auto mode runs both and picks whichever peak scores higher quality. Raw mode wins on smooth Lambert-shaded discs that fill the FOV where the per-pixel intensity carries unique-alignment signal; gradient mode wins when only the limb edge carries useful signal (a bright disc on a bright background, an over-exposed or saturated body).

Search strategy

The technique runs the shared pyramid-NCC entry point (navigate_with_pyramid_kpeaks()). At each pyramid level the NCC is evaluated coarse-to-fine, the top k peaks are kept, and consistency is measured between levels — a peak that drifts more than a documented threshold across levels is flagged spurious. The per-image quality metric is the peak-to-side-lobe ratio (PSR) at the finest level; the per-image consistency metric is the maximum Euclidean drift of the chosen peak across pyramid levels.

Rotation-aware schedule

When the per-instrument camera-rotation flag is on, the technique runs the rotation-aware schedule: the template is rotated about the body-centroid pivot at 11 angles spanning \(\pm \mathrm{max\_rotation\_deg}\) at the coarsest pyramid level, the best three rotations advance to a 5-sample refinement at the next level, and the best one advances to a 3-sample fine refinement at the finest level. The (dv, du, theta) triple at the global maximum is returned with a 3x3 covariance whose translation block is the CRLB from the chosen rotation’s correlation curvature. The technique reports its rotation as unobservable: the NCC-peak quality is a PSR/PMR separation ratio rather than a log-likelihood, so it carries no calibrated Fisher information about rotation, and the rotation diagonal holds the ROTATION_UNOBSERVABLE_VARIANCE sentinel. The ensemble’s pinvh combine maps that to a near-zero rotation contribution, so the disc technique constrains translation while abstaining on rotation.

Restrictions and assumptions

  • The orchestrator must populate image_ext and sensor_mask_ext on the per-image context; in their absence the technique cannot evaluate the NCC.

  • The composite template must have non-empty support inside the search window. An empty template (every body off-frame) collapses the NCC to a constant; the spurious gate flags the result.

  • Multi-body composites assume the per-body templates are coherent — the per-body BODY_DISC emission gates upstream (Body Navigation Model) ensure each contributing body has a sharp, high-contrast template.

  • The rotation-aware schedule assumes the rotation pivot is well-defined. When every consumed body has a degenerate centroid (single-pixel bodies) the pivot collapses to the image centre.

Sources of uncertainty

The reported covariance is the Cramer-Rao lower bound from the local NCC curvature at the chosen peak. It captures the noise-limited centroid uncertainty given the template / image power spectra; it does not capture systematic biases introduced by template-vs-image photometric mismatch (a body whose Lambert prediction differs from its true reflectance shifts the peak slightly), nor by the Z-buffer compositing itself when bodies are near-occluding. When the chosen peak 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 and the hard-zero gate forces confidence to zero. The pyramid-consistency check flags peaks that drift across levels as spurious.

Configuration

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

  • 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.

  • consistency_max_fraction_of_diameter / consistency_max_px — floats, defaults 0.025 / 4.0 px. Diameter-scaled and absolute floors on the accepted pyramid-level peak migration; the applied spurious cap is the larger of the two.

  • refine_lowpass_sigma_px — float, default 1.0 px. Gaussian low-pass applied to both surfaces in the full-resolution sub-pixel refine (see “Sub-pixel refinement band-limit”). Removes the sharp-edge cross-power aliasing that otherwise leaves a ~0.03 px (up to ~0.1 px at the worst two-axis phase) sub-pixel-phase S-curve in the recovered offset; 0.0 disables it and restores that bias.

The remaining numeric thresholds (NCC peak quality, consistency tolerance, top-k count) are shared across every pyramid-NCC technique and live as module-level constants in nav.support.correlate; consuming techniques pass overrides at call time when needed.

Per-instrument overrides

The per-instrument YAML files in src/nav/config_files/config_4N0_inst_*.yaml do not override rotation_at_edge_fraction. The search-window margin used by the at-edge test comes from the per-instrument InstrumentSettings.

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.BodyDiscCorrelateNav and consumes attributes off BodyDiscDiagnostics plus at_edge and spurious.

  • ncc_peak — alpha = 1.5, offset = 0.0, divisor = 6.0, cap at 1.0. PSR-style quality measure of the chosen NCC peak. Healthy body-disc fits report quality 6 to 15; the divisor maps that range onto the sigmoid’s responsive interval.

  • consistency_px — alpha = -1.0, offset = 0.0, divisor = 2.0, no cap. Mean per-axis disagreement between coarse-pyramid and full-resolution sub-pixel locations. Low values indicate a globally unambiguous peak.

  • body_count — alpha = 0.4, offset = 0.0, divisor = 3.0, cap at 1.0. Number of BODY_DISC features fused into the composite. More bodies sharpen the joint geometric constraint up to a 3-body saturation.

  • peak_to_runner_up_ratio — alpha = 0.0, offset = 0.0, divisor = 2.0, cap at 1.0. Ratio of the winning peak’s quality to the next-best peak outside the exclusion radius.

Hard-zero gate: at_edge and spurious either firing forces confidence to zero before the sigmoid evaluates. The constant baseline is \(\alpha_{0} = -2.0\). No post-sigmoid hard_cap is applied.

Implementation

Source files:

Public class BodyDiscCorrelateNav, base NavTechnique. Self-registers via __init_subclass__ so NavTechnique._registry discovers it.

Class attributes:

  • name'BodyDiscCorrelateNav'.

  • accepts_feature_typesfrozenset({BODY_DISC}).

  • requires_priorFalse. Runs in pass 1 of the orchestrator’s two-pass pipeline.

  • confidence_attributes{'at_edge', 'spurious', 'ncc_peak', 'peak_to_runner_up_ratio', 'consistency_px', 'used_gradient', 'body_count'}.

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

Diagnostics

BodyDiscDiagnostics:

  • ncc_peak — peak NCC quality at the finest pyramid level. Consumed by the confidence formula.

  • peak_to_runner_up_ratio — ratio of the winning peak’s quality to the next-best peak’s outside the exclusion radius.

  • consistency_px — maximum Euclidean drift across pyramid levels. Consumed by the spurious-detection gate.

  • used_gradient — True when auto mode picked the gradient pass. Diagnostic only; not in the confidence formula.

  • body_count — number of BODY_DISC features fused.

Call path

Call path traced through navigate():

  1. Open a logged section. Filter the offered features down to BODY_DISC entries that carry a template payload via the private filter helper.

  2. Fuse the per-body templates into a single composite via compose_template_features(). The composite carries a single bounding box, brightness image, and mask.

  3. Read the search-window margin off the observation via search_window_for_obs().

  4. Result-shape branches on fit_camera_rotation:

    • No rotation fit. Run navigate_with_pyramid_kpeaks() once on the unrotated composite. The pyramid returns the chosen peak’s (dv, du), the 2x2 CRLB covariance, quality, consistency, spurious, at_edge, used_gradient, and the top-k peak telemetry. rotation_rad and sigma_rotation_rad are None; the (2, 2) covariance is reported.

    • Rotation fit. Run the private 3-DoF pyramid: 11 rotation samples at the coarsest pyramid level, top 3 advance to 5 samples at the next level, top 1 advances to 3 samples at the finest level. At each rotation sample the template is rotated about the body-centroid pivot via the private template-rotate helper and the pyramid evaluates as usual. The (dv, du, theta) triple at the global maximum is returned with a 3x3 covariance: the translation block is the CRLB from the winning rotation’s correlation curvature, the rotation diagonal is the inverse second derivative of the cost across the rotation schedule (or the rotation-unobservable sentinel when the schedule is flat).

  5. Apply the at-edge tests against the search-window axis bounds and the rotation cap, and the spurious tests using the pyramid wrapper’s spurious and consistency readouts.

  6. Build a BodyDiscDiagnostics from the pyramid wrapper’s quality / consistency / used-gradient / runner-up-ratio readouts plus the composite body count, evaluate the confidence spec via evaluate_sigmoid_combination(), log the per-term breakdown via log_confidence_breakdown(), and assemble the NavTechniqueResult.

The feature_ids field preserves every consumed feature_id so the orchestrator’s curator can attribute each contribution at audit time.

Examples

body_full_fov (Cassini ISS NAC, image N1572105349_1)

Dione fills the FOV at predicted disc diameter approximately 155 px. The body model emits a BODY_DISC feature; the technique converges to (9.17, -17.01) px against the operator-verified ground truth \((\Delta v, \Delta u) = (8.68, -17.37)\) px (within 0.5 px of true). The pyramid wrapper’s consistency reports 2.78 px disagreement between coarse and fine pyramid levels in the auto-gradient pass, exceeding the consistency tolerance and tripping the spurious gate; the result is therefore reported with confidence zero even though the offset is geometrically correct.

body_partial_overflow (Cassini ISS NAC, image N1484593951_2)

Rhea visible in the upper right with about 22 % of the disc off-frame. The body model emits a BODY_DISC feature; the disc-template NCC peak collapses against the heavily-cropped silhouette and the technique correctly flags itself spurious. BodyLimbNav carries the navigation on this image; the operator-verified offset is \((\Delta v, \Delta u) = (11.0, 29.5)\) px.

multi_body (Cassini ISS NAC, image N1487595731_1)

Dione and Rhea both visible and overlapping at phase angle approximately 90 degrees. The body model emits two BODY_DISC features; BodyDiscCorrelateNav Z-buffer paints them into a composite (the closer body’s pixels overwriting the farther body’s) and the pyramid NCC converges to (6.76, -17.71) px against the operator-verified ground truth \((\Delta v, \Delta u) = (7.03, -18.42)\) px. The composite’s joint geometric constraint sharpens the peak relative to a per-body solo correlation; the multi-body body_count term contributes a positive offset to the confidence sum.