#!/usr/bin/env python3 """Run the independent RTK--IMU calibration against the project inventory.""" from __future__ import annotations import argparse import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) from rtk_imu.rtk_imu_replay import ( DEFAULT_RTK_FRAME_DEFINITION, DEFAULT_RTK_REFERENCE_POINT, load_inventory, load_sessions, run_calibration, ) def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "--inventory", type=Path, default=ROOT / "artifacts" / "rtk_imu_inventory_v1" / "rtk_session_inventory.csv", ) parser.add_argument( "--output-dir", type=Path, default=ROOT / "artifacts" / "rtk_imu_calibration_v1", ) parser.add_argument("--session", action="append", help="session id to include; repeatable") parser.add_argument("--batch", action="append", help="batch id to include; repeatable") parser.add_argument("--rotation-only", action="store_true") parser.add_argument("--no-loo", action="store_true") parser.add_argument("--knot-step-s", type=float, default=2.0) parser.add_argument("--per-batch", action="store_true") parser.add_argument("--rtk-frame-definition", default=DEFAULT_RTK_FRAME_DEFINITION) parser.add_argument("--rtk-reference-point", default=DEFAULT_RTK_REFERENCE_POINT) args = parser.parse_args(argv) entries = load_inventory(args.inventory) if args.session: selected = set(args.session) entries = [entry for entry in entries if entry.session_id in selected] if args.batch: selected_batches = set(args.batch) entries = [entry for entry in entries if entry.batch_id in selected_batches] if not entries: raise SystemExit("no inventory rows match the requested selection") sessions = load_sessions(entries) rotation, translation = run_calibration( sessions, args.output_dir, rotation_only=args.rotation_only, compute_loo=not args.no_loo, knot_step_s=args.knot_step_s, rtk_frame_definition=args.rtk_frame_definition, rtk_reference_point=args.rtk_reference_point, ) print( json.dumps( { "output": str(args.output_dir.resolve()), "sessions": [session.session_id for session in sessions], "rotation_ok": rotation.ok, "rotation_rpy_deg": rotation.rpy_deg.tolist(), "rotation_rms_deg": rotation.residual_rms_deg, "translation_ok": None if translation is None else translation.ok, "translation_m": None if translation is None else translation.t_RTK_IMU_m.tolist(), }, ensure_ascii=False, indent=2, ) ) if args.per_batch: for batch in sorted({entry.batch_id for entry in entries}): batch_entries = [entry for entry in entries if entry.batch_id == batch] if len(batch_entries) < 2: continue run_calibration( load_sessions(batch_entries), args.output_dir / "per_batch" / batch, rotation_only=args.rotation_only, compute_loo=False, knot_step_s=args.knot_step_s, rtk_frame_definition=args.rtk_frame_definition, rtk_reference_point=args.rtk_reference_point, ) return 0 if __name__ == "__main__": raise SystemExit(main())