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