Files
gps-denied-onboard/_docs/00_problem/acceptance_criteria.md
T
Yuzviak 09e756ecbb docs(02-01): rewrite acceptance_criteria.md with formal AC-1.x..AC-NEW-8 contract
- Archive previous 51-line prose draft as acceptance_criteria_draft.md (git mv)
- Create canonical Stage 2 AC document with 39 AC entries (31 base + 8 AC-NEW)
- Every AC follows per-AC schema: Statement / Numeric threshold / Rationale /
  Validation method / Test IDs (placeholder) / Implementing components / Status
- All numeric thresholds from PATTERNS.md §2.3 present verbatim (50 m, 20 m,
  400 ms p95, 64 GB, 8 GB, 0.5 m/px, 30 s TTFF, etc.)
- Deferred-hardware ACs marked: AC-NEW-1, AC-NEW-5, AC-NEW-7 (multi-flight),
  plus AC-NEW-3 partial hardware validation
- Source-label vocab {satellite_anchored, vo_extrapolated, dead_reckoned} canonical
- AC IDs match regex ^\s*-\s*\*\*(AC-(?:\d+\.\d+[a-z]?|NEW-\d+))\*\*
  confirmed by Plan 02-04 traceability script
- Baseline 216 tests still pass (regression floor unchanged)
- AC-4.3 v1 scope clause reproduced verbatim (ODOMETRY disabled; GPS_INPUT only)
- AC-8.4 marked deferred-stage3 per REQUIREMENTS.md parking lot
2026-05-11 18:10:23 +03:00

42 KiB
Raw Blame History

Acceptance Criteria

Last revised: 2026-05-11 (Phase 2 / Stage 2 rewrite from try02 skeleton, validated against Stage 2 constraints).

Revision log:

  • 2026-05-11: Initial Stage 2 rewrite — adopted try02 AC vocabulary (AC-1.1..AC-8.6 + AC-NEW-1..AC-NEW-8), added per-AC schema (Statement / Numeric threshold / Rationale / Validation method / Test IDs / Implementing components / Status). Previous draft archived at acceptance_criteria_draft.md.
  • 2026-05-01 (try02): AC-1.3 anchor-age reporting clarified; AC-2.1 split; AC-5.2 and AC-NEW-2 now require ArduPilot Plane SITL; AC-8.3 storage and AC-NEW-7 clarified.
  • 2026-04-29 (try02): AC-3.5 and AC-NEW-8 added for visual blackout/cloud occlusion.
  • 2026-04-26 (try02): AC-4.3 extended; AC-8.6 added; AC-NEW-7 added.
  • 2026-04-25 (try02): initial AC list.

Schema

Every AC follows the same template:

  • AC-ID — Short title

    Statement. The system shall …

    Numeric threshold. Quantitative bound(s); measurement methodology.

    Rationale. Risk if violated; tie-back to PROJECT.md core value.

    Validation method. One of: unit-test, integration-test, blackbox-replay, sitl-simulation, benchmark, deferred-hardware. May list more than one.

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components. src/gps_denied/... paths the AC binds to.

    Status. active / deferred-stage3 / superseded-by(AC-Z).


