1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
//! Channel simulation.
//!
//! This module contains the simulation of an AWGN channel.
use rand::Rng;
use rand_distr::{Distribution, Normal};
/// AWGN channel simulation.
///
/// This struct is used to add AWGN to symbols.
#[derive(Debug, Clone)]
pub struct AwgnChannel {
distr: Normal<f64>,
}
impl AwgnChannel {
/// Creates a new AWGN channel.
///
/// The channel noise follows a (real) normal distribution with mean zero
/// and standard deviation sigma.
///
/// # Panics
///
/// This function panics if `noise_sigma` is not a positive finite number.
pub fn new(noise_sigma: f64) -> AwgnChannel {
assert!(noise_sigma >= 0.0);
AwgnChannel {
distr: Normal::new(0.0, noise_sigma).unwrap(),
}
}
/// Adds noise to a sequence of symbols.
///
/// The noise is added in-place to the slice `symbols`. An [Rng] is used as
/// source of randomness.
pub fn add_noise<R: Rng>(&self, rng: &mut R, symbols: &mut [f64]) {
for x in symbols.iter_mut() {
*x += self.distr.sample(rng);
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn build_awgn() {
let _channel = AwgnChannel::new(0.2);
}
#[test]
#[should_panic]
fn negative_noise_sigma() {
let _channel = AwgnChannel::new(-3.5);
}
#[test]
fn zero_noise_sigma() {
let channel = AwgnChannel::new(0.0);
let mut rng = rand::thread_rng();
let mut symbols = vec![1.0; 1024];
let symbols_orig = symbols.clone();
channel.add_noise(&mut rng, &mut symbols);
assert_eq!(&symbols, &symbols_orig);
}
}