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, Reporter, Statistics},
8 modulation::{Bpsk, Psk8},
9};
10use crate::{
11 decoder::factory::{DecoderFactory, DecoderImplementation},
12 sparse::SparseMatrix,
13};
14use clap::ValueEnum;
15
16/// BER test.
17///
18/// This trait is used to define trait objects that implement BER tests.
19pub trait Ber {
20 /// Runs the BER test.
21 ///
22 /// This function runs the BER test until completion. It returns a list of
23 /// statistics for each Eb/N0, or an error.
24 fn run(self: Box<Self>) -> Result<Vec<Statistics>, Box<dyn std::error::Error>>;
25
26 /// Returns the frame size of the code.
27 ///
28 /// This corresponds to the frame size after puncturing.
29 fn n(&self) -> usize;
30
31 /// Returns the codeword size of the code.
32 ///
33 /// This corresponds to the codeword size before puncturing.
34 fn n_cw(&self) -> usize;
35
36 /// Returns the number of information bits of the code.
37 fn k(&self) -> usize;
38
39 /// Returns the rate of the code.
40 fn rate(&self) -> f64;
41}
42
43/// BER test builder.
44///
45/// This struct contains all the parameters needed to create a BER test.
46#[derive(Debug)]
47pub struct BerTestBuilder<'a, Dec = DecoderImplementation> {
48 /// LDPC parity check matrix.
49 pub h: SparseMatrix,
50 /// LDPC decoder implementation.
51 pub decoder_implementation: Dec,
52 /// Modulation.
53 pub modulation: Modulation,
54 /// Codeword puncturing pattern.
55 pub puncturing_pattern: Option<&'a [bool]>,
56 /// Codeword interleaving.
57 ///
58 /// A negative value indicates that the columns should be read backwards.
59 pub interleaving_columns: Option<isize>,
60 /// Maximum number of frame errors per Eb/N0.
61 pub max_frame_errors: u64,
62 /// Maximum number of iterations per codeword.
63 pub max_iterations: usize,
64 /// List of Eb/N0's (in dB) to simulate.
65 pub ebn0s_db: &'a [f32],
66 /// An optional reporter object to which the BER test will send periodic
67 /// updates about its progress.
68 pub reporter: Option<Reporter>,
69 /// Maximum number of bit errors that the BCH decoder can correct.
70 ///
71 /// A value of zero means that there is no BCH decoder.
72 pub bch_max_errors: u64,
73 /// Number of worker threads.
74 pub num_workers: usize,
75}
76
77/// Modulation.
78///
79/// This enum represents the modulations that can be simulated.
80#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, ValueEnum)]
81#[clap(rename_all = "UPPER")]
82pub enum Modulation {
83 /// BPSK modulation.
84 Bpsk,
85 /// 8PSK modulation.
86 Psk8,
87}
88
89impl std::str::FromStr for Modulation {
90 type Err = String;
91
92 fn from_str(s: &str) -> Result<Modulation, String> {
93 Ok(match s {
94 "BPSK" => Modulation::Bpsk,
95 "8PSK" => Modulation::Psk8,
96 _ => Err(format!("invalid modulation {s}"))?,
97 })
98 }
99}
100
101impl std::fmt::Display for Modulation {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
103 write!(
104 f,
105 "{}",
106 match self {
107 Modulation::Bpsk => "BPSK",
108 Modulation::Psk8 => "8PSK",
109 }
110 )
111 }
112}
113
114impl<Dec: DecoderFactory> BerTestBuilder<'_, Dec> {
115 /// Create a BER test.
116 ///
117 /// This function only defines the BER test. To run it it is necessary to
118 /// call the [`Ber::run`] method.
119 pub fn build(self) -> Result<Box<dyn Ber>, Box<dyn std::error::Error>> {
120 Ok(match self.modulation {
121 Modulation::Bpsk => Box::new(BerTest::<Bpsk, Dec>::new(
122 self.h,
123 self.decoder_implementation,
124 self.puncturing_pattern,
125 self.interleaving_columns,
126 self.max_frame_errors,
127 self.max_iterations,
128 self.ebn0s_db,
129 self.reporter,
130 self.bch_max_errors,
131 self.num_workers,
132 )?),
133 Modulation::Psk8 => Box::new(BerTest::<Psk8, Dec>::new(
134 self.h,
135 self.decoder_implementation,
136 self.puncturing_pattern,
137 self.interleaving_columns,
138 self.max_frame_errors,
139 self.max_iterations,
140 self.ebn0s_db,
141 self.reporter,
142 self.bch_max_errors,
143 self.num_workers,
144 )?),
145 })
146 }
147}