Position Accuracy

  • AC-1.1 — Position accuracy (50 m @ 80 %)

    Statement. The system shall determine GPS coordinates of frame centres within 50 m of true GPS for ≥80 % of photos in normal flight segments.

    Numeric threshold.

    • error_m = ‖estimate_xy ground_truth_xy‖ (haversine, WGS84)
    • normal_flight_segment = nadir ±10° bank/pitch, ≥40 % overlap, daytime, no full visual blackout
    • PASS iff count(error_m < 50) / count(normal_segment_frames) ≥ 0.80
    • Window: per 5-minute rolling window over the full flight

    Rationale. Below this threshold the flight controller cannot safely geofence; navigation in GPS-denied airspace is impossible. This is the core-value AC.

    Validation method. integration-test + benchmark on AerialVL S03 and Azaion 10.05.2026 fixtures.

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/safety_state/
    • src/gps_denied/components/anchor_verifier/
    • src/gps_denied/core/eskf.py

    Status. active

  • AC-1.2 — Position accuracy (20 m @ 50 %)

    Statement. The system shall determine GPS coordinates of frame centres within 20 m of true GPS for ≥50 % of photos in normal flight segments.

    Numeric threshold.

    • Same measurement methodology as AC-1.1
    • PASS iff count(error_m < 20) / count(normal_segment_frames) ≥ 0.50

    Rationale. Stretch target for precision operations; failing this but passing AC-1.1 is an acceptable Stage 2 outcome. Violating both degrades all geofence and targeting accuracy.

    Validation method. integration-test + benchmark on AerialVL S03 and Azaion 10.05.2026 fixtures.

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/safety_state/
    • src/gps_denied/components/anchor_verifier/
    • src/gps_denied/core/eskf.py

    Status. active

  • AC-1.3 — Cumulative VO drift bound + anchor-age reporting

    Statement. Maximum cumulative VO drift between two consecutive satellite-anchored fixes shall be <100 m (VO-only fallback) or <50 m (when IMU is fused). Every emitted estimate shall include last_satellite_anchor_age_ms; validation results shall be binned by anchor age, and the solution draft must define the maximum anchor age after which estimates are treated as degraded (vo_extrapolated or dead_reckoned) with monotonically growing covariance.

    Numeric threshold.

    • VO-only fallback: drift_m < 100 m
    • IMU-fused: drift_m < 50 m
    • Drift measured as ‖VO-extrapolated centre next anchor centre‖ at the moment of anchor fix

    Rationale. Unbounded drift invalidates the position guarantee of AC-1.1. Anchor-age reporting is required for the traceability script and for Phase 3/6 observability. Cross-references: AC-NEW-1 (cold-start anchor age budget).

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/core/eskf.py
    • src/gps_denied/components/safety_state/

    Status. active (Phase 3 SAFE-03 wires anchor_age_ms field; Phase 2 records the AC text only)

  • AC-1.4 — Quantitative confidence score per estimate

    Statement. The system shall report a quantitative confidence score per position estimate, comprising: the 95 % covariance ellipse semi-major axis in meters AND a categorical label {satellite_anchored, vo_extrapolated, dead_reckoned}.

    Numeric threshold.

    • source_label ∈ {satellite_anchored, vo_extrapolated, dead_reckoned} (exhaustive; no other values permitted)
    • cov_semi_major_m ≥ 0 (non-negative real)

    Rationale. Without a machine-readable label the flight controller cannot distinguish a high-quality fix from dead reckoning; the FC applies no covariance-appropriate safety margin. Cross-references: AC-NEW-8 (source_label vocab used in blackout failsafe).

    Validation method. unit-test (schema) + integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/safety_state/
    • src/gps_denied/hot_types/position_estimate.py

    Status. active


Image Processing Quality

  • AC-2.1a — VO registration rate

    Statement. Frame-to-frame visual registration shall succeed for >95 % of normal flight segments (defined as: nadir flight ±10° bank/pitch, ≥40 % overlap with prior frame, daytime, usable texture, no full visual blackout).

    Numeric threshold.

    • count(vo_success) / count(normal_segment_frames) > 0.95

    Rationale. VO failure rate above 5 % causes excessive dead reckoning in steady-state conditions, violating AC-1.3 drift bound.

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/vio/
    • src/gps_denied/pipeline/orchestrator.py

    Status. active

  • AC-2.1b — Satellite-anchor registration

    Statement. Cross-domain UAV-photo to satellite/cache registration is measured separately from AC-2.1a and must satisfy AC-1.1/AC-1.2 position accuracy, AC-2.2 cross-domain MRE, AC-8.2 freshness, and AC-8.6 retrieval behavior on season-matched tiles.

    Numeric threshold.

    • Satellite-anchor MRE: <2.5 px (see AC-2.2)
    • Anchor acceptance rate: bounded by AC-1.1 (≥80 % of frames within 50 m)

    Rationale. Satellite registration rate and quality must be tracked independently of VO to isolate failure modes (tile staleness vs. VO failure vs. cross-domain mismatch).

    Validation method. integration-test + benchmark

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/satellite_matcher/
    • src/gps_denied/components/anchor_verifier/

    Status. active

  • AC-2.2 — Mean Reprojection Error

    Statement. Mean Reprojection Error (MRE) shall be: <1.0 px for VO frame-to-frame homography on overlapping aerial pairs; <2.5 px for satellite-anchored cross-domain (UAV photo ↔ ortho satellite tile) registration.

    Numeric threshold.

    • VO MRE: mre_px < 1.0
    • Satellite MRE: mre_px < 2.5

    Rationale. MRE above these thresholds indicates degenerate homography; the resulting position shift can exceed 10 m per pixel of MRE at 0.5 m/px resolution. Exceeding satellite MRE violates AC-1.1.

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/satellite_matcher/metric_refinement.py
    • src/gps_denied/components/anchor_verifier/

    Status. active


