Skip to content

Instantly share code, notes, and snippets.

@jakelevi1996
Last active April 24, 2023 15:07
Show Gist options
  • Save jakelevi1996/76b654e4aba973e42d24cc1f5281ebfe to your computer and use it in GitHub Desktop.
Save jakelevi1996/76b654e4aba973e42d24cc1f5281ebfe to your computer and use it in GitHub Desktop.
Delta-sigma modulation demo

Delta-sigma modulation demo

  • Delta-sigma modulation is a technique for ADC (analog to digital conversion), which converts a continuous-time, continuous-voltage input signal into a discrete-time, binary-voltage output signal, from which the original input signal can later be recovered
  • There is a description of delta-sigma modulation on Wikipedia (although it is not the most concise or helpful of Wikipedia articles)
  • Below are explanations of the basic technique of delta-sigma modulation and how to recover the input signal, a simple Python implementation of modulation and recovery (in 10 + 3 lines of code + generating input data and plotting), and some visualisations of a sinusoidal input signal, its delta-sigma modulated output signal, the recovered input signal, and the time integral of each signal respectively

Basic technique

  • The basic principle of delta-sigma modulation is to output either +delta or -delta (where delta is a given parameter) on each time step in order to make the time integral of the output digital signal as close as possible to the time integral of the input continuous signal
  • This is achieved by either:
    • Outputting +delta if the time integral of the output signal < the time integral of the input signal
    • Outputting -delta if the time integral of the output signal > the time integral of the input signal
  • This is equivalent to outputting delta equal in sign to [the time integral of the input signal] minus [the time integral of the output signal]
  • Because integration is a linear operation, this is equivalent to outputting delta equal in sign to the time integral of [the input signal minus the output signal] (which is more efficient as it reduces the number of operations and memory required on each time step)
  • The input signal minus the output signal can be referred to as the error signal, and the time integral of the error signal is referred to as sigma (hence "delta-sigma modulation")
  • In summary, to perform delta-sigma modulation, the time integral of [the input signal minus the output signal] is accumulated in a variable called sigma, and the output signal at each time step has magnitude delta and sign equal to the sign of sigma
  • An example is provided below of an input signal, its delta-sigma modulated signal, and the time integrals of both signals:
    • Note that the input signal is represented by 64-bit floating point numbers, whereas the modulated signal can be represented using binary numbers at the same sampling frequency, thereby achieving 64x compression while still preserving most of the information content of the original signal and allowing the original signal to be reasonably recovered (see subsequent sections)

Recovering the input signal

  • To recover the continuous input signal from the binary output signal, note that:
    • The output signal contains much stronger high frequency components than the input signal (because the output signal frequently switches between +/- delta on adjacent time steps), but the time integral of the output signal is very close to the time integral of the original signal (by construction)
    • High frequency components frequently oscillate between positive and negative values which approximately cancel out over time during integration, and therefore integration is relatively insensitive to high frequency components (in contrast to differentiation, which is especially sensitive to high frequency components)
  • Because integration is insensitive to high frequency components, it is also reasonably insensitive to low-pass filtering, which approximately removes high frequencies from a signal but leaves the low frequencies unchanged
  • Therefore, if we low-pass filter the binary output signal, the high-frequency components will be removed, but its time integral will still match that of the input signal, which implies that the low-pass filtered output signal will be closer to the input signal
  • (Looking at this another way, if two signals have very different waveforms but have very similar time integrals, then it must be that these signals are different in their high-frequency components but similar in their low-frequency components, and therefore removing any high frequency components from the two signals should bring them closer together)
  • Therefore, the original input signal can be approximately recovered by low-pass filtering the binary output signal
  • EDIT: a simpler way to think about this is that since the time integrals of the input and output signals are close, but the time integral of the output signal has more high frequency noise, the input signal could be approximately recovered by low-pass filtering the time integral of the output signal and then differentiating it, but since integration, low-pass filtering and differentiation are all linear filtering operations that commute with each other, the integration and differentiation operations cancel out, and we are left with simply low-pass filtering the output signal in order to approximately recover the input signal

Implementation and visualisations

(The plotting module below and the util module which it also uses can be found in my aims repository on GitHub, although I intend to upload them soon to a single package in PyPI)

import numpy as np
import plotting

t_list = np.linspace(0, 1, 100)
x_list = np.sin(2 * np.pi * t_list)
y_list = []
delta = 1
sigma = 0
for x in x_list:
    if sigma > 0:
        y = delta
    else:
        y = -delta
    sigma += x - y
    y_list.append(y)

filter_coeffs = np.exp(-np.square(np.linspace(-2, 2, 20)))
filter_coeffs /= filter_coeffs.sum()
z_list = np.convolve(y_list, filter_coeffs, "same")

labels = [
    "Input signal (continuous)",
    "Output signal (digital)",
    "Decoded signal (continuous)",
]
plotting.plot(
    plotting.Line(t_list, x_list, c="b", label=labels[0]),
    plotting.Step(t_list, y_list, c="g", label=labels[1]),
    plotting.Line(t_list, z_list, c="r", label=labels[2]),
    legend=True,
    plot_name="Delta-sigma ADC of sine wave",
)
dt = t_list[1] - t_list[0]
plotting.plot(
    plotting.Line(t_list, dt * np.cumsum(x_list), c="b", label=labels[0]),
    plotting.Step(t_list, dt * np.cumsum(y_list), c="g", label=labels[1]),
    plotting.Line(t_list, dt * np.cumsum(z_list), c="r", label=labels[2]),
    legend=True,
    plot_name="Time integrals for delta-sigma ADC of sine wave",
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment