0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VCO-ADC

Posted at

1. 電圧 → 周波数変換(VCO部)

VCOは入力電圧に応じて発振周波数を変化させる回路。
3段または5段のリング発振器で構成される。

f_osc = f_0 + K_vco * V_in
  • f_osc : 出力発振周波数 [Hz]
  • f_0 : バイアス時の基準周波数 [Hz]
  • K_vco : 電圧-周波数変換感度 [Hz/V]
  • V_in : 入力アナログ電圧 [V]

入力電圧が高くなるとMOSインバータの駆動電流が増加し、
遅延時間 t_d が短くなるため、発振周期 T_osc = 2π / ω_osc が短縮し
f_osc が増加する。


2. 周波数 → デジタル変換(カウンタ部)

一定の観測時間 T_s の間に、VCO出力のパルス数をカウントする。

N_count = f_osc * T_s

出力デジタルコード D_out はこのカウント数に等しい。

D_out = N_count

すなわち、入力電圧に比例して出力コードが増加する。


3. 位相積分によるノイズシェーピング

VCO出力の位相 θ(t) は周波数を時間積分したものとして表される。

θ(t) = 2π * ∫[0→t] f_osc(τ) dτ

位相の離散化(カウント)によって量子化誤差が発生するが、
この誤差は積分過程により高周波側に押しやられる。
結果としてΔΣ(デルタシグマ)変調に類似したノイズシェーピング特性を得る。


4. 回路動作の全体式

VCO-ADCの信号変換を一連の関係式で表すと次のようになる。

1. V_in → f_osc  :  f_osc = f_0 + K_vco * V_in
2. f_osc → N_count :  N_count = f_osc * T_s
3. Digital Output :  D_out = N_count = (f_0 + K_vco * V_in) * T_s

よって、出力コードは線形式で表せる。

D_out = f_0 * T_s + K_vco * T_s * V_in

5. ノイズ・分解能・非線形性

(1) 位相ジッタ(周期ゆらぎ)

σ_jitter ≈ (ΔT / T_osc) * f_osc

位相ジッタ σ_jitter がSNRを制限する。

(2) 線形誤差(非線形VCO特性)

Error_lin = D_out_actual - (f_0 * T_s + K_vco * T_s * V_in)

補償手法としては、

  • デジタルキャリブレーション
  • ルックアップテーブル補正
    などが用いられる。

6. 設計パラメータの関係式

項目 説明
VCO感度 K_vco = Δf / ΔV 周波数変化率
サンプリング期間 T_s = 1 / f_sample 測定ウィンドウ
分解能 LSB = 1 / (K_vco * T_s) 1ビットあたりの電圧幅
SNR(ジッタ支配) SNR = 20 * log10(1 / (2π * f_in * σ_jitter)) 周波数ゆらぎの影響

7. 動作フロー(プレーンテキスト図)

アナログ入力電圧 V_in
        │
        ▼
  [Voltage-Controlled Oscillator]
        │  f_osc = f_0 + K_vco * V_in
        ▼
      [Counter / Integrator]
        │  D_out = f_osc * T_s
        ▼
  デジタル出力コード D_out

8. まとめ(要点)

  • アナログ電圧を時間領域の発振周波数に変換し、
     その周期情報をカウントしてデジタル化する方式。

  • オペアンプ不要、全デジタル構成に近い。

  • 微細化CMOS、低電圧環境に適する。

  • ΔΣ型に似た積分的ノイズ整形特性を持つ。

  • ジッタ・非線形性・温度ドリフトへの補償が設計上の要点。

  • Design of VCO‑based ADCs — V. Unnikrishnan (2016) (diva-portal.org)

  • Highly Digital Second‑Order VCO ADC — A. Jayaraj 他 (Lab Groups)

  • Ring‑VCO‑based ADC design for low‑energy smart … — P. Srikram (2023) (北大学術資源リポジトリ)

  • Analysis and Design of Voltage‑Controlled Oscillator‑Based ADCs — S. Naraghi (2009) (Deep Blue)

  • VCO‑based ADCs Design Techniques for Communication … — VMM Huamán 他 (Core)


import numpy as np
import matplotlib.pyplot as plt

# ==============================
# 0) Global Parameters / 変数一元管理
# ==============================
VDD          = 1.2          # [V] Supply (基準)
VIN_MIN      = 0.0          # [V] Input min
VIN_MAX      = 1.2          # [V] Input max
N_VIN_POINTS = 201          # [-] Number of Vin samples

f0           = 10e6         # [Hz] Base frequency at bias (f_0)
Kvco_lin     = 20e6         # [Hz/V] Linear VCO gain (K_vco)
alpha2       = -8e6         # [Hz/V^2] Quadratic nonlinearity term (2次非線形)
VIN_MID      = 0.6          # [V] Vertex for nonlinearity (非線形の中心電圧)

