use super::TimerMarker;
use crate::{
io::{Data, UniqueIdentifier, Write},
Update,
};
use std::{ops::Add, sync::Arc};
#[cfg(feature = "noise")]
use rand_distr::{Distribution, Normal, NormalError};
#[derive(Debug, Clone)]
pub enum Signal {
Constant(f64),
Sinusoid {
amplitude: f64,
sampling_frequency_hz: f64,
frequency_hz: f64,
phase_s: f64,
},
Ramp { a: f64, b: f64 },
Sigmoid {
amplitude: f64,
sampling_frequency_hz: f64,
},
#[cfg(feature = "noise")]
WhiteNoise(Normal<f64>),
Composite(Vec<Signal>),
}
#[cfg(feature = "noise")]
impl Signal {
pub fn white_noise() -> Result<Self, NormalError> {
Ok(Signal::WhiteNoise(Normal::new(0f64, 1f64)?))
}
pub fn std_dev(self, sigma: f64) -> Result<Self, NormalError> {
if let Signal::WhiteNoise(noise) = self {
Ok(Signal::WhiteNoise(Normal::new(noise.mean(), sigma)?))
} else {
Ok(self)
}
}
pub fn bias(self, bias: f64) -> Result<Self, NormalError> {
if let Signal::WhiteNoise(noise) = self {
Ok(Signal::WhiteNoise(Normal::new(bias, noise.std_dev())?))
} else {
Ok(self)
}
}
}
impl Signal {
pub fn get(&self, i: usize) -> f64 {
use Signal::*;
match self {
Constant(val) => *val,
Sinusoid {
amplitude,
sampling_frequency_hz,
frequency_hz,
phase_s,
} => {
(2f64
* std::f64::consts::PI
* (phase_s + i as f64 * frequency_hz / sampling_frequency_hz))
.sin()
* amplitude
}
Ramp { a, b } => a * i as f64 + b,
Sigmoid {
amplitude,
sampling_frequency_hz,
} => {
let u = i as f64 / sampling_frequency_hz - 0.75;
let r = (1. + (-5. * u).exp()).recip();
amplitude * r * r
}
#[cfg(feature = "noise")]
WhiteNoise(noise) => noise.sample(&mut rand::thread_rng()),
Composite(signals) => signals.iter().map(|signal| signal.get(i)).sum(),
}
}
}
#[derive(Debug, Clone)]
pub struct Signals {
size: usize,
pub signals: Vec<Signal>,
pub step: usize,
pub n_step: usize,
}
impl Signals {
pub fn new(n: usize, n_step: usize) -> Self {
let signals: Vec<_> = vec![Signal::Constant(0f64); n];
Self {
size: n,
signals,
step: 0,
n_step,
}
}
#[deprecated(note = "please use `channels` instead")]
pub fn signals(self, signal: Signal) -> Self {
let signals = vec![signal.clone(); self.size];
Self { signals, ..self }
}
#[deprecated(note = "please use `channel` instead")]
pub fn output_signal(self, k: usize, output_signal: Signal) -> Self {
let mut signals = self.signals;
signals[k] = output_signal;
Self { signals, ..self }
}
pub fn channels(self, signal: Signal) -> Self {
let signals = vec![signal.clone(); self.size];
Self { signals, ..self }
}
pub fn channel(self, k: usize, output_signal: Signal) -> Self {
let mut signals = self.signals;
signals[k] = output_signal;
Self { signals, ..self }
}
}
impl From<(Vec<f64>, usize)> for Signals {
fn from((data, n_step): (Vec<f64>, usize)) -> Self {
let n = data.len();
data.into_iter()
.enumerate()
.fold(Signals::new(n, n_step), |s, (i, v)| {
s.channel(i, Signal::Constant(v))
})
}
}
impl From<(&[f64], usize)> for Signals {
fn from((data, n_step): (&[f64], usize)) -> Self {
let n = data.len();
data.iter()
.enumerate()
.fold(Signals::new(n, n_step), |s, (i, v)| {
s.channel(i, Signal::Constant(*v))
})
}
}
impl Add for Signal {
type Output = Signal;
fn add(self, rhs: Self) -> Self::Output {
if let Signal::Composite(mut signals) = self {
signals.push(rhs);
Signal::Composite(signals)
} else {
Signal::Composite(vec![self, rhs])
}
}
}
impl TimerMarker for Signals {}
impl Update for Signals {
fn update(&mut self) {
}
}
impl<U: UniqueIdentifier<DataType = Vec<f64>>> Write<U> for Signals {
fn write(&mut self) -> Option<Arc<Data<U>>> {
if self.step < self.n_step {
let i = self.step;
let data = self.signals.iter().map(|signal| signal.get(i)).collect();
self.step += 1;
Some(Arc::new(Data::new(data)))
} else {
None
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum SignalsError {
#[error("Two many signal channels, should be only 1")]
OneSignal,
}
pub struct OneSignal {
pub signal: Signal,
pub step: usize,
pub n_step: usize,
}
impl From<Signals> for Result<OneSignal, SignalsError> {
fn from(mut signals: Signals) -> Self {
if signals.signals.len() > 1 {
Err(SignalsError::OneSignal)
} else {
Ok(OneSignal {
signal: signals.signals.remove(0),
step: signals.step,
n_step: signals.n_step,
})
}
}
}
impl Update for OneSignal {
fn update(&mut self) {
}
}
impl<U: UniqueIdentifier<DataType = f64>> Write<U> for OneSignal {
fn write(&mut self) -> Option<Arc<Data<U>>> {
if self.step < self.n_step {
let i = self.step;
let data = self.signal.get(i);
self.step += 1;
Some(Arc::new(Data::new(data)))
} else {
None
}
}
}