ldpc_toolbox/simulation/
factory.rs

1//! BER test factory.
2//!
3//! This module contains a factory that generates BER test objects as a boxed
4//! trait object using the [`BerTestBuilder`].
5
6use super::{
7    ber::{BerTest, BerTestParameters, Statistics},
8    modulation::{Bpsk, Psk8},
9};
10use crate::decoder::factory::{DecoderFactory, DecoderImplementation};
11use clap::ValueEnum;
12
13/// BER test.
14///
15/// This trait is used to define trait objects that implement BER tests.
16pub trait Ber {
17    /// Runs the BER test.
18    ///
19    /// This function runs the BER test until completion. It returns a list of
20    /// statistics for each Eb/N0, or an error.
21    fn run(self: Box<Self>) -> Result<Vec<Statistics>, Box<dyn std::error::Error>>;
22
23    /// Returns the frame size of the code.
24    ///
25    /// This corresponds to the frame size after puncturing.
26    fn n(&self) -> usize;
27
28    /// Returns the codeword size of the code.
29    ///
30    /// This corresponds to the codeword size before puncturing.
31    fn n_cw(&self) -> usize;
32
33    /// Returns the number of information bits of the code.
34    fn k(&self) -> usize;
35
36    /// Returns the rate of the code.
37    fn rate(&self) -> f64;
38}
39
40/// BER test builder.
41///
42/// This struct contains all the parameters needed to create a BER test.
43#[derive(Debug)]
44pub struct BerTestBuilder<'a, Dec = DecoderImplementation> {
45    /// BER test parameters.
46    pub parameters: BerTestParameters<'a, Dec>,
47    /// Modulation.
48    pub modulation: Modulation,
49}
50
51/// Modulation.
52///
53/// This enum represents the modulations that can be simulated.
54#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, ValueEnum)]
55#[clap(rename_all = "UPPER")]
56pub enum Modulation {
57    /// BPSK modulation.
58    Bpsk,
59    /// 8PSK modulation.
60    Psk8,
61}
62
63impl std::str::FromStr for Modulation {
64    type Err = String;
65
66    fn from_str(s: &str) -> Result<Modulation, String> {
67        Ok(match s {
68            "BPSK" => Modulation::Bpsk,
69            "8PSK" => Modulation::Psk8,
70            _ => Err(format!("invalid modulation {s}"))?,
71        })
72    }
73}
74
75impl std::fmt::Display for Modulation {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
77        write!(
78            f,
79            "{}",
80            match self {
81                Modulation::Bpsk => "BPSK",
82                Modulation::Psk8 => "8PSK",
83            }
84        )
85    }
86}
87
88impl<Dec: DecoderFactory> BerTestBuilder<'_, Dec> {
89    /// Create a BER test.
90    ///
91    /// This function only defines the BER test. To run it it is necessary to
92    /// call the [`Ber::run`] method.
93    pub fn build(self) -> Result<Box<dyn Ber>, Box<dyn std::error::Error>> {
94        macro_rules! impl_match {
95            ($($modulation:ident),*) => {
96                match self.modulation {
97                    $(
98                        Modulation::$modulation => Box::new(BerTest::<$modulation, Dec>::new(
99                            self.parameters
100                        )?),
101                    )*
102                }
103            }
104        }
105
106        Ok(impl_match!(Bpsk, Psk8))
107    }
108}