Ts           = 10e-6        # [s] Counter window / sampling period (カウント窓)
fs_sample    = 1.0 / Ts     # [Hz] Sample rate (= 1/Ts)
N_bits_cnt   = 16           # [-] Counter width (量子化幅は参考)
jitter_rms   = 1.0e-12      # [s_rms] Period jitter (位相ジッタ標準偏差)
fin_min      = 10e3         # [Hz] Input tone for SNR_jitter plot (min)
fin_max      = 2e6          # [Hz] Input tone for SNR_jitter plot (max)
N_FIN_POINTS = 200          # [-] Frequency points for SNR curve

# ==============================
# 1) VCO frequency model / VCO周波数モデル
#   f_osc(Vin) = f0 + Kvco_lin*Vin + alpha2*(Vin - VIN_MID)^2
#   2次非線形項で実機の曲がりを近似
# ==============================
Vin = np.linspace(VIN_MIN, VIN_MAX, N_VIN_POINTS)
f_osc_ideal = f0 + Kvco_lin * Vin
f_osc_nl    = f0 + Kvco_lin * Vin + alpha2 * (Vin - VIN_MID)**2

# Guard: limit to physical positive frequency
f_osc_nl = np.clip(f_osc_nl, 1.0, None)

# ==============================
# 2) Transfer characteristic / 伝達特性
#   D_out = floor( f_osc * Ts ) 近似(単純カウント)
#   LSB_voltage = 1/(Kvco_lin*Ts) を理想LSBと定義
# ==============================
D_out_ideal = f_osc_ideal * Ts
D_out_nl    = f_osc_nl    * Ts
LSB_V = 1.0 / (Kvco_lin * Ts)  # [V/LSB] ideal voltage LSB

# ==============================
# 3) Jitter-limited SNR model / ジッタ支配SNR
#   SNR_jitter[dB] = -20*log10( 2*pi*fin*jitter_rms )
#   周波数が高いほどSNR低下(時間ゆらぎ→位相誤差)
# ==============================
fin = np.logspace(np.log10(fin_min), np.log10(fin_max), N_FIN_POINTS)
SNR_jitter_dB = -20.0 * np.log10(2.0 * np.pi * fin * jitter_rms)

# ==============================
# 4) Optional Monte Carlo for code dispersion / ジッタによるコード分散(簡易MC)
#   N_count ≈ f_osc*Ts + ε。周期ジッタを独立と仮定し分散を近似。
#   ここでは簡便に正規雑音を加えてばらつきを可視化
# ==============================
rng = np.random.default_rng(42)
Vin_mc = np.linspace(VIN_MIN, VIN_MAX, 41)
f_mc   = f0 + Kvco_lin * Vin_mc
# 近似: counts = f*Ts、周期ジッタσ_tがN周期で √Nスケールの時間誤差 → counts誤差 ~ (σ_t / T)^*√N
T_mc   = 1.0 / f_mc
Ncyc   = np.maximum(f_mc * Ts, 1.0)
sigma_counts = (jitter_rms / T_mc) * np.sqrt(Ncyc)
D_mc   = f_mc * Ts + rng.normal(0.0, sigma_counts)

# ==============================
# 5) Plots (one figure per chart) / 図示(各図1プロット)
# ==============================

# 5-1) VCO frequency vs Vin
plt.figure(figsize=(8, 4))
plt.plot(Vin, f_osc_ideal/1e6, label="f_osc ideal [MHz]")
plt.plot(Vin, f_osc_nl/1e6,    label="f_osc with nonlinearity [MHz]", linestyle="--")
plt.title("VCO Frequency Characteristic")
plt.xlabel("Input Voltage Vin [V]")
plt.ylabel("Oscillation Frequency [MHz]")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

# 5-2) Transfer characteristic: D_out vs Vin
plt.figure(figsize=(8, 4))
plt.plot(Vin, D_out_ideal, label="D_out ideal = f_osc(Vin)*Ts")
plt.plot(Vin, D_out_nl,    label="D_out with nonlinearity", linestyle="--")
plt.scatter(Vin_mc, D_mc,  s=12, label="Monte Carlo (jittered counts)")
plt.title("VCO-ADC Transfer Characteristic")
plt.xlabel("Input Voltage Vin [V]")
plt.ylabel("Digital Output Code D_out [counts]")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

# 5-3) Jitter-limited SNR vs input frequency
plt.figure(figsize=(8, 4))
plt.semilogx(fin, SNR_jitter_dB, label="SNR limited by jitter")
plt.title("Jitter-Limited SNR vs Input Frequency")
plt.xlabel("Input Tone Frequency f_in [Hz]")
plt.ylabel("SNR_jitter [dB]")
plt.grid(True, which="both")
plt.legend()
plt.tight_layout()
plt.show()

# ==============================
# 6) Key metrics print / 指標出力
# ==============================
ENOB_jitter_at_100k = (SNR_jitter_dB[np.argmin(np.abs(fin-100e3))] - 1.76)/6.02
print("=== Key Metrics ===")
print(f"Ideal voltage LSB  = {LSB_V:.6f} V/LSB")
print(f"SNR_jitter@100kHz  = {SNR_jitter_dB[np.argmin(np.abs(fin-100e3))]:.2f} dB")
print(f"ENOB_jitter@100kHz = {ENOB_jitter_at_100k:.2f} bits")
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?