use crate::error::{Error, Result};
use crate::dotprod::DotProd;
use crate::filter::resampler::resamp::Resamp;
use crate::filter::resampler::resamp2::Resamp2Coeff;
use crate::filter::resampler::msresamp2::{MsResamp2, ResampType};
use std::f32;
use num_complex::ComplexFloat;
#[derive(Clone, Debug)]
pub struct MsResamp<T, Coeff = T> {
rate: f32,
type_: ResampType,
rate_arbitrary: f32,
num_halfband_stages: usize,
buffer: Vec<T>,
buffer_index: usize,
halfband_resamp: MsResamp2<T, Coeff>,
arbitrary_resamp: Resamp<T, Coeff>,
}
impl<T, Coeff> MsResamp<T, Coeff>
where
Coeff: Clone + Copy + ComplexFloat<Real = f32> + From<f32> + Resamp2Coeff,
T: Clone + Copy + ComplexFloat<Real = f32> + Default + From<f32> + std::ops::Mul<Coeff, Output = T>,
[Coeff]: DotProd<T, Output = T>,
{
pub fn new(rate: f32, as_: f32) -> Result<Self> {
if rate <= 0.0 {
return Err(Error::Config("resampling rate must be greater than zero".into()));
}
let type_ = if rate > 1.0 { ResampType::Interp } else { ResampType::Decim };
let mut rate_arbitrary = rate;
let mut num_halfband_stages = 0;
match type_ {
ResampType::Interp => {
while rate_arbitrary > 2.0 {
num_halfband_stages += 1;
rate_arbitrary *= 0.5;
}
}
ResampType::Decim => {
while rate_arbitrary < 0.5 {
num_halfband_stages += 1;
rate_arbitrary *= 2.0;
}
}
}
let buffer_len = 4 + (1 << num_halfband_stages);
let buffer = vec![T::default(); buffer_len];
let halfband_resamp = MsResamp2::new(type_, num_halfband_stages, 0.4, 0.0, as_)?;
let arbitrary_resamp = Resamp::new(
rate_arbitrary,
7,
f32::min(0.515 * rate_arbitrary, 0.49),
as_,
256,
)?;
Ok(Self {
rate,
type_,
rate_arbitrary,
num_halfband_stages,
buffer,
buffer_index: 0,
halfband_resamp,
arbitrary_resamp,
})
}
pub fn reset(&mut self) {
self.halfband_resamp.reset();
self.arbitrary_resamp.reset();
self.buffer_index = 0;
}
pub fn get_delay(&self) -> f32 {
let delay_halfband = self.halfband_resamp.get_delay();
let delay_arbitrary = self.arbitrary_resamp.get_delay() as f32;
if self.num_halfband_stages == 0 {
delay_arbitrary
} else if self.type_ == ResampType::Interp {
delay_halfband / self.rate_arbitrary + delay_arbitrary
} else {
let m = 1 << self.num_halfband_stages;
delay_halfband + m as f32 * delay_arbitrary
}
}
pub fn get_rate(&self) -> f32 {
self.rate
}
pub fn get_num_output(&self, num_input: usize) -> usize {
match self.type_ {
ResampType::Interp => {
let n = self.arbitrary_resamp.get_num_output(num_input);
n * (1 << self.num_halfband_stages)
}
ResampType::Decim => {
let n = (self.buffer_index + num_input) >> self.num_halfband_stages;
self.arbitrary_resamp.get_num_output(n)
}
}
}
pub fn execute(&mut self, x: &[T], y: &mut [T]) -> Result<usize> {
match self.type_ {
ResampType::Interp => self.interp_execute(x, y),
ResampType::Decim => self.decim_execute(x, y),
}
}
fn interp_execute(&mut self, x: &[T], y: &mut [T]) -> Result<usize> {
let mut ny = 0;
for &xi in x {
let nw = self.arbitrary_resamp.execute(xi, &mut self.buffer[..])?;
for k in 0..nw {
self.halfband_resamp.execute(&[self.buffer[k]], &mut y[ny..])?;
ny += 1 << self.num_halfband_stages;
}
}
Ok(ny)
}
fn decim_execute(&mut self, x: &[T], y: &mut [T]) -> Result<usize> {
let mut ny = 0;
let m = 1 << self.num_halfband_stages;
for &xi in x {
self.buffer[self.buffer_index] = xi;
self.buffer_index += 1;
if self.buffer_index == m {
let mut halfband_output = T::default();
self.halfband_resamp.execute(&self.buffer[..m], std::slice::from_mut(&mut halfband_output))?;
let nw = self.arbitrary_resamp.execute(halfband_output, &mut y[ny..])?;
ny += nw;
self.buffer_index = 0;
}
}
Ok(ny)
}
}
#[cfg(test)]
mod tests {
use super::*;
use test_macro::autotest_annotate;
use num_complex::Complex32;
use crate::random::randnf;
use crate::fft::spgram::Spgram;
use crate::framing::symstreamr::SymStreamR;
use crate::utility::test_helpers::{PsdRegion, validate_psd_spectrum};
use crate::modem::modem::ModulationScheme;
use crate::math::WindowType;
use crate::filter::FirFilterShape;
fn testbench_msresamp_crcf(r: f32, as_: f32) {
let n = 800000; let bw = 0.2f32; let nfft = 800;
let tol = 0.5f32;
let mut q = Spgram::<Complex32>::new(nfft, WindowType::Hann, nfft/2, nfft/4).unwrap();
let mut gen = SymStreamR::new_linear(FirFilterShape::Kaiser, r*bw, 25, 0.2, ModulationScheme::Qpsk).unwrap();
gen.set_gain((bw as f32).sqrt());
let mut resamp = MsResamp::<Complex32, f32>::new(r, as_).unwrap();
let buf_len = 256;
let mut buf_0 = vec![Complex32::default(); buf_len]; let mut buf_1 = vec![Complex32::default(); buf_len]; while q.get_num_samples_total() < n {
gen.write_samples(&mut buf_0).unwrap();
let nw = resamp.execute(&buf_0, &mut buf_1).unwrap();
q.write(&buf_1[..nw]);
}
let psd = q.get_psd();
let regions = vec![
PsdRegion { fmin: -0.5, fmax: -0.6*bw, pmin: 0.0, pmax: -as_+tol, test_lo: false, test_hi: true },
PsdRegion { fmin: -0.4*bw, fmax: 0.4*bw, pmin: 0.0-tol, pmax: 0.0+tol, test_lo: true, test_hi: true },
PsdRegion { fmin: 0.6*bw, fmax: 0.5, pmin: 0.0, pmax: -as_+tol, test_lo: false, test_hi: true },
];
assert!(validate_psd_spectrum(&psd, nfft, ®ions).unwrap());
}
#[test]
#[autotest_annotate(autotest_msresamp_crcf_01)]
fn test_msresamp_crcf_01() { testbench_msresamp_crcf(0.127115323, 60.0); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_02)]
fn test_msresamp_crcf_02() { testbench_msresamp_crcf(0.373737373, 60.0); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_03)]
fn test_msresamp_crcf_03() { testbench_msresamp_crcf(0.676543210, 60.0); }
fn testbench_msresamp_crcf_num_output(rate: f32) {
let as_ = 60.0f32;
let mut q = MsResamp::<Complex32, f32>::new(rate, as_).unwrap();
let s = if rate < 0.1 { 131 } else { 1 }; let sizes = [1*s, 2*s, 3*s, 20*s, 7*s, 64*s, 4*s, 4*s, 4*s, 27*s];
let max_input = 64 * s;
let max_output = 16 + (4.0 * max_input as f32 * rate) as usize;
let buf_0 = vec![Complex32::new(0.0, 0.0); max_input];
let mut buf_1 = vec![Complex32::new(0.0, 0.0); max_output];
for _b in 0..8 {
for (_i, &size) in sizes.iter().enumerate() {
let num_input = size;
let num_output = q.get_num_output(num_input);
let num_written = q.execute(&buf_0[..num_input], &mut buf_1[..]).unwrap();
assert_eq!(num_output, num_written);
}
}
}
#[test]
#[autotest_annotate(autotest_msresamp_crcf_num_output_0)]
fn test_msresamp_crcf_num_output_0() { testbench_msresamp_crcf_num_output(1.00); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_num_output_1)]
fn test_msresamp_crcf_num_output_1() { testbench_msresamp_crcf_num_output(1e3); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_num_output_2)]
fn test_msresamp_crcf_num_output_2() { testbench_msresamp_crcf_num_output(1e-3); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_num_output_3)]
fn test_msresamp_crcf_num_output_3() { testbench_msresamp_crcf_num_output(2f32.sqrt()); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_num_output_4)]
fn test_msresamp_crcf_num_output_4() { testbench_msresamp_crcf_num_output(17f32.sqrt()); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_num_output_5)]
fn test_msresamp_crcf_num_output_5() { testbench_msresamp_crcf_num_output(1.0 / std::f32::consts::PI); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_num_output_6)]
fn test_msresamp_crcf_num_output_6() { testbench_msresamp_crcf_num_output(8.0f32.exp()); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_num_output_7)]
fn test_msresamp_crcf_num_output_7() { testbench_msresamp_crcf_num_output((-8.0f32).exp()); }
#[test]
#[autotest_annotate(autotest_msresamp_crcf_copy)]
fn test_msresamp_crcf_copy() {
let rate = 0.071239213987520f32;
let mut q0 = MsResamp::<Complex32, f32>::new(rate, 60.0f32).unwrap();
let buf_len = 640;
let mut buf = vec![Complex32::new(0.0, 0.0); buf_len];
let mut buf_0 = vec![Complex32::new(0.0, 0.0); buf_len];
let mut buf_1 = vec![Complex32::new(0.0, 0.0); buf_len];
for i in 0..buf_len {
buf[i] = Complex32::new(randnf(), randnf());
}
let _nw_0 = q0.execute(&buf, &mut buf_0).unwrap();
let mut q1 = q0.clone();
for i in 0..buf_len {
buf[i] = Complex32::new(randnf(), randnf());
}
let nw_0 = q0.execute(&buf, &mut buf_0).unwrap();
let nw_1 = q1.execute(&buf, &mut buf_1).unwrap();
assert_eq!(nw_0, nw_1);
assert_eq!(&buf_0[..nw_0], &buf_1[..nw_1]);
}
}