CCSDS Synchronization and Channel Coding (131.0-B, 231.0-B)
0
fork

Configure Feed

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

irmin: tar backend — TAR→tree codec with SHA-256 Merkle tree

+84 -13
+78 -13
lib/coding.ml
··· 82 82 83 83 (* {1 Reed-Solomon} 84 84 85 - CCSDS RS(255,223) with interleaving. 85 + CCSDS RS(255,223) with dual-basis representation and interleaving. 86 + 87 + Per CCSDS 131.0-B-4 Annex F, the code operates in the Berlekamp dual 88 + basis. Data symbols are converted from conventional to dual basis before 89 + encoding, and parity symbols are converted back from dual to conventional 90 + after encoding. Decoding reverses the process. 91 + 92 + The RS code parameters in the conventional basis: 93 + - Field polynomial: 0x187 (x^8 + x^7 + x^2 + x + 1) 94 + - Primitive element: alpha^11 = 173 (in conventional representation) 95 + - First consecutive root: 112 96 + - Error correction capability: t = 16 86 97 87 98 For interleave depth I: 88 99 - Encode: split the input (223*I bytes) into I sub-streams via round-robin ··· 103 114 | I5 -> 5 104 115 | I8 -> 8 105 116 106 - let rs = Reed_solomon.ccsds 117 + (* CCSDS RS uses alpha^11 = 173 as the primitive element in the 118 + conventional representation. The generic reed_solomon library uses 119 + alpha=11, so we override the primitive_element here. *) 120 + let rs = { Reed_solomon.ccsds with primitive_element = 173 } 121 + 122 + (* {2 Dual-basis transformation} 123 + 124 + CCSDS 131.0-B-4 Annex F2 defines two 8x8 binary matrices for converting 125 + between conventional binary representation and Berlekamp dual basis: 126 + - T_inv (conventional -> dual): applied to data before encoding 127 + - T_str (dual -> conventional): applied to parity after encoding 128 + 129 + Each matrix is stored column-wise: entry [i] is a bitmask where bit j 130 + (MSB = bit 7) indicates row j of column i. Matrix-vector multiplication 131 + is computed as XOR of selected columns via bitwise AND + popcount. *) 132 + 133 + let straight_t = [| 0xFE; 0x69; 0x6B; 0x0D; 0xEF; 0xF2; 0x5B; 0xC7 |] 134 + let inverted_t = [| 0x9B; 0xDD; 0x3E; 0x1C; 0x37; 0xB3; 0x60; 0x94 |] 135 + 136 + (* Population count mod 2 for a byte: 1 if odd number of set bits. *) 137 + let parity8 x = 138 + let x = x lxor (x lsr 4) in 139 + let x = x lxor (x lsr 2) in 140 + x lxor (x lsr 1) land 1 141 + 142 + let matrix_mul_byte matrix x = 143 + let result = ref 0 in 144 + for i = 0 to 7 do 145 + let product = x land matrix.(i) land 0xFF in 146 + if parity8 product = 1 then result := !result lor (1 lsl (7 - i)) 147 + done; 148 + !result 149 + 150 + (* Pre-compute 256-entry lookup tables for fast byte-level conversion. *) 151 + let make_lut matrix = Array.init 256 (matrix_mul_byte matrix) 152 + let conv_to_dual = make_lut inverted_t 153 + let dual_to_conv = make_lut straight_t 154 + 155 + let transform_bytes lut b = 156 + Bytes.init (Bytes.length b) (fun i -> 157 + Char.chr lut.(Char.code (Bytes.get b i))) 158 + 159 + (* Encode a single 223-byte block: conv data -> dual -> RS -> dual parity -> conv *) 160 + let encode_block data = 161 + let data_dual = transform_bytes conv_to_dual data in 162 + let cw = Reed_solomon.encode_systematic rs data_dual in 163 + (* Build output: original (conventional) data + conventional parity *) 164 + let out = Bytes.make rs.n '\x00' in 165 + Bytes.blit data 0 out 0 rs.k; 166 + for i = 0 to (2 * rs.t) - 1 do 167 + Bytes.set out (rs.k + i) 168 + (Char.chr dual_to_conv.(Char.code (Bytes.get cw (rs.k + i)))) 169 + done; 170 + out 171 + 172 + (* Decode a single 255-byte block: conv cw -> dual -> RS decode -> dual data -> conv *) 173 + let decode_block cw = 174 + let cw_dual = transform_bytes conv_to_dual cw in 175 + match Reed_solomon.decode rs cw_dual with 176 + | Ok data_dual -> Ok (transform_bytes dual_to_conv data_dual) 177 + | Error e -> Error (Fmt.str "%a" Reed_solomon.pp_error e) 107 178 108 179 let encode ?(interleave = I1) data = 109 180 let depth = interleave_depth interleave in ··· 112 183 invalid_arg 113 184 (Fmt.str "Reed_solomon.encode: expected %d bytes (223*%d), got %d" 114 185 data_len depth (Bytes.length data)); 115 - if depth = 1 then Reed_solomon.encode_systematic rs data 186 + if depth = 1 then encode_block data 116 187 else begin 117 188 (* De-interleave input into [depth] sub-streams of 223 bytes each *) 118 189 let subs = Array.init depth (fun _ -> Bytes.make rs.k '\x00') in ··· 122 193 Bytes.set subs.(sub_idx) byte_idx (Bytes.get data i) 123 194 done; 124 195 (* Encode each sub-stream *) 125 - let coded = Array.map (Reed_solomon.encode_systematic rs) subs in 196 + let coded = Array.map encode_block subs in 126 197 (* Interleave the [depth] codewords of 255 bytes each *) 127 198 let out_len = rs.n * depth in 128 199 let out = Bytes.make out_len '\x00' in ··· 141 212 Error 142 213 (Fmt.str "Reed_solomon.decode: expected %d bytes (255*%d), got %d" 143 214 code_len depth (Bytes.length codeword)) 144 - else if depth = 1 then 145 - match Reed_solomon.decode rs codeword with 146 - | Ok data -> Ok data 147 - | Error e -> Error (Fmt.str "%a" Reed_solomon.pp_error e) 215 + else if depth = 1 then decode_block codeword 148 216 else begin 149 217 (* De-interleave into [depth] sub-streams of 255 bytes each *) 150 218 let subs = Array.init depth (fun _ -> Bytes.make rs.n '\x00') in ··· 154 222 done 155 223 done; 156 224 (* Decode each sub-stream *) 157 - let results = Array.map (Reed_solomon.decode rs) subs in 225 + let results = Array.map decode_block subs in 158 226 (* Check for errors *) 159 227 let err = 160 228 Array.fold_left 161 229 (fun acc r -> 162 230 match acc with 163 231 | Some _ -> acc 164 - | None -> ( 165 - match r with 166 - | Ok _ -> None 167 - | Error e -> Some (Fmt.str "%a" Reed_solomon.pp_error e))) 232 + | None -> ( match r with Ok _ -> None | Error e -> Some e)) 168 233 None results 169 234 in 170 235 match err with
+6
lib/coding.mli
··· 63 63 of correcting up to 16 symbol errors per codeword. Interleaving depths of 1, 64 64 2, 3, 4, 5, and 8 are defined. 65 65 66 + This implementation uses the Berlekamp dual-basis representation specified 67 + in CCSDS 131.0-B-4 Annex F. Data symbols are transparently converted between 68 + conventional binary and dual-basis representation during encoding and 69 + decoding. The output codeword has data in conventional representation 70 + followed by parity in conventional representation. 71 + 66 72 For interleave depth I, the encoder takes [223*I] data bytes, splits them 67 73 round-robin into I sub-streams, encodes each with RS(255,223), and 68 74 interleaves the I codewords into [255*I] output bytes.