1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
#![feature(use_extern_macros)] #![allow(non_camel_case_types)] #[macro_use] extern crate finite_fields; extern crate daggy; extern crate rand; finite_fields::binary_type! { b3, 3 } /// Descriptor for code types. pub enum CodeType { FIRCode, IIRCode } /// A description of a binary convolutional code, either nonrecursive (FIR), or /// recursive (IIR), including start state. pub struct Code { /// The starting state of the registers. pub start_state: Vec<b1>, // TODO make n-1 width type (see issue) /// Storage of the binary polynomial coefficients. Each polynomial corresponds /// to an output bit in the order in which they are stored. /// /// Coefficients are defined in order of increasing delay, e.g. `polys[0][0]` /// is applied to `signal[n]`, and `coefs[1]` is applied to `signal[n-1]`, and /// so on. pub polys: Vec<b3>, // TODO make static length array /// Enum describing the type of the code (FIR or IIR). pub code_type: CodeType } impl Code { /// Computes the adjacency matrix of states the code passes through. The /// output is a matrix indexed by `[start_index][destination_index]`, with a /// unit binary digit in each position (`1` if there is an edge, `0` if there /// is not). /// /// This turns out to be easy for an FIR encoder, because the transitions can /// be expressed solely as "pushes" onto an array of previous states that only /// differ by the next input bit. For example, for a 3-digit state register, /// the adjacency matrix looks like this: /// /// ```text /// 1 1 0 0 0 0 0 0 /// 0 0 1 1 0 0 0 0 /// 0 0 0 0 1 1 0 0 /// 0 0 0 0 0 0 1 1 /// 1 1 0 0 0 0 0 0 /// 0 0 1 1 0 0 0 0 /// 0 0 0 0 1 1 0 0 /// 0 0 0 0 0 0 1 1 /// ``` /// /// # Examples /// /// ``` /// use turbo::{Code, CodeType, b3, ONE, ZERO}; /// /// let toy_code = Code { /// start_state: vec![ZERO, ZERO], /// polys: vec![b3::new([ZERO, ZERO, ONE]), /// b3::new([ONE, ONE, ZERO])], /// code_type: CodeType::FIRCode /// }; /// /// assert_eq!(toy_code.state_adjacency(), /// vec![vec![ONE, ONE, ZERO, ZERO], /// vec![ZERO, ZERO, ONE, ONE], /// vec![ONE, ONE, ZERO, ZERO], /// vec![ZERO, ZERO, ONE, ONE]]); /// ``` pub fn state_adjacency(&self) -> Vec<Vec<b1>> { match self.code_type { CodeType::FIRCode => { // The dimension of the (square) adjacency matrix. let state_dim = 2usize.pow(self.start_state.len() as u32); (0..state_dim).map(|col_ind| { zero_padded_vec(state_dim, vec![ONE, ONE], col_ind * 2) }).collect() }, CodeType::IIRCode => vec![vec![ZERO]] // FIXME placeholder } } /// Computes the next states indices reachable given an index corresponding to /// an existing state index (numbered in monotonic ascending order). /// /// /// # Examples /// /// ``` /// use turbo::{Code, CodeType, b3, ONE, ZERO}; /// /// let toy_code = Code { /// start_state: vec![ZERO, ZERO], /// polys: vec![b3::new([ZERO, ZERO, ONE]), /// b3::new([ONE, ONE, ZERO])], /// code_type: CodeType::FIRCode /// }; /// /// assert_eq!(toy_code.next_states(0), /// vec![0, 1]); /// assert_eq!(toy_code.next_states(1), /// vec![2, 3]); /// assert_eq!(toy_code.next_states(2), /// vec![0, 1]); /// assert_eq!(toy_code.next_states(3), /// vec![2, 3]); /// ``` pub fn next_states(&self, state_ind: usize) -> Vec<usize> { match self.code_type { CodeType::FIRCode => { let state_count = 2usize.pow(self.start_state.len() as u32); let first_next = (state_ind * 2) % state_count; // 2 here is arity vec![first_next, &first_next + 1] }, // TODO do more than binary CodeType::IIRCode => vec![0] // FIXME placeholder } } } pub mod encoders; pub mod viterbi; // pub mod bcjr; fn zero_padded_vec(vec_len: usize, vals: Vec<b1>, offset: usize) -> Vec<b1> { let mut out_vec = vec![ZERO; offset % vec_len]; for val in vals { out_vec.push(val); } for _ in 0..(vec_len - out_vec.len()) { out_vec.push(ZERO); } out_vec }