Implemented generic up and downsampler
This commit is contained in:
commit
da69d0c76e
|
@ -0,0 +1,3 @@
|
|||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "rusty-dsp"
|
||||
version = "0.1.0"
|
||||
authors = ["LongHairedHacker <sebastian@sebastians-site.de>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
num = "*"
|
|
@ -0,0 +1,43 @@
|
|||
use std::iter::FromIterator;
|
||||
|
||||
pub struct SquaringAMDemodulator<'a> {
|
||||
iterator: Box<dyn Iterator<Item = f32> + 'a>,
|
||||
}
|
||||
|
||||
impl<'a> SquaringAMDemodulator<'a> {
|
||||
pub fn from<I>(iterator1: I) -> SquaringAMDemodulator<'a>
|
||||
where
|
||||
I: Iterator<Item = f32> + 'a,
|
||||
{
|
||||
SquaringAMDemodulator {
|
||||
iterator: Box::new(iterator1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for SquaringAMDemodulator<'a> {
|
||||
type Item = f32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iterator.next() {
|
||||
Some(x) => Some((x * x).sqrt()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_amdemod() {
|
||||
let test_data = vec![-1_f32, 2_f32, -3_f32, 4_f32, -5_f32];
|
||||
|
||||
let demod = SquaringAMDemodulator::from(test_data.into_iter());
|
||||
|
||||
let result_data = Vec::from_iter(demod);
|
||||
assert_eq!(result_data.len(), 5);
|
||||
assert_eq!(result_data, [1_f32, 2_f32, 3_f32, 4_f32, 5_f32]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
pub struct FIRFilter<'a> {
|
||||
coeffs: &'a [f32],
|
||||
state: Vec<f32>,
|
||||
pos: usize,
|
||||
iterator: Box<dyn Iterator<Item = f32> + 'a>,
|
||||
}
|
||||
|
||||
impl<'a> FIRFilter<'a> {
|
||||
pub fn from<I>(iterator: I, coeffs: &'a [f32]) -> FIRFilter<'a>
|
||||
where
|
||||
I: Iterator<Item = f32> + 'a,
|
||||
{
|
||||
let mut state = Vec::new();
|
||||
for _ in 0..coeffs.len() {
|
||||
state.push(0.0);
|
||||
}
|
||||
|
||||
FIRFilter {
|
||||
coeffs: coeffs,
|
||||
state: state,
|
||||
pos: 0,
|
||||
iterator: Box::new(iterator),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for FIRFilter<'a> {
|
||||
type Item = f32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let cur = match self.iterator.next() {
|
||||
Some(x) => x,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
self.pos = (self.pos + 1) % self.coeffs.len();
|
||||
self.state[self.pos] = cur;
|
||||
|
||||
let mut result = 0.0;
|
||||
for i in 0..self.coeffs.len() {
|
||||
let pos = (self.pos + self.coeffs.len() - i) % self.coeffs.len();
|
||||
result += self.state[pos] * self.coeffs[i];
|
||||
}
|
||||
|
||||
Some(result)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
mod amdemod;
|
||||
mod firfilter;
|
||||
mod resamplers;
|
|
@ -0,0 +1,120 @@
|
|||
use num::traits::{Num, NumCast};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
pub struct Upsampler<'a, NumType>
|
||||
where
|
||||
NumType: Num + Clone,
|
||||
{
|
||||
factor: u16,
|
||||
state: u16,
|
||||
sample: Option<NumType>,
|
||||
iterator: Box<dyn Iterator<Item = NumType> + 'a>,
|
||||
}
|
||||
|
||||
impl<'a, NumType> Upsampler<'a, NumType>
|
||||
where
|
||||
NumType: Num + Clone,
|
||||
{
|
||||
pub fn from<I>(iterator: I, factor: u16) -> Upsampler<'a, NumType>
|
||||
where
|
||||
I: Iterator<Item = NumType> + 'a,
|
||||
{
|
||||
Upsampler {
|
||||
factor: factor,
|
||||
state: 0,
|
||||
sample: Some(NumType::zero()),
|
||||
iterator: Box::new(iterator),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, NumType> Iterator for Upsampler<'a, NumType>
|
||||
where
|
||||
NumType: Num + Clone,
|
||||
{
|
||||
type Item = NumType;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.state == 0 {
|
||||
self.sample = self.iterator.next();
|
||||
}
|
||||
self.state = (self.state + 1) % self.factor;
|
||||
|
||||
return self.sample.clone();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Downsampler<'a, NumType>
|
||||
where
|
||||
NumType: Num + Clone + NumCast,
|
||||
{
|
||||
factor: u16,
|
||||
iterator: Box<dyn Iterator<Item = NumType> + 'a>,
|
||||
}
|
||||
|
||||
impl<'a, NumType> Downsampler<'a, NumType>
|
||||
where
|
||||
NumType: Num + Clone + NumCast,
|
||||
{
|
||||
pub fn from<I>(iterator: I, factor: u16) -> Downsampler<'a, NumType>
|
||||
where
|
||||
I: Iterator<Item = NumType> + 'a,
|
||||
{
|
||||
Downsampler {
|
||||
factor: factor,
|
||||
iterator: Box::new(iterator),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, NumType> Iterator for Downsampler<'a, NumType>
|
||||
where
|
||||
NumType: Num + Clone + NumCast,
|
||||
{
|
||||
type Item = NumType;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut result = NumType::zero();
|
||||
for _ in 0..self.factor {
|
||||
match self.iterator.next() {
|
||||
Some(x) => result = result + x,
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
result = result / NumType::from(self.factor).unwrap();
|
||||
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn upsampler_test() {
|
||||
let test_data = vec![1_f32, 2_f32, 3_f32, 4_f32, 5_f32];
|
||||
|
||||
let upsampler = Upsampler::from(test_data.into_iter(), 2);
|
||||
|
||||
let result_data = Vec::from_iter(upsampler);
|
||||
assert_eq!(result_data.len(), 10);
|
||||
assert_eq!(
|
||||
result_data,
|
||||
[1_f32, 1_f32, 2_f32, 2_f32, 3_f32, 3_f32, 4_f32, 4_f32, 5_f32, 5_f32]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downsampler_test() {
|
||||
let test_data = vec![
|
||||
1_f32, 1_f32, 2_f32, 2_f32, 3_f32, 3_f32, 4_f32, 4_f32, 5_f32, 5_f32,
|
||||
];
|
||||
|
||||
let downsampler = Downsampler::from(test_data.into_iter(), 2);
|
||||
|
||||
let result_data = Vec::from_iter(downsampler);
|
||||
assert_eq!(result_data.len(), 5);
|
||||
assert_eq!(result_data, [1_f32, 2_f32, 3_f32, 4_f32, 5_f32]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue