1use crate::C64;
29use crate::error::{Error, Result, expect_len, same_len};
30use crate::units::Hertz;
31use ndarray::{Array2, ArrayView1, ArrayViewMut1};
32
33pub const KNOWN_BIT_LLR: f64 = 30.0;
38
39pub fn hard_decisions(llr: &[f64]) -> Vec<u8> {
48 llr.iter().map(|l| u8::from(*l < 0.0)).collect()
49}
50
51macro_rules! container {
52 ($(#[$doc:meta])* $name:ident, $elem:ty, $zero:expr) => {
53 $(#[$doc])*
54 #[derive(Clone, Debug, PartialEq, Default)]
55 pub struct $name(Array2<$elem>);
56
57 impl $name {
58 pub fn new(data: Array2<$elem>) -> $name {
60 $name(data.as_standard_layout().into_owned())
61 }
62
63 pub fn zeros(n_streams: usize, n: usize) -> $name {
65 $name(Array2::from_elem((n_streams, n), $zero))
66 }
67
68 pub fn from_stream(v: Vec<$elem>) -> Result<$name> {
73 let n = v.len();
74 Array2::from_shape_vec((1, n), v)
75 .map($name)
76 .map_err(|e| Error::Shape(e.to_string()))
77 }
78
79 pub fn from_streams(streams: &[Vec<$elem>]) -> Result<$name> {
84 let n = streams.first().map_or(0, Vec::len);
85 for s in streams {
86 same_len(s.len(), n, "streams")?;
87 }
88 let flat: Vec<$elem> = streams.iter().flatten().copied().collect();
89 Array2::from_shape_vec((streams.len(), n), flat)
90 .map($name)
91 .map_err(|e| Error::Shape(e.to_string()))
92 }
93
94 pub fn n_streams(&self) -> usize {
96 self.0.nrows()
97 }
98
99 pub fn len(&self) -> usize {
101 self.0.ncols()
102 }
103
104 pub fn is_empty(&self) -> bool {
106 self.0.is_empty()
107 }
108
109 pub fn stream(&self, i: usize) -> &[$elem] {
111 let n = self.len();
112 &self.as_slice()[i * n..(i + 1) * n]
113 }
114
115 pub fn stream_view(&self, i: usize) -> ArrayView1<'_, $elem> {
117 self.0.row(i)
118 }
119
120 pub fn stream_view_mut(&mut self, i: usize) -> ArrayViewMut1<'_, $elem> {
122 self.0.row_mut(i)
123 }
124
125 pub fn as_slice(&self) -> &[$elem] {
127 self.0.as_slice().unwrap_or(&[])
128 }
129
130 pub fn set_stream(&mut self, x: &[$elem]) {
133 self.resize(1, x.len());
134 self.as_slice_mut().copy_from_slice(x);
135 }
136
137 pub fn assign(&mut self, a: &Array2<$elem>) {
140 self.resize(a.nrows(), a.ncols());
141 self.0.assign(a);
142 }
143
144 pub fn stream_mut(&mut self, i: usize) -> &mut [$elem] {
146 let n = self.len();
147 &mut self.as_slice_mut()[i * n..(i + 1) * n]
148 }
149
150 pub fn as_slice_mut(&mut self) -> &mut [$elem] {
152 self.0.as_slice_mut().unwrap_or(&mut [])
153 }
154
155 pub fn as_array(&self) -> &Array2<$elem> {
157 &self.0
158 }
159
160 pub fn as_array_mut(&mut self) -> &mut Array2<$elem> {
162 &mut self.0
163 }
164
165 pub fn resize(&mut self, n_streams: usize, n: usize) {
168 if self.0.dim() != (n_streams, n) {
169 self.0 = Array2::from_elem((n_streams, n), $zero);
170 }
171 }
172 }
173 };
174}
175
176container!(
177 Bits, u8, 0
179);
180container!(
181 Llr, f64, 0.0
184);
185container!(
186 Symbols, C64, C64::new(0.0, 0.0)
188);
189container!(
190 Labels, usize, 0
195);
196
197#[derive(Clone, Debug, PartialEq)]
199pub struct Signal {
200 data: Symbols,
201 sample_rate: Hertz,
202}
203
204impl Signal {
205 pub fn new(data: Array2<C64>, sample_rate: Hertz) -> Signal {
207 Signal { data: Symbols::new(data), sample_rate }
208 }
209
210 pub fn zeros(n_streams: usize, n_samples: usize, sample_rate: Hertz) -> Signal {
212 Signal { data: Symbols::zeros(n_streams, n_samples), sample_rate }
213 }
214
215 pub fn from_stream(x: Vec<C64>, sample_rate: Hertz) -> Result<Signal> {
220 Ok(Signal { data: Symbols::from_stream(x)?, sample_rate })
221 }
222
223 pub fn from_streams(streams: &[Vec<C64>], sample_rate: Hertz) -> Result<Signal> {
228 Ok(Signal { data: Symbols::from_streams(streams)?, sample_rate })
229 }
230
231 pub fn sample_rate(&self) -> Hertz {
233 self.sample_rate
234 }
235
236 pub fn n_streams(&self) -> usize {
238 self.data.n_streams()
239 }
240
241 pub fn len(&self) -> usize {
243 self.data.len()
244 }
245
246 pub fn is_empty(&self) -> bool {
248 self.data.is_empty()
249 }
250
251 pub fn stream(&self, i: usize) -> &[C64] {
253 self.data.stream(i)
254 }
255
256 pub fn stream_view(&self, i: usize) -> ArrayView1<'_, C64> {
258 self.data.stream_view(i)
259 }
260
261 pub fn stream_mut(&mut self, i: usize) -> &mut [C64] {
263 self.data.stream_mut(i)
264 }
265
266 pub fn to_streams(&self) -> Vec<Vec<C64>> {
279 (0..self.n_streams()).map(|i| self.stream(i).to_vec()).collect()
280 }
281
282 pub fn as_array(&self) -> &Array2<C64> {
284 self.data.as_array()
285 }
286
287 pub fn as_array_mut(&mut self) -> &mut Array2<C64> {
289 self.data.as_array_mut()
290 }
291
292 pub fn resize(&mut self, n_streams: usize, n_samples: usize, sample_rate: Hertz) {
295 self.data.resize(n_streams, n_samples);
296 self.sample_rate = sample_rate;
297 }
298
299 pub fn set_stream(&mut self, x: &[C64], sample_rate: Hertz) {
302 self.resize(1, x.len(), sample_rate);
303 self.data.as_slice_mut().copy_from_slice(x);
304 }
305
306 pub fn assign(&mut self, other: &Signal) {
309 self.data.assign(other.data.as_array());
310 self.sample_rate = other.sample_rate;
311 }
312
313 pub fn set_streams(&mut self, streams: &[Vec<C64>], sample_rate: Hertz) -> Result<()> {
320 let n = streams.first().map_or(0, Vec::len);
321 for s in streams {
322 same_len(s.len(), n, "streams")?;
323 }
324 self.resize(streams.len(), n, sample_rate);
325 for (i, x) in streams.iter().enumerate() {
326 self.data.stream_mut(i).copy_from_slice(x);
327 }
328 Ok(())
329 }
330
331 pub fn try_map_streams(
340 &self,
341 out: &mut Signal,
342 mut f: impl FnMut(usize, &[C64]) -> Result<Vec<C64>>,
343 ) -> Result<()> {
344 out.resize(self.n_streams(), self.len(), self.sample_rate());
345 for s in 0..self.n_streams() {
346 let y = f(s, self.stream(s))?;
347 expect_len(y.len(), self.len(), "samples returned")?;
348 for (o, v) in out.as_array_mut().row_mut(s).iter_mut().zip(y) {
349 *o = v;
350 }
351 }
352 Ok(())
353 }
354
355 pub fn map_streams(&self, out: &mut Signal, mut f: impl FnMut(usize, &[C64]) -> Vec<C64>) {
361 if let Err(e) = self.try_map_streams(out, |s, x| Ok(f(s, x))) {
362 panic!("map_streams: {e}");
363 }
364 }
365
366 pub fn map_streams_in_place(&self, out: &mut Signal, mut f: impl FnMut(usize, &mut [C64])) {
383 out.assign(self);
384 for s in 0..out.n_streams() {
385 f(s, out.data.stream_mut(s));
386 }
387 }
388
389 pub fn power(&self) -> Vec<f64> {
391 let n = self.len().max(1) as f64;
392 (0..self.n_streams()).map(|i| self.stream(i).iter().map(C64::norm_sqr).sum::<f64>() / n).collect()
393 }
394}
395
396#[derive(Clone, Debug, PartialEq)]
398pub struct DualPol {
399 pub x: Vec<C64>,
401 pub y: Vec<C64>,
403}
404
405impl DualPol {
406 pub fn new(x: Vec<C64>, y: Vec<C64>) -> Result<DualPol> {
411 same_len(x.len(), y.len(), "polarisations")?;
412 Ok(DualPol { x, y })
413 }
414
415 pub fn len(&self) -> usize {
417 self.x.len()
418 }
419
420 pub fn is_empty(&self) -> bool {
422 self.x.is_empty()
423 }
424
425 pub fn power(&self) -> f64 {
427 let n = self.len().max(1) as f64;
428 self.x.iter().chain(&self.y).map(C64::norm_sqr).sum::<f64>() / n
429 }
430
431 pub fn scale(&mut self, s: f64) {
433 for v in self.x.iter_mut().chain(self.y.iter_mut()) {
434 *v *= s;
435 }
436 }
437
438 pub fn to_signal(&self, sample_rate: Hertz) -> Result<Signal> {
443 Signal::from_streams(&[self.x.clone(), self.y.clone()], sample_rate)
444 }
445
446 pub fn from_signal(s: &Signal) -> Result<DualPol> {
452 same_len(s.n_streams(), 2, "streams of a dual-polarisation field")?;
453 Ok(DualPol { x: s.stream(0).to_vec(), y: s.stream(1).to_vec() })
454 }
455}
456
457#[cfg(test)]
458mod tests {
459 use super::*;
460
461 #[test]
462 fn the_setters_reuse_the_storage_of_an_unchanged_shape() {
463 let mut out = Signal::zeros(1, 4, Hertz(1.0));
464 let p = out.as_array().as_ptr();
465 out.set_stream(&[C64::new(1.0, 0.0); 4], Hertz(2.0));
466 assert_eq!((out.as_array().as_ptr(), out.sample_rate()), (p, Hertz(2.0)));
467 out.set_streams(&[vec![C64::new(0.0, 1.0); 2], vec![C64::new(0.0, 2.0); 2]], Hertz(2.0)).unwrap();
468 assert_eq!(out.stream(1), &[C64::new(0.0, 2.0); 2]);
469 assert!(out.set_streams(&[vec![C64::new(0.0, 1.0); 2], vec![]], Hertz(2.0)).is_err());
470 let mut b = Bits::zeros(2, 3);
471 let p = b.as_slice().as_ptr();
472 b.assign(&Array2::from_elem((2, 3), 1));
473 b.stream_mut(1)[0] = 0;
474 assert_eq!((b.as_slice().as_ptr(), b.as_slice()), (p, &[1, 1, 1, 0, 1, 1][..]));
475 }
476
477 #[test]
478 fn streams_and_reshape() {
479 let s = Signal::from_streams(&[vec![C64::new(1.0, 0.0); 3], vec![C64::new(0.0, 2.0); 3]], Hertz(1.0)).unwrap();
480 assert_eq!(s.power(), vec![1.0, 4.0]);
481 assert!(Symbols::from_streams(&[vec![C64::new(0.0, 0.0); 2], vec![]]).is_err());
482 let mut b = Bits::zeros(1, 2);
483 b.resize(2, 5);
484 assert_eq!((b.n_streams(), b.len(), b.as_slice().len()), (2, 5, 10));
485 let d = DualPol::from_signal(&s).unwrap();
486 assert_eq!(d.to_signal(Hertz(1.0)).unwrap(), s);
487 assert!((d.power() - 5.0).abs() < 1e-12);
488 }
489
490 #[test]
491 fn try_map_streams_rejects_a_short_stream_instead_of_keeping_stale_samples() {
492 let x = Signal::from_streams(&[vec![C64::new(1.0, 0.0); 4]], Hertz(1.0)).unwrap();
493 let mut out = Signal::from_streams(&[vec![C64::new(9.0, 9.0); 4]], Hertz(1.0)).unwrap();
495 let err = x.try_map_streams(&mut out, |_, s| Ok(s[..3].to_vec())).unwrap_err();
496 assert!(matches!(err, Error::Shape(_)), "{err}");
497 assert!(x.try_map_streams(&mut out, |_, s| Ok([s, s].concat())).is_err());
498 x.try_map_streams(&mut out, |_, s| Ok(s.iter().map(|v| v * 2.0).collect())).unwrap();
499 assert_eq!(out.stream(0), &[C64::new(2.0, 0.0); 4]);
500 }
501
502 #[test]
503 fn map_streams_in_place_reuses_the_output_and_keeps_the_rate() {
504 let x = Signal::from_streams(&[vec![C64::new(1.0, 0.0); 4], vec![C64::new(0.0, 1.0); 4]], Hertz(3.0)).unwrap();
505 let mut out = Signal::zeros(2, 4, Hertz(1.0));
506 let p = out.as_array().as_ptr();
507 x.map_streams_in_place(&mut out, |s, y| y[0] *= (s + 2) as f64);
508 assert_eq!((out.as_array().as_ptr(), out.sample_rate()), (p, Hertz(3.0)));
509 assert_eq!(
510 (out.stream(0)[0], out.stream(1)[0], out.stream(1)[1]),
511 (C64::new(2.0, 0.0), C64::new(0.0, 3.0), C64::new(0.0, 1.0))
512 );
513 }
514
515 #[test]
516 #[should_panic(expected = "map_streams")]
517 fn map_streams_panics_on_a_short_stream() {
518 let x = Signal::from_streams(&[vec![C64::new(1.0, 0.0); 4]], Hertz(1.0)).unwrap();
519 let mut out = x.clone();
520 x.map_streams(&mut out, |_, s| s[..2].to_vec());
521 }
522}