# Topotek KHP20S30 camera calibration (factory-sheet approximation) **Task**: AZ-702_khp20s30_calibration **Name**: Provide a calibration JSON for the Topotek KHP20S30 nadir camera (factory-sheet approximation) **Description**: Compute and commit a `CameraCalibrationArtifact` JSON for the Derkachi camera (Topotek KHP20S30) from manufacturer factory data. Replaces the `adti26.json` placeholder that AC-3 currently uses. Documents the residual error vs a per-unit checkerboard refinement. **Complexity**: 1 point **Dependencies**: None **Component**: input_data / shared_helpers **Tracker**: AZ-702 **Epic**: AZ-696 ## Problem `_docs/00_problem/input_data/flight_derkachi/camera_info.md` states the Topotek KHP20S30 intrinsics are unknown. `tests/e2e/replay/conftest.py` (line 50–56) substitutes `tests/fixtures/calibration/adti26.json` as a placeholder. AC-3 (≤ 100 m horizontal error for 80 % of ticks) is `@xfail` until a real calibration ships. The cheapest reasonable starting point is a factory-sheet approximation — compute `K` from the manufacturer's published focal length + sensor geometry, accept the 1–3 % focal-length residual as a documented budget, and let AC-3 either PASS or honestly FAIL with the residual attributed. ## Outcome - A calibration JSON `khp20s30_factory.json` exists in the Derkachi input directory, parses against the project's `CameraCalibrationArtifact` schema, and documents the acquisition method as `factory_sheet`. - `camera_info.md` is updated to reference the new calibration + the residual budget + the deferral handle (`AZ-XXX_checkerboard_refinement`). - AZ-699 (T3) uses this calibration as its `--camera-calibration` input. ## Scope ### Included - Source manufacturer factory data for the Topotek KHP20S30 (sensor: 1/2.8" CMOS, 2.13 MP, 1920×1080; lens focal length, FOV, pixel pitch). - Compute `K = [[fx, 0, cx], [0, fy, cy], [0, 0, 1]]` from `fx = fy = focal_length_mm × (image_width_px / sensor_width_mm)`. - Set distortion to `[0, 0, 0, 0, 0]` (factory-sheet approximation). - Set `body_to_camera_se3` to identity-down (nadir; camera-z = aircraft-down). - Set `acquisition_method = "factory_sheet"`. - Write `_docs/00_problem/input_data/flight_derkachi/khp20s30_factory.json`. - Update `_docs/00_problem/input_data/flight_derkachi/camera_info.md`. - New unit test under `tests/unit/calibration/` asserting the JSON parses and matches the documented inputs. ### Excluded - Physical checkerboard calibration (needs hardware). - PnP-from-tlog back-computation (deferred follow-up). - Updating `adti26.json` or other test fixtures. ## Acceptance Criteria **AC-1: Calibration JSON parses** Given the new `khp20s30_factory.json` When loaded by the project's calibration parser (same schema as `adti26.json`) Then it parses without error and all fields are populated **AC-2: Doc updated** Given `camera_info.md` before When the calibration is committed Then `camera_info.md` says "factory-sheet approximation; per-unit checkerboard refinement deferred — see " and lists the residual budget **AC-3: Unit test snapshot** Given the new JSON When the unit test runs Then it asserts `fx == fy` (square pixels), `cx ≈ width/2`, `cy ≈ height/2`, distortion all zero **AC-4: T3 consumes this calibration** Given AZ-699's `test_derkachi_real_tlog.py` When it runs Then it loads `khp20s30_factory.json` as `--camera-calibration` (no longer the `adti26.json` placeholder) ## Non-Functional Requirements **Compatibility** - JSON schema MUST be identical to existing calibration fixtures (`adti26.json`) — no schema changes in this task. ## Unit Tests | AC Ref | What to Test | Required Outcome | |--------|-------------|-----------------| | AC-1 | JSON loads via existing parser | Object populated | | AC-3 | Field values match factory inputs | fx == fy, cx/cy at centre, zero distortion | ## Blackbox Tests | AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | |--------|------------------------|-------------|-------------------|----------------| | AC-4 | T3 test pointed at new JSON | T3 launches without calibration parse error | Test starts cleanly | Compat | ## Constraints - MUST follow the calibration contract in `_docs/02_document/contracts/shared_helpers/descriptor_normaliser.md` (or wherever the camera-calibration schema lives). - MUST be a single committed JSON — no generator script with side effects. ## Risks & Mitigation **Risk 1: Factory data unavailable at required precision** - *Risk*: Topotek does not publish the exact focal length / sensor width to the precision needed. - *Mitigation*: Document the gap; ship with the best-available estimate; flag in `camera_info.md` so T3 surfaces the uncertainty in its failure message. **Risk 2: Residual error exceeds AC-3 budget** - *Risk*: 1–3 % focal-length error may push horizontal error past 100 m at 1 km AGL. - *Mitigation*: That's the honest finding. T3 reports it. A follow-up task can pursue checkerboard refinement if needed.