Source code for spindoctor.nav_technique.diagnostics

"""Per-technique diagnostics dataclasses.

Each NavTechnique returns a typed diagnostics object on its
``NavTechniqueResult.diagnostics`` field.  The curator walks
``CURATOR_FIELDS`` on each diagnostics class to decide which fields land in
the JSON metadata; an unmapped field is a CI failure.
"""

from dataclasses import dataclass
from typing import ClassVar

__all__ = [
    'BodyBlobDiagnostics',
    'BodyDiscDiagnostics',
    'BodyLimbDiagnostics',
    'BodyTerminatorDiagnostics',
    'ManualNavDiagnostics',
    'NavTechniqueDiagnostics',
    'RingAnnulusDiagnostics',
    'RingEdgeDiagnostics',
    'StarFieldDiagnostics',
    'StarRefineDiagnostics',
    'StarUniqueMatchDiagnostics',
]


[docs] @dataclass(frozen=True) class BodyDiscDiagnostics: """Diagnostics emitted by ``BodyDiscCorrelateNav``. Parameters: ncc_peak: Peak normalized cross-correlation value. peak_to_runner_up_ratio: Ratio of NCC peak to second-highest peak outside the exclusion radius around the peak. consistency_px: Inter-pyramid peak migration in pixels (raw). consistency_ratio: ``consistency_px`` divided by the per-image spurious threshold (which scales with body diameter). A value <= 1.0 means the result is within the diameter-scaled consistency budget; the confidence formula consumes this normalized form so a healthy fit on a large body is not penalized by the same divisor that's appropriate for a small body. used_gradient: True if gradient mode was selected by ``auto``. body_count: Number of BODY_DISC features fused into the combined template. """ ncc_peak: float = 0.0 peak_to_runner_up_ratio: float = 0.0 consistency_px: float = 0.0 consistency_ratio: float = 0.0 used_gradient: bool = False body_count: int = 0 CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'ncc_peak': 'ncc_peak', 'peak_to_runner_up_ratio': 'peak_to_runner_up_ratio', 'consistency_px': 'consistency_px', 'consistency_ratio': 'consistency_ratio', 'used_gradient': 'used_gradient', 'body_count': 'body_count', }
[docs] @dataclass(frozen=True) class BodyLimbDiagnostics: """Diagnostics emitted by ``BodyLimbNav``. Parameters: visible_limb_arc_fraction: Fused visible-arc fraction across input LIMB_ARC features. visible_arc_px: Total surviving polyline arc length in pixels. dt_fit_rms_px: Final root-mean-square DT residual. lm_iterations: Levenberg-Marquardt iteration count. tukey_inlier_count: Number of polyline vertices accepted by the Tukey biweight robust estimator. lm_converged: True when the LM met its step-norm tolerance before the iteration cap; False marks an unverified fit whose confidence the shared DT gates cap. polarity_rejection_fraction: Fraction of model vertices whose local gradient direction disagreed with the model normal at the seed. coarse_peak_fraction: The winning coarse-NCC shift's in-bounds match fraction over the RASTERIZED polyline pixels (acquisition quality). Its denominator is mask pixels, not vertices, so it is not directly comparable to ``tukey_inlier_count``. """ visible_limb_arc_fraction: float = 0.0 visible_arc_px: float = 0.0 dt_fit_rms_px: float = 0.0 lm_iterations: int = 0 tukey_inlier_count: int = 0 lm_converged: bool = True polarity_rejection_fraction: float = 0.0 coarse_peak_fraction: float = 0.0 CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'visible_limb_arc_fraction': 'visible_limb_arc_fraction', 'visible_arc_px': 'visible_arc_px', 'dt_fit_rms_px': 'dt_fit_rms_px', 'lm_iterations': 'lm_iterations', 'tukey_inlier_count': 'tukey_inlier_count', 'lm_converged': 'lm_converged', 'polarity_rejection_fraction': 'polarity_rejection_fraction', 'coarse_peak_fraction': 'coarse_peak_fraction', }
[docs] @dataclass(frozen=True) class BodyTerminatorDiagnostics: """Diagnostics emitted by ``BodyTerminatorNav``. Parameters: same shape as ``BodyLimbDiagnostics`` with ``visible_terminator_arc_fraction`` substituted, plus the terminator-specific confidence inputs and the basin second-opinion pair: mean_phase_angle_factor: Vertex-weighted mean ``sin(phase)`` factor across the consumed terminator features. A confidence term (a terminator sharpens with phase), so it is recorded per result for the calibration fit. mean_albedo_penalty: Vertex-weighted mean catalog albedo-variation penalty across the consumed features; likewise a recorded confidence input. secondary_basin_distance_px: Distance from the converged offset to the best competing DT-cost basin in the search window; ``None`` when the scan did not run or found no eligible shift (``0.0`` is a legitimate measured value, so it is not the sentinel). secondary_basin_cost_ratio: Competing basin's mean per-vertex DT cost divided by the converged cost (epsilon-guarded); values below the technique's ``basin_cost_ratio_threshold`` mark the fit spurious. ``None`` when not measured. lm_converged: Shared DT gate diagnostic; the field carries the same meaning as on ``BodyLimbDiagnostics``. polarity_rejection_fraction: Shared DT gate diagnostic; the field carries the same meaning as on ``BodyLimbDiagnostics``. coarse_peak_fraction: Shared DT gate diagnostic; the field carries the same meaning as on ``BodyLimbDiagnostics``. """ visible_terminator_arc_fraction: float = 0.0 visible_arc_px: float = 0.0 dt_fit_rms_px: float = 0.0 lm_iterations: int = 0 tukey_inlier_count: int = 0 mean_phase_angle_factor: float = 0.0 mean_albedo_penalty: float = 0.0 secondary_basin_distance_px: float | None = None secondary_basin_cost_ratio: float | None = None lm_converged: bool = True polarity_rejection_fraction: float = 0.0 coarse_peak_fraction: float = 0.0 CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'visible_terminator_arc_fraction': 'visible_terminator_arc_fraction', 'visible_arc_px': 'visible_arc_px', 'dt_fit_rms_px': 'dt_fit_rms_px', 'lm_iterations': 'lm_iterations', 'tukey_inlier_count': 'tukey_inlier_count', 'mean_phase_angle_factor': 'mean_phase_angle_factor', 'mean_albedo_penalty': 'mean_albedo_penalty', 'secondary_basin_distance_px': 'secondary_basin_distance_px', 'secondary_basin_cost_ratio': 'secondary_basin_cost_ratio', 'lm_converged': 'lm_converged', 'polarity_rejection_fraction': 'polarity_rejection_fraction', 'coarse_peak_fraction': 'coarse_peak_fraction', }
[docs] @dataclass(frozen=True) class BodyBlobDiagnostics: """Diagnostics emitted by ``BodyBlobNav``. Parameters: body_snr_inside_predicted_bbox: SNR within the predicted bbox. body_extent_px: Predicted body's longer-axis extent in pixels. blob_count: Number of BODY_BLOB features fused. residual_px: Centroid-fit RMS residual. max_phase_angle_deg: Maximum raw phase angle across the consumed blobs. Recorded for diagnostic inspection only; the confidence formula consumes ``max_phase_irregularity_factor`` instead because raw phase understates the centroid uncertainty for an irregular body. max_phase_irregularity_factor: Maximum ``(ellipsoid_rms_residual_km / body_radius_km) * (1 + 2 * sin(phase/2)**2)`` across the consumed blobs. The confidence formula uses this term to down-weight irregular high-phase scenes where the lit-weighted predicted centroid cannot fully correct for the unknown-orientation shadowing on a non-ellipsoidal body. """ body_snr_inside_predicted_bbox: float = 0.0 body_extent_px: float = 0.0 blob_count: int = 0 residual_px: float = 0.0 max_phase_angle_deg: float = 0.0 max_phase_irregularity_factor: float = 0.0 CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'body_snr_inside_predicted_bbox': 'body_snr_inside_predicted_bbox', 'body_extent_px': 'body_extent_px', 'blob_count': 'blob_count', 'residual_px': 'residual_px', 'max_phase_angle_deg': 'max_phase_angle_deg', 'max_phase_irregularity_factor': 'max_phase_irregularity_factor', }
[docs] @dataclass(frozen=True) class RingEdgeDiagnostics: """Diagnostics emitted by ``RingEdgeNav``. Parameters: total_edge_length_px: Cumulative pixel length of all surviving ring-edge polylines. per_edge_dt_rms_summed: Sum of per-edge final DT RMS values. per_edge_dt_rms_mean: Mean per-edge final DT RMS value (``per_edge_dt_rms_summed / edge_count``). Edge-count independent, so it -- not the raw sum -- is the scale the confidence formula uses; the sum grows with the number of fused edges and a fixed divisor cannot normalise it. per_edge_dt_median_max: Largest per-edge median absolute DT residual (px). The mis-convergence gate statistic: a wholly misaligned edge (the wrong-ringlet failure mode) drives its own median to the ringlet spacing, while a minority of vertices snapping to a neighbouring parallel edge (routine on flat multi-edge scenes) leaves every median near the fit residual. edge_count: Number of RING_EDGE features fused. is_rank_1: True if every ring-edge feature was straight-line and the combined covariance is rank-1. lm_converged: Shared DT gate diagnostic; the field carries the same meaning as on ``BodyLimbDiagnostics``. coarse_peak_fraction: Shared DT gate diagnostic; the field carries the same meaning as on ``BodyLimbDiagnostics``. sigma_orbit_radial_px: Effective fully-correlated radial orbit-uncertainty sigma (px) added in quadrature to the reported covariance along the fit's radial direction (the weight-weighted combine of the consumed features' ``sigma_orbit_radial_px``); ``0.0`` when no consumed feature declares an orbit uncertainty. """ total_edge_length_px: float = 0.0 per_edge_dt_rms_summed: float = 0.0 per_edge_dt_rms_mean: float = 0.0 per_edge_dt_median_max: float = 0.0 edge_count: int = 0 is_rank_1: bool = False lm_converged: bool = True coarse_peak_fraction: float = 0.0 sigma_orbit_radial_px: float = 0.0 CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'total_edge_length_px': 'total_edge_length_px', 'per_edge_dt_rms_summed': 'per_edge_dt_rms_summed', 'per_edge_dt_rms_mean': 'per_edge_dt_rms_mean', 'per_edge_dt_median_max': 'per_edge_dt_median_max', 'edge_count': 'edge_count', 'is_rank_1': 'is_rank_1', 'lm_converged': 'lm_converged', 'coarse_peak_fraction': 'coarse_peak_fraction', 'sigma_orbit_radial_px': 'sigma_orbit_radial_px', }
[docs] @dataclass(frozen=True) class RingAnnulusDiagnostics: """Diagnostics emitted by ``RingAnnulusNav``. Parameters: ncc_peak: Peak NCC value. peak_to_runner_up_ratio: NCC peak ratio. annulus_count: Number of RING_ANNULUS features (one per planet). used_gradient: True if gradient mode was selected. """ ncc_peak: float = 0.0 peak_to_runner_up_ratio: float = 0.0 annulus_count: int = 0 used_gradient: bool = False CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'ncc_peak': 'ncc_peak', 'peak_to_runner_up_ratio': 'peak_to_runner_up_ratio', 'annulus_count': 'annulus_count', 'used_gradient': 'used_gradient', }
[docs] @dataclass(frozen=True) class StarFieldDiagnostics: """Diagnostics emitted by ``StarFieldFromCatalogNav``. Parameters: n_inliers: Number of detection-to-catalog inliers after RANSAC. median_residual_px: Median position residual on inliers. n_detected_sources: Number of bright sources detected in the image. n_catalog_predicted: Number of catalog stars in the extfov. n_triplets_evaluated: Number of triplet candidates considered by RANSAC. rotation_below_separability_floor: True when a co-fitted camera rotation's magnitude fell below the roll/translation separability floor (``rotation_separability_floor_deg``) and the rotation was therefore reported as unobservable rather than as a confident near-zero value. """ n_inliers: int = 0 median_residual_px: float = 0.0 n_detected_sources: int = 0 n_catalog_predicted: int = 0 n_triplets_evaluated: int = 0 rotation_below_separability_floor: bool = False CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'n_inliers': 'n_inliers', 'median_residual_px': 'median_residual_px', 'n_detected_sources': 'n_detected_sources', 'n_catalog_predicted': 'n_catalog_predicted', 'n_triplets_evaluated': 'n_triplets_evaluated', 'rotation_below_separability_floor': 'rotation_below_separability_floor', }
[docs] @dataclass(frozen=True) class StarUniqueMatchDiagnostics: """Diagnostics emitted by ``StarUniqueMatchNav``. Parameters: mode: ``'one_star'`` or ``'two_star'``. predicted_snr: Predicted SNR of the brightest catalog star. brightness_margin_mag: Mag difference to the next-brightest *unmatched* catalog source predictable in extfov; ``+inf`` when no unmatched star exists (a 1-star scene with no other predictable star, or a 2-star scene with no third predictable star to compare against). residual_px: Detection-vs-prediction residual. detection_peak_ratio: Background-subtracted peak-to-runner-up ratio of the 1-star path's detection inside its search window (``inf`` when the runner-up does not clear the background; 0.0 on the 2-star path, which cross-checks via its assignment residual instead). """ mode: str = '' predicted_snr: float = 0.0 brightness_margin_mag: float = 0.0 residual_px: float = 0.0 detection_peak_ratio: float = 0.0 CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'mode': 'mode', 'predicted_snr': 'predicted_snr', 'brightness_margin_mag': 'brightness_margin_mag', 'residual_px': 'residual_px', 'detection_peak_ratio': 'detection_peak_ratio', }
[docs] @dataclass(frozen=True) class StarRefineDiagnostics: """Diagnostics emitted by ``StarRefineNav``. Parameters: n_stars_used: Number of stars that survived per-star quality gates. median_pos_err_px: Median refinement positional error. residual_scatter_px: Per-axis RMS scatter of the per-star residuals. """ n_stars_used: int = 0 median_pos_err_px: float = 0.0 residual_scatter_px: float = 0.0 CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'n_stars_used': 'n_stars_used', 'median_pos_err_px': 'median_pos_err_px', 'residual_scatter_px': 'residual_scatter_px', }
[docs] @dataclass(frozen=True) class ManualNavDiagnostics: """Diagnostics emitted by ``NavTechniqueManual``. Parameters: operator_accepted: ``True`` when the operator confirmed the dialog's chosen offset. Always ``True`` on results that reach the curator (cancelled picks short-circuit before the ``NavResult`` is built), but kept explicit so the JSON metadata records the fact that a human, not an autonomous technique, set the offset. """ operator_accepted: bool = True CURATOR_FIELDS: ClassVar[dict[str, str | None]] = { 'operator_accepted': 'operator_accepted', }
NavTechniqueDiagnostics = ( BodyDiscDiagnostics | BodyLimbDiagnostics | BodyTerminatorDiagnostics | BodyBlobDiagnostics | ManualNavDiagnostics | RingEdgeDiagnostics | RingAnnulusDiagnostics | StarFieldDiagnostics | StarUniqueMatchDiagnostics | StarRefineDiagnostics ) """Sum type spanning every per-technique diagnostics dataclass. The orchestrator's curator and the technique-result type both consume this union; adding a new technique means adding both its diagnostics dataclass above and a new entry into this union. """