Struct idsp::hbf::SymFir

source ·
pub struct SymFir<'a, T, const M: usize, const N: usize> { /* private fields */ }
Expand description

Symmetric FIR filter prototype.

§Generics

  • M: number of taps, one-sided. The filter has effectively 2*M DSP taps
  • N: state size: N = 2*M - 1 + {input/output}.len()

§Half band decimation/interpolation filters

Half-band filters (rate change of 2) and cascades of HBFs are implemented in HbfDec and HbfInt etc. The half-band filter has unique properties that make it preferrable in many cases:

  • only needs M multiplications (fused multiply accumulate) for 4*M taps
  • HBF decimator stores less state than a generic FIR filter
  • as a FIR filter has linear phase/flat group delay
  • very small passband ripple and excellent stopband attenuation
  • as a cascade of decimation/interpolation filters, the higher-rate filters need successively fewer taps, allowing the filtering to be dominated by only the highest rate filter with the fewest taps
  • In a cascade of HBF the overall latency, group delay, and impulse response length are dominated by the lowest-rate filter which, due to its manageable transition band width (compared to single-stage filters) can be smaller, shorter, and faster.
  • high dynamic range and inherent stability compared with an IIR filter
  • can be combined with a CIC filter for non-power-of-two or even higher rate changes

The implementations here are all no_std and no-alloc. They support (but don’t require) in-place filtering to reduce memory usage. They unroll and optimmize extremely well targetting current architectures, e.g. requiring less than 4 instructions per input item for the full HbfDecCascade on Skylake. The filters are optimized for decent block sizes and perform best (i.e. with negligible overhead) for blocks of 32 high-rate items or more, depending very much on architecture.

Implementations§

source§

impl<'a, T: Copy + Zero + Add + Mul<Output = T> + Sum, const M: usize, const N: usize> SymFir<'a, T, M, N>

source

pub fn new(taps: &'a [T; M]) -> Self

Create a new SymFir.

§Args
  • taps: one-sided FIR coefficients, expluding center tap, oldest to one-before-center
source

pub fn buf_mut(&mut self) -> &mut [T]

Obtain a mutable reference to the input items buffer space.

source

pub fn get(&self) -> impl Iterator<Item = T> + '_

Perform the FIR convolution and yield results iteratively.

source

pub fn keep_state(&mut self, offset: usize)

Move items as new filter state.

§Args
  • offset: Keep the 2*M-1 items at offset as the new filter state.

Trait Implementations§

source§

impl<'a, T: Clone, const M: usize, const N: usize> Clone for SymFir<'a, T, M, N>

source§

fn clone(&self) -> SymFir<'a, T, M, N>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<'a, T: Debug, const M: usize, const N: usize> Debug for SymFir<'a, T, M, N>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'a, T: Copy, const M: usize, const N: usize> Copy for SymFir<'a, T, M, N>

Auto Trait Implementations§

§

impl<'a, T, const M: usize, const N: usize> Freeze for SymFir<'a, T, M, N>
where T: Freeze,

§

impl<'a, T, const M: usize, const N: usize> RefUnwindSafe for SymFir<'a, T, M, N>
where T: RefUnwindSafe,

§

impl<'a, T, const M: usize, const N: usize> Send for SymFir<'a, T, M, N>
where T: Send + Sync,

§

impl<'a, T, const M: usize, const N: usize> Sync for SymFir<'a, T, M, N>
where T: Sync,

§

impl<'a, T, const M: usize, const N: usize> Unpin for SymFir<'a, T, M, N>
where T: Unpin,

§

impl<'a, T, const M: usize, const N: usize> UnwindSafe for SymFir<'a, T, M, N>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.