1use super::channel::ChannelType;
7use crate::gf2::GF2;
8use ndarray::{ArrayBase, Data, Ix1};
9use num_complex::Complex;
10use num_traits::{One, Zero};
11
12pub trait Modulation: 'static {
19 type T: ChannelType;
23 type Modulator: Modulator<T = Self::T>;
25 type Demodulator: Demodulator<T = Self::T>;
27 const BITS_PER_SYMBOL: f64;
29}
30
31pub trait Modulator: Default + Clone + Send {
36 type T;
38
39 fn modulate<S>(&self, codeword: &ArrayBase<S, Ix1>) -> Vec<Self::T>
41 where
42 S: Data<Elem = GF2>;
43}
44
45pub trait Demodulator: Send {
50 type T;
52
53 fn from_noise_sigma(noise_sigma: f64) -> Self;
59
60 fn demodulate(&self, symbols: &[Self::T]) -> Vec<f64>;
62}
63
64#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
66pub struct Bpsk {}
67
68impl Modulation for Bpsk {
69 type T = f64;
70 type Modulator = BpskModulator;
71 type Demodulator = BpskDemodulator;
72 const BITS_PER_SYMBOL: f64 = 1.0;
73}
74
75#[derive(Debug, Clone, Default)]
79pub struct BpskModulator {}
80
81impl BpskModulator {
82 pub fn new() -> BpskModulator {
84 BpskModulator::default()
85 }
86
87 fn modulate_bit(bit: GF2) -> f64 {
88 if bit.is_zero() {
89 -1.0
90 } else if bit.is_one() {
91 1.0
92 } else {
93 panic!("invalid GF2 value")
94 }
95 }
96}
97
98impl Modulator for BpskModulator {
99 type T = f64;
100
101 fn modulate<S>(&self, codeword: &ArrayBase<S, Ix1>) -> Vec<f64>
102 where
103 S: Data<Elem = GF2>,
104 {
105 codeword.iter().cloned().map(Self::modulate_bit).collect()
106 }
107}
108
109#[derive(Debug, Clone, Default)]
113pub struct BpskDemodulator {
114 scale: f64,
115}
116
117impl BpskDemodulator {
118 pub fn new(noise_sigma: f64) -> BpskDemodulator {
124 BpskDemodulator {
125 scale: -2.0 / (noise_sigma * noise_sigma),
128 }
129 }
130}
131
132impl Demodulator for BpskDemodulator {
133 type T = f64;
134
135 fn from_noise_sigma(noise_sigma: f64) -> BpskDemodulator {
136 BpskDemodulator::new(noise_sigma)
137 }
138
139 fn demodulate(&self, symbols: &[f64]) -> Vec<f64> {
140 symbols.iter().map(|&x| self.scale * x).collect()
141 }
142}
143
144#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
146pub struct Psk8 {}
147
148impl Modulation for Psk8 {
149 type T = Complex<f64>;
150 type Modulator = Psk8Modulator;
151 type Demodulator = Psk8Demodulator;
152 const BITS_PER_SYMBOL: f64 = 3.0;
153}
154
155#[derive(Debug, Clone, Default)]
160pub struct Psk8Modulator {}
161
162impl Psk8Modulator {
163 pub fn new() -> Psk8Modulator {
165 Psk8Modulator::default()
166 }
167
168 fn modulate_bits(b0: GF2, b1: GF2, b2: GF2) -> Complex<f64> {
169 let a = (0.5f64).sqrt();
170 match (b0.is_one(), b1.is_one(), b2.is_one()) {
171 (false, false, false) => Complex::new(a, a),
172 (true, false, false) => Complex::new(0.0, 1.0),
173 (true, true, false) => Complex::new(-a, a),
174 (false, true, false) => Complex::new(-1.0, 0.0),
175 (false, true, true) => Complex::new(-a, -a),
176 (true, true, true) => Complex::new(0.0, -1.0),
177 (true, false, true) => Complex::new(a, -a),
178 (false, false, true) => Complex::new(1.0, 0.0),
179 }
180 }
181}
182
183impl Modulator for Psk8Modulator {
184 type T = Complex<f64>;
185
186 fn modulate<S>(&self, codeword: &ArrayBase<S, Ix1>) -> Vec<Complex<f64>>
192 where
193 S: Data<Elem = GF2>,
194 {
195 assert_eq!(codeword.len() % 3, 0);
196 codeword
197 .iter()
198 .step_by(3)
199 .zip(codeword.iter().skip(1).step_by(3))
200 .zip(codeword.iter().skip(2).step_by(3))
201 .map(|((&b0, &b1), &b2)| Self::modulate_bits(b0, b1, b2))
202 .collect()
203 }
204}
205
206#[derive(Debug, Clone, Default)]
211pub struct Psk8Demodulator {
212 scale: f64,
213}
214
215impl Psk8Demodulator {
216 pub fn new(noise_sigma: f64) -> Psk8Demodulator {
223 Psk8Demodulator {
224 scale: 1.0 / (noise_sigma * noise_sigma),
225 }
226 }
227
228 fn demodulate_symbol(&self, symbol: Complex<f64>) -> [f64; 3] {
229 let a = (0.5f64).sqrt();
230 let symbol = symbol * self.scale;
231 let d000 = dot(symbol, Complex::new(a, a));
232 let d100 = dot(symbol, Complex::new(0.0, 1.0));
233 let d110 = dot(symbol, Complex::new(-a, a));
234 let d010 = dot(symbol, Complex::new(-1.0, 0.0));
235 let d011 = dot(symbol, Complex::new(-a, -a));
236 let d111 = dot(symbol, Complex::new(0.0, -1.0));
237 let d101 = dot(symbol, Complex::new(a, -a));
238 let d001 = dot(symbol, Complex::new(1.0, 0.0));
239 let b0 = [d000, d001, d010, d011]
240 .into_iter()
241 .reduce(maxstar)
242 .unwrap()
243 - [d100, d101, d110, d111]
244 .into_iter()
245 .reduce(maxstar)
246 .unwrap();
247 let b1 = [d000, d001, d100, d101]
248 .into_iter()
249 .reduce(maxstar)
250 .unwrap()
251 - [d010, d011, d110, d111]
252 .into_iter()
253 .reduce(maxstar)
254 .unwrap();
255 let b2 = [d000, d010, d100, d110]
256 .into_iter()
257 .reduce(maxstar)
258 .unwrap()
259 - [d001, d011, d101, d111]
260 .into_iter()
261 .reduce(maxstar)
262 .unwrap();
263 [b0, b1, b2]
264 }
265}
266
267impl Demodulator for Psk8Demodulator {
268 type T = Complex<f64>;
269
270 fn from_noise_sigma(noise_sigma: f64) -> Psk8Demodulator {
271 Psk8Demodulator::new(noise_sigma)
272 }
273
274 fn demodulate(&self, symbols: &[Complex<f64>]) -> Vec<f64> {
275 symbols
276 .iter()
277 .flat_map(|&x| self.demodulate_symbol(x))
278 .collect()
279 }
280}
281
282fn dot(a: Complex<f64>, b: Complex<f64>) -> f64 {
283 a.re * b.re + a.im * b.im
284}
285
286fn maxstar(a: f64, b: f64) -> f64 {
287 a.max(b) + (-((a - b).abs())).exp().ln_1p()
288}
289
290#[cfg(test)]
291mod test {
292 use super::*;
293
294 #[test]
295 fn bpsk_modulator() {
296 let modulator = BpskModulator::new();
297 let x = modulator.modulate(&ndarray::arr1(&[GF2::one(), GF2::zero()]));
298 assert_eq!(&x, &[1.0, -1.0]);
299 }
300
301 #[test]
302 fn bpsk_demodulator() {
303 let demodulator = BpskDemodulator::new(2.0_f64.sqrt());
304 let x = demodulator.demodulate(&[1.0, -1.0]);
305 assert_eq!(x.len(), 2);
306 let tol = 1e-4;
307 assert!((x[0] + 1.0).abs() < tol);
308 assert!((x[1] - 1.0).abs() < tol);
309 }
310
311 #[test]
312 fn psk8_modulator() {
313 let o = GF2::one();
314 let z = GF2::zero();
315 let modulator = Psk8Modulator::new();
316 let x = modulator.modulate(&ndarray::arr1(&[o, o, z, z, z, z, o, z, o]));
317 let a = (0.5f64).sqrt();
318 assert_eq!(
319 &x,
320 &[Complex::new(-a, a), Complex::new(a, a), Complex::new(a, -a)]
321 );
322 }
323
324 #[test]
325 fn psk8_demodulator_signs() {
326 let noise_sigma = 1.0;
327 let demodulator = Psk8Demodulator::new(noise_sigma);
328 let a = (0.5f64).sqrt();
329 let llr = demodulator.demodulate(&[
330 Complex::new(1.0, 0.0),
331 Complex::new(a, a),
332 Complex::new(0.0, 1.0),
333 ]);
334 assert!(llr[0] > 0.0);
336 assert!(llr[1] > 0.0);
337 assert!(llr[2] < 0.0);
338 assert!(llr[3] > 0.0);
340 assert!(llr[4] > 0.0);
341 assert!(llr[5] > 0.0);
342 assert!(llr[6] < 0.0);
344 assert!(llr[7] > 0.0);
345 assert!(llr[8] > 0.0);
346 }
347}