Delta-Sigma ADC

Simulation of a first-order delta-sigma analog-to-digital converter.

You can also find this example as a single file in the GitHub repository.

block diagram of delta sigma adc

Delta-Sigma ADC Principle

A delta-sigma ADC works by:

  1. Oversampling the input signal at a high frequency

  2. Using a 1-bit quantizer (comparator)

  3. Negative feedback through a DAC to shape quantization noise

  4. Digital filtering (FIR) to downsample and reconstruct the signal

The key advantage is that quantization noise is pushed to high frequencies (noise shaping), where it can be filtered out.

The system uses DAC, Comparator, SampleHold, and FIR blocks to implement a complete delta-sigma ADC with digital filtering.

[1]:
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import firwin

# Apply PathSim docs matplotlib style for consistent, theme-friendly figures
plt.style.use('../pathsim_docs.mplstyle')

from pathsim import Simulation, Connection
from pathsim.blocks import (
    Integrator, Adder, Scope, Source,
    SampleHold, DAC, Comparator, FIR
)
from pathsim.solvers import RKBS32

System Parameters

We set the key parameters:

  • Clock frequency: 100 Hz (oversampling rate)

  • Reference voltage: 1.0 V

  • FIR filter: 20 taps, cutoff at Fs/50

The input signal is a 1 Hz sine wave, so the oversampling ratio is 100.

[2]:
v_ref = 1.0           # DAC reference
f_clk = 100           # Sampling frequency
T_clk = 1.0 / f_clk   # Sampling period

# Design FIR lowpass filter for decimation
fir_coeffs = firwin(20, f_clk/50, fs=f_clk)

Block Diagram

We create the blocks for the delta-sigma modulator:

  • src: Input signal (sine wave)

  • sub: Subtractor (input - feedback)

  • itg: Integrator (loop filter)

  • sah: Sample & Hold

  • qtz: Comparator (1-bit quantizer)

  • dac: 1-bit DAC for feedback

  • lpf: FIR lowpass filter for reconstruction

[3]:
# Blocks that define the system
src = Source(lambda t: np.sin(2*np.pi*t))
sub = Adder("+-")
itg = Integrator()
sah = SampleHold(T=T_clk, tau=T_clk*1e-3)
qtz = Comparator(span=[0, 1])
dac = DAC(n_bits=1, span=[-v_ref, v_ref], T=T_clk, tau=T_clk*2e-3)
lpf = FIR(coeffs=fir_coeffs, T=T_clk, tau=T_clk*2e-3)
sc1 = Scope(labels=["src", "qtz", "dac", "lpf"])
sc2 = Scope(labels=["itg", "sah"])

blocks = [src, sub, itg, sah, qtz, dac, lpf, sc1, sc2]

Connections

The connections form the delta-sigma loop with digital filtering.

[4]:
connections = [
    Connection(src, sub[0], sc1[0]),      # Source to subtractor and scope
    Connection(dac, sub[1], lpf, sc1[2]), # DAC feedback and to FIR filter
    Connection(sub, itg),                 # Difference to integrator
    Connection(itg, sah, sc2[0]),         # Integrator to S&H
    Connection(sah, qtz, sc2[1]),         # S&H to comparator
    Connection(qtz, dac[0], sc1[1]),      # Comparator to DAC
    Connection(lpf, sc1[3]),              # Filtered output
]

Simulation

We use an adaptive solver (RKBS32) with a maximum timestep to handle the discrete-time sampling events properly.

[5]:
# Simulation with adaptive solver
Sim = Simulation(
    blocks,
    connections,
    dt_max=T_clk*0.1,
    Solver=RKBS32
)

# Run simulation for 2 seconds
Sim.run(2)
10:28:30 - INFO - LOGGING (log: True)
10:28:30 - INFO - BLOCKS (total: 9, dynamic: 1, static: 8, eventful: 4)
10:28:30 - INFO - GRAPH (nodes: 9, edges: 13, alg. depth: 2, loop depth: 0, runtime: 0.049ms)
10:28:30 - INFO - STARTING -> TRANSIENT (Duration: 2.00s)
10:28:30 - INFO - --------------------   1% | 0.0s<0.3s | 6542.6 it/s
10:28:30 - INFO - ####----------------  20% | 0.1s<0.3s | 6678.8 it/s
10:28:30 - INFO - ########------------  40% | 0.2s<0.2s | 5806.8 it/s
10:28:30 - INFO - ############--------  60% | 0.2s<0.1s | 6606.6 it/s
10:28:30 - INFO - ################----  80% | 0.3s<0.1s | 6670.4 it/s
10:28:30 - INFO - #################### 100% | 0.4s<--:-- | 6055.3 it/s
10:28:30 - INFO - FINISHED -> TRANSIENT (total steps: 2402, successful: 2401, runtime: 411.18 ms)
[5]:
{'total_steps': 2402,
 'successful_steps': 2401,
 'runtime_ms': 411.1834680006723}

Results

The plots show:

  1. src (blue): Original analog input signal

  2. qtz (orange): 1-bit quantizer output (high-frequency switching)

  3. dac (green): 1-bit DAC feedback signal

  4. lpf (red): Reconstructed signal after FIR filtering

Notice how the 1-bit stream encodes the analog signal, and the FIR filter successfully reconstructs it.

[6]:
Sim.plot()
plt.show()
../_images/examples_delta_sigma_adc_14_0.svg
../_images/examples_delta_sigma_adc_14_1.svg