Show HN: SIMD Viterbi Decoder in Rust

Aug 05, 2026 05:37 AM - 3 hours ago 1

Crates.io Docs.rs CI

Forward correction correction for SDR, space, and outer applications.

fec implements 2 error-correcting codes that show up throughout software-defined power and spacecraft links:

  • Convolutional codes pinch a Viterbi decoder (hard and soft decision), including the communal rate-1/2 k=7, rate-1/2 k=9, rate-1/3 k=9, and rate-1/6 k=15 codes. Supports immoderate complaint from 1/2 to 1/8 and immoderate bid from k=4 to k=16. On nightly Rust, the simd characteristic enables a Viterbi decoder with acceleration connected SSE/AVX2/AVX512.
  • Reed–Solomon codes complete GF(2⁸) pinch correction and erasure decoding, including the modular CCSDS (255,223) codification successful some the accepted and the on-the-wire dual-basis (Berlekamp) representations.

fec started arsenic and draws dense inspiration from the author's own libcorrect, a C library for guardant correction correction. This crate besides credits Phil Karn's libfec C room for offering an original implementation of these codes, although this crate does not get immoderate root aliases person immoderate narration pinch that library, and the sanction is purely coincidental.

Standard parameters (primitive polynomials, the CCSDS dual-basis transform) are derived from the published CCSDS modular (CCSDS 131.0-B, Annex D for the dual basis).

use fec::{ConvEncoder, ConvDecoder}; // Rate-1/2, order-7 NASA code. let polys = [0o161, 0o127]; let mut enc = ConvEncoder::new(2, 7, &polys); let mut dec = ConvDecoder::new(2, 7, &polys); let msg = b"hello, correction correction"; let mut encoded = vec![0u8; enc.encode_len(msg.len())]; let num_bits = enc.encode(msg, &mut encoded).unwrap(); // ... encoded is corrupted successful transit ... let mut recovered = vec![0u8; msg.len()]; dec.decode_hard(&encoded, num_bits, &mut recovered).unwrap();

decode_soft takes 8-bit soft symbols instead, which corrects much errors when the demodulator tin study its confidence.

use fec::{RsEncoder, RsDecoder}; // Standard CCSDS (255,223) code. let mut enc = RsEncoder::new_ccsds(); let mut dec = RsDecoder::new_ccsds(); let msg: Vec<u8> = (0..223).collect(); let mut artifact = vec![0u8; 255]; enc.encode(&msg, &mut block).unwrap(); // ... artifact is corrupted successful transit ... let mut recovered = vec![0u8; 223]; let corrected = dec.decode(&block, &mut recovered).unwrap(); println!("corrected {corrected} awesome error(s)");

For existent spacecraft telemetry (dual-basis symbols connected the wire), use encode_ccsds_dual / decode_ccsds_dual.

The codes are bit-compatible pinch libfec (Phil Karn, KA9Q), truthful fec tin decode information Karn's room produced and vice versa. A companion shim crate, fec-shim, exposes fec nether libfec's C ABI (init_rs_char, create_viterbi27, encode_rs_ccsds, etc) arsenic a drop-in for existing C codebases. With the simd feature enabled (requires nightly), this crate is more performant than either libcorrect aliases libfec connected x86.

  • More widths for the Reed-Solomon encoder/decoder (narrower than GF(2⁸) and arsenic wide arsenic GF(2¹⁶))
  • Hard-decision erasures successful the convolutional (Viterbi) decoder
  • Punctured codes for the convolutional encoder and decoder

BSD-3-Clause.

More