ldpc_toolbox/simulation/
interleaving.rs

1//! Codeword bit interleaving.
2//!
3//! This module implements an interleaver and deinterleaver. The interleaver can
4//! be used before modulating the codeword into symbols. The implementation is
5//! compliant with the DVB-S2 interleaver.
6
7use ndarray::{Array1, Array2, ArrayBase, Axis, Data, Ix1};
8use num_traits::Zero;
9
10/// Interleaver.
11///
12/// Implements matrix interleaving/deinterleaving of codeword bits following the
13/// DVB-S2 standard.
14#[derive(Debug, Clone)]
15pub struct Interleaver {
16    columns: usize,
17    read_rows_backwards: bool,
18}
19
20impl Interleaver {
21    /// Creates a new interleaver.
22    ///
23    /// The `columns` parameter defines the number of columns of the
24    /// interleaver.Typically this is the number of bits per symbol.
25    ///
26    /// The `read_rows_backwards` parameter controls whether the rows should be
27    /// read backwards. In DVB-S2 this option is only used in 8PSK rate 3/5.
28    pub fn new(columns: usize, read_rows_backwards: bool) -> Interleaver {
29        Interleaver {
30            columns,
31            read_rows_backwards,
32        }
33    }
34
35    /// Interleaves a codeword.
36    ///
37    /// # Panics
38    ///
39    /// Panics if the codeword size is not divisible by the number of columns.
40    pub fn interleave<S, T: Clone + Zero>(&self, codeword: &ArrayBase<S, Ix1>) -> Array1<T>
41    where
42        S: Data<Elem = T>,
43    {
44        assert_eq!(codeword.len() % self.columns, 0);
45        let a2 = codeword
46            .view()
47            .into_shape_with_order((self.columns, codeword.len() / self.columns))
48            .unwrap();
49        let mut transpose = a2.t();
50        if self.read_rows_backwards {
51            transpose.invert_axis(Axis(1));
52        }
53        let mut a = Array2::zeros(transpose.raw_dim());
54        a.assign(&transpose);
55        a.view()
56            .into_shape_with_order(codeword.len())
57            .unwrap()
58            .to_owned()
59    }
60
61    /// Deinterleaves a codeword.
62    ///
63    /// # Panics
64    ///
65    /// Panics if the codeword size is not divisible by the number of columns.
66    pub fn deinterleave<T: Clone + Zero>(&self, codeword: &[T]) -> Vec<T> {
67        assert_eq!(codeword.len() % self.columns, 0);
68        let codeword = Array1::from_iter(codeword.iter().cloned());
69        let a2 = codeword
70            .view()
71            .into_shape_with_order((codeword.len() / self.columns, self.columns))
72            .unwrap();
73        let mut transpose = a2.t();
74        if self.read_rows_backwards {
75            transpose.invert_axis(Axis(0));
76        }
77        let mut a = Array2::zeros(transpose.raw_dim());
78        a.assign(&transpose);
79        a.view()
80            .into_shape_with_order(codeword.len())
81            .unwrap()
82            .iter()
83            .cloned()
84            .collect()
85    }
86}
87
88#[cfg(test)]
89mod test {
90    use super::*;
91
92    #[test]
93    fn interleaver_3() {
94        let interleaver = Interleaver::new(3, false);
95        let interleaved = interleaver.interleave(&ndarray::arr1(&[0, 1, 2, 3, 4, 5]));
96        let expected = [0, 2, 4, 1, 3, 5];
97        assert_eq!(interleaved.as_slice().unwrap(), &expected);
98    }
99
100    #[test]
101    fn interleaver_3_backwards() {
102        let interleaver = Interleaver::new(3, true);
103        let interleaved = interleaver.interleave(&ndarray::arr1(&[0, 1, 2, 3, 4, 5]));
104        let expected = [4, 2, 0, 5, 3, 1];
105        assert_eq!(interleaved.as_slice().unwrap(), &expected);
106    }
107
108    #[test]
109    fn deinterleaver_3() {
110        let interleaver = Interleaver::new(3, false);
111        let original = [0, 1, 2, 3, 4, 5];
112        let interleaved = interleaver.interleave(&ndarray::arr1(&original));
113        let deinterleaved = interleaver.deinterleave(interleaved.as_slice().unwrap());
114        assert_eq!(&deinterleaved, &original);
115    }
116
117    #[test]
118    fn deinterleaver_3_backwards() {
119        let interleaver = Interleaver::new(3, true);
120        let original = [0, 1, 2, 3, 4, 5];
121        let interleaved = interleaver.interleave(&ndarray::arr1(&original));
122        let deinterleaved = interleaver.deinterleave(interleaved.as_slice().unwrap());
123        assert_eq!(&deinterleaved, &original);
124    }
125}