Added first parts signal generator. Not yet for sweeps, not yet filters.
This commit is contained in:
parent
23ddf39a4a
commit
ec010945c6
11
Cargo.toml
11
Cargo.toml
@ -14,24 +14,27 @@ categories = [
|
|||||||
"mathematics"]
|
"mathematics"]
|
||||||
[lib]
|
[lib]
|
||||||
name = "lasprs"
|
name = "lasprs"
|
||||||
crate-type = ["cdylib", "lib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
pyo3 = { version = "0.20", features=["anyhow", "extension-module"]}
|
|
||||||
|
|
||||||
# Optional future feature for ndarray: blas
|
# Optional future feature for ndarray: blas
|
||||||
ndarray = { version = "0.15.3", features = ["rayon"] }
|
ndarray = { version = "0.15.3", features = ["rayon"] }
|
||||||
num = "0.4.1"
|
num = "0.4.1"
|
||||||
rayon = "1.8.0"
|
rayon = "1.8.0"
|
||||||
numpy = { version = "0.20" }
|
numpy = { version = "0.20" }
|
||||||
|
strum_macros = "0.25.3"
|
||||||
|
pyo3 = { version = "0.20", features=["anyhow", "extension-module"]}
|
||||||
|
rand = "0.8.5"
|
||||||
|
rand_distr = "0.4.3"
|
||||||
# blas-src = { version = "0.8", features = ["openblas"] }
|
# blas-src = { version = "0.8", features = ["openblas"] }
|
||||||
# openblas-src = { version = "0.10", features = ["cblas", "system"] }
|
# openblas-src = { version = "0.10", features = ["cblas", "system"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# default = ["f64"]
|
default = ["f64"]
|
||||||
# Use this for debugging extension
|
# Use this for debugging extension
|
||||||
default = ["f64", "extension-module", "pyo3/extension-module"]
|
# default = ["f64", "extension-module", "pyo3/extension-module"]
|
||||||
f64 = []
|
f64 = []
|
||||||
f32 = []
|
f32 = []
|
||||||
extension-module = ["pyo3/extension-module"]
|
extension-module = ["pyo3/extension-module"]
|
||||||
|
@ -16,6 +16,9 @@ use numpy::ndarray::{Array1, Array2};
|
|||||||
pub type Vd = Vec<Flt>;
|
pub type Vd = Vec<Flt>;
|
||||||
pub type Vc = Vec<Cflt>;
|
pub type Vc = Vec<Cflt>;
|
||||||
|
|
||||||
|
pub type Dcol = Array1<Flt>;
|
||||||
|
pub type Ccol = Array1<Cflt>;
|
||||||
|
|
||||||
pub type Dmat = Array2<Flt>;
|
pub type Dmat = Array2<Flt>;
|
||||||
pub type Cmat = Array2<Cflt>;
|
pub type Cmat = Array2<Cflt>;
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
pub mod filter;
|
pub mod filter;
|
||||||
|
// pub mod window;
|
||||||
|
// pub mod ps;
|
||||||
|
pub mod siggen;
|
||||||
|
|
||||||
extern crate pyo3;
|
extern crate pyo3;
|
||||||
#[cfg(feature = "extension-module")]
|
#[cfg(feature = "extension-module")]
|
||||||
|
181
src/siggen.rs
Normal file
181
src/siggen.rs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
use super::config::*;
|
||||||
|
use super::filter::Filter;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use rand::prelude::*;
|
||||||
|
use rand::rngs::ThreadRng;
|
||||||
|
use rand_distr::StandardNormal;
|
||||||
|
|
||||||
|
pub trait Source: Send {
|
||||||
|
fn genSignal_unscaled(&mut self, sig: &mut [Flt]);
|
||||||
|
fn reset(&mut self, fs: Flt);
|
||||||
|
fn clone_dyn(&self) -> Box<dyn Source>;
|
||||||
|
}
|
||||||
|
impl Clone for Box<dyn Source> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
self.clone_dyn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// White noise source
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct WhiteNoise {}
|
||||||
|
impl WhiteNoise {
|
||||||
|
/// Generate new WhiteNoise generator
|
||||||
|
fn new() -> WhiteNoise {
|
||||||
|
WhiteNoise {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Source for WhiteNoise {
|
||||||
|
fn genSignal_unscaled(&mut self, sig: &mut [Flt]) {
|
||||||
|
sig.iter_mut()
|
||||||
|
.for_each(|s| *s = thread_rng().sample(StandardNormal));
|
||||||
|
}
|
||||||
|
fn reset(&mut self,_fs: Flt) {}
|
||||||
|
fn clone_dyn(&self) -> Box<dyn Source> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sine wave, with configurable frequency
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Sine {
|
||||||
|
// Sampling freq [Hz]
|
||||||
|
fs: Flt,
|
||||||
|
// current stored phase
|
||||||
|
phase: Flt,
|
||||||
|
// Signal frequency [rad/s]
|
||||||
|
omg: Flt,
|
||||||
|
}
|
||||||
|
impl Sine {
|
||||||
|
/// Create new sine source signal
|
||||||
|
///
|
||||||
|
/// Args:
|
||||||
|
///
|
||||||
|
/// * fs: Sampling freq [Hz]
|
||||||
|
/// *
|
||||||
|
fn new(freq: Flt) -> Sine {
|
||||||
|
Sine {
|
||||||
|
fs: -1.,
|
||||||
|
phase: 0.,
|
||||||
|
omg: 2. * pi * freq,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Source for Sine {
|
||||||
|
fn genSignal_unscaled(&mut self, sig: &mut [Flt]) {
|
||||||
|
if self.fs < 0. {
|
||||||
|
sig.iter_mut().for_each(|s| {
|
||||||
|
*s = 0.;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sig.iter_mut().for_each(|s| {
|
||||||
|
*s = Flt::sin(self.phase);
|
||||||
|
self.phase += self.omg / self.fs;
|
||||||
|
});
|
||||||
|
while self.phase > 2. * pi {
|
||||||
|
self.phase -= 2. * pi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn reset(&mut self, fs: Flt) {
|
||||||
|
self.fs = fs;
|
||||||
|
self.phase = 0.;
|
||||||
|
}
|
||||||
|
fn clone_dyn(&self) -> Box<dyn Source> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sweep signal
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// Signal generator. Able to create acoustic output signals
|
||||||
|
pub struct Siggen {
|
||||||
|
source: Box<dyn Source>,
|
||||||
|
prefilter: Option<Box<dyn Filter>>,
|
||||||
|
muted: bool,
|
||||||
|
gain: Flt,
|
||||||
|
DCOffset: Flt,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A struct that implements the Siggen trait is able to generate a signal.
|
||||||
|
impl Siggen {
|
||||||
|
/// Set new pre-filter that filters the source signal
|
||||||
|
pub fn setPreFilter(&mut self, pref: Option<Box<dyn Filter>>) {
|
||||||
|
self.prefilter = pref.clone();
|
||||||
|
}
|
||||||
|
pub fn newWhiteNoise() -> Siggen {
|
||||||
|
Siggen::new(Box::new(WhiteNoise::new()))
|
||||||
|
}
|
||||||
|
pub fn newSineWave(freq: Flt) -> Siggen {
|
||||||
|
Siggen::new(Box::new(Sine::new(freq)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new signal generator wiht an arbitrary source.
|
||||||
|
pub fn new(source: Box<dyn Source>) -> Siggen {
|
||||||
|
Siggen {
|
||||||
|
source,
|
||||||
|
prefilter: None,
|
||||||
|
muted: false,
|
||||||
|
gain: 1.0,
|
||||||
|
DCOffset: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate new signal data.
|
||||||
|
///
|
||||||
|
/// # Args
|
||||||
|
///
|
||||||
|
/// sig: Reference of array of float values to be filled with signal data.
|
||||||
|
///
|
||||||
|
/// # Details
|
||||||
|
///
|
||||||
|
/// - When muted, the DC offset is still applied
|
||||||
|
/// - The order of the generation is:
|
||||||
|
/// - First, the source is generated.
|
||||||
|
/// - If a prefilter is installed, this pre-filter is applied to the source signal.
|
||||||
|
/// - Gain is applied.
|
||||||
|
/// - Offset is applied (thus, no gain is applied to the DC offset).
|
||||||
|
///
|
||||||
|
fn genSignal(&mut self, sig: &mut [Flt]) {
|
||||||
|
if self.muted {
|
||||||
|
sig.iter_mut().for_each(|x| {
|
||||||
|
*x = 0.0;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.source.genSignal_unscaled(sig);
|
||||||
|
if let Some(f) = &mut self.prefilter {
|
||||||
|
f.filter(sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sig.iter_mut().for_each(|x| {
|
||||||
|
// First apply gain, then offset
|
||||||
|
*x *= self.gain;
|
||||||
|
*x += self.DCOffset;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset signal generator. Applies any kind of cleanup necessary.
|
||||||
|
///
|
||||||
|
/// Args
|
||||||
|
///
|
||||||
|
/// * fs: (New) Sampling frequency [Hz]
|
||||||
|
///
|
||||||
|
fn reset(&mut self, fs: Flt) {
|
||||||
|
self.source.reset(fs);
|
||||||
|
if let Some(f) = self.prefilter {
|
||||||
|
f.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_whitenoise() {
|
||||||
|
println!("{:?}", WhiteNoise::new().genSignal(10));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user