pccc/lib.rs
1//! # Parallel-concatenated convolutional code (PCCC)
2//!
3//! This crate implements encoding and decoding functionality for a _parallel-concatenated
4//! convolutional code_ (PCCC), commonly referred to as a
5//! [turbo code](https://en.wikipedia.org/wiki/Turbo_code). An instance of such a code is
6//! used for forward error correction in the 4G LTE standard for wireless broadband communication
7//! (see [3GPP TS 36.212](https://www.3gpp.org/ftp/Specs/archive/36_series/36.212/)).
8//!
9//! The encoder for a PCCC comprises the parallel concatenation of two identical _recursive
10//! systematic convolutional_ (RSC) encoders, separated by an internal interleaver. The decoder is
11//! based on "turbo" iterations between two corresponding soft-input/soft-output _a posteriori
12//! probability_ (APP) decoders, separated by an interleaver and deinterleaver.
13//!
14//! The [`encoder`] and [`decoder`] functions handle PCCC encoding and decoding, respectively,
15//! while the [`Interleaver`] struct models the internal interleaver and associated deinterleaver.
16//! The [`Bit`] enum represents binary symbol values, and the [`DecodingAlgo`] enum the supported
17//! decoding algorithms; each variant of the latter holds a [`u32`] representing the number of
18//! turbo iterations. The code below illustrates their usage through a toy example.
19//!
20//! # Examples
21//!
22//! ```
23//! use pccc::{decoder, encoder, Bit, DecodingAlgo, Interleaver};
24//! use Bit::{One, Zero};
25//!
26//! // Rate-1/3 PCCC in LTE, 4 information bits, Log-MAP decoding (8 turbo iterations)
27//! let code_polynomials = [0o13, 0o15];
28//! let interleaver = Interleaver::new(&[3, 0, 1, 2])?;
29//!
30//! // Encoding
31//! let info_bits = [One, Zero, Zero, One];
32//! let code_bits = encoder(&info_bits, &interleaver, &code_polynomials)?;
33//! assert_eq!(
34//! code_bits,
35//! [
36//! One, One, One, Zero, One, Zero, Zero, One, Zero, One, Zero, Zero, One, Zero, One, One,
37//! Zero, Zero, Zero, One, One, One, Zero, Zero
38//! ]
39//! );
40//!
41//! // Decoding
42//! let code_bits_llr = [
43//! -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
44//! 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0,
45//! ];
46//! let info_bits_hat = decoder(
47//! &code_bits_llr,
48//! &interleaver,
49//! &code_polynomials,
50//! DecodingAlgo::LogMAP(8),
51//! )?;
52//! assert_eq!(info_bits_hat, [One, Zero, Zero, One]);
53//! # Ok::<(), Box<dyn std::error::Error>>(())
54//! ```
55//!
56//! The [`lte`] module contains encoder and decoder functions specifically for the rate-1/3 PCCC
57//! used in the LTE standard; the block size is restricted to the values in Table 5.1.3-3 of 3GPP
58//! TS 36.212 (from 40 to 6144 bits), and the interleaver for each of these block sizes is
59//! automatically set to the _quadratic permutation polynomial_ (QPP) interleaver prescribed
60//! therein. This module also has functions to evaluate the performance of the LTE PCCC over a
61//! BPSK-AWGN channel by simulation. Finally, the [`utils`] module has some useful functions for
62//! such a simulation.
63
64#![warn(
65 clippy::complexity,
66 clippy::pedantic,
67 clippy::perf,
68 clippy::style,
69 clippy::suspicious,
70 missing_copy_implementations,
71 missing_debug_implementations,
72 missing_docs,
73 trivial_casts,
74 trivial_numeric_casts,
75 unused_allocation,
76 unused_import_braces,
77 unused_qualifications
78)]
79
80use std::fmt;
81use std::io;
82
83use rand::{rngs::ThreadRng, seq::SliceRandom};
84use serde::{Deserialize, Serialize};
85use thiserror::Error;
86
87pub mod lte;
88mod rsc;
89pub mod utils;
90
91/// Custom error type
92#[derive(Error, Debug)]
93pub enum Error {
94 /// Invalid input error
95 #[error("{0}")]
96 InvalidInput(String),
97 /// File read/write error
98 #[error("{0}")]
99 FileReadWriteError(#[from] io::Error),
100 /// Serde read/write error
101 #[error("{0}")]
102 SerdeReadWriteError(#[from] serde_json::Error),
103 /// Unknown error
104 #[error("Unknown error")]
105 Unknown,
106}
107
108/// Enumeration of binary symbol values
109#[derive(Clone, Eq, PartialEq, Debug, Copy)]
110pub enum Bit {
111 /// Binary symbol `0`
112 Zero = 0,
113 /// Binary symbol `1`
114 One = 1,
115}
116
117/// Enumeration of PCCC decoding algorithms
118#[derive(Clone, Eq, Hash, PartialEq, Debug, Copy, Deserialize, Serialize)]
119pub enum DecodingAlgo {
120 /// Log-MAP decoding with given number of turbo iterations
121 LogMAP(u32),
122 /// Max-Log-MAP decoding with given number of turbo iterations
123 MaxLogMAP(u32),
124 /// Linear-Log-MAP decoding (Valenti & Sun, 2001) with given number of turbo iterations
125 LinearLogMAP(u32),
126}
127
128impl DecodingAlgo {
129 /// Returns the name of the variant.
130 fn name(&self) -> &str {
131 match self {
132 DecodingAlgo::LogMAP(_) => "Log-MAP",
133 DecodingAlgo::MaxLogMAP(_) => "Max-Log-MAP",
134 DecodingAlgo::LinearLogMAP(_) => "Linear-Log-MAP",
135 }
136 }
137
138 /// Returns the number of turbo iterations held in the variant.
139 fn num_iter(self) -> u32 {
140 match self {
141 DecodingAlgo::LogMAP(n)
142 | DecodingAlgo::MaxLogMAP(n)
143 | DecodingAlgo::LinearLogMAP(n) => n,
144 }
145 }
146}
147
148impl fmt::Display for DecodingAlgo {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 write!(
151 f,
152 "{} decoding, {} iterations",
153 self.name(),
154 self.num_iter()
155 )
156 }
157}
158
159/// Interleaver for sequences of a given length
160#[derive(Eq, PartialEq, Debug)]
161pub struct Interleaver {
162 /// Length of input/output sequence
163 length: usize,
164 /// Input index for each output index (needed in interleaving)
165 all_in_index_given_out_index: Vec<usize>,
166 /// Output index for each input index (needed in deinterleaving)
167 all_out_index_given_in_index: Vec<usize>,
168}
169
170impl Interleaver {
171 /// Returns interleaver corresponding to a given permutation.
172 ///
173 /// # Parameters
174 ///
175 /// - `perm`: Permutation of integers in `[0, L)` for some positive integer `L`. If the
176 /// interleaver input is the sequence `x[0], x[1], ..., x[L-1]`, then its output is the
177 /// sequence `x[perm[0]], x[perm[1]], ..., x[perm[L-1]]`.
178 ///
179 /// # Errors
180 ///
181 /// Returns an error if `perm` is not a permutation of the integers in `[0, L)` for some
182 /// positive integer `L`.
183 ///
184 /// # Examples
185 ///
186 /// ```
187 /// use pccc::Interleaver;
188 ///
189 /// let perm = [0, 3, 2, 5, 4, 7, 6, 1];
190 /// let interleaver = Interleaver::new(&perm)?;
191 /// # Ok::<(), Box<dyn std::error::Error>>(())
192 /// ```
193 pub fn new(perm: &[usize]) -> Result<Self, Error> {
194 if perm.is_empty() {
195 return Err(Error::InvalidInput(
196 "Permutation cannot be empty".to_string(),
197 ));
198 }
199 let perm_vec = perm.to_vec();
200 let mut perm_vec_sorted = perm.to_vec();
201 perm_vec_sorted.sort_unstable();
202 if !perm_vec_sorted.into_iter().eq(0 .. perm_vec.len()) {
203 return Err(Error::InvalidInput(format!(
204 "Expected permutation of all integers in the range [0, {})",
205 perm_vec.len()
206 )));
207 }
208 Ok(Self::from_valid_perm(perm_vec))
209 }
210
211 /// Returns random interleaver for sequences of a given length.
212 ///
213 /// # Parameters
214 ///
215 /// - `length`: Length of input/output sequence.
216 ///
217 /// - `rng`: Random number generator to be used.
218 ///
219 /// # Errors
220 ///
221 /// Returns an error if `length` is `0`.
222 ///
223 /// # Examples
224 ///
225 /// ```
226 /// use pccc::Interleaver;
227 ///
228 /// let mut rng = rand::thread_rng();
229 /// let length = 8;
230 /// let interleaver = Interleaver::random(length, &mut rng)?;
231 /// # Ok::<(), Box<dyn std::error::Error>>(())
232 /// ```
233 pub fn random(length: usize, rng: &mut ThreadRng) -> Result<Self, Error> {
234 if length == 0 {
235 return Err(Error::InvalidInput(
236 "Length must be a positive integer".to_string(),
237 ));
238 }
239 let mut perm_vec: Vec<usize> = (0 .. length).collect();
240 perm_vec.shuffle(rng);
241 Ok(Self::from_valid_perm(perm_vec))
242 }
243
244 /// Generates interleaver output given its input.
245 ///
246 /// # Parameters
247 ///
248 /// - `input`: Interleaver input.
249 ///
250 /// - `output`: Buffer for interleaver output (any pre-existing contents will be cleared).
251 ///
252 /// # Errors
253 ///
254 /// Returns an error if `input.len()` is not equal to `self.length`.
255 ///
256 /// # Examples
257 ///
258 /// ```
259 /// use pccc::Interleaver;
260 ///
261 /// let perm = [0, 3, 2, 5, 4, 7, 6, 1];
262 /// let interleaver = Interleaver::new(&perm)?;
263 /// let input = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
264 /// let mut output = Vec::new();
265 /// interleaver.interleave(&input, &mut output)?;
266 /// assert_eq!(output, ['a', 'd', 'c', 'f', 'e', 'h', 'g', 'b']);
267 /// # Ok::<(), Box<dyn std::error::Error>>(())
268 /// ```
269 pub fn interleave<T: Copy>(&self, input: &[T], output: &mut Vec<T>) -> Result<(), Error> {
270 if input.len() != self.length {
271 return Err(Error::InvalidInput(format!(
272 "Interleaver input has length {} (expected {})",
273 input.len(),
274 self.length,
275 )));
276 }
277 output.clear();
278 for out_index in 0 .. self.length {
279 output.push(input[self.all_in_index_given_out_index[out_index]]);
280 }
281 Ok(())
282 }
283
284 /// Generates interleaver input given its output.
285 ///
286 /// # Parameters
287 ///
288 /// - `output`: Interleaver output.
289 ///
290 /// - `input`: Buffer for interleaver input (any pre-existing contents will be cleared).
291 ///
292 /// # Errors
293 ///
294 /// Returns an error if `output.len()` is not equal to `self.length`.
295 ///
296 /// # Examples
297 ///
298 /// ```
299 /// use pccc::Interleaver;
300 ///
301 /// let perm = [0, 3, 2, 5, 4, 7, 6, 1];
302 /// let interleaver = Interleaver::new(&perm)?;
303 /// let output = ['a', 'd', 'c', 'f', 'e', 'h', 'g', 'b'];
304 /// let mut input = Vec::new();
305 /// interleaver.deinterleave(&output, &mut input)?;
306 /// assert_eq!(input, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
307 /// # Ok::<(), Box<dyn std::error::Error>>(())
308 /// ```
309 pub fn deinterleave<T: Copy>(&self, output: &[T], input: &mut Vec<T>) -> Result<(), Error> {
310 if output.len() != self.length {
311 return Err(Error::InvalidInput(format!(
312 "Interleaver output has length {} (expected {})",
313 output.len(),
314 self.length,
315 )));
316 }
317 input.clear();
318 for in_index in 0 .. self.length {
319 input.push(output[self.all_out_index_given_in_index[in_index]]);
320 }
321 Ok(())
322 }
323
324 /// Returns interleaver corresponding to a valid permutation.
325 fn from_valid_perm(perm_vec: Vec<usize>) -> Self {
326 let length = perm_vec.len();
327 let all_in_index_given_out_index: Vec<usize> = perm_vec;
328 let mut all_out_index_given_in_index: Vec<usize> = (0 .. length).collect();
329 all_out_index_given_in_index.sort_by_key(|&k| all_in_index_given_out_index[k]);
330 Self {
331 length,
332 all_in_index_given_out_index,
333 all_out_index_given_in_index,
334 }
335 }
336}
337
338/// Returns code bits from PCCC encoder for given information bits.
339///
340/// # Parameters
341///
342/// - `info_bits`: Information bits to be encoded.
343///
344/// - `interleaver`: Internal interleaver for the code.
345///
346/// - `code_polynomials`: Integer representations of the generator polynomials for the code. Must
347/// have length `N >= 2` for a PCCC code of rate `1/(2*N-1)`. The first element is taken as the
348/// feedback polynomial (this corresponds to the systematic bit), and all subsequent ones as the
349/// feedforward polynomials (these correspond to the parity bits from each RSC encoder). For a
350/// code of constraint length `L`, the feedback polynomial must be in the range `(2^(L-1), 2^L)`,
351/// and each feedforward polynomial must be in the range `[1, 2^L)` and different from the
352/// feedback polynomial.
353///
354/// # Returns
355///
356/// - `code_bits`: Code bits from the PCCC encoder.
357///
358/// # Errors
359///
360/// Returns an error if the number of information bits is not equal to `interleaver.length` or if
361/// `code_polynomials` is invalid. The latter condition holds if the number of code polynomials is
362/// less than `2`, if the first code polynomial is either `0` or a power of `2`, or if any
363/// subsequent code polynomial is either not in the range `[1, 2^L)` or equals the first code
364/// polynomial; here, `L` is the positive integer such that the first code polynomial is in the
365/// range `(2^(L-1), 2^L)`.
366///
367/// # Examples
368/// ```
369/// use pccc::{encoder, Bit, Interleaver};
370/// use Bit::{One, Zero};
371///
372/// let code_polynomials = [0o13, 0o15]; // Rate-1/3 PCCC in LTE
373/// let interleaver = Interleaver::new(&[3, 0, 1, 2])?; // 4 information bits
374/// let info_bits = [One, Zero, Zero, One];
375/// let code_bits = encoder(&info_bits, &interleaver, &code_polynomials)?;
376/// assert_eq!(
377/// code_bits,
378/// [
379/// One, One, One, Zero, One, Zero, Zero, One, Zero, One, Zero, Zero, One, Zero, One, One,
380/// Zero, Zero, Zero, One, One, One, Zero, Zero
381/// ]
382/// );
383/// # Ok::<(), Box<dyn std::error::Error>>(())
384/// ```
385pub fn encoder(
386 info_bits: &[Bit],
387 interleaver: &Interleaver,
388 code_polynomials: &[usize],
389) -> Result<Vec<Bit>, Error> {
390 let mut sm = rsc::StateMachine::new(code_polynomials)?;
391 let num_info_bits = interleaver.length;
392 let num_code_bits_per_rsc = (num_info_bits + sm.memory_len) * sm.num_output_bits;
393 // Top RSC encoder output
394 let mut top_code_bits = Vec::with_capacity(num_code_bits_per_rsc);
395 rsc::encode(info_bits, &mut sm, &mut top_code_bits);
396 // Bottom RSC encoder output
397 let mut bottom_code_bits = Vec::with_capacity(num_code_bits_per_rsc);
398 let mut interleaved_info_bits = Vec::with_capacity(num_info_bits);
399 interleaver.interleave(info_bits, &mut interleaved_info_bits)?;
400 rsc::encode(&interleaved_info_bits, &mut sm, &mut bottom_code_bits);
401 // PCCC encoder output
402 let mut code_bits = Vec::with_capacity(2 * num_code_bits_per_rsc - num_info_bits);
403 let i_first_rsc_tail_code_bit = num_info_bits * sm.num_output_bits;
404 // Code bits corresponding to information bits
405 for (top_chunk, bottom_chunk) in top_code_bits[.. i_first_rsc_tail_code_bit]
406 .chunks_exact(sm.num_output_bits)
407 .zip(bottom_code_bits[.. i_first_rsc_tail_code_bit].chunks_exact(sm.num_output_bits))
408 {
409 code_bits.extend(top_chunk.iter());
410 code_bits.extend(bottom_chunk.iter().skip(1));
411 }
412 // Code bits corresponding to tail bits
413 code_bits.extend(top_code_bits[i_first_rsc_tail_code_bit ..].iter());
414 code_bits.extend(bottom_code_bits[i_first_rsc_tail_code_bit ..].iter());
415 Ok(code_bits)
416}
417
418/// Returns information bit decisions from PCCC decoder for given code bit LLR values.
419///
420/// # Parameters
421///
422/// - `code_bits_llr`: Log-likelihood-ratio (LLR) values for the code bits.
423///
424/// - `interleaver`: Internal interleaver for the code.
425///
426/// - `code_polynomials`: Integer representations of the generator polynomials for the code. Must
427/// have length `N >= 2` for a PCCC code of rate `1/(2*N-1)`. The first element is taken as the
428/// feedback polynomial (this corresponds to the systematic bit), and all subsequent ones as the
429/// feedforward polynomials (these correspond to the parity bits from each RSC encoder). For a
430/// code of constraint length `L`, the feedback polynomial must be in the range `(2^(L-1), 2^L)`,
431/// and each feedforward polynomial must be in the range `[1, 2^L)` and different from the
432/// feedback polynomial.
433///
434/// - `decoding_algo`: Decoding algorithm to use, and associated number of turbo iterations.
435///
436/// # Returns
437///
438/// - `info_bits_hat`: Decisions on the information bits.
439///
440/// # Errors
441///
442/// Returns an error if the number of code bit LLR values is incompatible with `interleaver.length`
443/// or if `code_polynomials` is invalid. The latter condition holds if the number of code
444/// polynomials is less than `2`, if the first code polynomial is either `0` or a power of `2`, or
445/// if any subsequent code polynomial is either not in the range `[1, 2^L)` or equals the first
446/// code polynomial; here, `L` is the positive integer such that the first code polynomial is in
447/// the range `(2^(L-1), 2^L)`.
448///
449/// # Examples
450/// ```
451/// use pccc::{decoder, Bit, DecodingAlgo, Interleaver};
452/// use Bit::{One, Zero};
453///
454/// let code_polynomials = [0o13, 0o15]; // Rate-1/3 PCCC in LTE
455/// let interleaver = Interleaver::new(&[3, 0, 1, 2])?; // 4 information bits
456/// let code_bits_llr = [
457/// -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
458/// 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0,
459/// ];
460/// let info_bits_hat = decoder(
461/// &code_bits_llr,
462/// &interleaver,
463/// &code_polynomials,
464/// DecodingAlgo::LogMAP(8),
465/// )?; // Log-MAP decoding with 8 turbo iterations
466/// assert_eq!(info_bits_hat, [One, Zero, Zero, One]);
467/// # Ok::<(), Box<dyn std::error::Error>>(())
468/// ```
469pub fn decoder(
470 code_bits_llr: &[f64],
471 interleaver: &Interleaver,
472 code_polynomials: &[usize],
473 decoding_algo: DecodingAlgo,
474) -> Result<Vec<Bit>, Error> {
475 let mut sm = rsc::StateMachine::new(code_polynomials)?;
476 check_decoder_inputs(code_bits_llr, interleaver, &sm)?;
477 let num_info_bits = interleaver.length;
478 if decoding_algo.num_iter() == 0 {
479 return Ok(vec![Bit::Zero; num_info_bits]);
480 }
481 let mut ws = rsc::DecoderWorkspace::new(sm.num_states, num_info_bits, decoding_algo);
482 let (top_code_bits_llr, bottom_code_bits_llr) = bcjr_inputs(code_bits_llr, interleaver, &sm);
483 let mut info_bits_llr_prior = vec![0.0; num_info_bits];
484 for i_iter in 0 .. decoding_algo.num_iter() {
485 // Bottom RSC decoder
486 if i_iter > 0 {
487 interleaver.interleave(&ws.extrinsic_info, &mut info_bits_llr_prior)?;
488 }
489 rsc::decode(
490 &bottom_code_bits_llr,
491 &info_bits_llr_prior,
492 &mut sm,
493 &mut ws,
494 )?;
495 // Top RSC decoder
496 interleaver.deinterleave(&ws.extrinsic_info, &mut info_bits_llr_prior)?;
497 rsc::decode(&top_code_bits_llr, &info_bits_llr_prior, &mut sm, &mut ws)?;
498 }
499 Ok(utils::bpsk_slicer(&ws.llr_posterior))
500}
501
502/// Checks validity of decoder inputs.
503fn check_decoder_inputs(
504 code_bits_llr: &[f64],
505 interleaver: &Interleaver,
506 sm: &rsc::StateMachine,
507) -> Result<(), Error> {
508 let num_info_bits = interleaver.length;
509 let num_code_bits_per_rsc = (num_info_bits + sm.memory_len) * sm.num_output_bits;
510 let expected_code_bits_llr_len = 2 * num_code_bits_per_rsc - num_info_bits;
511 if code_bits_llr.len() == expected_code_bits_llr_len {
512 Ok(())
513 } else {
514 Err(Error::InvalidInput(format!(
515 "For interleaver of length {}, expected {} code bit LLR values (found {})",
516 num_info_bits,
517 expected_code_bits_llr_len,
518 code_bits_llr.len(),
519 )))
520 }
521}
522
523/// Returns code bit LLR values to be input to top and bottom BCJR decoders.
524fn bcjr_inputs(
525 code_bits_llr: &[f64],
526 interleaver: &Interleaver,
527 sm: &rsc::StateMachine,
528) -> (Vec<f64>, Vec<f64>) {
529 let num_info_bits = interleaver.length;
530 let inverse_code_rate = 2 * sm.num_output_bits - 1;
531 let num_code_bits_per_rsc = (num_info_bits + sm.memory_len) * sm.num_output_bits;
532 let mut top_code_bits_llr = Vec::with_capacity(num_code_bits_per_rsc);
533 let mut bottom_code_bits_llr = Vec::with_capacity(num_code_bits_per_rsc);
534 // Information bits
535 for k in 0 .. num_info_bits {
536 let i_top = k * inverse_code_rate;
537 top_code_bits_llr.extend_from_slice(&code_bits_llr[i_top .. i_top + sm.num_output_bits]);
538 let i_bottom = interleaver.all_in_index_given_out_index[k] * inverse_code_rate;
539 bottom_code_bits_llr.push(code_bits_llr[i_bottom]);
540 bottom_code_bits_llr.extend_from_slice(
541 &code_bits_llr[i_top + sm.num_output_bits .. i_top + inverse_code_rate],
542 );
543 }
544 // Tail bits
545 top_code_bits_llr.extend_from_slice(
546 &code_bits_llr[num_info_bits * inverse_code_rate
547 .. num_info_bits * inverse_code_rate + sm.memory_len * sm.num_output_bits],
548 );
549 bottom_code_bits_llr.extend_from_slice(
550 &code_bits_llr[num_info_bits * inverse_code_rate + sm.memory_len * sm.num_output_bits ..],
551 );
552 (top_code_bits_llr, bottom_code_bits_llr)
553}
554
555#[cfg(test)]
556mod tests_of_interleaver {
557 use super::*;
558
559 #[test]
560 fn test_new() {
561 // Invalid input
562 assert!(Interleaver::new(&[]).is_err());
563 assert!(Interleaver::new(&[1, 2, 3, 4]).is_err());
564 assert!(Interleaver::new(&[0, 1, 2, 4]).is_err());
565 assert!(Interleaver::new(&[0, 0, 1, 2]).is_err());
566 // Valid input
567 let interleaver = Interleaver::new(&[0, 3, 2, 5, 4, 7, 6, 1]).unwrap();
568 assert_eq!(interleaver.length, 8);
569 assert_eq!(
570 interleaver.all_in_index_given_out_index,
571 [0, 3, 2, 5, 4, 7, 6, 1]
572 );
573 assert_eq!(
574 interleaver.all_out_index_given_in_index,
575 [0, 7, 2, 1, 4, 3, 6, 5]
576 );
577 }
578
579 #[test]
580 fn test_random() {
581 let mut rng = rand::thread_rng();
582 // Invalid input
583 assert!(Interleaver::random(0, &mut rng).is_err());
584 // Valid input
585 let length = 8;
586 let interleaver = Interleaver::random(length, &mut rng).unwrap();
587 let mut o2i = interleaver.all_in_index_given_out_index;
588 o2i.sort_unstable();
589 assert!(o2i == (0 .. length).collect::<Vec<usize>>());
590 }
591
592 #[test]
593 fn test_interleave() {
594 let interleaver = Interleaver::new(&[0, 3, 2, 5, 4, 7, 6, 1]).unwrap();
595 let mut output = Vec::new();
596 // Invalid input
597 let input = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
598 assert!(interleaver.interleave(&input, &mut output).is_err());
599 // Valid input
600 let input = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
601 for _ in 0 .. 2 {
602 interleaver.interleave(&input, &mut output).unwrap();
603 assert_eq!(output, ['a', 'd', 'c', 'f', 'e', 'h', 'g', 'b']);
604 }
605 }
606
607 #[test]
608 fn test_deinterleave() {
609 let interleaver = Interleaver::new(&[0, 3, 2, 5, 4, 7, 6, 1]).unwrap();
610 let mut input = Vec::new();
611 // Invalid output
612 let output = ['a', 'd', 'c', 'f', 'e', 'h', 'g'];
613 assert!(interleaver.deinterleave(&output, &mut input).is_err());
614 // Valid output
615 let output = ['a', 'd', 'c', 'f', 'e', 'h', 'g', 'b'];
616 for _ in 0 .. 2 {
617 interleaver.deinterleave(&output, &mut input).unwrap();
618 assert_eq!(input, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
619 }
620 }
621
622 #[test]
623 fn test_from_valid_perm() {
624 let interleaver = Interleaver::from_valid_perm(vec![0, 3, 2, 5, 4, 7, 6, 1]);
625 assert_eq!(interleaver.length, 8);
626 assert_eq!(
627 interleaver.all_in_index_given_out_index,
628 [0, 3, 2, 5, 4, 7, 6, 1]
629 );
630 assert_eq!(
631 interleaver.all_out_index_given_in_index,
632 [0, 7, 2, 1, 4, 3, 6, 5]
633 );
634 }
635}
636
637#[cfg(test)]
638mod tests_of_functions {
639 use super::*;
640 use float_eq::assert_float_eq;
641 use Bit::{One, Zero};
642
643 #[test]
644 fn test_encoder() {
645 let code_polynomials = [0o13, 0o15];
646 let interleaver = Interleaver::new(&[3, 0, 1, 2]).unwrap();
647 // Invalid inputs
648 let info_bits = [Zero, One, One];
649 assert!(encoder(&info_bits, &interleaver, &code_polynomials).is_err());
650 // Valid inputs
651 let info_bits = [One, Zero, Zero, One];
652 let code_bits = encoder(&info_bits, &interleaver, &code_polynomials).unwrap();
653 assert_eq!(
654 code_bits,
655 [
656 One, One, One, Zero, One, Zero, Zero, One, Zero, One, Zero, Zero, One, Zero, One,
657 One, Zero, Zero, Zero, One, One, One, Zero, Zero
658 ]
659 );
660 }
661
662 #[test]
663 fn test_decoder() {
664 let code_polynomials = [0o13, 0o15];
665 let interleaver = Interleaver::new(&[3, 0, 1, 2]).unwrap();
666 // Invalid inputs
667 let code_bits_llr = [10.0, -10.0, -10.0];
668 assert!(decoder(
669 &code_bits_llr,
670 &interleaver,
671 &code_polynomials,
672 DecodingAlgo::LinearLogMAP(8),
673 )
674 .is_err());
675 // Valid inputs
676 let code_bits_llr = [
677 -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0,
678 -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0,
679 ];
680 let info_bits_hat = decoder(
681 &code_bits_llr,
682 &interleaver,
683 &code_polynomials,
684 DecodingAlgo::LinearLogMAP(8),
685 )
686 .unwrap();
687 assert_eq!(info_bits_hat, [One, Zero, Zero, One]);
688 }
689
690 #[test]
691 fn test_check_decoder_inputs() {
692 let sm = rsc::StateMachine::new(&[0o13, 0o15]).unwrap();
693 let interleaver = Interleaver::new(&[0, 3, 1, 2]).unwrap();
694 // Invalid inputs
695 let code_bits_llr = [
696 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
697 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0,
698 ];
699 assert!(check_decoder_inputs(&code_bits_llr, &interleaver, &sm).is_err());
700 let code_bits_llr = [
701 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
702 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0,
703 ];
704 assert!(check_decoder_inputs(&code_bits_llr, &interleaver, &sm).is_err());
705 // Valid inputs
706 let code_bits_llr = [
707 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
708 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0,
709 ];
710 assert!(check_decoder_inputs(&code_bits_llr, &interleaver, &sm).is_ok());
711 }
712
713 #[test]
714 fn test_bcjr_inputs() {
715 let sm = rsc::StateMachine::new(&[0o13, 0o15]).unwrap();
716 let interleaver = Interleaver::new(&[0, 3, 1, 2]).unwrap();
717 let code_bits_llr = [
718 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
719 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0,
720 ];
721 let (top_code_bits_llr, bottom_code_bits_llr) =
722 bcjr_inputs(&code_bits_llr, &interleaver, &sm);
723 assert_float_eq!(
724 top_code_bits_llr,
725 [0.0, 1.0, 3.0, 4.0, 6.0, 7.0, 9.0, 10.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0].to_vec(),
726 abs_all <= 1e-8
727 );
728 assert_float_eq!(
729 bottom_code_bits_llr,
730 [0.0, 2.0, 9.0, 5.0, 3.0, 8.0, 6.0, 11.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0].to_vec(),
731 abs_all <= 1e-8
732 );
733 }
734}