mfsk_core/fec/ldpc/
mod.rs1pub mod bp;
24pub mod osd;
25pub mod tables;
26
27pub use bp::{BpResult, bp_decode, check_crc14, crc14};
28pub use osd::{OsdResult, ldpc_encode, osd_decode, osd_decode_deep, osd_decode_deep4};
29
30use crate::core::{FecCodec, FecOpts, FecResult};
31
32pub const LDPC_N: usize = 174;
34pub const LDPC_K: usize = 91;
36pub const LDPC_M: usize = LDPC_N - LDPC_K; #[derive(Copy, Clone, Debug, Default)]
44pub struct Ldpc174_91;
45
46impl FecCodec for Ldpc174_91 {
47 const N: usize = LDPC_N;
48 const K: usize = LDPC_K;
49
50 fn encode(&self, info: &[u8], codeword: &mut [u8]) {
51 assert_eq!(info.len(), LDPC_K, "info must be {} bits", LDPC_K);
52 assert_eq!(codeword.len(), LDPC_N, "codeword must be {} bits", LDPC_N);
53 let mut arr = [0u8; LDPC_K];
54 arr.copy_from_slice(info);
55 let cw = ldpc_encode(&arr);
56 codeword.copy_from_slice(&cw);
57 }
58
59 fn decode_soft(&self, llr: &[f32], opts: &FecOpts<'_>) -> Option<FecResult> {
60 assert_eq!(llr.len(), LDPC_N, "llr must be {} values", LDPC_N);
61 let mut llr_arr = [0f32; LDPC_N];
62 llr_arr.copy_from_slice(llr);
63
64 let ap_storage;
69 let ap_mask: Option<&[bool; LDPC_N]> = match opts.ap_mask {
70 Some((mask, values)) => {
71 assert_eq!(mask.len(), LDPC_N, "ap mask must be {} bits", LDPC_N);
72 assert_eq!(values.len(), LDPC_N, "ap values must be {} bits", LDPC_N);
73 let apmag = llr_arr.iter().map(|x| x.abs()).fold(0.0f32, f32::max) * 1.01;
74 let mut a = [false; LDPC_N];
75 for i in 0..LDPC_N {
76 if mask[i] != 0 {
77 a[i] = true;
78 llr_arr[i] = if values[i] != 0 { apmag } else { -apmag };
79 }
80 }
81 ap_storage = a;
82 Some(&ap_storage)
83 }
84 None => None,
85 };
86
87 if let Some(r) = bp_decode(&llr_arr, ap_mask, opts.bp_max_iter) {
88 let mut info = vec![0u8; LDPC_K];
89 info[..77].copy_from_slice(&r.message77);
90 info[77..].copy_from_slice(&r.codeword[77..LDPC_K]);
91 return Some(FecResult {
92 info,
93 hard_errors: r.hard_errors,
94 iterations: r.iterations,
95 });
96 }
97
98 if opts.osd_depth == 0 {
99 return None;
100 }
101
102 let r = if opts.osd_depth >= 4 {
103 osd_decode_deep4(&llr_arr, 30)?
104 } else {
105 osd_decode_deep(&llr_arr, opts.osd_depth.min(3) as u8)?
106 };
107 let mut info = vec![0u8; LDPC_K];
108 info[..77].copy_from_slice(&r.message77);
109 info[77..].copy_from_slice(&r.codeword[77..LDPC_K]);
110 Some(FecResult {
111 info,
112 hard_errors: r.hard_errors,
113 iterations: 0,
114 })
115 }
116}