use num_complex::Complex32;
pub fn bpsk_modulate(code: &[u8], chip_rate: f64, samp_rate: f64) -> impl Iterator<Item = f32> {
let chips_per_sample = chip_rate / samp_rate;
let mut code_phase = 0.0;
std::iter::repeat_with(move || {
let chip = code[code_phase as usize];
assert!((chip == 1) || (chip == 0));
let x = [1.0, -1.0][usize::from(chip)];
code_phase += chips_per_sample;
if code_phase as usize >= code.len() {
code_phase -= code.len() as f64;
}
x
})
}
pub fn local_oscillator(frequency: f64, samp_rate: f64) -> impl Iterator<Item = Complex32> {
let rad_per_sample = 2.0 * std::f64::consts::PI * frequency / samp_rate;
let mut phase = 0.0;
std::iter::repeat_with(move || {
let phi = phase as f32;
let z = Complex32::new(phi.cos(), phi.sin());
phase += rad_per_sample;
if phase >= std::f64::consts::PI {
phase -= 2.0 * std::f64::consts::PI;
} else if phase < -std::f64::consts::PI {
phase += 2.0 * std::f64::consts::PI;
}
z
})
}
pub fn frequency_shift<I: Iterator<Item = Complex32>>(
samples: I,
frequency: f64,
samp_rate: f64,
) -> impl Iterator<Item = Complex32> {
samples
.zip(local_oscillator(frequency, samp_rate))
.map(|(z, w)| z * w)
}
pub fn real_to_complex<I: Iterator<Item = f32>>(samples: I) -> impl Iterator<Item = Complex32> {
samples.map(|x| Complex32::new(x, 0.0))
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn bspsk_modulate_simple() {
let result = bpsk_modulate(&[0, 1], 0.5, 1.0).take(8).collect::<Vec<_>>();
let expected = [1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0];
assert_eq!(result, expected);
}
}