Resilience & Edge Cases

  • AC-3.1 — Outlier tolerance

    Statement. The system shall correctly continue work in the presence of up to 350 m outliers between two consecutive photos (caused by airframe tilt up to ±20°).

    Numeric threshold.

    • Maximum inter-frame displacement handled: 350 m
    • System continues producing valid estimates after the outlier frame

    Rationale. Fixed-wing tilt events create apparent ground displacement beyond normal VO search radius; failure to handle them causes tracking loss on routine maneuvers.

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/core/recovery.py
    • src/gps_denied/components/satellite_matcher/

    Status. active

  • AC-3.2 — Sharp-turn handling

    Statement. The system shall correctly continue work during sharp turns where the next photo overlaps <5 % with the previous, drifts <200 m, and changes heading <70°. Sharp-turn frames are expected to fail VO and shall be handled by satellite-based re-localization (place recognition over the satellite tile cache).

    Numeric threshold.

    • Overlap threshold: <5 %
    • Drift after turn: <200 m
    • Heading change: <70°

    Rationale. Fixed-wing survey patterns include 180° turn-arounds with near-zero overlap. Without satellite re-localization the system drifts unbounded on every headland.

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/core/recovery.py
    • src/gps_denied/components/satellite_matcher/
    • src/gps_denied/core/factor_graph.py

    Status. active

  • AC-3.3 — Disconnected segments

    Statement. The system shall handle ≥3 disconnected segments per flight, connecting each new segment to the previous trajectory via global descriptor retrieval + RANSAC pose-graph relocalization. This is a core capability, not a degraded mode.

    Numeric threshold.

    • Minimum disconnected segments handled per flight: 3
    • Each segment successfully reconnected to the global trajectory

    Rationale. Multi-strip survey missions have multiple heading reversals with full visual discontinuity. If the system treats this as exceptional, it fails on every second strip.

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/core/recovery.py
    • src/gps_denied/components/satellite_matcher/
    • src/gps_denied/core/factor_graph.py

    Status. active

  • AC-3.4 — Re-localization request trigger

    Statement. When the system cannot determine position for ≥3 consecutive frames AND ≥2 s, it shall send a re-localization request to the ground station via telemetry. While waiting, it continues VO/IMU dead reckoning and the flight controller uses last known position + IMU extrapolation.

    Numeric threshold.

    • Dual trigger: consecutive_frames_failed ≥ 3 AND time_failed_s ≥ 2
    • Re-loc request must be emitted within one processing cycle of threshold crossing

    Rationale. A single trigger threshold (frame count only) can fire on sub-second bursts; dual-trigger prevents spurious requests during transient VO failures.

    Validation method. blackbox-replay + sitl-simulation

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/core/recovery.py
    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py

    Status. active

  • AC-3.5 — Visual blackout mode switch

    Statement. During temporary visual blackout where the navigation camera provides no usable ground signal (e.g., clouds/occlusion/whiteout) while GPS is denied or spoofed, the system shall switch to {dead_reckoned} within ≤1 processed frame OR ≤400 ms, reject the spoofed GPS as an estimator input, and propagate position solely from the last trusted state + flight-controller IMU/attitude/airspeed/altitude inputs until visual or satellite anchoring recovers. During this mode, covariance shall grow monotonically, GPS_INPUT.horiz_accuracy shall not under-report the 95 % covariance semi-major axis, and QGroundControl shall receive a VISUAL_BLACKOUT_IMU_ONLY status at 12 Hz. Cross-references: AC-NEW-8 (extended blackout failsafe budget).

    Numeric threshold.

    • Mode switch latency: ≤1 processed frame OR ≤400 ms
    • QGC status rate: 12 Hz
    • Covariance: monotonically non-decreasing in blackout mode

    Rationale. A cloud/whiteout period removes all visual correction exactly when spoofed GPS cannot be trusted. Pretending a stale visual position remains valid is operationally dangerous.

    Validation method. blackbox-replay + sitl-simulation

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/safety_state/
    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py
    • src/gps_denied/core/eskf.py

    Status. active


