use super::super::{
Buffer, DataDomain, DspVec, ErrorReason, FrequencyDomainOperations, InsertZerosOpsBuffered,
MetaData, NumberSpace, RealNumberSpace, RededicateForceOps, ResizeOps, TimeDomain,
TimeDomainOperations, ToFreqResult, ToSliceMut, TransRes, Vector,
};
use super::fft;
use crate::numbers::*;
use crate::window_functions::*;
pub trait TimeToFrequencyDomainOperations<S, T>: ToFreqResult
where
S: ToSliceMut<T>,
T: RealNumber,
{
fn plain_fft<B>(self, buffer: &mut B) -> Self::FreqResult
where
B: for<'a> Buffer<'a, S, T>;
fn fft<B>(self, buffer: &mut B) -> Self::FreqResult
where
B: for<'a> Buffer<'a, S, T>;
fn windowed_fft<B>(self, buffer: &mut B, window: &WindowFunction<T>) -> Self::FreqResult
where
B: for<'a> Buffer<'a, S, T>;
}
pub trait SymmetricTimeToFrequencyDomainOperations<S, T>: ToFreqResult
where
S: ToSliceMut<T>,
T: RealNumber,
{
fn plain_sfft<B>(self, buffer: &mut B) -> TransRes<Self::FreqResult>
where
B: for<'a> Buffer<'a, S, T>;
fn sfft<B>(self, buffer: &mut B) -> TransRes<Self::FreqResult>
where
B: for<'a> Buffer<'a, S, T>;
fn windowed_sfft<B>(
self,
buffer: &mut B,
window: &WindowFunction<T>,
) -> TransRes<Self::FreqResult>
where
B: for<'a> Buffer<'a, S, T>;
}
impl<S, T, N, D> TimeToFrequencyDomainOperations<S, T> for DspVec<S, T, N, D>
where
DspVec<S, T, N, D>: ToFreqResult,
<DspVec<S, T, N, D> as ToFreqResult>::FreqResult:
RededicateForceOps<DspVec<S, T, N, D>> + FrequencyDomainOperations<S, T>,
S: ToSliceMut<T>,
T: RealNumber,
N: NumberSpace,
D: TimeDomain,
{
fn plain_fft<B>(mut self, buffer: &mut B) -> Self::FreqResult
where
B: for<'a> Buffer<'a, S, T>,
{
if self.domain() != DataDomain::Time {
self.mark_vector_as_invalid();
self.number_space.to_complex();
self.domain.to_freq();
return Self::FreqResult::rededicate_from_force(self);
}
if !self.is_complex() {
self.zero_interleave_b(buffer, 2);
self.number_space.to_complex();
}
fft(&mut self, buffer, false);
self.domain.to_freq();
Self::FreqResult::rededicate_from_force(self)
}
fn fft<B>(self, buffer: &mut B) -> Self::FreqResult
where
B: for<'a> Buffer<'a, S, T>,
{
let mut result = self.plain_fft(buffer);
result.fft_shift();
result
}
fn windowed_fft<B>(mut self, buffer: &mut B, window: &WindowFunction<T>) -> Self::FreqResult
where
B: for<'a> Buffer<'a, S, T>,
{
self.apply_window(window);
let mut result = self.plain_fft(buffer);
result.fft_shift();
result
}
}
macro_rules! unmirror {
($self_: ident, $points: ident) => {
let len = $points;
let len = len / 2 + 1;
$self_
.resize(len)
.expect("Shrinking a vector should always succeed");
};
}
impl<S, T, N, D> SymmetricTimeToFrequencyDomainOperations<S, T> for DspVec<S, T, N, D>
where
DspVec<S, T, N, D>: ToFreqResult,
<DspVec<S, T, N, D> as ToFreqResult>::FreqResult:
RededicateForceOps<DspVec<S, T, N, D>> + FrequencyDomainOperations<S, T> + ResizeOps,
S: ToSliceMut<T>,
T: RealNumber,
N: RealNumberSpace,
D: TimeDomain,
{
fn plain_sfft<B>(mut self, buffer: &mut B) -> TransRes<Self::FreqResult>
where
B: for<'a> Buffer<'a, S, T>,
{
if self.domain() != DataDomain::Time || self.is_complex() {
self.mark_vector_as_invalid();
self.number_space.to_complex();
self.domain.to_freq();
return Err((
ErrorReason::InputMustBeInTimeDomain,
Self::FreqResult::rededicate_from_force(self),
));
}
if self.points() % 2 == 0 {
self.mark_vector_as_invalid();
self.number_space.to_complex();
self.domain.to_freq();
return Err((
ErrorReason::InputMustHaveAnOddLength,
Self::FreqResult::rededicate_from_force(self),
));
}
self.zero_interleave_b(buffer, 2);
self.number_space.to_complex();
let points = self.points();
let mut result = self.plain_fft(buffer);
unmirror!(result, points);
Ok(result)
}
fn sfft<B>(mut self, buffer: &mut B) -> TransRes<Self::FreqResult>
where
B: for<'a> Buffer<'a, S, T>,
{
if self.domain() != DataDomain::Time || self.is_complex() {
self.mark_vector_as_invalid();
self.number_space.to_complex();
self.domain.to_freq();
return Err((
ErrorReason::InputMustBeInTimeDomain,
Self::FreqResult::rededicate_from_force(self),
));
}
if self.points() % 2 == 0 {
self.mark_vector_as_invalid();
self.number_space.to_complex();
self.domain.to_freq();
return Err((
ErrorReason::InputMustHaveAnOddLength,
Self::FreqResult::rededicate_from_force(self),
));
}
self.zero_interleave_b(buffer, 2);
self.number_space.to_complex();
let points = self.points();
let mut result = self.fft(buffer);
unmirror!(result, points);
Ok(result)
}
fn windowed_sfft<B>(
mut self,
buffer: &mut B,
window: &WindowFunction<T>,
) -> TransRes<Self::FreqResult>
where
B: for<'a> Buffer<'a, S, T>,
{
if self.domain() != DataDomain::Time || self.is_complex() {
self.mark_vector_as_invalid();
self.number_space.to_complex();
self.domain.to_freq();
return Err((
ErrorReason::InputMustBeInTimeDomain,
Self::FreqResult::rededicate_from_force(self),
));
}
if self.points() % 2 == 0 {
self.mark_vector_as_invalid();
self.number_space.to_complex();
self.domain.to_freq();
return Err((
ErrorReason::InputMustHaveAnOddLength,
Self::FreqResult::rededicate_from_force(self),
));
}
self.zero_interleave_b(buffer, 2);
self.number_space.to_complex();
self.apply_window(window);
let points = self.points();
let mut result = self.fft(buffer);
unmirror!(result, points);
Ok(result)
}
}