pccc/
lte.rs

1//! # Encoder and decoder for the rate-1/3 PCCC in LTE
2//!
3//! The encoder and decoder for the LTE PCCC are implemented in [`encoder`] and [`decoder`],
4//! respectively. The [`bpsk_awgn_sim`] function simulates the performance of this code over a
5//! BPSK-AWGN channel. The parameters of the simulation and the results from it are captured in the
6//! [`SimParams`] and [`SimResults`] structs, respectively. Finally, the [`run_bpsk_awgn_sims`]
7//! function can run multiple such simulations and save the results to a JSON file.
8//!
9//! # Examples
10//!
11//! This example shows how to encode 40 information bits with the LTE PCCC, pass the resulting code
12//! bits through a BPSK-AWGN channel at an SNR of -3 dB, and decode the resulting channel output
13//! with the Log-MAP algorithm and 8 turbo iterations:
14//! ```
15//! use pccc::{lte, utils, DecodingAlgo};
16//!
17//! let num_info_bits = 40;
18//! let es_over_n0_db = -3.0;
19//! let decoding_algo = DecodingAlgo::LogMAP(8);
20//!
21//! let info_bits = utils::random_bits(num_info_bits);
22//! let code_bits = lte::encoder(&info_bits)?;
23//! let code_bits_llr = utils::bpsk_awgn_channel(&code_bits, es_over_n0_db);
24//! let info_bits_hat = lte::decoder(&code_bits_llr, decoding_algo)?;
25//! # Ok::<(), Box<dyn std::error::Error>>(())
26//! ```
27
28use itertools::Itertools;
29use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
30use serde::{Deserialize, Serialize};
31use std::fmt;
32use std::fs::File;
33use std::io::BufReader;
34use std::io::BufWriter;
35
36use crate::{utils, Bit, DecodingAlgo, Error, Interleaver};
37
38const CODE_POLYNOMIALS: [usize; 2] = [0o13, 0o15];
39const INVERSE_CODE_RATE: usize = 3;
40const NUM_TAIL_CODE_BITS: usize = 12;
41
42/// Parameters for LTE PCCC simulation over BPSK-AWGN channel
43#[derive(Clone, PartialEq, Debug, Copy, Deserialize, Serialize)]
44pub struct SimParams {
45    /// Number of information bits per block
46    pub num_info_bits_per_block: u32,
47    /// Decoding algorithm to be used
48    pub decoding_algo: DecodingAlgo,
49    /// Ratio (dB) of symbol energy to noise power spectral density at BPSK-AWGN channel output
50    pub es_over_n0_db: f64,
51    /// Desired minimum number of block errors
52    pub num_block_errors_min: u32,
53    /// Number of blocks to be transmitted per run
54    pub num_blocks_per_run: u32,
55    /// Minimum number of runs of blocks to be simulated
56    pub num_runs_min: u32,
57    /// Maximum number of runs of blocks to be simulated
58    pub num_runs_max: u32,
59}
60
61impl SimParams {
62    /// Checks validity of simulation parameters.
63    fn check(&self) -> Result<(), Error> {
64        if qpp_coefficients(self.num_info_bits_per_block as usize).is_err() {
65            return Err(Error::InvalidInput(format!(
66                "{} is not a valid number of information bits per block",
67                self.num_info_bits_per_block
68            )));
69        }
70        if self.num_blocks_per_run == 0 {
71            return Err(Error::InvalidInput(
72                "Number of blocks per run cannot be zero".to_string(),
73            ));
74        }
75        if self.num_runs_min > self.num_runs_max {
76            return Err(Error::InvalidInput(format!(
77                "Minimum number of runs ({}) exceeds maximum number of runs ({})",
78                self.num_runs_min, self.num_runs_max
79            )));
80        }
81        Ok(())
82    }
83
84    /// Prints simulation parameters.
85    fn print(&self) {
86        eprintln!();
87        self.print_num_info_bits_per_block();
88        self.print_decoding_algo();
89        self.print_es_over_n0_db();
90        self.print_num_block_errors_min();
91        self.print_num_blocks_per_run();
92        self.print_num_runs_min();
93        self.print_num_runs_max();
94    }
95
96    /// Prints information block size.
97    fn print_num_info_bits_per_block(&self) {
98        eprintln!(
99            "{:?} information bits per block",
100            self.num_info_bits_per_block,
101        );
102    }
103
104    /// Prints decoding algorithm to use.
105    fn print_decoding_algo(&self) {
106        eprintln!("{}", self.decoding_algo);
107    }
108
109    /// Prints Es/N0 (dB) value.
110    fn print_es_over_n0_db(&self) {
111        eprintln!("Es/N0 of {} dB", self.es_over_n0_db);
112    }
113
114    /// Prints desired minimum number of block errors.
115    fn print_num_block_errors_min(&self) {
116        eprintln!("Minimum of {} block errors", self.num_block_errors_min);
117    }
118
119    /// Prints number of blocks to be transmitted per run.
120    fn print_num_blocks_per_run(&self) {
121        eprintln!("{} blocks per run", self.num_blocks_per_run);
122    }
123
124    /// Prints minimum number of runs of blocks to be simulated.
125    fn print_num_runs_min(&self) {
126        eprintln!("Minimum of {} runs", self.num_runs_min);
127    }
128
129    /// Prints maximum number of runs of blocks to be simulated.
130    fn print_num_runs_max(&self) {
131        eprintln!("Maximum of {} runs", self.num_runs_max);
132    }
133}
134
135/// Results from LTE PCCC simulation over BPSK-AWGN channel
136#[derive(Clone, PartialEq, Debug, Copy, Deserialize, Serialize)]
137pub struct SimResults {
138    /// Simulation parameters
139    pub params: SimParams,
140    /// Number of blocks transmitted
141    pub num_blocks: u32,
142    /// Number of information bits transmitted
143    pub num_info_bits: u32,
144    /// Number of block errors
145    pub num_block_errors: u32,
146    /// Number of information bit errors
147    pub num_info_bit_errors: u32,
148}
149
150impl SimResults {
151    /// Returns initialized simulation results.
152    #[must_use]
153    fn new(params: &SimParams) -> Self {
154        Self {
155            params: *params,
156            num_blocks: 0,
157            num_info_bits: 0,
158            num_block_errors: 0,
159            num_info_bit_errors: 0,
160        }
161    }
162
163    /// Returns block error rate.
164    #[must_use]
165    pub fn block_error_rate(&self) -> f64 {
166        if self.num_blocks > 0 {
167            f64::from(self.num_block_errors) / f64::from(self.num_blocks)
168        } else {
169            0.0
170        }
171    }
172
173    /// Returns information bit error rate.
174    #[must_use]
175    pub fn info_bit_error_rate(&self) -> f64 {
176        if self.num_info_bits > 0 {
177            f64::from(self.num_info_bit_errors) / f64::from(self.num_info_bits)
178        } else {
179            0.0
180        }
181    }
182
183    /// Prints progress message.
184    #[allow(dead_code)]
185    fn print_progress_message(&self) {
186        if self.run_complete() {
187            eprint!(
188                "\rBER = {}/{}, BLER = {}/{}",
189                self.num_info_bit_errors,
190                self.num_info_bits,
191                self.num_block_errors,
192                self.num_blocks,
193            );
194            if self.sim_complete() {
195                eprintln!();
196            }
197        }
198    }
199
200    /// Returns `true` iff a run of blocks is now complete.
201    fn run_complete(&self) -> bool {
202        self.num_blocks % self.params.num_blocks_per_run == 0
203    }
204
205    /// Returns `true` iff the simulation is now complete.
206    fn sim_complete(&self) -> bool {
207        self.run_complete()
208            && self.num_blocks >= self.params.num_runs_min * self.params.num_blocks_per_run
209            && (self.num_block_errors >= self.params.num_block_errors_min
210                || self.num_blocks >= self.params.num_runs_max * self.params.num_blocks_per_run)
211    }
212
213    /// Updates simulation results after a block.
214    fn update_after_block(&mut self, num_info_bit_errors_this_block: u32) {
215        self.num_blocks += 1;
216        self.num_info_bits += self.params.num_info_bits_per_block;
217        if num_info_bit_errors_this_block > 0 {
218            self.num_block_errors += 1;
219            self.num_info_bit_errors += num_info_bit_errors_this_block;
220        }
221    }
222}
223
224/// Parameters that identify a distinct simulation case
225#[derive(Clone, Eq, Hash, PartialEq, Debug, Copy)]
226struct SimCase {
227    num_info_bits_per_block: u32,
228    decoding_algo: DecodingAlgo,
229}
230
231impl fmt::Display for SimCase {
232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233        write!(
234            f,
235            "{} bits/block, {}",
236            self.num_info_bits_per_block, self.decoding_algo
237        )
238    }
239}
240
241impl From<&SimResults> for SimCase {
242    fn from(results: &SimResults) -> SimCase {
243        SimCase {
244            num_info_bits_per_block: results.params.num_info_bits_per_block,
245            decoding_algo: results.params.decoding_algo,
246        }
247    }
248}
249
250/// Returns code bits from rate-1/3 LTE PCCC encoder for given information bits.
251///
252/// # Parameters
253///
254/// - `info_bits`: Information bits to be encoded.
255///
256/// # Returns
257///
258/// - `code_bits`: Code bits from the encoder.
259///
260/// # Errors
261///
262/// Returns an error if the number of information bits does not equal any of the block sizes in
263/// Table 5.1.3-3 of 3GPP TS 36.212.
264pub fn encoder(info_bits: &[Bit]) -> Result<Vec<Bit>, Error> {
265    let qpp_interleaver = interleaver(info_bits.len())?;
266    crate::encoder(info_bits, &qpp_interleaver, &CODE_POLYNOMIALS)
267}
268
269/// Returns information bit decisions from rate-1/3 LTE PCCC decoder for given code bit LLR values.
270///
271/// # Parameters
272///
273/// - `code_bits_llr`: Log-likelihood-ratio (LLR) values for the code bits, with positive values
274///   indicating that `Zero` is more likely.
275///
276/// - `decoding_algo`: Decoding algorithm to use, and associated number of turbo iterations.
277///
278/// # Returns
279///
280/// - `info_bits_hat`: Information bit decisions from the decoder.
281///
282/// # Errors
283///
284/// Returns an error if the number of code bit LLR values does not correspond to any of the block
285/// sizes in Table 5.1.3-3 of 3GPP TS 36.212.
286pub fn decoder(code_bits_llr: &[f64], decoding_algo: DecodingAlgo) -> Result<Vec<Bit>, Error> {
287    if code_bits_llr.len() < NUM_TAIL_CODE_BITS {
288        return Err(Error::InvalidInput(format!(
289            "Expected a minimum of {NUM_TAIL_CODE_BITS} code bit LLR values (found {})",
290            code_bits_llr.len()
291        )));
292    }
293    let num_info_bits = (code_bits_llr.len() - NUM_TAIL_CODE_BITS) / INVERSE_CODE_RATE;
294    let qpp_interleaver = interleaver(num_info_bits)?;
295    crate::decoder(
296        code_bits_llr,
297        &qpp_interleaver,
298        &CODE_POLYNOMIALS,
299        decoding_algo,
300    )
301}
302
303/// Runs simulation of rate-1/3 LTE PCCC over a BPSK-AWGN channel.
304///
305/// # Parameters
306///
307/// - `params`: Parameters for the simulation.
308///
309/// # Returns
310///
311/// - `results`: Results from the simulation.
312///
313/// # Errors
314///
315/// Returns an error if `params.num_info_bits_per_block` is not one of the values specified in
316/// Table 5.1.3-3 of 3GPP TS 36.212, if `params.num_blocks_per_run` is `0`, or if
317/// `params.num_runs_min` exceeds `params.num_runs_max`.
318///
319/// # Examples
320///
321/// ```
322/// use pccc::{lte, DecodingAlgo};
323///
324/// let params = lte::SimParams {
325///     num_info_bits_per_block: 40,
326///     decoding_algo: DecodingAlgo::LogMAP(8),
327///     es_over_n0_db: -3.0,
328///     num_block_errors_min: 10,
329///     num_blocks_per_run: 10,
330///     num_runs_min: 1,
331///     num_runs_max: 2,
332/// };
333/// let results: lte::SimResults = lte::bpsk_awgn_sim(&params)?;
334/// # Ok::<(), Box<dyn std::error::Error>>(())
335/// ```
336#[allow(clippy::cast_possible_truncation)]
337#[allow(clippy::missing_panics_doc)]
338pub fn bpsk_awgn_sim(params: &SimParams) -> Result<SimResults, Error> {
339    params.check()?;
340    let mut results = SimResults::new(params);
341    while !results.sim_complete() {
342        let all_num_info_bit_errors_this_run: Vec<usize> = (0 .. params.num_blocks_per_run)
343            .into_par_iter()
344            .map(|_| {
345                let info_bits = utils::random_bits(params.num_info_bits_per_block as usize);
346                let code_bits = encoder(&info_bits).unwrap();
347                let code_bits_llr = utils::bpsk_awgn_channel(&code_bits, params.es_over_n0_db);
348                let info_bits_hat = decoder(&code_bits_llr, params.decoding_algo).unwrap();
349                utils::error_count(&info_bits_hat, &info_bits)
350            })
351            .collect();
352        // OK to unwrap: Since the simulation parameters have already been checked, an `Err` will
353        // not be returned by the `encoder` and `decoder` functions.
354        for num_info_bit_errors_this_block in all_num_info_bit_errors_this_run {
355            results.update_after_block(num_info_bit_errors_this_block as u32);
356        }
357    }
358    Ok(results)
359}
360
361/// Runs simulations of rate-1/3 LTE PCCC over a BPSK-AWGN channel and saves results to a JSON file.
362///
363/// # Parameters
364///
365/// - `all_params`: Parameters for each simulation scenario of interest.
366///
367/// - `json_filename`: Name of the JSON file to which all simulation results must be written.
368///
369/// # Errors
370///
371/// Returns an error if any invalid simulation parameters are encountered, or if there is an error
372/// in creating or writing to the JSON file for the simulation results.
373///
374/// # Examples
375///
376/// ```
377/// use pccc::{lte, DecodingAlgo};
378///
379/// let mut all_params = Vec::new();
380/// for num_info_bits_per_block in [40, 48] {
381///     all_params.push(lte::SimParams {
382///         num_info_bits_per_block,
383///         decoding_algo: DecodingAlgo::LogMAP(8),
384///         es_over_n0_db: -3.0,
385///         num_block_errors_min: 1,
386///         num_blocks_per_run: 1,
387///         num_runs_min: 1,
388///         num_runs_max: 2,
389///     });
390/// }
391/// lte::run_bpsk_awgn_sims(&all_params, "results.json")?;
392/// # Ok::<(), Box<dyn std::error::Error>>(())
393/// ```
394pub fn run_bpsk_awgn_sims(all_params: &[SimParams], json_filename: &str) -> Result<(), Error> {
395    for params in all_params {
396        if params.check().is_err() {
397            params.print();
398            eprintln!("WARNING: Ignoring above simulation parameters as they are invalid");
399        }
400    }
401    let all_results: Vec<SimResults> = all_params
402        .par_iter()
403        .filter_map(|params| bpsk_awgn_sim(params).ok())
404        .collect();
405    summarize_all_sim_results(&all_results);
406    save_all_sim_results_to_file(&all_results, json_filename)?;
407    Ok(())
408}
409
410/// Prints a summary of all the simulation results in a JSON file.
411///
412/// # Parameters
413///
414/// - `json_filename`: Name of the JSON file containing all the simulation results.
415///
416/// # Errors
417///
418/// Returns an error if opening or reading from the JSON file fails.
419pub fn summarize_all_sim_results_in_file(json_filename: &str) -> Result<(), Error> {
420    let all_results = all_sim_results_from_file(json_filename)?;
421    summarize_all_sim_results(&all_results);
422    Ok(())
423}
424
425/// Saves all simulation results to a JSON file.
426fn save_all_sim_results_to_file(
427    all_results: &[SimResults],
428    json_filename: &str,
429) -> Result<(), Error> {
430    let writer = BufWriter::new(File::create(json_filename)?);
431    serde_json::to_writer_pretty(writer, all_results)?;
432    Ok(())
433}
434
435/// Returns all simulation results from a JSON file.
436fn all_sim_results_from_file(json_filename: &str) -> Result<Vec<SimResults>, Error> {
437    let reader = BufReader::new(File::open(json_filename)?);
438    let all_results = serde_json::from_reader(reader)?;
439    Ok(all_results)
440}
441
442/// Prints summary of all simulation results.
443fn summarize_all_sim_results(all_results: &[SimResults]) {
444    let mut all_cases: Vec<SimCase> = all_results.iter().map(SimCase::from).unique().collect();
445    all_cases.sort_by_key(|case| case.num_info_bits_per_block);
446    for case in all_cases {
447        let all_results_for_case = all_sim_results_for_sim_case(all_results, case);
448        let all_es_over_n0_db = all_results_for_case
449            .iter()
450            .map(|&results| results.params.es_over_n0_db);
451        let all_info_bit_error_rate = all_results_for_case
452            .iter()
453            .map(|&results| results.info_bit_error_rate());
454        let all_block_error_rate = all_results_for_case
455            .iter()
456            .map(|&results| results.block_error_rate());
457        let banner_str = "=".repeat(case.to_string().len());
458        println!("\n{banner_str}");
459        println!("{case}");
460        println!("{banner_str}");
461        println!(" Es/N0 (dB)    BER        BLER");
462        all_info_bit_error_rate
463            .zip(all_block_error_rate)
464            .zip(all_es_over_n0_db)
465            .for_each(|((ber, bler), es_over_n0_db)| {
466                println!("{es_over_n0_db:>8.2}     {ber:7.2e}     {bler:7.2e}");
467            });
468    }
469}
470
471/// Returns all simulation results for a given simulation case.
472#[allow(clippy::cast_possible_truncation)]
473fn all_sim_results_for_sim_case(all_results: &[SimResults], case: SimCase) -> Vec<SimResults> {
474    let mut all_results_for_case = Vec::new();
475    for results in all_results {
476        if SimCase::from(results) == case {
477            all_results_for_case.push(*results);
478        }
479    }
480    all_results_for_case.sort_by_key(|results| (1e6 * results.params.es_over_n0_db) as i32);
481    all_results_for_case
482}
483
484/// Returns quadratic permutation polynomial (QPP) interleaver for rate-1/3 LTE PCCC.
485fn interleaver(num_info_bits: usize) -> Result<Interleaver, Error> {
486    let (coeff1, coeff2) = qpp_coefficients(num_info_bits)?;
487    let perm: Vec<usize> = (0 .. num_info_bits)
488        .map(|out_index| ((coeff1 + coeff2 * out_index) * out_index) % num_info_bits)
489        .collect();
490    Interleaver::new(&perm)
491}
492
493/// Returns QPP coefficients for given number of information bits.
494fn qpp_coefficients(num_info_bits: usize) -> Result<(usize, usize), Error> {
495    if num_info_bits <= 128 {
496        qpp_coefficients_40_to_128_bits(num_info_bits)
497    } else if num_info_bits <= 256 {
498        qpp_coefficients_136_to_256_bits(num_info_bits)
499    } else if num_info_bits <= 512 {
500        qpp_coefficients_264_to_512_bits(num_info_bits)
501    } else if num_info_bits <= 1024 {
502        qpp_coefficients_528_to_1024_bits(num_info_bits)
503    } else if num_info_bits <= 2048 {
504        qpp_coefficients_1056_to_2048_bits(num_info_bits)
505    } else if num_info_bits <= 4096 {
506        qpp_coefficients_2112_to_4096_bits(num_info_bits)
507    } else {
508        qpp_coefficients_4160_to_6144_bits(num_info_bits)
509    }
510}
511
512/// Returns QPP coefficients for `40 <= num_info_bits <= 128`.
513fn qpp_coefficients_40_to_128_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
514    match num_info_bits {
515        40 => Ok((3, 10)),
516        48 => Ok((7, 12)),
517        56 => Ok((19, 42)),
518        64 => Ok((7, 16)),
519        72 => Ok((7, 18)),
520        80 => Ok((11, 20)),
521        88 => Ok((5, 22)),
522        96 => Ok((11, 24)),
523        104 => Ok((7, 26)),
524        112 => Ok((41, 84)),
525        120 => Ok((103, 90)),
526        128 => Ok((15, 32)),
527        _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
528            num_info_bits,
529        ))),
530    }
531}
532
533/// Returns QPP coefficients for `136 <= num_info_bits <= 256`.
534fn qpp_coefficients_136_to_256_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
535    match num_info_bits {
536        136 => Ok((9, 34)),
537        144 => Ok((17, 108)),
538        152 => Ok((9, 38)),
539        160 => Ok((21, 120)),
540        168 => Ok((101, 84)),
541        176 => Ok((21, 44)),
542        184 => Ok((57, 46)),
543        192 => Ok((23, 48)),
544        200 => Ok((13, 50)),
545        208 => Ok((27, 52)),
546        216 => Ok((11, 36)),
547        224 => Ok((27, 56)),
548        232 => Ok((85, 58)),
549        240 => Ok((29, 60)),
550        248 => Ok((33, 62)),
551        256 => Ok((15, 32)),
552        _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
553            num_info_bits,
554        ))),
555    }
556}
557
558/// Returns QPP coefficients for `264 <= num_info_bits <= 512`.
559fn qpp_coefficients_264_to_512_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
560    match num_info_bits {
561        264 => Ok((17, 198)),
562        272 => Ok((33, 68)),
563        280 => Ok((103, 210)),
564        288 => Ok((19, 36)),
565        296 => Ok((19, 74)),
566        304 => Ok((37, 76)),
567        312 => Ok((19, 78)),
568        320 => Ok((21, 120)),
569        328 => Ok((21, 82)),
570        336 => Ok((115, 84)),
571        344 => Ok((193, 86)),
572        352 => Ok((21, 44)),
573        360 => Ok((133, 90)),
574        368 => Ok((81, 46)),
575        376 => Ok((45, 94)),
576        384 => Ok((23, 48)),
577        392 => Ok((243, 98)),
578        400 => Ok((151, 40)),
579        408 => Ok((155, 102)),
580        416 => Ok((25, 52)),
581        424 => Ok((51, 106)),
582        432 => Ok((47, 72)),
583        440 => Ok((91, 110)),
584        448 => Ok((29, 168)),
585        456 => Ok((29, 114)),
586        464 => Ok((247, 58)),
587        472 => Ok((29, 118)),
588        480 => Ok((89, 180)),
589        488 => Ok((91, 122)),
590        496 => Ok((157, 62)),
591        504 => Ok((55, 84)),
592        512 => Ok((31, 64)),
593        _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
594            num_info_bits,
595        ))),
596    }
597}
598
599/// Returns QPP coefficients for `528 <= num_info_bits <= 1024`.
600fn qpp_coefficients_528_to_1024_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
601    match num_info_bits {
602        528 => Ok((17, 66)),
603        544 => Ok((35, 68)),
604        560 => Ok((227, 420)),
605        576 => Ok((65, 96)),
606        592 => Ok((19, 74)),
607        608 => Ok((37, 76)),
608        624 => Ok((41, 234)),
609        640 => Ok((39, 80)),
610        656 => Ok((185, 82)),
611        672 => Ok((43, 252)),
612        688 => Ok((21, 86)),
613        704 => Ok((155, 44)),
614        720 => Ok((79, 120)),
615        736 => Ok((139, 92)),
616        752 => Ok((23, 94)),
617        768 => Ok((217, 48)),
618        784 => Ok((25, 98)),
619        800 => Ok((17, 80)),
620        816 => Ok((127, 102)),
621        832 => Ok((25, 52)),
622        848 => Ok((239, 106)),
623        864 => Ok((17, 48)),
624        880 => Ok((137, 110)),
625        896 => Ok((215, 112)),
626        912 => Ok((29, 114)),
627        928 => Ok((15, 58)),
628        944 => Ok((147, 118)),
629        960 => Ok((29, 60)),
630        976 => Ok((59, 122)),
631        992 => Ok((65, 124)),
632        1008 => Ok((55, 84)),
633        1024 => Ok((31, 64)),
634        _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
635            num_info_bits,
636        ))),
637    }
638}
639
640/// Returns QPP coefficients for `1056 <= num_info_bits <= 2048`.
641fn qpp_coefficients_1056_to_2048_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
642    match num_info_bits {
643        1056 => Ok((17, 66)),
644        1088 => Ok((171, 204)),
645        1120 => Ok((67, 140)),
646        1152 => Ok((35, 72)),
647        1184 => Ok((19, 74)),
648        1216 => Ok((39, 76)),
649        1248 => Ok((19, 78)),
650        1280 => Ok((199, 240)),
651        1312 => Ok((21, 82)),
652        1344 => Ok((211, 252)),
653        1376 => Ok((21, 86)),
654        1408 => Ok((43, 88)),
655        1440 => Ok((149, 60)),
656        1472 => Ok((45, 92)),
657        1504 => Ok((49, 846)),
658        1536 => Ok((71, 48)),
659        1568 => Ok((13, 28)),
660        1600 => Ok((17, 80)),
661        1632 => Ok((25, 102)),
662        1664 => Ok((183, 104)),
663        1696 => Ok((55, 954)),
664        1728 => Ok((127, 96)),
665        1760 => Ok((27, 110)),
666        1792 => Ok((29, 112)),
667        1824 => Ok((29, 114)),
668        1856 => Ok((57, 116)),
669        1888 => Ok((45, 354)),
670        1920 => Ok((31, 120)),
671        1952 => Ok((59, 610)),
672        1984 => Ok((185, 124)),
673        2016 => Ok((113, 420)),
674        2048 => Ok((31, 64)),
675        _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
676            num_info_bits,
677        ))),
678    }
679}
680
681/// Returns QPP coefficients for `2112 <= num_info_bits <= 4096`.
682fn qpp_coefficients_2112_to_4096_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
683    match num_info_bits {
684        2112 => Ok((17, 66)),
685        2176 => Ok((171, 136)),
686        2240 => Ok((209, 420)),
687        2304 => Ok((253, 216)),
688        2368 => Ok((367, 444)),
689        2432 => Ok((265, 456)),
690        2496 => Ok((181, 468)),
691        2560 => Ok((39, 80)),
692        2624 => Ok((27, 164)),
693        2688 => Ok((127, 504)),
694        2752 => Ok((143, 172)),
695        2816 => Ok((43, 88)),
696        2880 => Ok((29, 300)),
697        2944 => Ok((45, 92)),
698        3008 => Ok((157, 188)),
699        3072 => Ok((47, 96)),
700        3136 => Ok((13, 28)),
701        3200 => Ok((111, 240)),
702        3264 => Ok((443, 204)),
703        3328 => Ok((51, 104)),
704        3392 => Ok((51, 212)),
705        3456 => Ok((451, 192)),
706        3520 => Ok((257, 220)),
707        3584 => Ok((57, 336)),
708        3648 => Ok((313, 228)),
709        3712 => Ok((271, 232)),
710        3776 => Ok((179, 236)),
711        3840 => Ok((331, 120)),
712        3904 => Ok((363, 244)),
713        3968 => Ok((375, 248)),
714        4032 => Ok((127, 168)),
715        4096 => Ok((31, 64)),
716        _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
717            num_info_bits,
718        ))),
719    }
720}
721
722/// Returns QPP coefficients for `4160 <= num_info_bits <= 6144`.
723fn qpp_coefficients_4160_to_6144_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
724    match num_info_bits {
725        4160 => Ok((33, 130)),
726        4224 => Ok((43, 264)),
727        4288 => Ok((33, 134)),
728        4352 => Ok((477, 408)),
729        4416 => Ok((35, 138)),
730        4480 => Ok((233, 280)),
731        4544 => Ok((357, 142)),
732        4608 => Ok((337, 480)),
733        4672 => Ok((37, 146)),
734        4736 => Ok((71, 444)),
735        4800 => Ok((71, 120)),
736        4864 => Ok((37, 152)),
737        4928 => Ok((39, 462)),
738        4992 => Ok((127, 234)),
739        5056 => Ok((39, 158)),
740        5120 => Ok((39, 80)),
741        5184 => Ok((31, 96)),
742        5248 => Ok((113, 902)),
743        5312 => Ok((41, 166)),
744        5376 => Ok((251, 336)),
745        5440 => Ok((43, 170)),
746        5504 => Ok((21, 86)),
747        5568 => Ok((43, 174)),
748        5632 => Ok((45, 176)),
749        5696 => Ok((45, 178)),
750        5760 => Ok((161, 120)),
751        5824 => Ok((89, 182)),
752        5888 => Ok((323, 184)),
753        5952 => Ok((47, 186)),
754        6016 => Ok((23, 94)),
755        6080 => Ok((47, 190)),
756        6144 => Ok((263, 480)),
757        _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
758            num_info_bits,
759        ))),
760    }
761}
762
763/// Returns error message for invalid number of information bits.
764fn invalid_num_info_bits_message(num_info_bits: usize) -> String {
765    format!("Number of information bits {num_info_bits} is not in Table 5.1.3-3 of 3GPP TS 36.212")
766}
767
768#[cfg(test)]
769mod tests_of_simparams {
770    use super::*;
771
772    #[test]
773    fn test_check() {
774        // Invalid input
775        let params = SimParams {
776            num_info_bits_per_block: 32,
777            decoding_algo: DecodingAlgo::LinearLogMAP(8),
778            es_over_n0_db: -3.0,
779            num_block_errors_min: 10,
780            num_blocks_per_run: 1,
781            num_runs_min: 1,
782            num_runs_max: 2,
783        };
784        assert!(params.check().is_err());
785        let params = SimParams {
786            num_info_bits_per_block: 40,
787            decoding_algo: DecodingAlgo::LinearLogMAP(8),
788            es_over_n0_db: -3.0,
789            num_block_errors_min: 10,
790            num_blocks_per_run: 0,
791            num_runs_min: 1,
792            num_runs_max: 2,
793        };
794        assert!(params.check().is_err());
795        let params = SimParams {
796            num_info_bits_per_block: 40,
797            decoding_algo: DecodingAlgo::LinearLogMAP(8),
798            es_over_n0_db: -3.0,
799            num_block_errors_min: 10,
800            num_blocks_per_run: 1,
801            num_runs_min: 2,
802            num_runs_max: 1,
803        };
804        assert!(params.check().is_err());
805        // Valid input
806        let params = SimParams {
807            num_info_bits_per_block: 40,
808            decoding_algo: DecodingAlgo::LinearLogMAP(8),
809            es_over_n0_db: -3.0,
810            num_block_errors_min: 10,
811            num_blocks_per_run: 1,
812            num_runs_min: 1,
813            num_runs_max: 2,
814        };
815        assert!(params.check().is_ok());
816    }
817
818    #[test]
819    fn test_print() {
820        let params = SimParams {
821            num_info_bits_per_block: 40,
822            decoding_algo: DecodingAlgo::LinearLogMAP(8),
823            es_over_n0_db: -3.0,
824            num_block_errors_min: 100,
825            num_blocks_per_run: 1000,
826            num_runs_min: 1,
827            num_runs_max: 10,
828        };
829        params.print();
830    }
831}
832
833#[cfg(test)]
834mod tests_of_simresults {
835    use super::*;
836    use float_eq::assert_float_eq;
837
838    fn params_for_test() -> SimParams {
839        SimParams {
840            num_info_bits_per_block: 48,
841            decoding_algo: DecodingAlgo::LinearLogMAP(8),
842            es_over_n0_db: -3.0,
843            num_block_errors_min: 100,
844            num_blocks_per_run: 1000,
845            num_runs_min: 1,
846            num_runs_max: 10,
847        }
848    }
849
850    fn results_for_test(num_blocks: u32, num_block_errors: u32) -> SimResults {
851        let params = params_for_test();
852        let num_info_bits = num_blocks * params.num_info_bits_per_block;
853        let num_info_bit_errors = num_block_errors * 10;
854        SimResults {
855            params,
856            num_blocks,
857            num_info_bits,
858            num_block_errors,
859            num_info_bit_errors,
860        }
861    }
862
863    #[test]
864    fn test_new() {
865        let results = SimResults::new(&params_for_test());
866        assert_eq!(results.num_blocks, 0);
867        assert_eq!(results.num_info_bits, 0);
868        assert_eq!(results.num_block_errors, 0);
869        assert_eq!(results.num_info_bit_errors, 0);
870    }
871
872    #[test]
873    fn test_block_error_rate() {
874        let results = results_for_test(2000, 10);
875        assert_float_eq!(results.block_error_rate(), 10.0 / 2000.0, abs <= 1e-8);
876    }
877
878    #[test]
879    fn test_info_bit_error_rate() {
880        let results = results_for_test(2000, 10);
881        assert_float_eq!(results.info_bit_error_rate(), 100.0 / 96000.0, abs <= 1e-8);
882    }
883
884    #[test]
885    fn test_print_progress_message() {
886        let results = results_for_test(1000, 10);
887        results.print_progress_message();
888    }
889
890    #[test]
891    fn test_run_complete() {
892        let results = results_for_test(999, 0);
893        assert!(!results.run_complete());
894        let results = results_for_test(1000, 0);
895        assert!(results.run_complete());
896        let results = results_for_test(1001, 0);
897        assert!(!results.run_complete());
898    }
899
900    #[test]
901    fn test_sim_complete() {
902        // Test of `num_block_errors_min`
903        let results = results_for_test(5000, 99);
904        assert!(!results.sim_complete());
905        let results = results_for_test(5000, 100);
906        assert!(results.sim_complete());
907        // Test of `num_blocks_per_run`
908        let results = results_for_test(4999, 500);
909        assert!(!results.sim_complete());
910        let results = results_for_test(5000, 500);
911        assert!(results.sim_complete());
912        let results = results_for_test(5001, 500);
913        assert!(!results.sim_complete());
914        // Test of `num_runs_min`
915        let results = results_for_test(999, 500);
916        assert!(!results.sim_complete());
917        let results = results_for_test(1000, 500);
918        assert!(results.sim_complete());
919        // Test of `num_runs_max`
920        let results = results_for_test(9999, 50);
921        assert!(!results.sim_complete());
922        let results = results_for_test(10000, 50);
923        assert!(results.sim_complete());
924    }
925
926    #[test]
927    fn test_update_after_block() {
928        // Zero info bit errors
929        let mut results = results_for_test(100, 10);
930        results.update_after_block(0);
931        assert_eq!(results.num_blocks, 101);
932        assert_eq!(results.num_info_bits, 4848);
933        assert_eq!(results.num_block_errors, 10);
934        assert_eq!(results.num_info_bit_errors, 100);
935        // Nonzero info bit errors
936        let mut results = results_for_test(100, 10);
937        results.update_after_block(10);
938        assert_eq!(results.num_blocks, 101);
939        assert_eq!(results.num_info_bits, 4848);
940        assert_eq!(results.num_block_errors, 11);
941        assert_eq!(results.num_info_bit_errors, 110);
942    }
943}
944
945#[cfg(test)]
946mod tests_of_functions {
947    use super::*;
948
949    #[test]
950    fn test_encoder() {
951        let info_bits = utils::random_bits(40);
952        assert!(encoder(&info_bits).is_ok());
953    }
954
955    #[test]
956    fn test_decoder() {
957        let code_bits_llr = utils::bpsk_awgn_channel(&utils::random_bits(132), 10.0);
958        assert!(decoder(&code_bits_llr, DecodingAlgo::LinearLogMAP(8)).is_ok());
959    }
960
961    #[test]
962    fn test_bpsk_awgn_sim() {
963        // Invalid input
964        let params = SimParams {
965            num_info_bits_per_block: 32,
966            decoding_algo: DecodingAlgo::LinearLogMAP(8),
967            es_over_n0_db: -3.0,
968            num_block_errors_min: 10,
969            num_blocks_per_run: 10,
970            num_runs_min: 1,
971            num_runs_max: 2,
972        };
973        assert!(bpsk_awgn_sim(&params).is_err());
974        // Valid input
975        let params = SimParams {
976            num_info_bits_per_block: 40,
977            decoding_algo: DecodingAlgo::LinearLogMAP(8),
978            es_over_n0_db: -3.0,
979            num_block_errors_min: 10,
980            num_blocks_per_run: 10,
981            num_runs_min: 1,
982            num_runs_max: 2,
983        };
984        assert!(bpsk_awgn_sim(&params).is_ok());
985    }
986
987    #[test]
988    fn test_run_bpsk_awgn_sims() {
989        let all_params = vec![
990            SimParams {
991                num_info_bits_per_block: 36,
992                decoding_algo: DecodingAlgo::LinearLogMAP(8),
993                es_over_n0_db: -3.0,
994                num_block_errors_min: 20,
995                num_blocks_per_run: 10,
996                num_runs_min: 1,
997                num_runs_max: 2,
998            },
999            SimParams {
1000                num_info_bits_per_block: 40,
1001                decoding_algo: DecodingAlgo::LinearLogMAP(8),
1002                es_over_n0_db: -3.0,
1003                num_block_errors_min: 10,
1004                num_blocks_per_run: 10,
1005                num_runs_min: 1,
1006                num_runs_max: 2,
1007            },
1008            SimParams {
1009                num_info_bits_per_block: 44,
1010                decoding_algo: DecodingAlgo::LinearLogMAP(8),
1011                es_over_n0_db: -3.0,
1012                num_block_errors_min: 10,
1013                num_blocks_per_run: 10,
1014                num_runs_min: 1,
1015                num_runs_max: 2,
1016            },
1017            SimParams {
1018                num_info_bits_per_block: 48,
1019                decoding_algo: DecodingAlgo::LinearLogMAP(8),
1020                es_over_n0_db: -3.0,
1021                num_block_errors_min: 10,
1022                num_blocks_per_run: 10,
1023                num_runs_min: 1,
1024                num_runs_max: 2,
1025            },
1026        ];
1027        run_bpsk_awgn_sims(&all_params, "results.json").unwrap();
1028    }
1029
1030    fn all_sim_params_for_test() -> Vec<SimParams> {
1031        let mut all_params = Vec::new();
1032        for num_info_bits_per_block in [40, 48] {
1033            for es_over_n0_db in [-3.5, -3.0, -4.0] {
1034                all_params.push(SimParams {
1035                    num_info_bits_per_block,
1036                    decoding_algo: DecodingAlgo::LinearLogMAP(8),
1037                    es_over_n0_db,
1038                    num_block_errors_min: 20,
1039                    num_blocks_per_run: 10,
1040                    num_runs_min: 1,
1041                    num_runs_max: 10,
1042                });
1043            }
1044        }
1045        all_params
1046    }
1047
1048    fn all_sim_results_for_test(all_params: &[SimParams]) -> Vec<SimResults> {
1049        let mut all_results = Vec::new();
1050        for params in all_params {
1051            all_results.push(SimResults::new(params));
1052        }
1053        all_results
1054    }
1055
1056    #[test]
1057    fn test_summarize_all_sim_results() {
1058        let all_results = all_sim_results_for_test(&all_sim_params_for_test());
1059        summarize_all_sim_results(&all_results);
1060    }
1061
1062    #[test]
1063    fn test_all_sim_results_for_sim_case() {
1064        let all_results = all_sim_results_for_test(&all_sim_params_for_test());
1065        assert_eq!(
1066            all_sim_results_for_sim_case(
1067                &all_results,
1068                SimCase {
1069                    num_info_bits_per_block: 40,
1070                    decoding_algo: DecodingAlgo::LinearLogMAP(8),
1071                },
1072            ),
1073            [all_results[2], all_results[0], all_results[1]]
1074        );
1075        assert_eq!(
1076            all_sim_results_for_sim_case(
1077                &all_results,
1078                SimCase {
1079                    num_info_bits_per_block: 48,
1080                    decoding_algo: DecodingAlgo::LinearLogMAP(8),
1081                },
1082            ),
1083            [all_results[5], all_results[3], all_results[4]]
1084        );
1085    }
1086
1087    #[test]
1088    fn test_interleaver() {
1089        // Invalid input
1090        assert!(interleaver(32).is_err());
1091        // Valid input
1092        for num in 0 .. 60 {
1093            let num_info_bits = 40 + 8 * num;
1094            assert!(interleaver(num_info_bits).is_ok());
1095        }
1096        for num in 0 .. 32 {
1097            let num_info_bits = 528 + 16 * num;
1098            assert!(interleaver(num_info_bits).is_ok());
1099        }
1100        for num in 0 .. 32 {
1101            let num_info_bits = 1056 + 32 * num;
1102            assert!(interleaver(num_info_bits).is_ok());
1103        }
1104        for num in 0 .. 64 {
1105            let num_info_bits = 2112 + 64 * num;
1106            assert!(interleaver(num_info_bits).is_ok());
1107        }
1108        // Invalid input
1109        assert!(interleaver(6208).is_err());
1110    }
1111
1112    #[test]
1113    fn test_qpp_coefficients() {
1114        // Invalid input
1115        assert!(qpp_coefficients(32).is_err());
1116        // Valid input
1117        for num in 0 .. 60 {
1118            let num_info_bits = 40 + 8 * num;
1119            assert!(qpp_coefficients(num_info_bits).is_ok());
1120        }
1121        for num in 0 .. 32 {
1122            let num_info_bits = 528 + 16 * num;
1123            assert!(qpp_coefficients(num_info_bits).is_ok());
1124        }
1125        for num in 0 .. 32 {
1126            let num_info_bits = 1056 + 32 * num;
1127            assert!(qpp_coefficients(num_info_bits).is_ok());
1128        }
1129        for num in 0 .. 64 {
1130            let num_info_bits = 2112 + 64 * num;
1131            assert!(qpp_coefficients(num_info_bits).is_ok());
1132        }
1133        // Invalid input
1134        assert!(qpp_coefficients(6208).is_err());
1135    }
1136
1137    #[test]
1138    fn test_qpp_coefficients_40_to_128_bits() {
1139        // Invalid input
1140        assert!(qpp_coefficients_40_to_128_bits(32).is_err());
1141        assert!(qpp_coefficients_40_to_128_bits(84).is_err());
1142        assert!(qpp_coefficients_40_to_128_bits(136).is_err());
1143        // Valid input
1144        assert_eq!(qpp_coefficients_40_to_128_bits(40).unwrap(), (3, 10));
1145        assert_eq!(qpp_coefficients_40_to_128_bits(128).unwrap(), (15, 32));
1146    }
1147
1148    #[test]
1149    fn test_qpp_coefficients_136_to_256_bits() {
1150        // Invalid input
1151        assert!(qpp_coefficients_136_to_256_bits(128).is_err());
1152        assert!(qpp_coefficients_136_to_256_bits(196).is_err());
1153        assert!(qpp_coefficients_136_to_256_bits(264).is_err());
1154        // Valid input
1155        assert_eq!(qpp_coefficients_136_to_256_bits(136).unwrap(), (9, 34));
1156        assert_eq!(qpp_coefficients_136_to_256_bits(256).unwrap(), (15, 32));
1157    }
1158
1159    #[test]
1160    fn test_qpp_coefficients_264_to_512_bits() {
1161        // Invalid input
1162        assert!(qpp_coefficients_264_to_512_bits(256).is_err());
1163        assert!(qpp_coefficients_264_to_512_bits(388).is_err());
1164        assert!(qpp_coefficients_264_to_512_bits(520).is_err());
1165        // Valid input
1166        assert_eq!(qpp_coefficients_264_to_512_bits(264).unwrap(), (17, 198));
1167        assert_eq!(qpp_coefficients_264_to_512_bits(512).unwrap(), (31, 64));
1168    }
1169
1170    #[test]
1171    fn test_qpp_coefficients_528_to_1024_bits() {
1172        // Invalid input
1173        assert!(qpp_coefficients_528_to_1024_bits(512).is_err());
1174        assert!(qpp_coefficients_528_to_1024_bits(776).is_err());
1175        assert!(qpp_coefficients_528_to_1024_bits(1040).is_err());
1176        // Valid input
1177        assert_eq!(qpp_coefficients_528_to_1024_bits(528).unwrap(), (17, 66));
1178        assert_eq!(qpp_coefficients_528_to_1024_bits(1024).unwrap(), (31, 64));
1179    }
1180
1181    #[test]
1182    fn test_qpp_coefficients_1056_to_2048_bits() {
1183        // Invalid input
1184        assert!(qpp_coefficients_1056_to_2048_bits(1024).is_err());
1185        assert!(qpp_coefficients_1056_to_2048_bits(1552).is_err());
1186        assert!(qpp_coefficients_1056_to_2048_bits(2080).is_err());
1187        // Valid input
1188        assert_eq!(qpp_coefficients_1056_to_2048_bits(1056).unwrap(), (17, 66));
1189        assert_eq!(qpp_coefficients_1056_to_2048_bits(2048).unwrap(), (31, 64));
1190    }
1191
1192    #[test]
1193    fn test_qpp_coefficients_2112_to_4096_bits() {
1194        // Invalid input
1195        assert!(qpp_coefficients_2112_to_4096_bits(2048).is_err());
1196        assert!(qpp_coefficients_2112_to_4096_bits(3104).is_err());
1197        assert!(qpp_coefficients_2112_to_4096_bits(4160).is_err());
1198        // Valid input
1199        assert_eq!(qpp_coefficients_2112_to_4096_bits(2112).unwrap(), (17, 66));
1200        assert_eq!(qpp_coefficients_2112_to_4096_bits(4096).unwrap(), (31, 64));
1201    }
1202
1203    #[test]
1204    fn test_qpp_coefficients_4160_to_6144_bits() {
1205        // Invalid input
1206        assert!(qpp_coefficients_4160_to_6144_bits(4096).is_err());
1207        assert!(qpp_coefficients_4160_to_6144_bits(5152).is_err());
1208        assert!(qpp_coefficients_4160_to_6144_bits(6208).is_err());
1209        // Valid input
1210        assert_eq!(qpp_coefficients_4160_to_6144_bits(4160).unwrap(), (33, 130));
1211        assert_eq!(
1212            qpp_coefficients_4160_to_6144_bits(6144).unwrap(),
1213            (263, 480)
1214        );
1215    }
1216}