bazbandilo/
css.rs

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
68
69
70
71
72
73
74
75
76
77
use crate::{angle_diff, iter::Iter, linspace, Bit};
use num_complex::Complex;
use std::f64::consts::PI;

pub fn tx_css_signal<I: Iterator<Item = Bit>>(
    message: I,
    samples_per_symbol: usize,
) -> impl Iterator<Item = Complex<f64>> {
    assert!(samples_per_symbol >= 8);

    let delta_theta_max: f64 = 0.75 * PI;
    let delta_thetas: Vec<f64> =
        linspace(-delta_theta_max, delta_theta_max, samples_per_symbol - 1).collect();

    let mut theta: f64 = 0f64;
    message
        .flat_map(move |bit| {
            let mut out = Vec::with_capacity(samples_per_symbol);
            out.push(theta);

            for delta in delta_thetas.iter() {
                if bit {
                    theta += delta;
                } else {
                    theta -= delta;
                }
                out.push(theta);
            }
            out.into_iter()
        })
        .map(|angle| Complex::new(0f64, angle).exp())
}

pub fn rx_css_signal<I: Iterator<Item = Complex<f64>>>(
    message: I,
    samples_per_symbol: usize,
) -> impl Iterator<Item = Bit> {
    assert!(samples_per_symbol >= 8);

    message.chunks(samples_per_symbol).map(|symbol| {
        let angular_velocities: Vec<f64> = symbol
            .iter()
            .zip(symbol[1..].iter())
            .map(|(&w1, &w2)| angle_diff(w1, w2))
            .collect();

        let angular_accelerations = angular_velocities
            .iter()
            .zip(angular_velocities[1..].iter())
            .map(|(&v1, &v2)| v2 - v1);

        // Check average angular velocity.
        angular_accelerations.sum::<f64>().is_sign_positive()
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    extern crate rand;
    extern crate rand_distr;
    use crate::Rng;

    #[test]
    fn css() {
        let mut rng = rand::thread_rng();
        let num_bits = 9001;
        let data_bits: Vec<Bit> = (0..num_bits).map(|_| rng.gen::<Bit>()).collect();

        let samples_per_symbol = 1000;

        let css_tx: Vec<Complex<f64>> =
            tx_css_signal(data_bits.iter().cloned(), samples_per_symbol).collect();
        let css_rx: Vec<Bit> = rx_css_signal(css_tx.iter().cloned(), samples_per_symbol).collect();
        assert_eq!(data_bits, css_rx);
    }
}