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
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_extandsensor_mask_exton 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_DISCemission 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, default0.95(dimensionless). Whenfit_camera_rotationis true, the converged rotation magnitude tripsat_edgeonce it crosses this fraction of the per-imagemax_rotation_degcap.consistency_max_fraction_of_diameter/consistency_max_px— floats, defaults0.025/4.0px. 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, default1.0px. 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.0disables 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 ofBODY_DISCfeatures 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:
src/nav/nav_technique/nav_technique_body_disc.py—BodyDiscCorrelateNavand the rotation / template-rotate / composite helpers.src/nav/feature/composition.py—compose_template_features(), the Z-buffer paint helper that fuses per-body templates into a single composite.src/nav/support/correlate.py—navigate_with_pyramid_kpeaks(), the shared pyramid-NCC entry point.src/nav/nav_technique/confidence.py— shared sigmoid-combination evaluator; documented at Confidence Calibration (Shared Sigmoid-of-Linear Combination).src/nav/nav_technique/diagnostics.py—BodyDiscDiagnostics; documented at Per-Technique Diagnostics (Shared Dataclass Family).
Public class BodyDiscCorrelateNav, base
NavTechnique. Self-registers via
__init_subclass__ so NavTechnique._registry discovers it.
Class attributes:
name—'BodyDiscCorrelateNav'.accepts_feature_types—frozenset({BODY_DISC}).requires_prior—False. 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
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 whenautomode picked the gradient pass. Diagnostic only; not in the confidence formula.body_count— number ofBODY_DISCfeatures fused.
Call path
Call path traced through
navigate():
Open a logged section. Filter the offered features down to
BODY_DISCentries that carry a template payload via the private filter helper.Fuse the per-body templates into a single composite via
compose_template_features(). The composite carries a single bounding box, brightness image, and mask.Read the search-window margin off the observation via
search_window_for_obs().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-kpeak telemetry.rotation_radandsigma_rotation_radareNone; 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).
Apply the at-edge tests against the search-window axis bounds and the rotation cap, and the spurious tests using the pyramid wrapper’s
spuriousandconsistencyreadouts.Build a
BodyDiscDiagnosticsfrom the pyramid wrapper’s quality / consistency / used-gradient / runner-up-ratio readouts plus the composite body count, evaluate the confidence spec viaevaluate_sigmoid_combination(), log the per-term breakdown vialog_confidence_breakdown(), and assemble theNavTechniqueResult.
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, imageN1572105349_1)Dione fills the FOV at predicted disc diameter approximately 155 px. The body model emits a
BODY_DISCfeature; 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’sconsistencyreports 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, imageN1484593951_2)Rhea visible in the upper right with about 22 % of the disc off-frame. The body model emits a
BODY_DISCfeature; the disc-template NCC peak collapses against the heavily-cropped silhouette and the technique correctly flags itself spurious.BodyLimbNavcarries the navigation on this image; the operator-verified offset is \((\Delta v, \Delta u) = (11.0, 29.5)\) px.multi_body(Cassini ISS NAC, imageN1487595731_1)Dione and Rhea both visible and overlapping at phase angle approximately 90 degrees. The body model emits two
BODY_DISCfeatures;BodyDiscCorrelateNavZ-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.