Skip to content

Commit

Permalink
Merge pull request #24 from quartiq/dsm
Browse files Browse the repository at this point in the history
Dsm: add delta sigma modulator
  • Loading branch information
jordens authored Jan 17, 2024
2 parents 0d79217 + d5b64d3 commit 5922878
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased](https://github.com/quartiq/idsp/compare/v0.14.1..main) - 2024-01-15

### Added

* `Dsm`: Delta sigma modulator/noise shaper in MASH-(1)^K architecture.

## [0.14.1](https://github.com/quartiq/idsp/compare/v0.14.0..v0.14.1) - 2024-01-15

* Fixed changelog
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,7 @@ bandpass, and notch filtering of a signal.
Fast `f32` symmetric FIR filters, optimized half-band filters, half-band filter decimators and integators and cascades.
These are used in [`stabilizer-stream`](https://github.com/quartiq/stabilizer-stream) for online PSD calculation on log
frequency scale for arbitrarily large amounts of data.

## Delta Sigma modulator/noise shaper

[`Dsm`] is a delta sigma modulator/noise shaper in MASH-(1)^K architecture.
55 changes: 55 additions & 0 deletions src/dsm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/// Delta-sigma modulator
///
/// * MASH-(1)^K architecture
/// * `0 <= K <= 8` (`K=0` is valid but the output will be the constant quantized 0)
/// * The output range is `1 - (1 << K - 1)..=(1 << K - 1)`.
/// * Given constant input `x0`, the average output is `x0/(1 << 32)`.
/// * The noise goes up as `K * 20 dB/decade`.
///
/// ```
/// # use idsp::Dsm;
/// let mut d = Dsm::<3>::default();
/// let x = 0x87654321;
/// let n = 1 << 20;
/// let y = (0..n).map(|_| d.update(x) as f32).sum::<f32>() / n as f32;
/// let m = x as f32 / (1u64 << 32) as f32;
/// assert!((y / m - 1.0).abs() < (1.0 / n as f32).sqrt(), "{y} != {m}");
/// ```
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
pub struct Dsm<const K: usize> {
a: [u32; K],
c: [i8; K],
}

impl<const K: usize> Default for Dsm<K> {
fn default() -> Self {
Self {
a: [0; K],
c: [0; K],
}
}
}

impl<const K: usize> Dsm<K> {
/// Ingest input sample, emit new output.
///
/// # Arguments
/// * `x`: New input sample
///
/// # Returns
/// New output
pub fn update(&mut self, x: u32) -> i8 {
let mut d = 0i8;
let mut c = false;
self.a.iter_mut().fold(x, |x, a| {
(*a, c) = a.overflowing_add(x);
d = (d << 1) | c as i8;
*a
});
self.c.iter_mut().take(K - 1).fold(d & 1, |mut y, c| {
d >>= 1;
(y, *c) = ((d & 1) + y - *c, y);
y
})
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ pub use unwrap::*;
pub mod hbf;
mod num;
pub use num::*;
mod dsm;
pub mod svf;
pub use dsm::*;

#[cfg(test)]
pub mod testing;

0 comments on commit 5922878

Please sign in to comment.