ldpc_toolbox/simulation/
channel.rs1use num_complex::Complex;
6use rand::Rng;
7use rand_distr::{Distribution, Normal};
8
9pub trait ChannelType: sealed::Sealed + std::ops::AddAssign + Sized {
16 #[doc(hidden)]
17 fn noise<R: Rng>(awgn_channel: &AwgnChannel, rng: &mut R) -> Self;
18}
19
20pub trait Channel {
25 fn add_noise<R: Rng, T: ChannelType>(&self, rng: &mut R, symbols: &mut [T]);
30}
31
32#[derive(Debug, Clone)]
36pub struct AwgnChannel {
37 distr: Normal<f64>,
38}
39
40impl AwgnChannel {
41 pub fn new(noise_sigma: f64) -> AwgnChannel {
53 assert!(noise_sigma >= 0.0);
54 AwgnChannel {
55 distr: Normal::new(0.0, noise_sigma).unwrap(),
56 }
57 }
58}
59
60impl Channel for AwgnChannel {
61 fn add_noise<R: Rng, T: ChannelType>(&self, rng: &mut R, symbols: &mut [T]) {
62 for x in symbols.iter_mut() {
63 *x += T::noise(self, rng);
64 }
65 }
66}
67
68impl ChannelType for f64 {
69 fn noise<R: Rng>(awgn_channel: &AwgnChannel, rng: &mut R) -> f64 {
70 awgn_channel.distr.sample(rng)
71 }
72}
73
74impl ChannelType for Complex<f64> {
75 fn noise<R: Rng>(awgn_channel: &AwgnChannel, rng: &mut R) -> Complex<f64> {
76 Complex::new(
77 awgn_channel.distr.sample(rng),
78 awgn_channel.distr.sample(rng),
79 )
80 }
81}
82
83mod sealed {
84 use num_complex::Complex;
85 pub trait Sealed {}
86 impl Sealed for f64 {}
87 impl Sealed for Complex<f64> {}
88}
89
90#[cfg(test)]
91mod test {
92 use super::*;
93
94 #[test]
95 fn build_awgn() {
96 let _channel = AwgnChannel::new(0.2);
97 }
98
99 #[test]
100 #[should_panic]
101 fn negative_noise_sigma() {
102 let _channel = AwgnChannel::new(-3.5);
103 }
104
105 #[test]
106 fn zero_noise_sigma() {
107 let channel = AwgnChannel::new(0.0);
108 let mut rng = rand::rng();
109 let mut symbols = vec![1.0; 1024];
110 let symbols_orig = symbols.clone();
111 channel.add_noise(&mut rng, &mut symbols);
112 assert_eq!(&symbols, &symbols_orig);
113 }
114}