これは典型的な パイプラインADCの1段目(MDAC: Multiplying DAC) や SAR ADCのキャパシタアレイ残差生成部 に相当する回路トポロジーです。
「ビットから生まれた Vdac」「スイッチ」「キャパシタ」「増幅器」を組み合わせ、サンプリングと増幅を交互に切り替えて残差を出力します。
1. 回路構成
-
Vdac
- ビット判定から生成された基準電圧。
- 典型的には $0, V_{DD}/2, V_{DD}$ のような値をとる。
- 「入力との差」を表現するために使う。
-
スイッチ (SW: samp / amp)
- 2つの位相で交互に動作。
- samp位相: キャパシタに入力電圧 $V_{in}$ をサンプル。
- amp位相: キャパシタを再接続し、Vdacを差し引いた電圧を増幅器に渡す。
-
キャパシタ
- サンプリング用 $C_S$ とフィードバック用 $C_F$。
- 電荷保存の原理で残差が生成される。
-
増幅器 (Op-Amp)
- 理想では無限利得 → 完全な「仮想接地」が成り立つ。
- 現実では有限利得 ($A_{ol} \approx 10^4$)。
- フィードバック制御により 理想ゲイン 2倍 → 実効ゲイン ≈ 1.9998 程度。
2. 動作原理(2フェーズ)
(1) samp フェーズ(サンプリング)
- 入力電圧 $V_{in}$ をキャパシタ $C_S$ にサンプル。
- 下側は共通モードまたは基準点に接続される。
(2) amp フェーズ(増幅)
-
$C_S$ の上端を Vdac に切り替える。
-
オペアンプ+フィードバック容量 $C_F$ が動作し、電荷保存から残差電圧が出力される。
-
理想式:
$$
V_{res} = \left(1+\frac{C_S}{C_F}\right) V_{in} - \frac{C_S}{C_F} V_{DAC}
$$$C_S = C_F$ なら
$$
V_{res} = 2(V_{in} - V_{DAC})
$$
3. 有限利得アンプの効果
-
アンプ利得 $A_{ol}=10000$
-
フィードバック係数 $\beta = 1/2$(ゲイン=2構成)
-
実効クローズドループゲイン:
$$
G_{eff} = \frac{A_{ol}}{1+A_{ol}\beta} \cdot \frac{1}{\beta}
\approx 2 \cdot \frac{10000}{10001} \approx 1.9998
$$ -
誤差は約 0.01% 程度。
4. ADC動作への意味
- 各ステージで「入力-Vdac」を 2倍して次段へ残差として渡す。
- これにより 逐次的に量子化誤差を削り、全体で高ビット精度を達成。
- 有限利得やセットリング不足により誤差(DNL, INL)が発生。
✅ まとめ
このトポロジーは スイッチトキャパシタMDAC回路。
- Vdac: ビット判定からの基準電圧
- SW: サンプリングと増幅を切替
- C: 電荷保存で残差生成
- OpAmp: フィードバックで約2倍のゲイン
理想残差式:
$$
V_{res} = 2(V_{in} - V_{DAC})
$$
現実残差式:
$$
V_{res} \approx G_{eff}(V_{in} - V_{DAC}), \quad G_{eff} \approx 1.9998
$$
-
記号
$V_{in}$:入力,$V_{DAC}$:ビットDAC,$V_{cm}=V_{DD}/2$(基準),$V_x$:比較節点,$V_{res}$:残差出力,容量は等容量 $C_S=C_F=C$,アンプ開ループ利得 $A_{ol}\approx10^4$,フィードバック係数 $\beta=1/2$(ゲイン2構成)。 -
サンプル→増幅(電荷保存)
サンプル位相で上板に $V_{in}$ を蓄え,増幅位相で上板を $V_{DAC}$ に切替:
$$
2C,(V_{in}-V_{cm})=2C,(V_{DAC}-V_x)
\quad\Rightarrow\quad
V_x-V_{cm}=(V_{DAC}-V_{cm})-(V_{in}-V_{cm}) \tag{1}
$$
- 比較器入力(基準との差)
$$
\Delta_x \equiv V_x-V_{cm}=(V_{DAC}-V_{cm})-(V_{in}-V_{cm}) \tag{2}
$$
- アンプ出力(残差):開ループ近似
$$
V_{res}^{(\mathrm{ol})}\approx A_{ol},\Delta_x \tag{3}
$$
- アンプ出力(残差):閉ループ(等容量・理想は係数2と1)
有限利得で理想係数にスケール $k$ が掛かる近似:
$$
k ;\equiv; \frac{A_{ol}}{1+A_{ol}\beta}
;;\xrightarrow{;A_{ol}=10^4,;\beta=\tfrac12;};;
k\approx \frac{10000}{1+5000}\approx 1.9996
$$
$$
V_{res};\approx; k\Big[,2,(V_{in}-V_{cm})-(V_{DAC}-V_{cm}),\Big] \tag{4}
$$
- 理想(参考)
$$
V_{res}^{(\mathrm{ideal})}=2,(V_{in}-V_{cm})-(V_{DAC}-V_{cm})
= 2(V_{in}-V_{DAC}) \tag{5}
$$
- フィードバック動作(増幅位相)
増幅位相では $C_F$ が出力 $V_{res}$ と節点 $V_x$ を結び,(4) で得た残差が $C_F$ 経由で $V_x$ に帰還($\beta=1/2$)して仮想接地点を形成。次段へは $V_{res}$ が「差分を2倍(≒$k$)」した残差として渡る。
# Program Name: mdac_residue_demo.py
# Creation Date: 20250821
# Overview: Simulate an MDAC (Multiplying DAC) residue generator for a switched-capacitor ADC stage. Plots ideal vs finite-gain residue curves and time-domain settling.
# Usage: Run as-is. Adjust parameters in the block below (VDD, A_ol, GBW_Hz, Cs, Cf, Vin range, Vdac set). Requires numpy and matplotlib.
!pip install numpy matplotlib -q
import numpy as np
import matplotlib.pyplot as plt
# =========================
# Parameters / パラメータ一元管理
# =========================
VDD = 1.2 # Supply voltage [V] / 電源電圧
Vcm = VDD/2 # Common-mode [V] / 共通モード
Cs = 1e-12 # Sampling cap [F] / サンプリング容量
Cf = 1e-12 # Feedback cap [F] / フィードバック容量
A_ol = 1.0e4 # Op-amp open-loop gain / オペアンプ開ループ利得
GBW_Hz = 50e6 # Op-amp gain-bandwidth [Hz] / GBW(1極モデル)
Vin_min = 0.0 # Vin sweep min [V] / 入力掃引最小
Vin_max = VDD # Vin sweep max [V] / 入力掃引最大
N_pts = 401 # Sweep points / 掃引点数
Vdac_set = [0.0, VDD/2, VDD] # DAC candidate levels / DAC電圧の候補
Vin_demo = 0.73 # Time demo Vin [V] / 時間応答デモ用Vin
Vdac_demo = VDD/2 # Time demo Vdac [V] / 時間応答デモ用Vdac
T_set = 200e-9 # Plot horizon [s] / 表示する時間の長さ
Nt = 1000 # Time samples / 時間サンプル数
# =========================
# Helpers / ヘルパー関数
# =========================
def beta_feedback(Cs: float, Cf: float) -> float:
# Feedback factor for equal-cap SC MDAC (approx) / 等容量SC-MDACの近似β
# 直感的には「出力のどれだけが負入力へ戻るか」→ Cf/(Cs+Cf)
return Cf / (Cs + Cf)
def k_scale(A_ol: float, beta: float) -> float:
# Finite-gain scaling factor / 有限利得によるスケーリング係数
# 一様に係数が縮む近似:k = A_ol / (1 + A_ol * beta)
return A_ol / (1.0 + A_ol * beta)
def residue_ideal(Vin: np.ndarray, Vdac: float, Cs: float, Cf: float, Vcm: float) -> np.ndarray:
# Ideal residue around Vcm (single-ended, Vcm-subtracted) / 理想残差(Vcm基準で単端・Vcm差し引き)
# Ṽ_res = (1 + Cs/Cf)*(Ṽ_in) - (Cs/Cf)*(Ṽ_DAC)
Vin_t = Vin - Vcm
Vdac_t = Vdac - Vcm
return (1.0 + Cs/Cf)*Vin_t - (Cs/Cf)*Vdac_t
def residue_finite(Vin: np.ndarray, Vdac: float, Cs: float, Cf: float, Vcm: float, A_ol: float) -> np.ndarray:
# Finite-gain residue (uniform shrink by k) / 有限利得残差(kで一様に縮小)
b = beta_feedback(Cs, Cf)
k = k_scale(A_ol, b)
return k * residue_ideal(Vin, Vdac, Cs, Cf, Vcm)
def tau_closed_loop(GBW_Hz: float, Cs: float, Cf: float) -> float:
# First-order closed-loop time constant / 1次近似の閉ループ時定数
# 1極OPAMP: ω_p = 2π*GBW/A_ol, 閉ループ極: ω_cl ≈ 2π*GBW*β → τ = 1/ω_cl
b = beta_feedback(Cs, Cf)
w_cl = 2.0*np.pi*GBW_Hz*b
return 1.0 / w_cl
# =========================
# Static transfer: sweep Vin / 静特性:Vin掃引
# =========================
Vin = np.linspace(Vin_min, Vin_max, N_pts)
plt.figure(figsize=(8,4))
for Vdac in Vdac_set:
v_id = residue_ideal(Vin, Vdac, Cs, Cf, Vcm)
v_fin = residue_finite(Vin, Vdac, Cs, Cf, Vcm, A_ol)
# Plot ideal / 理想
plt.plot(Vin, v_id, linestyle='--', label=f"Ideal, Vdac={Vdac:.3f} V")
# Plot finite-gain / 有限利得
plt.plot(Vin, v_fin, label=f"Finite gain, Vdac={Vdac:.3f} V")
plt.title("MDAC Residue vs Vin (about Vcm)")
plt.xlabel("Vin [V]")
plt.ylabel("Residue (single-ended, about Vcm) [V]")
plt.legend()
plt.grid(True)
plt.show()
# =========================
# Time-domain settling / 時間応答(セットリング)
# =========================
t = np.linspace(0.0, T_set, Nt)
v_inf = residue_finite(np.array([Vin_demo]), Vdac_demo, Cs, Cf, Vcm, A_ol)[0] # Final residue / 最終残差
tau = tau_closed_loop(GBW_Hz, Cs, Cf)
v_t = v_inf * (1.0 - np.exp(-t / tau)) # 1st-order settling / 1次の指数応答
plt.figure(figsize=(8,4))
plt.plot(t, v_t, label="Residue(t)")
plt.plot(t, np.full_like(t, v_inf), linestyle='--', label="Final residue")
plt.title("MDAC Residue Settling (first-order)")
plt.xlabel("Time [s]")
plt.ylabel("Residue (about Vcm) [V]")
plt.legend()
plt.grid(True)
plt.show()
# =========================
# Print key numbers / 主要数値の表示
# =========================
b = beta_feedback(Cs, Cf) # β
k = k_scale(A_ol, b) # k縮小係数
Gid = 1.0 + Cs/Cf # 理想ゲイン(Ṽ_in係数)
Geff = k * Gid # 実効ゲイン(Ṽ_in係数)
print("# MDAC key numbers / 主要数値")
print(f"beta = {b:.6f}")
print(f"k (finite-gain shrink) = {k:.6f}")
print(f"G_ideal (coeff of Ṽ_in) = {Gid:.6f}")
print(f"G_effective (coeff of Ṽ_in) = {Geff:.6f}")
print(f"tau (s) = {tau:.3e}")
print(f"Residue_final (Vin={Vin_demo:.3f} V, Vdac={Vdac_demo:.3f} V) = {v_inf:.6f} V (about Vcm)")
