labrador_ldpc/
lib.rs

1// Copyright 2017 Adam Greig
2// Licensed under the MIT license, see LICENSE for details.
3
4#![no_std]
5#![warn(missing_docs)]
6
7//! Labrador-LDPC implements a selection of LDPC error correcting codes,
8//! including encoders and decoders.
9//!
10//! It is designed for use with other Labrador components but does not have any dependencies
11//! on anything (including `std`) and thus may be used totally standalone. It is reasonably
12//! efficient on both serious computers and on small embedded systems. Considerations have
13//! been made to accommodate both use cases.
14//!
15//! No memory allocations are made inside this crate so most methods require you to pass in an
16//! allocated block of memory for them to use. Check individual method documentation for further
17//! details.
18//!
19//! ## Example
20//!
21//! ```
22//! use labrador_ldpc::LDPCCode;
23//!
24//! // Pick the TC128 code, n=128 k=64
25//! // (that's 8 bytes of user data encoded into 16 bytes)
26//! let code = LDPCCode::TC128;
27//!
28//! // Generate some data to encode
29//! let txdata: Vec<u8> = (0..8).collect();
30//!
31//! // Allocate memory for the encoded data
32//! let mut txcode = vec![0u8; code.n()/8];
33//!
34//! // Encode, copying `txdata` into the start of `txcode` then computing the parity bits
35//! code.copy_encode(&txdata, &mut txcode);
36//!
37//! // Copy the transmitted data and corrupt a few bits
38//! let mut rxcode = txcode.clone();
39//! rxcode[0] ^= 0x55;
40//!
41//! // Allocate some memory for the decoder's working area and output
42//! let mut working = vec![0u8; code.decode_bf_working_len()];
43//! let mut rxdata = vec![0u8; code.output_len()];
44//!
45//! // Decode for at most 20 iterations
46//! code.decode_bf(&rxcode, &mut rxdata, &mut working, 20);
47//!
48//! // Check the errors got corrected
49//! assert_eq!(&rxdata[..8], &txdata[..8]);
50//! ```
51//!
52//! ## Codes
53//!
54//! *Nomenclature:* we use n to represent the code length (number of bits you have to
55//! transmit per codeword), k to represent the code dimension (number of useful information bits
56//! per codeword), and r to represent the *rate* k/n, the number of useful information bits per
57//! bit transmitted.
58//!
59//! Several codes are available in a range of lengths and rates. Current codes come from two
60//! sets of CCSDS recommendations, their TC (telecommand) short-length low-rate codes, and their
61//! TM (telemetry) higher-length various-rates codes. These are all published and standardised
62//! codes which have good performance.
63//!
64//! The TC codes are available in rate r=1/2 and dimensions k=128, k=256, and k=512.
65//! They are the same codes defined in CCSDS document 231.1-O-1 and subsequent revisions (although
66//! the n=256 code is eventually removed, it lives on here as it's quite useful).
67//!
68//! The TM codes are available in r=1/2, r=2/3, and r=4/5, for dimensions k=1024 and k=4096.
69//! They are the same codes defined in CCSDS document 131.0-B-2 and subsequent revisions.
70//!
71//! For more information on the codes themselves please see the CCSDS publications:
72//! https://public.ccsds.org/
73//!
74//! The available codes are the variants of the `LDPCCode` enum, and pretty much everything
75//! else (encoders, decoders, utility methods) are implemented as methods on this enum.
76//!
77//! *Which code should I pick?*: for short and highly-reliable messages, the TC codes make sense,
78//! especially if they need to be decoded on a constrained system such as an embedded platform.
79//! For most other data transfer, the TM codes are more flexible and generally better suited.
80//!
81//! The very large k=16384 TM codes have not been included due to the complexity in generating
82//! their generator matrices and the very long constants involved, but it would be theoretically
83//! possible to include them. The relevant parity check constants are already included.
84//!
85//! ### Generator Matrices
86//!
87//! To encode a codeword, we need a generator matrix, which is a large binary matrix of shape
88//! k rows by n columns. For each bit set in the data to encode, we sum the corresponding row
89//! of the generator matrix to find the output codeword. Because all our codes are *systematic*,
90//! the first k bits of our codewords are exactly the input data, which means we only need to
91//! encode the final n-k parity bits at the end of the codeword.
92//!
93//! These final n-k columns of the generator are stored in a compact form, where only a small
94//! number of the final rows are stored, and the rest can be inferred from those at runtime. Our
95//! encoder methods just use this compact form directly, so it doesn't ever need to be expanded.
96//!
97//! The relevant constants are in the `codes.compact_generators` module, with names like `TC128_G`.
98//!
99//! ### Parity Check Matrices
100//!
101//! These are the counterpart to the generator matrices of the previous section. They are used by
102//! the decoders to work out which bits are wrong and need to be changed. When fully expanded,
103//! they are a large matrix with n-k rows (one per parity check) of n columns (one per input data
104//! bit, or variable). We can store and use them in an extremely compact form due to the way these
105//! specific codes have been constructed.
106//!
107//! The constants are in `codes.compact_parity_checks` and reflect the construction defined
108//! in the CCSDS documents.
109//!
110//! ## Encoders
111//!
112//! There are two encoder methods implemented on `LDPCCode`: `encode` and `copy_encode`.
113//!
114//! `copy_encode` is a convenience wrapper that copies your data to encode into the codeword
115//! memory first, and then performs the encode as usual. In comparison, `encode` requires that
116//! your data is already at the start of the codeword memory, and just fills in the parity bits
117//! at the end. It doesn't take very much time to do the copy, so use whichever is more convenient.
118//!
119//! The encode methods require you to pass in a slice of allocated codeword memory, `&mut [T]`,
120//! which must be `n` bits long exactly. You can pass this as slices of `u8`, `u32`, or `u64`. In
121//! general the larger types will encode up to three times faster, so it's usually worth using
122//! them. They are interpreted as containing your data in little-endian, so you can directly
123//! cast between the `&[u8]` and larger interpretations on all little-endian systems (which is to
124//! say, most systems).
125//!
126//! The encode methods always return an `&mut [u8]` view on the codeword memory, which you
127//! can use if you need this type for further use (such as transmission out of a radio), or if you
128//! ignore the return value you can continue using your original slice of codeword memory.
129//!
130//! ```
131//! # use labrador_ldpc::LDPCCode;
132//! let code = LDPCCode::TC128;
133//!
134//! // Encode into u32, but then access results as u8
135//! let mut codeword: [u32; 4] = [0x03020100, 0x07060504, 0x00000000, 0x00000000];
136//! let txcode = code.encode(&mut codeword);
137//! assert_eq!(txcode, [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
138//!                     0x34, 0x99, 0x98, 0x87, 0x94, 0xE1, 0x62, 0x56]);
139//!
140//! // Encode into u64, but maintain access as a u64 afterwards
141//! let mut codeword: [u64; 2] = [0x0706050403020100, 0x0000000000000000];
142//! code.encode(&mut codeword);
143//! assert_eq!(codeword, [0x0706050403020100, 0x5662E19487989934]);
144//! ```
145//!
146//! The required memory (in bytes) to encode with each code is:
147//!
148//! Code   | Input (RAM) | Output (RAM)    | Generator const (text)
149//! -------|-------------|-----------------|-----------------------
150//!        | =k/8        | =n/8            |
151//! TC128  |           8 |              16 |              32
152//! TC256  |          16 |              32 |              64
153//! TC512  |          32 |              64 |             128
154//! TM1280 |         128 |             160 |            1024
155//! TM1536 |         128 |             192 |            1024
156//! TM2048 |         128 |             256 |            1024
157//! TM5120 |         512 |             640 |            4096
158//! TM6144 |         512 |             768 |            4096
159//! TM8192 |         512 |            1024 |            4096
160//!
161//! ## Decoders
162//!
163//! There are two decoders available:
164//!
165//! * The low-memory decoder, `decode_bf`, uses a bit flipping algorithm with hard information.
166//!   This is maybe 1 or 2dB from optimal for decoding, but requires much less RAM and is usually
167//!   a few times faster. It's only really useful on something very slow or with very little memory
168//!   available.
169//! * The high-performance decoder, `decode_ms`, uses a modified min-sum decoding algorithm with
170//!   soft information to perform near-optimal decoding albeit slower and with much higher memory
171//!   overhead.  This decoder can operate on a variety of types for the soft information, with
172//!   corresponding differences in the memory overhead.
173//!
174//! The required memory (in bytes) to decode with each code is:
175//!
176//! Code   | Hard input  | Soft input  |   Output | Parity const | `bf` overhead | `mp` overhead
177//! -------|-------------|-------------|----------|--------------|---------------|---------------
178//!        | (`bf`, RAM) | (`mp`, RAM) | (RAM)    | (text)       | (RAM)         | (RAM)
179//!        | =n/8        | =n*T        | =(n+p)/8 |              |               |
180//! TC128  |          16 |        128T |       16 |          132 |           128 | 1280T    +   8
181//! TC256  |          32 |        256T |       32 |          132 |           256 | 2560T    +  16
182//! TC512  |          64 |        512T |       64 |          132 |           512 | 5120T    +  32
183//! TM1280 |         160 |       1280T |      176 |          366 |          1408 | 12160T   +  48
184//! TM1536 |         192 |       1536T |      224 |          366 |          1792 | 15104T   +  96
185//! TM2048 |         256 |       2048T |      320 |          366 |          2560 | 20992T   + 192
186//! TM5120 |         640 |       5120T |      704 |          366 |          5632 | 48640T   + 192
187//! TM6144 |         768 |       6144T |      896 |          366 |          7168 | 60416T   + 384
188//! TM8192 |        1024 |       8192T |     1280 |          366 |         10240 | 83968T   + 768
189//!
190//! `T` reflects the size of the type for your soft information: for `i8` this is 1, for `i16` 2,
191//! for `i32` and `f32` it's 4, and for `f64` it is 8. You should use a type commensurate with
192//! the quality of your soft information; usually `i16` would suffice for instance.
193//!
194//! Both decoders require the same output storage and parity constants. The `bf` decoder takes
195//! smaller hard inputs and has a much smaller working area, while the `mp` decoder requires
196//! soft inputs and uses soft information internally, requiring a larger working area.
197//!
198//! The required sizes are available both at compile-time in the `CodeParams` consts, and at
199//! runtime with methods on `LDPCCode` such as `decode_ms_working_len()`. You can therefore
200//! allocate the required memory either statically or dynamically at runtime.
201//!
202//! Please see the individual decoder methods for more details on their requirements.
203//!
204//! ### Bit Flipping Decoder
205//! This decoder is based on the original Gallagher decoder. It is not very optimal but is fast.
206//! The idea is to see which bits are connected to the highest number of parity checks that are not
207//! currently satisfied, and flip those bits, and iterate until things get better.
208//! However, this routine cannot correct erasures (it only knows about bit flips). All of the TM
209//! codes are *punctured*, which means some parity bits are not transmitted and so are unknown at
210//! the receiver. We use a separate algorithm to decode the erasures first, based on a paper by
211//! Archonta, Kanistras and Paliouras, doi:10.1109/MOCAST.2016.7495161.
212//!
213//! ### Message Passing Decoder
214//! This is a modified min-sum decoder that computes the probability of each bit being set given
215//! the other bits connected to it via the parity check matrix. It takes soft information in,
216//! so inherently covers the punctured codes as well. This implementation is based on one described
217//! by Savin, arXiv:0803.1090. It is both reasonably efficient (no `atahn` required), and
218//! performs very close to optimal sum-product decoding.
219
220#[cfg(test)]
221#[macro_use]
222extern crate std;
223
224pub mod codes;
225pub mod encoder;
226pub mod decoder;
227pub use codes::{LDPCCode};