CCSDS Frame Security Report (FSR)
0
fork

Configure Feed

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

Add TEME-to-J2000 frame conversion; fix station contacts; SGP4 bug found

ocaml-coordinate: Add teme_to_j2000_at and j2000_to_teme_at using IAU-76
precession + IAU-1980 nutation (top 13 terms covering 99.9% of signal).
Proper rotation chain: TEME -> TOD (undo nutation) -> MOD -> J2000 (undo
precession).

ocaml-sgp4 interop:
- Fix station contacts report path (GMAT writes to its output/ dir)
- 14 contact windows from LA over 3 days committed as trace
- SGP4-vs-GMAT now uses TEME->J2000 conversion before comparison
- SGP4 STILL fails: 42.8 km error after 14 hours. This is NOT a frame
issue (conversion only improved by 0.2 km). Genuine SGP4 implementation
difference — needs investigation (likely WGS72/WGS84 or B* model).

+29 -8
+8 -1
lib/fsr.ml
··· 95 95 } 96 96 97 97 let v ~alarm ~bad_sn ~bad_mac ~bad_sa ~spi ~arsn_lsb = 98 - { alarm; bad_sn; bad_mac; bad_sa; spi; arsn_lsb = arsn_lsb land 0xFF } 98 + { 99 + alarm; 100 + bad_sn; 101 + bad_mac; 102 + bad_sa; 103 + spi = spi land 0xFFFF; 104 + arsn_lsb = arsn_lsb land 0xFF; 105 + } 99 106 100 107 (* {1 Encoding/Decoding} *) 101 108
+21 -7
test/test_fsr.ml
··· 152 152 in 153 153 Alcotest.(check int) "ARSN masked to 8 bits" 0xAB t.arsn_lsb 154 154 155 + (** Test SPI is masked to 16 bits. *) 156 + let test_spi_masking () = 157 + let t = 158 + Fsr.v ~alarm:false ~bad_sn:false ~bad_mac:false ~bad_sa:false ~spi:0x1FFFF 159 + ~arsn_lsb:0 160 + in 161 + Alcotest.(check int) "SPI masked to 16 bits" 0xFFFF t.spi 162 + 155 163 (** Test pretty-printer produces meaningful output. *) 156 164 let test_pp () = 157 165 let t = ··· 159 167 ~arsn_lsb:0xFF 160 168 in 161 169 let s = Format.asprintf "%a" Fsr.pp t in 162 - Alcotest.(check bool) "contains alarm" true (String.length s > 10); 163 - (* Check that "spi" appears in the pretty-printed output *) 164 - let rec contains_at s sub i = 165 - if i + String.length sub > String.length s then false 166 - else if String.sub s i (String.length sub) = sub then true 167 - else contains_at s sub (i + 1) 170 + let contains sub = 171 + let rec check i = 172 + if i + String.length sub > String.length s then false 173 + else if String.sub s i (String.length sub) = sub then true 174 + else check (i + 1) 175 + in 176 + check 0 168 177 in 169 - Alcotest.(check bool) "contains spi" true (contains_at s "spi" 0) 178 + Alcotest.(check bool) "contains alarm=true" true (contains "alarm=true"); 179 + Alcotest.(check bool) "contains bad_mac=true" true (contains "bad_mac=true"); 180 + Alcotest.(check bool) "contains spi=66" true (contains "spi=66"); 181 + Alcotest.(check bool) "contains bad_sn=false" true (contains "bad_sn=false"); 182 + Alcotest.(check bool) "contains bad_sa=false" true (contains "bad_sa=false") 170 183 171 184 let suite = 172 185 ( "fsr", ··· 188 201 Alcotest.test_case "alarm persistence" `Quick test_alarm_persistence; 189 202 Alcotest.test_case "set/reset alarm" `Quick test_set_reset_alarm; 190 203 Alcotest.test_case "ARSN masking" `Quick test_arsn_masking; 204 + Alcotest.test_case "SPI masking" `Quick test_spi_masking; 191 205 Alcotest.test_case "pretty-printer" `Quick test_pp; 192 206 ] )