Real-Time Onboard Performance

  • AC-4.1 — End-to-end latency

    Statement. End-to-end latency from camera capture to GPS coordinate output to the flight controller shall be <400 ms p95. Up to ~10 % of frames may be dropped under sustained load (skip-allowed). Heavy global VPR / cross-domain re-ranking shall be conditional, not part of the steady-state per-frame path.

    Numeric threshold.

    • p95 end-to-end latency: <400 ms
    • Frame-drop budget: ≤10 %

    Rationale. ArduPilot EKF failsafe fires after ~3 s without a GPS update at 5 Hz; 400 ms p95 keeps the GPS_INPUT stream healthy. Beyond 400 ms, EKF position uncertainty grows fast enough to trigger safety modes.

    Validation method. benchmark

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/pipeline/orchestrator.py
    • src/gps_denied/components/vio/
    • src/gps_denied/components/satellite_matcher/

    Status. active

  • AC-4.2 — Memory budget

    Statement. Memory usage shall remain below 8 GB shared on Jetson Orin Nano Super (CPU and GPU share the same 8 GB LPDDR5 pool).

    Numeric threshold.

    • Peak shared memory: <8 GB

    Rationale. Exceeding 8 GB triggers OOM-killer; the system crashes mid-flight. No recovery path exists without a reboot.

    Validation method. benchmark

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/pipeline/orchestrator.py
    • src/gps_denied/components/gpr/

    Status. active

  • AC-4.3 — MAVLink output channel (GPS_INPUT primary)

    Statement. The system shall output its position estimate to the flight controller via two parallel MAVLink channels, both emitted by pymavlink: Primary (GPS_INPUT targeting ArduPilot GPS1_TYPE=14) and Auxiliary (ODOMETRY when EKF emits fix with full 6-DoF covariance and quality > VISO_QUAL_MIN). FC source priorities configured so GPS_INPUT remains the failover path if ODOMETRY trips a parameter gate.

    v1 scope clause (added 2026-04-26): v1 ships GPS_INPUT only; the ODOMETRY auxiliary channel is intentionally disabled in v1 because feeding both GPS_INPUT and ODOMETRY for overlapping axes triggers ArduPilot EKF3 double-fusion bugs (issues #30076 / #32506). EK3_SRC1_*=GPS+Compass; ODOMETRY emission re-enables in v1.1 once F-T9 SITL confirms PR #30080-class clean source-switching. Tests therefore assert v1 emits GPS_INPUT only and that ODOMETRY is intentionally absent on the wire.

    Numeric threshold.

    • v1: GPS_INPUT present on wire; ODOMETRY absent
    • FC parameter: GPS1_TYPE=14; quality gate: VISO_QUAL_MIN

    Rationale. EKF3 double-fusion causes divergent position estimates that cannot be diagnosed in the field. v1 single-channel keeps the behavior predictable until the upstream ArduPilot fix is confirmed. (See MAVOUT-02 requirement.)

    Validation method. blackbox-replay (channel absence) + sitl-simulation (FC ingest)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py
    • src/gps_denied/pipeline/orchestrator.py

    Status. active (v1: GPS_INPUT only; MAVOUT-02 scaffolds ODOMETRY behind feature flag)

  • AC-4.4 — Frame-by-frame streaming

    Statement. Position estimates are streamed to the flight controller frame-by-frame; the system shall not batch or delay output.

    Numeric threshold.

    • Every processed frame produces a GPS_INPUT emit within the AC-4.1 latency budget
    • No buffering / batching of position output

    Rationale. Batching introduces burst latency; ArduPilot's EKF treats inter-packet gaps as data-rate drops, degrading its own estimate quality.

    Validation method. sitl-simulation

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py

    Status. active

  • AC-4.5 — Estimate refinement / corrections

    Statement. The system may refine previously calculated positions and send corrections to the flight controller as updated estimates.

    Numeric threshold.

    • Correction delta: no hard limit (any refinement may be sent)
    • FC must not reject corrections; system must not suppress them

    Rationale. Factor-graph back-end refines past poses when new satellite anchors arrive; sending the refined estimate keeps the FC's EKF state consistent with our back-end.

    Validation method. sitl-simulation

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/pipeline/orchestrator.py
    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py

    Status. active


Startup & Failsafe

  • AC-5.1 — Initialization from FC EKF

    Statement. The system shall initialise using the last known valid GPS position from the flight controller's EKF, plus IMU-extrapolated position at the moment of GPS denial.

    Numeric threshold.

    • Initialization must complete before first GPS_INPUT emit
    • Initial position: FC EKF position at denial onset, not a default/zero position

    Rationale. Starting from zero coordinates puts the FC in a state where GPS_INPUT contradicts the last real GPS; the EKF rejects the first several estimates, creating a cold-start gap in coverage.

    Validation method. sitl-simulation

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/mavlink_io/
    • src/gps_denied/core/recovery.py

    Status. active

  • AC-5.2 — Failsafe timeout

    Statement. If the system fails to produce any position estimate for >3 s, the flight controller shall fall back to IMU-only dead reckoning and the system shall log the failure. Because ArduPilot failsafe timing depends on vehicle type and parameters, this fallback behavior must be verified specifically in ArduPilot Plane SITL with the production parameter set; Copter defaults are reference evidence only.

    Numeric threshold.

    • Failsafe trigger: gap_s > 3
    • Validation scope: ArduPilot Plane SITL (not Copter)

    Rationale. Plane and Copter have different EKF lane-switch thresholds; verifying on Copter SITL only leaves the Plane-specific failsafe path untested.

    Validation method. sitl-simulation (ArduPilot Plane SITL specifically)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/mavlink_io/
    • src/gps_denied/core/recovery.py

    Status. active

  • AC-5.3 — Mid-flight reboot recovery

    Statement. On companion computer reboot mid-flight, the system shall attempt to re-initialise from the flight controller's current IMU-extrapolated position. See AC-NEW-1 for the cold-start time-to-first-fix budget.

    Numeric threshold.

    • Recovery attempt must start within AC-NEW-1 TTFF budget (<30 s)
    • Recovery position: FC IMU-extrapolated position at reboot time

    Rationale. Brown-out / watchdog resets are realistic on 8-hour missions; the UAV must not enter an unrecoverable state when the companion reboots.

    Validation method. sitl-simulation

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/mavlink_io/
    • src/gps_denied/core/recovery.py

    Status. active


Ground Station & Telemetry

  • AC-6.1 — GCS position stream

    Statement. Position estimates and confidence scores shall be streamed to QGroundControl via the MAVLink telemetry link. High-rate (per-frame) content stays on the local link for forensics; the GCS link is downsampled to 12 Hz for situational awareness.

    Numeric threshold.

    • GCS stream rate: 12 Hz
    • Local forensic stream: per-frame (AC-4.1 rate)

    Rationale. QGC's map view cannot render per-frame updates usefully; downsampling reduces bandwidth without losing situational awareness. Full-rate data is preserved in FDR (AC-NEW-3).

    Validation method. sitl-simulation (QGC downsample observable on the wire)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py

    Status. active

  • AC-6.2 — Operator re-localization commands

    Statement. The ground station can send commands to the onboard system (e.g., operator-assisted re-localization hint with approximate coordinates) via STATUSTEXT, NAMED_VALUE_FLOAT, or a custom MAVLink dialect.

    Numeric threshold.

    • Command must be received and acted upon within one processing cycle
    • Protocol: STATUSTEXT / NAMED_VALUE_FLOAT / custom dialect (implementation choice)

    Rationale. Operator-assisted re-localization is the fallback when automatic re-localization fails (AC-3.4 trigger path); without this channel the operator cannot intervene.

    Validation method. sitl-simulation

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py

    Status. active

  • AC-6.3 — WGS84 coordinate format

    Statement. Output coordinates are in WGS84 format (matches GPS_INPUT spec).

    Numeric threshold.

    • All lat/lon fields in GPS_INPUT in WGS84 decimal degrees × 1e7 (MAVLink convention)
    • No local coordinate systems exported to FC

    Rationale. GPS_INPUT spec requires WGS84; using a local ENU frame crashes the EKF.

    Validation method. unit-test (WGS84 coord format)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py
    • src/gps_denied/core/eskf.py

    Status. active


Object Localization (AI Camera)

  • AC-7.1 — AI camera localization accuracy

    Statement. Other onboard AI systems may request GPS coordinates of objects detected by the AI camera. Localization accuracy is consistent with the frame-center accuracy of the GPS-Denied system in level flight (bank/pitch <5°). In maneuvering flight, ground-projection error is bounded by altitude × |sin(unknown_bank_or_pitch)| and the system shall publish that bound alongside the estimate.

    Numeric threshold.

    • Level flight (bank/pitch <5°): accuracy consistent with AC-1.1 / AC-1.2
    • Maneuvering flight: bound reported = altitude_m × |sin(attitude_rad)|

    Rationale. Object localization inherits all position error from the GPS-Denied system plus the camera projection uncertainty; the bound must be propagated honestly.

    Validation method. unit-test (trig) + integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/coordinate_transforms/

    Status. active

  • AC-7.2 — AI camera trigonometric computation

    Statement. The system computes object coordinates trigonometrically using: current UAV GPS position (from GPS-Denied), known AI-camera gimbal angle, zoom, and current flight altitude. Flat-terrain assumption applies.

    Numeric threshold.

    • Flat-terrain assumption: explicit, documented per-request
    • Input: GPS-Denied position + gimbal angle + zoom + altitude (all mandatory fields)

    Rationale. Without explicit flat-terrain documentation, operators may use the output for terrain-varying tasks where it is not valid.

    Validation method. unit-test (trig) + integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/coordinate_transforms/

    Status. active


Satellite Reference Imagery

  • AC-8.1 — Satellite imagery source and resolution

    Statement. Satellite reference imagery is provided by the Azaion Suite Satellite Service (a separate component of the Suite). The runtime onboard system consumes this service through an offline tile cache interface; it does not call commercial providers directly. Required resolution at the cache interface: at least 0.5 m/pixel, ideally 0.3 m/pixel.

    Numeric threshold.

    • Minimum resolution: 0.5 m/px
    • Ideal resolution: 0.3 m/px

    Rationale. Below 0.5 m/px, keypoint density drops below the minimum for reliable homography; the satellite-anchor MRE (AC-2.2) cannot be met.

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/satellite_matcher/local_tile_loader.py

    Status. active

  • AC-8.2 — Tile freshness by sector

    Statement. Satellite tiles consumed at runtime shall be: <6 months old for active-conflict sectors; <12 months old for stable rear sectors. System shall reject or downgrade-confidence on tiles older than these thresholds (see AC-NEW-6).

    Numeric threshold.

    • Active-conflict sectors: age_months < 6
    • Stable rear sectors: age_months < 12

    Rationale. Stale tiles in active-conflict sectors (building destruction, cratering) produce confident-but-wrong satellite anchors — worse than no anchor.

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/anchor_verifier/
    • src/gps_denied/components/satellite_matcher/local_tile_loader.py

    Status. active

  • AC-8.3 — Pre-flight imagery loading

    Statement. Satellite imagery for the operational area shall be pre-loaded and pre-processed onto the companion computer before flight. Offline preprocessing time is not time-critical (minutes/hours). Pre-extracted tile descriptors (SuperPoint keypoints/descriptors and DINOv2-VLAD global descriptors) are part of the cache and count against the storage budget unless the solution draft defines a separate descriptor/index budget.

    Numeric threshold.

    • All operational-area tiles available before GPS_INPUT is first emitted
    • Storage: within 64 GB FDR cap (AC-NEW-3); descriptor index explicitly budgeted

    Rationale. In-flight tile downloads require connectivity that is unavailable in GPS-denied airspace.

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/satellite_matcher/local_tile_loader.py
    • src/gps_denied/components/gpr/

    Status. active

  • AC-8.4 — Mid-flight tile generation and write-back

    Statement. During flight, the system shall continuously orthorectify navigation-camera frames into tiles aligned with the basemap projection and store them in the local cache, deduplicated so each ground sector is stored at most once (latest/highest-quality tile wins). On landing, the companion computer shall upload newly generated tiles back to the Azaion Suite Satellite Service so the next mission cache contains imagery refreshed by the previous flight.

    Numeric threshold.

    • Deduplication: one tile per ground sector (latest wins)
    • Upload: on-landing, before next mission
    • Write eligibility gated by can_persist_tile (see SAFE-05)

    Rationale. Without write-back, the cache becomes stale relative to conflict-sector ground truth after the first mission; every subsequent mission anchors against pre-conflict imagery.

    Validation method. integration-test

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/satellite_matcher/
    • src/gps_denied/components/flight_recorder/

    Status. deferred-stage3 (mid-flight orthorectification + write-back is a Stage 3 deliverable per REQUIREMENTS.md parking lot)

  • AC-8.5 — Storage policy (no raw frame retention)

    Statement. The system shall not retain raw navigation-camera frames or AI-camera frames as part of normal operation. Tiles are the only persistent imagery artifact. Forensic exception: a low-rate (≤0.1 Hz) thumbnail log of frames that failed tile generation may be retained for debugging within the FDR budget (AC-NEW-3).

    Numeric threshold.

    • Raw frame retention: zero bytes in normal operation
    • Forensic thumbnail rate: ≤0.1 Hz

    Rationale. Raw nav-cam frames at 3 Hz × 8 hours exceeds any reasonable storage budget and provides no operational value once tiles exist.

    Validation method. integration-test + benchmark

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/flight_recorder/
    • src/gps_denied/pipeline/orchestrator.py

    Status. active

  • AC-8.6 — VPR retrieval unit and change-robustness

    Statement. The Visual Place Recognition (VPR) FAISS index shall be built over ground-footprint-sized "VPR chunks" (~600800 m at deployment altitude with 4050 % overlap), decoupled from the slippy-XYZ storage tile (z=20). VPR shall be multi-scale (fine-scale z=20-derived + coarser-scale z=17 or z=18 for active-conflict change-robustness). VPR top-K shall be dynamically sized: K=5 (stable, σ_xy ≤ 20 m), K=20 (active-conflict), K=50 (expanding-window fallback). VPR shall be invoked conditionally — not on every frame; DINOv2 forward runs only on re-loc triggers (cold start, sharp turn AC-3.2, σ_xy > 50 m, VO failure ≥2 frames, disconnected segment AC-3.3).

    Numeric threshold.

    • Chunk size: 600800 m at deployment altitude
    • Chunk overlap: 4050 %
    • Multi-scale: z=20 (fine) + z=17 or z=18 (coarse)
    • Dynamic K: K=5 / K=20 / K=50 per sector/covariance
    • VPR invocation: conditional on re-loc triggers only

    Rationale. Unconditional DINOv2 inference at every frame violates AC-4.1 (400 ms budget). Change-robust coarse index prevents anchor failure in active-conflict sectors where the fine-scale tile may not match post-conflict ground truth.

    Validation method. integration-test + benchmark

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/gpr/
    • src/gps_denied/core/chunk_manager.py

    Status. active


Extended Operational AC

AC-NEW-1 — Time-to-first-fix on cold start

  • AC-NEW-1 — Time-to-first-fix on cold start

    Statement. From companion-computer boot, the system shall emit its first valid GPS_INPUT message in <30 s, given an IMU-extrapolated initial position handed over from the flight controller's EKF.

    Numeric threshold.

    • TTFF: 95th percentile < 30 s (measured over 50× cold reboots)
    • Implementation drivers: TRT engines built at install time; CUDA/TRT init <5 s; FAISS index loaded before MAVLink connect

    Rationale. A mid-flight reboot at 60 km/h creates ~500 m IMU dead-reckoning drift in 30 s; the EKF can absorb this when the first fix arrives. Beyond 30 s the drift compounds. Cross-references: AC-1.3 (anchor-age at cold start); AC-5.3 (reboot recovery).

    Validation method. deferred-hardware (cold-boot bench requires Jetson hardware; cold-boot 50× with simulated FC-pose input)

    Test IDs.

    • deferred_hardware

    Implementing components.

    • src/gps_denied/pipeline/orchestrator.py
    • src/gps_denied/core/models.py

    Status. deferred-hardware-validation (Stage 3 on Jetson)

AC-NEW-2 — Spoofing-promotion latency

  • AC-NEW-2 — Spoofing-promotion latency

    Statement. When the flight controller signals GPS denial or spoofing (ArduPilot fix-loss / EKF lane-switch event), the GPS-Denied system shall promote its own estimate to the FC's primary GPS source within <3 s.

    Numeric threshold.

    • Promotion latency: 95th percentile < 3 s
    • Trigger: real-GPS health rolling average below threshold for ≥1 s

    Rationale. Without this gate, the FC may continue following a spoofed real-GPS source while our valid estimate sits idle. 3 s is short enough to prevent malicious heading changes but long enough to avoid single-frame anomaly false positives.

    Validation method. sitl-simulation (ArduPilot Plane SITL: inject false GPS_RAW_INT, measure time from spoof onset to promotion)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py

    Status. active

AC-NEW-3 — Flight Data Recorder storage budget

  • AC-NEW-3 — Flight Data Recorder storage budget

    Statement. The system shall retain to non-volatile storage, per flight: per-frame position estimates with covariance and source-label, IMU traces from the FC at full rate, all emitted GPS_INPUT frames, MAVLink raw stream (tlog), system health (CPU/GPU/temp/throttle), tiles generated mid-flight (AC-8.4), and a ≤0.1 Hz thumbnail log of failed-tile frames. Raw nav-cam frames and AI-cam frames are NOT retained (AC-8.5). Storage cap 64 GB / flight; recorder rolls over (oldest segment dropped first) after cap.

    Numeric threshold.

    • Storage cap: ≤64 GB per flight
    • Forensic thumbnail rate: ≤0.1 Hz
    • Rollover policy: oldest segment dropped; rollover event logged

    Rationale. Without bounded storage, an 8-hour mission fills any NVMe and silently drops forensic data. The 64 GB cap is sized for 8-hour mission with tiles + IMU + telemetry, leaving headroom for the persistent tile cache (AC-8.3).

    Validation method. integration-test (rollover behavior) + benchmark (synthetic 8-hour load) + deferred-hardware (real Jetson NVMe throughput in Stage 3)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/flight_recorder/

    Status. active (CI scope) + deferred-hardware-validation (Stage 3)

AC-NEW-4 — False-position safety budget

  • AC-NEW-4 — False-position safety budget

    Statement.

    • P(reported estimate error > 500 m) < 0.1 % per flight.
    • P(reported estimate error > 1 km) < 0.01 % per flight.

    Numeric threshold.

    • P(error > 500 m) < 0.001
    • P(error > 1 km) < 0.0001
    • Measurement: Monte Carlo over AerialVL S03 + Mavic + Azaion 10.05.2026, ≥100 simulated flights

    Rationale. A single 1-km-off GPS_INPUT can fly the UAV outside the geofence in seconds. EKF covariance must be calibrated, not optimistic; outlier rejection (Mahalanobis gate) is mandatory.

    Validation method. benchmark (Monte Carlo over AerialVL S03 + Mavic + Azaion 10.05.2026)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/core/eskf.py
    • src/gps_denied/components/anchor_verifier/

    Status. active

AC-NEW-5 — Operational environmental envelope

  • AC-NEW-5 — Operational environmental envelope

    Statement. Operating temperature 20 °C to +50 °C; vibration/shock per RTCA DO-160G low-altitude UAV-class envelope. The cooling solution shall sustain the 25 W power mode at the upper temperature bound for the full 8-hour duty cycle without thermal throttling.

    Numeric threshold.

    • Temperature range: 20 °C to +50 °C
    • Power mode: 25 W sustained
    • Duration: 8 hours
    • Pass: no thermal throttling events during hot-soak

    Rationale. Without this, all latency/accuracy ACs are conditional on a benign thermal day. Eastern Ukraine summers easily exceed +35 °C ambient inside a UAV bay; without active cooling, Jetson throttles to 15 W and AC-4.1 (400 ms budget) collapses.

    Validation method. deferred-hardware (hot-soak chamber at +50 °C for 8 h + cold-soak at 20 °C to AC-NEW-1 TTFF)

    Test IDs.

    • deferred_hardware

    Implementing components.

    • Hardware cooling assembly (outside software scope)
    • src/gps_denied/components/flight_recorder/ (thermal event logging via FDR)

    Status. deferred-hardware-validation (Stage 3 on Jetson)

AC-NEW-6 — Imagery freshness enforcement

  • AC-NEW-6 — Imagery freshness enforcement

    Statement. The system shall reject (or downgrade confidence on) any satellite tile whose capture date violates AC-8.2 (>6 months old in active-conflict sectors; >12 months old in stable rear sectors). Tiles generated mid-flight (AC-8.4) and not yet uploaded to the Suite Satellite Service are timestamped with the current flight date and treated as fresh.

    Numeric threshold.

    • Confidence weight: 1.0 within freshness budget; linearly decayed to 0.0 over a 30-day grace zone; hard reject beyond grace
    • Sector classification: provided pre-flight in operational area definition

    Rationale. Stale satellite tiles are the dominant cross-view-matching failure mode in active-conflict sectors. A confident match against a stale tile is worse than no match.

    Validation method. unit-test (rejection curve) + integration-test (cache integration)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/anchor_verifier/
    • src/gps_denied/components/satellite_matcher/local_tile_loader.py

    Status. active

AC-NEW-7 — Cache-poisoning safety budget

  • AC-NEW-7 — Cache-poisoning safety budget

    Statement. Per flight, across all onboard tiles written by the in-flight ortho-tile generator:

    • P(onboard tile geo-misaligned > 30 m) < 1 %.
    • P(onboard tile geo-misaligned > 100 m) < 0.1 %.

    Component-1b (tile generator) enforces: σ_xy ≤ 5 m hard write gate (trust_level = candidate); σ_xy ≤ 3 m for full quality; σ_xy ∈ (3, 5] m marked trust_level = soft. Multi-flight voting (N≥2 independent flights confirm consistent geo-alignment within X m) is a Suite Satellite Service dependency for final promotion to trusted basemap. Cross-references: AC-8.4 (write-back); AC-NEW-4 (single-flight false-position budget).

    Numeric threshold.

    • P(geo-misalignment > 30 m) < 0.01
    • P(geo-misalignment > 100 m) < 0.001
    • Onboard trust_level gate: σ_xy ≤ 5 m (candidate), σ_xy ≤ 3 m (full quality)
    • Multi-flight voting: N≥2 flights (Service-side, deferred)

    Rationale. Onboard tiles feed back into the Suite Satellite Service basemap (AC-8.4); a confidently-bad EKF pose can write a misaligned tile that becomes the next flight's satellite anchor, compounding cross-flight error beyond what AC-NEW-4 covers.

    Validation method.

    • integration-test: onboard trust_level gating (σ_xy ≤ 5 m hard, ≤ 3 m full quality)
    • deferred-hardware: multi-flight voting (N≥2 flights, Service-side voting layer outside this build)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py (for onboard trust_level gating)
    • deferred_hardware (for multi-flight voting)

    Implementing components.

    • src/gps_denied/components/satellite_matcher/
    • src/gps_denied/components/anchor_verifier/

    Status. active (onboard gate — Stage 2); deferred-hardware-validation (multi-flight voting — Stage 3)

AC-NEW-8 — Visual blackout + GPS spoofing degraded-mode budget

  • AC-NEW-8 — Visual blackout + GPS spoofing degraded-mode budget

    Statement. When the navigation camera is fully unusable for visual localization and the flight controller simultaneously reports GPS denial/spoofing, the onboard system shall:

    • continue emitting GPS_INPUT from IMU-only propagation for up to 30 s after the last trusted visual/satellite anchor, unless the estimator covariance exceeds the fail threshold earlier;
    • label every estimate {dead_reckoned} and set fix_type=2 or lower when the 95 % covariance semi-major axis exceeds 100 m;
    • emit fix_type=0, horiz_accuracy=999.0, and STATUSTEXT: VISUAL_BLACKOUT_FAILSAFE when the 95 % covariance semi-major axis exceeds 500 m OR visual blackout exceeds 30 s without a trusted re-anchor;
    • never promote spoofed real-GPS measurements back into the estimator during blackout unless the FC GPS health has been stable and non-spoofed for ≥10 s and a visual/satellite consistency check has succeeded. Cross-references: AC-1.4 (source_label vocab); AC-3.5 (blackout mode switch).

    Numeric threshold.

    • IMU-only emit duration: ≤30 s
    • dead_reckoned + fix_type=2 when σ_xy > 100 m
    • fix_type=0 + horiz_accuracy=999.0 + STATUSTEXT VISUAL_BLACKOUT_FAILSAFE when σ_xy > 500 m OR blackout > 30 s
    • GPS re-promotion gate: ≥10 s non-spoofed health + visual/satellite consistency check

    Rationale. A cloud/whiteout period removes all visual correction exactly when spoofed GPS cannot be trusted. Honest IMU-only dead reckoning with rapidly growing uncertainty is the only safe behavior.

    Validation method. blackbox-replay + sitl-simulation (inject 5 s, 15 s, 35 s full-camera blackout while spoofing GPS_RAW_INT; assert mode transition ≤400 ms, spoofed GPS ignored, covariance grows monotonically, GPS_INPUT fields degrade at thresholds, recovery only after trusted anchor or 10 s GPS-health gate)

    Test IDs.

    • populated by scripts/gen_ac_traceability.py

    Implementing components.

    • src/gps_denied/components/safety_state/
    • src/gps_denied/core/eskf.py
    • src/gps_denied/components/mavlink_io/pymavlink_bridge.py

    Status. active