1. 入力信号 Vin
- アナログ入力信号。
- この信号をディジタル値に変換するのが最終目的。
2. 加算器
-
入力 Vin とフィードバック信号(DAC出力)との差をとる。
-
出力は「誤差信号 e[n]」。
-
数式で表すと:
e[n] = Vin[n] - y_dac[n]
3. デジタル積分器
-
誤差信号を時間的に累積(積分)する。
-
積分により、低周波成分を強調し、量子化誤差を高周波に押し上げる(ノイズシェーピング)。
-
z領域での伝達関数:
H(z) = 1 / (1 - z^-1)
4. 量子器(Quantizer)
- 積分器の出力を有限ビット(典型的には1ビット)に丸める。
- 実際にはコンパレータのような動作で、出力は「+Vref または -Vref」。
- 出力がそのままディジタル出力 Dout となる。
5. DAC(フィードバック経路)
- 量子器の出力を再びアナログ値に戻す。
- これを加算器に戻すことで、ループが閉じる。
- ループにより誤差が補正され、入力信号が正しく追従される。
6. 出力 Dout
- 量子器の出力を取り出したもの。
- 1ビットストリームの形だが、後段のデジタルフィルタとデシメーションで高分解能の多ビットディジタル信号に変換できる。
まとめ
- Vin → 加算器 → 積分器 → 量子器 → Dout
- さらに Dout → DAC → フィードバック → 加算器
というループ構成。 - このループにより「量子化雑音が高周波に追いやられ(ノイズシェーピング)、帯域内では高SNRを実現」するのがΔΣ型ADCの基本原理。
# Program Name: delta_sigma_adc_blocks.py
# Creation Date: 20250912
# Overview: Visualize each block of a first-order Delta-Sigma ADC (adder, integrator, quantizer, DAC, digital filter)
# Usage: Run this script. It shows each signal in matplotlib plots.
!pip install numpy matplotlib scipy
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import firwin, lfilter
# ================= Parameters =================
fs = 48000 # サンプリング周波数 [Hz]
fin = 1000 # 入力サイン波の周波数 [Hz]
A = 0.5 # 入力振幅 [V] (最大±0.5Vのサイン波)
N = 1024 # 総サンプル数(シミュレーションの長さ)
Vref = 1.0 # DACの基準電圧(±Vrefで1ビット出力を表現)
decim = 16 # デシメーション比(フィルタ後に16分の1へ間引き)
# ================= Input Signal =================
# 時間軸を生成(0 ~ (N-1)/fs)
t = np.arange(N) / fs
# 入力アナログ信号(サイン波)
x = A * np.sin(2*np.pi*fin*t)
# ================= Delta-Sigma Modulator =================
# 状態変数の初期化
v_int = 0.0 # 積分器内部状態
y_dac = 0.0 # フィードバック信号(DAC出力)
e_arr = np.zeros(N) # 加算器出力(誤差信号)の記録
v_arr = np.zeros(N) # 積分器出力の記録
y_out = np.zeros(N) # 量子化器(1ビット)出力の記録
for n in range(N):
# --- 加算器 (Σ部) ---
# 入力信号とDAC出力(フィードバック)との差を取る
# 数式: e[n] = x[n] - y[n-1]
e = x[n] - y_dac
e_arr[n] = e
# --- 積分器 (Δ部) ---
# 誤差信号を逐次的に積分する
# 数式: v[n] = v[n-1] + e[n]
v_int += e
v_arr[n] = v_int
# --- 量子化器 (Comparator, 1-bit) ---
# 積分器出力を±Vrefに変換(1ビット符号化)
# 数式: y[n] = Q{ v[n] } = ±Vref
if v_int >= 0:
y_out[n] = Vref
else:
y_out[n] = -Vref
# --- DAC (フィードバック経路) ---
# 量子化出力をアナログ値(±Vref)に戻し、次サイクルの入力と比較する
y_dac = y_out[n]
# ================= デジタルフィルタ (FIR + Decimation) =================
# FIRローパスフィルタを設計
# cutoff=1/decim → 帯域内信号を通し、帯域外ノイズを抑える
numtaps = 63
fir = firwin(numtaps, cutoff=1/decim, window="hamming")
# 1ビット出力にFIRフィルタを適用(帯域外ノイズ除去)
y_filt = lfilter(fir, 1.0, y_out)
# デシメーション(サンプルを decim 倍間引き)
y_dec = y_filt[::decim]
t_dec = t[::decim]
# ================= Plot =================
plt.figure(figsize=(12,14))
# 入力信号
plt.subplot(6,1,1)
plt.plot(t*1000, x, label="Input x[n]")
plt.ylabel("Vin [V]"); plt.grid(); plt.legend()
# 加算器出力(誤差信号)
plt.subplot(6,1,2)
plt.plot(t*1000, e_arr, label="Adder Output e[n]")
plt.ylabel("e[n]"); plt.grid(); plt.legend()
# 積分器出力
plt.subplot(6,1,3)
plt.plot(t*1000, v_arr, label="Integrator Output v[n]")
plt.ylabel("v[n]"); plt.grid(); plt.legend()
# 量子化器出力(±Vrefの1ビット)
plt.subplot(6,1,4)
plt.step(t*1000, y_out, where="mid", label="Quantizer Output y_out[n]")
plt.ylabel("y_out"); plt.grid(); plt.legend()
# FIRフィルタ後の波形
plt.subplot(6,1,5)
plt.plot(t*1000, y_filt, label="Filtered Output")
plt.ylabel("FIR Out"); plt.grid(); plt.legend()
# デシメーション後の波形(多ビット相当)
plt.subplot(6,1,6)
plt.plot(t_dec*1000, y_dec, label="Decimated Output")
plt.xlabel("Time [ms]"); plt.ylabel("Decimated"); plt.grid(); plt.legend()
plt.suptitle("Delta-Sigma ADC Block Visualization")
plt.tight_layout()
plt.show()
コメント解説のポイント
-
数式との対応を明示
e[n] = x[n] - y[n-1]v[n] = v[n-1] + e[n]y[n] = Q{v[n]} = ±Vref- など、理論式をそのままコードに対応させる。
-
信号の流れをブロックごとに整理
- 入力サイン波 → 加算器(誤差) → 積分器(蓄積) → 量子化器(1ビット) → DAC(FB) → デジタルフィルタ(帯域内抽出)。
-
プロットで各ブロックの役割を可視化
- 上から順に信号が処理されていく流れが見える。
