Collision probability computation for conjunction assessment
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Split ocaml-transport into ocaml-cltu and ocaml-cop1

- ocaml-cltu: CLTU encoding/decoding (CCSDS 231.0-B) with BCH(63,56),
ASM sync markers (131.0-B), and stream sync parsers
- ocaml-cop1: COP-1 state machines (CCSDS 232.1-B) for FOP-1 (ground)
and FARM-1 (flight) with Eio service layer
- cltu-eio: CLTU/ASM send/recv over Eio flows
- cop1-eio: COP-1 service layer with Eio timer management

+100 -8
+100 -8
test/interop/gmat/test.ml
··· 1 1 (** GMAT interop tests for ocaml-collision. 2 2 3 - Uses two-object OEM traces from GMAT R2026a to compute miss distances and 4 - validate conjunction geometry. 3 + Uses two-object OEM traces from GMAT R2026a to validate conjunction 4 + geometry. Tests both plumbing (can we parse the data) and mission-ready 5 + properties (is our TCA/miss distance accurate enough for CA decisions). 5 6 6 7 Source: GMAT R2026a, conjunction_leo.script. *) 7 8 ··· 41 42 min_dist := d; 42 43 min_epoch := sv1.(i).epoch) 43 44 done; 44 - (* Two objects on crossing orbits should have closest approach *) 45 45 Alcotest.(check bool) "min distance found" true (Float.is_finite !min_dist); 46 46 Alcotest.(check bool) "min distance < 1000 km" true (!min_dist < 1000.0); 47 - (* Should not collide (different orbital planes cross at two points, 48 - but the satellites are unlikely to be at the crossing point simultaneously) *) 49 47 Alcotest.(check bool) "no collision (> 1 km)" true (!min_dist > 1.0); 50 - Printf.printf " Closest approach: %.3f km at %s\n" !min_dist !min_epoch 48 + Printf.printf " Step-based closest approach: %.3f km at %s\n" !min_dist 49 + !min_epoch 51 50 52 51 let test_relative_velocity () = 53 52 let oem1 = parse_oem "conjunction_sat1.oem" in 54 53 let oem2 = parse_oem "conjunction_sat2.oem" in 55 54 let sv1 = Odm.state_vectors (List.hd (Odm.segments oem1)) in 56 55 let sv2 = Odm.state_vectors (List.hd (Odm.segments oem2)) in 57 - (* At closest approach, relative velocity should be high (crossing orbits) *) 58 56 let n = min (Array.length sv1) (Array.length sv2) in 59 57 let min_i = ref 0 in 60 58 let min_dist = ref Float.infinity in ··· 69 67 Alcotest.(check bool) "high relative velocity" true (dv > 5.0); 70 68 Printf.printf " Relative velocity at TCA: %.3f km/s\n" dv 71 69 70 + (* MISSION-READY TEST: TCA precision. 71 + We find the closest approach by stepping through 10s-spaced data. 72 + The REAL TCA is between two steps. Our step-based TCA has up to 10s error. 73 + 74 + For a conjunction with ~10 km/s relative velocity, 10s uncertainty means 75 + ~100 km position uncertainty — completely unacceptable for CA. 76 + 77 + This test measures how much the miss distance changes around TCA to show 78 + that step-based TCA finding is not sufficient for mission use. *) 79 + let test_tca_precision () = 80 + let oem1 = parse_oem "conjunction_sat1.oem" in 81 + let oem2 = parse_oem "conjunction_sat2.oem" in 82 + let sv1 = Odm.state_vectors (List.hd (Odm.segments oem1)) in 83 + let sv2 = Odm.state_vectors (List.hd (Odm.segments oem2)) in 84 + let n = min (Array.length sv1) (Array.length sv2) in 85 + let min_i = ref 0 in 86 + let min_dist = ref Float.infinity in 87 + for i = 0 to n - 1 do 88 + let d = vec3_norm (vec3_sub sv1.(i).Odm.pos sv2.(i).pos) in 89 + if d < !min_dist then ( 90 + min_dist := d; 91 + min_i := i) 92 + done; 93 + (* Check distance at adjacent steps *) 94 + let d_before = 95 + if !min_i > 0 then 96 + vec3_norm (vec3_sub sv1.(!min_i - 1).Odm.pos sv2.(!min_i - 1).pos) 97 + else !min_dist 98 + in 99 + let d_after = 100 + if !min_i < n - 1 then 101 + vec3_norm (vec3_sub sv1.(!min_i + 1).Odm.pos sv2.(!min_i + 1).pos) 102 + else !min_dist 103 + in 104 + let delta_before = d_before -. !min_dist in 105 + let delta_after = d_after -. !min_dist in 106 + Printf.printf " Distance at TCA-10s: %.3f km (+%.3f km from min)\n" d_before 107 + delta_before; 108 + Printf.printf " Distance at TCA: %.3f km\n" !min_dist; 109 + Printf.printf " Distance at TCA+10s: %.3f km (+%.3f km from min)\n" d_after 110 + delta_after; 111 + (* The miss distance changes by 10s of km in one time step. 112 + This shows the actual TCA is between steps and our step-based 113 + approach misses it. For mission CA, we need interpolation-based 114 + TCA refinement (e.g., quadratic fit around the minimum). *) 115 + let max_delta = Float.max delta_before delta_after in 116 + Printf.printf 117 + " Miss distance changes by %.1f km in 10s — step-based TCA is imprecise\n" 118 + max_delta; 119 + if max_delta > 1.0 then 120 + Printf.printf 121 + " WARNING: >1 km variation in 10s — need TCA refinement for mission CA\n" 122 + 123 + (* MISSION-READY TEST: Pc computation gap. 124 + Real conjunction assessment requires covariance matrices to compute Pc. 125 + GMAT OEMs don't include covariance — we can't compute Pc from OEMs alone. 126 + This test documents the gap: we have positions but no uncertainty estimate. 127 + 128 + Without covariance, the miss distance alone is meaningless for CA decisions. 129 + A 50 km miss distance could be Pc=1e-3 (bad) or Pc=1e-10 (fine) depending 130 + on covariance size. *) 131 + let test_pc_requires_covariance () = 132 + (* We can compute miss distance from GMAT OEMs *) 133 + let oem1 = parse_oem "conjunction_sat1.oem" in 134 + let oem2 = parse_oem "conjunction_sat2.oem" in 135 + let sv1 = Odm.state_vectors (List.hd (Odm.segments oem1)) in 136 + let sv2 = Odm.state_vectors (List.hd (Odm.segments oem2)) in 137 + let n = min (Array.length sv1) (Array.length sv2) in 138 + let min_dist = ref Float.infinity in 139 + for i = 0 to n - 1 do 140 + let d = vec3_norm (vec3_sub sv1.(i).Odm.pos sv2.(i).pos) in 141 + if d < !min_dist then min_dist := d 142 + done; 143 + Printf.printf " Miss distance: %.3f km\n" !min_dist; 144 + Printf.printf " Pc: CANNOT COMPUTE — no covariance in OEM\n"; 145 + Printf.printf 146 + " GAP: Need GMAT covariance propagation (Propagate ... Covariance)\n"; 147 + Printf.printf 148 + " or CDM with covariance to test ocaml-collision Pc computation.\n"; 149 + (* This test passes but documents the gap. The real test would be: 150 + 1. Generate GMAT OEM WITH covariance 151 + 2. Construct a CDM from the GMAT data 152 + 3. Compute Pc with ocaml-collision 153 + 4. Compare against GMAT's Pc *) 154 + Alcotest.(check bool) 155 + "miss distance computed" true 156 + (Float.is_finite !min_dist) 157 + 72 158 let () = 73 159 Alcotest.run "collision-gmat" 74 160 [ 75 - ( "conjunction", 161 + ( "plumbing", 76 162 [ 77 163 Alcotest.test_case "parse both OEMs" `Quick test_parse_both; 78 164 Alcotest.test_case "minimum distance" `Quick test_minimum_distance; 79 165 Alcotest.test_case "relative velocity" `Quick test_relative_velocity; 166 + ] ); 167 + ( "mission-ready", 168 + [ 169 + Alcotest.test_case "TCA precision" `Quick test_tca_precision; 170 + Alcotest.test_case "Pc requires covariance" `Quick 171 + test_pc_requires_covariance; 80 172 ] ); 81 173 ]