0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コピペとPythonでわかるADC(アナログデジタル変換)

0
Last updated at Posted at 2025-10-17

はじめに

アナログ・デジタル変換器(ADC: Analog-to-Digital Converter)は、
現実世界の連続的なアナログ信号を、デジタルシステムが理解・処理できる離散的な数値データへ変換する中核的なデバイスである。
本教材では、このADCの原理と動作をPythonによる数値シミュレーション生成AIによる可視化学習を通じて体系的に理解する。

逐次比較型ADC

# ===============================
# 必要なライブラリをインストール / Install libraries
# ===============================
!pip install numpy matplotlib

import numpy as np
import matplotlib.pyplot as plt

# ===============================
# パラメータ設定 / Global parameters
# ===============================
Vref = 1.0          # 参照電圧 [V] / Reference voltage
Vin = 0.63           # 入力電圧 [V] / Analog input
Nbit = 8             # 分解能 [bit] / Resolution
C_total = 1e-12      # キャパシタ合計 [F] / Total capacitance
fs = 1e6             # サンプリング周波数 [Hz]
t_comp = 1e-6        # 比較器応答時間 [s]
debug = True         # ステップ表示ON/OFF

# ===============================
# SAR動作シミュレーション関数 / SAR ADC simulation
# ===============================
def sar_adc(Vin, Vref, Nbit):
    """逐次比較型ADCの二分探索動作を模擬 / Binary search simulation of SAR ADC"""
    digital = 0
    dac_history = []
    for bit in range(Nbit - 1, -1, -1):
        trial = digital | (1 << bit)
        Vdac = Vref * trial / (2 ** Nbit)
        dac_history.append(Vdac)
        if debug:
            print(f"Step {Nbit - bit}: trial={trial:0{Nbit}b}, Vdac={Vdac:.4f} V, ", end="")
        if Vin >= Vdac:
            digital = trial
            if debug:
                print("Comparator=1 (Vin>=Vdac)")
        else:
            if debug:
                print("Comparator=0 (Vin<Vdac)")
    code = digital
    Vout = Vref * code / (2 ** Nbit)
    return code, Vout, dac_history

# ===============================
# 実行 / Run simulation
# ===============================
code, Vout, dac_trace = sar_adc(Vin, Vref, Nbit)
print(f"\nResult: Vin={Vin:.3f} V → Code={code:0{Nbit}b} ({code}) → Vout={Vout:.4f} V")

# ===============================
# 可視化 / Plot DAC output steps
# ===============================
plt.figure(figsize=(6,4))
plt.step(range(1, Nbit+1), dac_trace, where='post', label='DAC output')
plt.axhline(Vin, color='r', linestyle='--', label='Vin')
plt.title("SAR ADC Binary Search Process")
plt.xlabel("Comparison Step")
plt.ylabel("Voltage [V]")
plt.legend()
plt.grid(True)
plt.show()

# ===============================
# エネルギー計算 / Energy estimation
# ===============================
E_conv = 0.5 * C_total * (Vref ** 2)
print(f"Approx. conversion energy: {E_conv:.2e} J/conv")

# ===============================
# kT/C 熱ノイズの評価
# ===============================
!pip install numpy

import numpy as np

# ===============================
# パラメータ設定 / Parameters
# ===============================
k = 1.38e-23           # ボルツマン定数 [J/K]
T = 300                # 絶対温度 [K] (27°C)
Vref = 1.0             # 参照電圧 [V]
Nbit = 12              # ADC分解能 [bit]
SNR_ideal = 6.02 * Nbit + 1.76

# ===============================
# SAR ADCのコンデンサ総容量とノイズの評価
# ===============================

# 1. 理想SNR達成に必要なVrms
q = Vref / (2**Nbit)
Vn_quant_rms = q / np.sqrt(12)  # 量子化ノイズ RMS

# 理想SNRを達成するためには、熱ノイズ Vrms が量子化ノイズよりも十分小さい必要。
# ここでは、熱ノイズを量子化ノイズの 1/5 に抑えると仮定する。
Vn_thermal_max = Vn_quant_rms / 5
print(f"許容される熱ノイズ RMS: {Vn_thermal_max:.3e} Vrms")

# 2. 許容Vrmsを実現するために必要なサンプリング容量 Cs
# Cs = kT / (Vn_thermal_max)^2
Cs_required = k * T / (Vn_thermal_max**2)

# ===============================
# 結果出力 / Results
# ===============================
print("\n--- kT/C Thermal Noise Analysis ---")
print(f"ADC 分解能 Nbit      : {Nbit} bit")
print(f"理想 SNR             : {SNR_ideal:.2f} dB")
print(f"量子化ノイズ RMS     : {Vn_quant_rms:.3e} Vrms")
print("-" * 39)
print(f"要求されるサンプリング容量 Cs: {Cs_required*1e12:.2f} pF")
print(f"→ 高分解能ADCの設計では、kT/Cノイズを抑えるため大きなキャパシタが必要となることが分かります。")

デルタシグマ型ADC


# ===============================
# 必要なライブラリをインストール / Install libraries
# ===============================
!pip install numpy matplotlib

import numpy as np
import matplotlib.pyplot as plt

# ===============================
# パラメータ設定 / Global parameters
# ===============================
fs = 1e5             # サンプリング周波数 [Hz] / Sampling frequency
fin = 1e3            # 入力信号周波数 [Hz] / Input frequency
N = 4096             # サンプル数 / Number of samples
Vref = 1.0           # 参照電圧 [V] / Reference voltage
Ain = 0.8            # 入力振幅 [V] / Input amplitude
OSR = 64             # オーバーサンプリング比 / Oversampling ratio

# ===============================
# 入力信号生成 / Generate analog input
# ===============================
t = np.arange(N) / fs
x = Ain * np.sin(2 * np.pi * fin * t)

# ===============================
# ΔΣ変調器 1次ループ / First-order ΔΣ modulator
# ===============================
v = 0                # 積分器の状態変数 / Integrator state
y = np.zeros(N)      # 出力ビット列 / Output bitstream
e = np.zeros(N)      # 量子化誤差 / Quantization error

for n in range(N):
    v += x[n] - y[n-1] * Vref if n > 0 else x[n]          # 積分器 (Integrator)
    if v >= 0:
        y[n] = 1.0                                        # 量子化器出力 +Vref
    else:
        y[n] = -1.0                                       # 量子化器出力 -Vref
    e[n] = v - y[n]                                       # 誤差蓄積 (noise shaping)

# ===============================
# デシメーション / Decimation (単純平均)
# ===============================
decim = int(OSR)
M = N // decim
y_dec = np.array([np.mean(y[i*decim:(i+1)*decim]) for i in range(M)])

# ===============================
# 結果表示 / Display results
# ===============================
plt.figure(figsize=(10,6))

# 入力信号とビットストリーム / Input vs Output bitstream
plt.subplot(2,1,1)
plt.plot(t[:500], x[:500], label="Input Signal (x)")
plt.step(t[:500], y[:500], where='mid', label="ΔΣ Bitstream (y)")
plt.title("First-Order Delta-Sigma Modulator")
plt.xlabel("Time [s]")
plt.ylabel("Amplitude [V]")
plt.legend()
plt.grid(True)

# パワースペクトル密度 / Power Spectral Density (PSD)
Yf = np.fft.fft(y * np.hanning(N))
freq = np.fft.fftfreq(N, 1/fs)
PSD = 20 * np.log10(np.abs(Yf[:N//2]) / np.max(np.abs(Yf)))
plt.subplot(2,1,2)
plt.plot(freq[:N//2], PSD)
plt.title("Noise Shaping Effect (1st-Order ΔΣ ADC)")
plt.xlabel("Frequency [Hz]")
plt.ylabel("Normalized Magnitude [dB]")
plt.grid(True)
plt.tight_layout()
plt.show()

# ===============================
# 出力情報 / Output summary
# ===============================
print(f"Input amplitude = {Ain} V, Sampling freq = {fs/1e3:.1f} kHz, OSR = {OSR}")
print(f"Decimated output samples = {M}")



# ================== 必要ライブラリ ==================
!pip install numpy matplotlib scipy

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import welch

# ================== パラメータ設定 ==================
fs = 48000              # サンプリング周波数 [Hz] / Sampling frequency
fin = 1000              # 入力サイン波周波数 [Hz] / Input sine frequency
A = 0.5                 # 入力振幅 / Input amplitude
N = 2**14               # サンプル数 / Number of samples
t = np.arange(N) / fs   # 時間軸 / Time vector

# ================== 入力信号生成 ==================
Vin = A * np.sin(2 * np.pi * fin * t)

# ================== ノイズモデル ==================
np.random.seed(0)
Q = (np.random.rand(N) - 0.5) * (2**-10)   # 量子化誤差 / Quantization noise
Vn = np.random.randn(N) * 1e-3             # 熱ノイズ / Thermal noise

# ================== ノイズシェーピング処理 ==================
noise = Q + Vn
shaped_noise = np.zeros_like(noise)
for n in range(1, N):
    shaped_noise[n] = noise[n] - noise[n-1]   # 一次差分 = 1st-order noise shaping

# 出力信号 (Vin + shaped_noise)
Dout = Vin + shaped_noise

# ================== PSD計算(Welch法) ==================
f_in, Pxx_in = welch(Vin, fs=fs, nperseg=2048)
f_out, Pxx_out = welch(Dout, fs=fs, nperseg=2048)

# 入力の最大値を基準に正規化
ref = np.max(Pxx_in)
Pxx_in_dB  = 10 * np.log10(Pxx_in / ref + 1e-20)
Pxx_out_dB = 10 * np.log10(Pxx_out / ref + 1e-20)

# ================== 時間波形(入力) ==================
plt.figure(figsize=(12,4))
plt.plot(t[:500], Vin[:500], label="Input Vin (sine)")
plt.xlabel("Time [s]")
plt.ylabel("Amplitude [V]")
plt.title("Input Signal (time domain, first 500 samples)")
plt.legend()
plt.grid(True)
plt.show()

# ================== 入力信号スペクトル ==================
plt.figure(figsize=(12,6))
plt.semilogx(f_in, Pxx_in_dB, label="Input Vin (normalized to 0 dB)")
plt.xlabel("Frequency [Hz]")
plt.ylabel("PSD [dB]")
plt.title("Input Signal Spectrum")
plt.grid(True, which="both")
plt.legend()
plt.show()

# ================== 時間波形(出力) ==================
plt.figure(figsize=(12,4))
plt.plot(t[:500], Dout[:500], label="Output Dout (with noise shaping)")
plt.xlabel("Time [s]")
plt.ylabel("Amplitude [V]")
plt.title("Output Signal (time domain, first 500 samples)")
plt.legend()
plt.grid(True)
plt.show()

# ================== 出力スペクトル ==================
plt.figure(figsize=(12,6))
plt.semilogx(f_out, Pxx_out_dB, label="Output Dout (Noise-Shaped)")
plt.xlabel("Frequency [Hz]")
plt.ylabel("PSD [dB]")
plt.title("Output Signal Spectrum (Noise-Shaped by 1st-order ΔΣ)")
plt.grid(True, which="both")
plt.legend()
plt.show()

# ================== 要約 ==================
print("ΔΣ ADC 1次ノイズシェーピングモデル実行完了")
print(f"Sampling frequency: {fs} Hz, Input frequency: {fin} Hz, Samples: {N}")




!pip install numpy matplotlib

import numpy as np
import matplotlib.pyplot as plt

# ==============================
# パラメータ設定 / Parameter setup
# ==============================
fs = 1000        # サンプリング周波数 [Hz] / Sampling frequency
f_in = 10        # 入力信号周波数 [Hz] / Input signal frequency
A_in = 0.8       # 入力信号振幅 / Input amplitude (0〜1推奨)
N = 500          # サンプル数 / Number of samples
Vref = 1.0       # 量子化器基準電圧 / Quantizer reference voltage

# ==============================
# 入力信号生成 / Generate input signal
# ==============================
t = np.arange(N) / fs
x_in = A_in * np.sin(2 * np.pi * f_in * t)

# ==============================
# ΔΣ変調の主要構造 / Delta-Sigma modulation
# ==============================
integ = 0.0
y_out = np.zeros(N)
quant = np.zeros(N)
err = np.zeros(N)

for n in range(N):
    integ += x_in[n] - quant[n-1] if n > 0 else x_in[n]  # 積分器 / Integrator
    # 1bit 量子化器(コンパレータ動作)/ 1-bit quantizer
    quant[n] = Vref if integ >= 0 else -Vref
    y_out[n] = quant[n]
    err[n] = x_in[n] - y_out[n]

# ==============================
# 結果のプロット / Plot results
# ==============================
plt.figure(figsize=(10,6))

plt.subplot(3,1,1)
plt.plot(t, x_in, label='Input signal (x_in)')
plt.title('ΔΣ ADC Simulation: Input, Integrator, Quantizer')
plt.ylabel('Amplitude [V]')
plt.legend()

plt.subplot(3,1,2)
plt.plot(t, np.cumsum(x_in - y_out)/fs, label='Integrator output')
plt.ylabel('Integrator')
plt.legend()

plt.subplot(3,1,3)
plt.step(t, y_out, label='Quantized output (1-bit)', where='post')
plt.xlabel('Time [s]')
plt.ylabel('Output [V]')
plt.legend()

plt.tight_layout()
plt.show()

パイプライン型ADC



!pip install numpy matplotlib

import numpy as np
import matplotlib.pyplot as plt

# ===============================
# パラメータ設定 / Parameters
# ===============================
Vref = 1.0
N_stage = 8
N_point = 200
Ain = 0.9 * Vref / 2
fs = 1e6
fin = fs / 40
t = np.arange(N_point) / fs
Vin_all = Ain * np.sin(2 * np.pi * fin * t)

# ===============================
# ステージ関数 / 1.5-bit stage model
# ===============================
def stage(Vin, Vref):
    D = np.zeros_like(Vin)
    Vdac = np.zeros_like(Vin)
    Vres = np.zeros_like(Vin)
    for i in range(len(Vin)):
        if Vin[i] > 0.25 * Vref:
            D[i] = +1
        elif Vin[i] < -0.25 * Vref:
            D[i] = -1
        else:
            D[i] = 0
        Vdac[i] = D[i] * 0.5 * Vref
        Vres[i] = 2 * (Vin[i] - Vdac[i])
    return D, Vres

# ===============================
# 残差伝搬 / Residue propagation
# ===============================
Vin_stage = [Vin_all]
Dout_stage = []
for k in range(N_stage):
    Dk, Vres = stage(Vin_stage[-1], Vref)
    Dout_stage.append(Dk)
    Vin_stage.append(Vres)

# ===============================
# 各ステージを個別プロット / Plot each stage separately
# ===============================
for k in range(N_stage):
    plt.figure(figsize=(10,3))
    plt.plot(t, Vin_stage[k], label=f"Stage {k+1} Input (V_in{k+1})")
    plt.xlabel("Time [s]")
    plt.ylabel("Voltage [V]")
    plt.title(f"Pipeline ADC Stage {k+1} Residue Input")
    plt.grid(True)
    plt.legend()
    plt.tight_layout()
    plt.show()

# ===============================
# デジタルコード確認 / Check one sample
# ===============================
sample_index = 50
codes = [int(Dout_stage[k][sample_index]) for k in range(N_stage)]
digital_out = sum([(codes[k] + 1) * (2 ** (N_stage - k - 1)) for k in range(N_stage)])
print(f"Sample {sample_index}: Input={Vin_all[sample_index]:.3f} V → Digital Code={digital_out}")

フラッシュ型ADC


# ===============================
# 必要ライブラリ / Required libraries
# ===============================
!pip install numpy matplotlib

import numpy as np
import matplotlib.pyplot as plt

# ===============================
# パラメータ設定 / Parameters
# ===============================
Nbit = 8                   # 分解能 [bit]
Vref = 1.0                 # 参照電圧 [V]
N_comp = 2**Nbit - 1        # 比較器数 = 255
N_point = 400               # 入力サンプル数
t = np.linspace(0, 1, N_point)

# 入力信号(0〜Vref範囲の正弦波) / Input analog sine wave
Vin = 0.5 * Vref * (1 + np.sin(2 * np.pi * 2 * t))

# ===============================
# 比較器群 / Comparator array
# ===============================
Vref_levels = np.linspace(0, Vref, N_comp + 1)[1:]  # Vref_i = i/2^N * Vref
C = np.zeros((N_point, N_comp))                      # サーモコード配列 / Thermometer code

for i in range(N_point):
    for j in range(N_comp):
        C[i, j] = 1 if Vin[i] >= Vref_levels[j] else 0

# ===============================
# サーモコード→デジタル出力変換 / Thermometer to binary
# ===============================
D = np.sum(C, axis=1)                  # D = Σ C_i
Vout = D * (Vref / (2**Nbit))          # Vout = D × Δ
LSB = Vref / (2**Nbit)                 # 1LSB

# ===============================
# 結果表示 / Plot results
# ===============================
plt.figure(figsize=(10,4))
plt.plot(t, Vin, label="Analog Input Vin")
plt.step(t, Vout, where='mid', label=f"Flash ADC 8-bit Output (Quantized)")
plt.xlabel("Time [s]")
plt.ylabel("Voltage [V]")
plt.title(f"8-bit Flash ADC Simulation (255 Comparators, 1 LSB = {LSB:.5f} V)")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

# ===============================
# サーモコード確認(例: 1サンプル) / Example of thermometer code
# ===============================
sample_idx = 120
print(f"Sample {sample_idx}: Vin = {Vin[sample_idx]:.4f} V")
print(f"Digital output D = {int(D[sample_idx])}, Vout = {Vout[sample_idx]:.4f} V")
print(f"Thermometer code (first 32 of 255 comparators):")
print(C[sample_idx][:32])

サイクリック型ADC


# Program Name: beta_expansion_adc.py
# Creation Date: 20251020
# Overview: Simulate Cyclic ADC operation using β-expansion representation
# Usage: Run in Google Colab or Python → visualize convergence of residue

!pip install numpy matplotlib

import numpy as np
import matplotlib.pyplot as plt

# ==============================
# パラメータ設定 / Parameters
# ==============================
beta = 2.0          # 拡大率 (gain) β = 2 
Vref = 1.0          # 基準電圧
Vin = 0.37          # 入力電圧 (0~1 の範囲)
N = 8               # 展開桁数 (サイクル数)

# ==============================
# β進数展開 / Beta Expansion
# ==============================
digits = []         # 量子化符号列 Dk
residues = [Vin]    # 残差履歴

for k in range(N):
    # 量子化:入力を +1, 0, -1 に符号化
    if Vin >= +Vref/2:
        Dk = 1
    elif Vin <= -Vref/2:
        Dk = -1
    else:
        Dk = 0
    
    # β進数的残差更新
    Vin = beta * (Vin - Dk * (Vref/2))
    digits.append(Dk)
    residues.append(Vin)

# ==============================
# 再構成値 / Reconstructed Value
# ==============================
reconstructed = 0
for k, Dk in enumerate(digits):
    reconstructed += (Dk / (beta ** (k + 1))) * (Vref / 2)

# ==============================
# 結果出力 / Results
# ==============================
print("β = ", beta)
print("入力電圧 Vin =", 0.37)
print("量子化符号列 Dk =", digits)
print("再構成値 =", round(reconstructed, 4))
print("誤差 =", round(0.37 - reconstructed, 6))

# ==============================
# 可視化 / Visualization
# ==============================
plt.figure(figsize=(6,4))
plt.plot(range(len(residues)), residues, marker='o')
plt.title("Cyclic ADC (β-expansion) Residue per Iteration")
plt.xlabel("Iteration (k)")
plt.ylabel("Residue Voltage [V]")
plt.grid(True)
plt.show()


!pip install numpy matplotlib

import numpy as np
import matplotlib.pyplot as plt

# =======================================
# --- Parameter Block ---
# =======================================
Vref = 1.0        # Reference voltage [V]
Nbit = 8           # ADC resolution
A = 2000           # Amplifier finite gain
beta_true = 1.85   # Actual internal β used in ADC core
Nsamp = 80
Vin = np.linspace(0, Vref, Nsamp)
Vin_centered = Vin - Vref/2

# =======================================
# --- Function: β-expansion ADC model ---
# =======================================
def beta_expansion_adc(vin, Vref, Nbit, A, beta):
    gain_eff = A / (A + 1)
    bits = np.zeros((len(vin), Nbit))
    vres = vin.copy()
    for k in range(Nbit):
        Dk = (vres >= 0).astype(int)
        bits[:, k] = Dk
        Vdac = (2*Dk - 1)*(Vref/2)
        vres = gain_eff * beta * (vres - Vdac)
    return bits

# =======================================
# --- Step 1: Generate two sequences for β estimation ---
# =======================================
# Fixed DC input (Vin=Vref/4) with MSB forced 0 and 1
def simulate_forced(vin, Vref, Nbit, A, beta, msb_force):
    gain_eff = A / (A + 1)
    vres = np.ones(len(vin))*vin
    bits = np.zeros((len(vin), Nbit))
    for k in range(Nbit):
        if k == 0:
            Dk = np.ones(len(vin))*msb_force
        else:
            Dk = (vres >= 0).astype(int)
        bits[:, k] = Dk
        Vdac = (2*Dk - 1)*(Vref/2)
        vres = gain_eff * beta * (vres - Vdac)
    return bits[0]  # return bit sequence for 1 sample

Vin_dc = np.array([0.25])
X0 = simulate_forced(Vin_dc, Vref, Nbit, A, beta_true, 0)
X1 = simulate_forced(Vin_dc, Vref, Nbit, A, beta_true, 1)

# =======================================
# --- Step 2: Dynamic β estimation algorithm ---
# =======================================
def reconstruct_x(bits, beta):
    d = bits - 0.5
    pow_inv = beta ** (-np.arange(1, len(bits)+1))
    return 0.5 + np.sum(d * pow_inv)

def estimate_beta(X0, X1, beta_lo=1.5, beta_hi=2.1, iters=40):
    phi = (np.sqrt(5)-1)/2
    a, b = beta_lo, beta_hi
    c = b - phi*(b-a); d = a + phi*(b-a)
    for _ in range(iters):
        e_c = abs(reconstruct_x(X0, c) - reconstruct_x(X1, c))
        e_d = abs(reconstruct_x(X0, d) - reconstruct_x(X1, d))
        if e_c > e_d:
            a = c; c = d; d = a + phi*(b-a)
        else:
            b = d; d = c; c = b - phi*(b-a)
    return 0.5*(a+b)

beta_est = estimate_beta(X0, X1)
print(f"Estimated β value = {beta_est:.4f} (true={beta_true:.2f})")

# =======================================
# --- Step 3: Conversion β→Binary ---
# =======================================
def beta_to_binary(bits, beta_eff, Nbit):
    S = 0.0
    invb = 1.0 / beta_eff
    for d in bits:
        S = invb * (S + (d - 0.5))
    xhat = 0.5 + S
    xhat = min(max(xhat, 0.0), 1.0)
    D_bin = int(np.clip(np.round((2**Nbit) * xhat), 0, 2**Nbit - 1))
    return D_bin, xhat

# =======================================
# --- Step 4: Simulate β-expansion ADC and compare with binary ADC ---
# =======================================
bits_beta = beta_expansion_adc(Vin_centered, Vref, Nbit, A, beta_est)
codes_beta = np.array([beta_to_binary(bits_beta[i], beta_est, Nbit)[0] for i in range(Nsamp)])
Vout_beta = Vref * codes_beta / (2**Nbit)

# Ideal binary for comparison
bits_bin = beta_expansion_adc(Vin_centered, Vref, Nbit, A, 2.0)
codes_bin = np.array([beta_to_binary(bits_bin[i], 2.0, Nbit)[0] for i in range(Nsamp)])
Vout_bin = Vref * codes_bin / (2**Nbit)

# =======================================
# --- Step 5: Plot results ---
# =======================================
plt.figure(figsize=(10,6))
plt.plot(Vin, Vout_bin, label="Binary (β=2.0)")
plt.plot(Vin, Vout_beta, label=f"β-expansion (β_est={beta_est:.2f})")
plt.plot(Vin, Vin, 'k--', label="Ideal")
plt.title("β-expansion ADC vs Binary ADC")
plt.xlabel("Input Voltage [V]")
plt.ylabel("Output Voltage [V]")
plt.legend()
plt.grid(True)
plt.show()

# =======================================
# --- Step 6: Print example bit sequences ---
# =======================================
print("\nExample bit sequences (MSB→LSB):")
for i in range(0, Nsamp, Nsamp//6):
    seq_bet = ''.join(str(int(x)) for x in bits_beta[i])
    seq_bin = ''.join(str(int(x)) for x in bits_bin[i])
    print(f"Vin={Vin[i]:.3f} | β-seq={seq_bet}{codes_beta[i]:3d} | 2^seq={seq_bin}{codes_bin[i]:3d}")

NS-SAR型ADC



# ===============================
# ライブラリ導入 / Import libraries
# ===============================
!pip install numpy matplotlib
import numpy as np
import matplotlib.pyplot as plt

# ===============================
# パラメータ設定 / Global parameters
# ===============================
fs = 1e5             # サンプリング周波数 [Hz]
fin = 1000           # 入力信号周波数 [Hz]
N = 8192             # サンプル数
Vref = 1.0           # 参照電圧 [V]
Ain = 0.6            # 入力振幅 [V]
Nbit = 8             # SAR分解能 [bit]
alpha = 1.0          # 積分ゲイン
beta = 1.0           # フィードバック係数

# ===============================
# 入力信号生成 / Input sine signal
# ===============================
t = np.arange(N) / fs
x = Ain * np.sin(2 * np.pi * fin * t)

# ===============================
# NS-SARループシミュレーション / NS-SAR discrete-time loop
# ===============================
v = 0.0
y = np.zeros(N)
for n in range(N):
    # 逐次比較(SAR量子化)+積分フィードバック
    y[n] = np.round((x[n] + beta * v) * (2**Nbit - 1)) / (2**Nbit - 1)
    v = v + alpha * (x[n] - y[n])  # 誤差を積分(ノイズ整形)

# ===============================
# FFT解析 / FFT spectrum analysis
# ===============================
Yf = np.fft.fft(y * np.hanning(N))
freq = np.fft.fftfreq(N, 1/fs)
PSD = 20 * np.log10(np.abs(Yf[:N//2]) / np.max(np.abs(Yf)))

# ===============================
# 可視化 / Visualization
# ===============================

plt.figure(figsize=(10,5))
plt.semilogx(freq[:N//2], PSD, label="Output Spectrum (NS-SAR ADC)")
plt.xlabel("Frequency [Hz]")
plt.ylabel("Normalized Magnitude [dB]")
plt.title("Noise-Shaping SAR ADC Spectrum (FFT method)")
plt.grid(True, which="both")
plt.legend()
plt.tight_layout()
plt.show()

# ===============================
# 比較:通常SAR ADC(ノイズシェーピングなし)
# ===============================
y_sar = np.round(x * (2**Nbit - 1)) / (2**Nbit - 1)
Yf_sar = np.fft.fft(y_sar * np.hanning(N))
PSD_sar = 20 * np.log10(np.abs(Yf_sar[:N//2]) / np.max(np.abs(Yf_sar)))

plt.figure(figsize=(10,5))
plt.semilogx(freq[:N//2], PSD_sar, label="Conventional SAR ADC")
plt.semilogx(freq[:N//2], PSD, label="Noise-Shaping SAR ADC (1st-order)")
plt.xlabel("Frequency [Hz]")
plt.ylabel("Normalized Magnitude [dB]")
plt.title("FFT Comparison: SAR vs Noise-Shaping SAR ADC")
plt.legend()
plt.grid(True, which="both")
plt.tight_layout()
plt.show()

# ===============================
# 結果要約 / Summary
# ===============================
print("Simulation complete.")
print("✓ Noise-Shaping SAR ADC shows 1st-order shaping (20 dB/dec slope).")
print("✓ Quantization noise suppressed in low-frequency band.")
print("✓ Compare with conventional SAR → flat noise floor (no shaping).")

FFTとサイン波


!pip install numpy matplotlib scipy

import numpy as np
import matplotlib.pyplot as plt

# -------------------- Function Definitions --------------------

def freq_search(N: int, fs: float, finRate=8):
    """整合サンプリング用入力周波数を計算 / Calculate input frequency for coherent sampling"""
    freq = []
    FFT_points = 2**N
    for n in range(2, N):
        prime = np.exp(n * np.log(2)) - 1
        fin_per_fs = prime / FFT_points
        freq.append(fin_per_fs)
    array = np.array(freq)
    index = (np.abs(array - (1 / finRate))).argmin()
    fin = freq[index] * fs
    return fin

def ideal_adc(input_voltage, n_bits: int, v_min: float, v_max: float):
    """理想ADC変換 / Ideal ADC conversion"""
    LSB = (v_max - v_min) / (2**n_bits)
    digital_level = ((input_voltage - v_min) / LSB).astype(int)
    digital_level = np.clip(digital_level, 0, 2**n_bits - 1)
    return digital_level

def sine_wave_generator(N: int, f_signal: float, fs: float, amplitude: float, offset: float):
    """正弦波信号生成 / Generate sine wave"""
    t_sampling = 1 / fs
    duration = N * t_sampling
    t = np.arange(0, duration, t_sampling)
    signal = amplitude * np.sin(2 * np.pi * f_signal * t) + offset
    return signal

def AC_evaluation(bit: int, data, N: int, fs: float, f_in: float, power_W=1e-3):
    """FFT解析でSNDR, ENOB, SFDR, FoM算出 / FFT-based AC evaluation"""
    f = np.divide(data, 2 ** (bit - 1))
    dt = 1 / fs
    t = np.arange(0, N * dt, dt)
    freq = np.fft.fftfreq(N, dt)
    F = np.fft.fft(f * np.hanning(N)) / (N/2)
    Power = np.abs(F) ** 2
    Pow_dB = 10 * np.log10(Power / np.max(Power))

    signal_index = np.argmax(Power[1:int(N/2)]) + 1
    Signal = Power[signal_index]
    Noise = np.sum(Power[1:int(N/2)]) - Signal
    SNDR = 10 * np.log10(Signal / Noise)
    ENOB = (SNDR - 1.76) / 6.02
    spurious = [np.max(Pow_dB[(signal_index * i) - 2: signal_index * i + 2]) for i in range(2, 5)]
    SFDR = Pow_dB[signal_index] - np.max(spurious)

    # FoM計算 / Figure of Merit
    FoM_W = power_W / (2**ENOB * fs)
    FoM_S = SNDR + 10 * np.log10(fs / power_W)

    # --- 結果表示 / Print results ---
    print("===== ADC AC Evaluation Results =====")
    print(f"SNR or SNDR = {SNDR:.2f} dB")
    print(f"ENOB        = {ENOB:.2f} bit")
    print(f"SFDR        = {SFDR:.2f} dB")
    print(f"FoM_W       = {FoM_W:.2e} J/step")
    print(f"FoM_S       = {FoM_S:.1f} dB")
    print("=====================================")

    # --- FFTスペクトル表示 / Plot spectrum ---
    freq_norm = freq / fs
    plt.figure(figsize=(8,4))
    plt.plot(freq_norm[1:int(N/2)], Pow_dB[1:int(N/2)])
    plt.title("FFT Spectrum and Performance Metrics")
    plt.xlabel("Normalized Frequency (f/fs)")
    plt.ylabel("Power [dBFS]")
    plt.grid(True)
    plt.text(0.3, -5, f"SNDR={SNDR:.2f} dB")
    plt.text(0.3, -10, f"ENOB={ENOB:.2f} bit")
    plt.text(0.3, -15, f"SFDR={SFDR:.2f} dB")
    plt.tight_layout()
    plt.show()

# -------------------- Main Execution --------------------

N = 12                 # FFT exponent → FFT points = 2^N
fs = 1_000_000         # Sampling frequency [Hz]
bit = 8                # ADC resolution [bit]
fin_rate = 8           # fs/fin ratio for coherent sampling
v_amplitude = 2.5      # Amplitude [V]
v_offset = 2.5         # DC offset [V]
v_min = 0              # ADC minimum voltage [V]
v_max = 5              # ADC maximum voltage [V]
noise = 0.0            # Noise amplitude [V]

# 入力周波数計算 / Calculate coherent input frequency
f_in = freq_search(N, fs, fin_rate)
print(f"Input frequency f_in = {f_in:.2f} Hz")

# 信号生成 / Generate input signal
v_signal = sine_wave_generator(2**N, f_in, fs, v_amplitude, v_offset)
v_signal += noise * np.random.randn(2**N)

# ADC変換 / Ideal ADC conversion
data = ideal_adc(v_signal, bit, v_min, v_max)

# AC特性評価 / Evaluate ADC AC performance
AC_evaluation(bit, data, 2**N, fs, f_in)

# 時間波形プロット / Plot input signal and ADC code
t = np.arange(0, 2**N) / fs

plt.figure(figsize=(10,4))
plt.plot(t[:500], v_signal[:500], label="Analog Input")
plt.step(t[:500], data[:500], where='post', label="ADC Code")
plt.title("ADC Input and Quantized Output (First 500 samples)")
plt.xlabel("Time [s]")
plt.ylabel("Voltage / Code")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

ADCに必要なパラメータ



import numpy as np

# ===============================
# パラメータ設定 / Global parameters
# ===============================
N = 12              # 分解能 [bit]
Vref_p = 1.0        # 正基準電圧 [V]
Vref_n = 0.0        # 負基準電圧 [V]
fs = 1e6            # サンプリング周波数 [Hz]
fclk = 10e6         # クロック周波数 [Hz](SAR用)
P = 5e-3            # 消費電力 [W]
Idd = 2e-3          # 電源電流 [A]
Vdd = 2.5           # 電源電圧 [V]
fB = 20e3           # 信号帯域幅 [Hz]
OSR = fs / (2 * fB) # オーバーサンプリング比
A_area = 10e-12     # キャパシタ面積 [m²](例)

# ===============================
# 基本パラメータ
# ===============================
Vfs = Vref_p - Vref_n
q = Vfs / (2**N)
eq_max = q / 2

# ===============================
# 時間関連
# ===============================
Ts = 1 / fs
fN = fs / 2
Tconv = N / fclk

# ===============================
# 性能関連
# ===============================
SNR_ideal = 6.02 * N + 1.76
Pn = q**2 / 12
Vn_rms = q / np.sqrt(12)

# テスト値設定(実測やシミュレーションの仮値)
SINAD = SNR_ideal - 3.0  # 実際は理想より低下
ENOB = (SINAD - 1.76) / 6.02
SFDR = 70.0              # 仮定値 [dB]
THD = -80.0              # 仮定値 [dB]

# ===============================
# 電力効率・FoM
# ===============================
FoM_W = P / (2**N * fs)
FoM_S = SNR_ideal + 10 * np.log10(fs / P)

# ===============================
# エラー・誤差要素
# ===============================
E_FS = Vfs - Vfs  # 理想的には0
E_off = 0.0
E_gain = 0.0
sigmaC_C = 1 / np.sqrt(A_area / 1e-12)  # 面積1µm²基準

# ===============================
# 出力プリント / Print summary
# ===============================
print("===============================================")
print(" ADC Parameter Summary")
print("===============================================")
print(f"Resolution (N)            : {N} bit")
print(f"Full-scale Voltage (Vfs)  : {Vfs:.4f} V")
print(f"Quantization Step (q)     : {q:.6e} V/LSB")
print(f"Max Quantization Error    : {eq_max:.6e} V")
print("-----------------------------------------------")
print(f"Sampling Freq (fs)        : {fs:.3e} Hz")
print(f"Nyquist Freq (fN)         : {fN:.3e} Hz")
print(f"Sampling Period (Ts)      : {Ts:.3e} s")
print(f"Conversion Time (SAR)     : {Tconv:.3e} s")
print("-----------------------------------------------")
print(f"SNR (ideal)               : {SNR_ideal:.2f} dB")
print(f"SINAD (assumed)           : {SINAD:.2f} dB")
print(f"ENOB                      : {ENOB:.2f} bit")
print(f"Noise Power (Pn)          : {Pn:.3e} V^2")
print(f"Input-Referred Noise      : {Vn_rms:.3e} Vrms")
print(f"THD (assumed)             : {THD:.2f} dB")
print(f"SFDR (assumed)            : {SFDR:.2f} dB")
print("-----------------------------------------------")
print(f"Power Consumption (P)     : {P:.3e} W")
print(f"Vdd, Idd                  : {Vdd:.2f} V, {Idd:.3e} A")
print(f"Walden FoM (J/step)       : {FoM_W:.3e}")
print(f"Schreier FoM (dB)         : {FoM_S:.2f} dB")
print("-----------------------------------------------")
print(f"Oversampling Ratio (OSR)  : {OSR:.2f}")
print(f"Noise Shaping Gain (1st)  : {10*np.log10(OSR**3/3):.2f} dB")
print("-----------------------------------------------")
print(f"Capacitor Matching σC/C   : {sigmaC_C:.2f} % (for A={A_area*1e12:.1f} µm²)")
print("===============================================")
print(" All formulas implemented from ADC performance definitions.")

ADCのサンプルホールド

import numpy as np
import matplotlib.pyplot as plt

# ----- Parameters -----
Vref = 1.0              # Reference voltage
bits = 4                # Number of bits in ADC
Ceq = 2.0               # Equivalent total capacitance (arbitrary)
fs = 1000               # Sampling frequency (Hz)
t = np.linspace(0, 1, fs)
Vin = 0.6 * np.sin(2 * np.pi * 3 * t) + 0.6  # Input analog signal

# ----- Sample and Hold -----
# Sample at discrete times
Ts = 0.05   # Sampling period
sample_times = np.arange(0, 1, Ts)
samples = np.interp(sample_times, t, Vin)  # Sample values

# Hold: keep each value constant until next sample
Vhold = np.repeat(samples, int(Ts * fs))
Vhold = np.append(Vhold, np.full(fs - len(Vhold), samples[-1]))  # pad

# ----- SAR Conversion Simulation -----
def sar_adc(vin, bits=4, Vref=1.0):
    """Simulate charge-redistribution SAR ADC conversion."""
    Vc = -vin        # hold voltage from sample
    D = np.zeros(bits)
    for k in range(bits):
        # Tentatively set bit = 1
        D[k] = 1
        Vtest = -vin + np.sum(D * Vref / 2**np.arange(1, bits+1))
        if Vtest < 0:
            # comparator output high -> keep bit = 1
            pass
        else:
            # comparator output low -> reset bit to 0
            D[k] = 0
    code = np.sum(D * 2**np.arange(bits-1, -1, -1))
    return D, code

codes = []
for vin in samples:
    _, code = sar_adc(vin, bits, Vref)
    codes.append(code)

Vout = np.array(codes) * (Vref / (2**bits - 1))  # digital-to-analog reconstructed value

# ----- Plot Results -----
plt.figure(figsize=(10, 6))
plt.plot(t, Vin, label="Analog Input (Vin)", linewidth=1.5)
plt.step(sample_times, Vout, where="post", label="Quantized Output (SAR Result)")
plt.step(t, Vhold, where="post", label="Sample & Hold Output", alpha=0.6)
plt.title("Sample-Hold and Charge Redistribution SAR ADC Simulation", fontsize=13)
plt.xlabel("Time [s]")
plt.ylabel("Voltage [V]")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

二部探索アルゴリズムでつかうβ推定


# --- 比較用のデータ ---
# βコード列 (L=10)
beta_code = "0101101000"

# β変換プロセスを経て得られた通常の10ビット2進コード (D=385)
conventional_binary_code = "0110000001"

# 10進数コード D (確認用)
D_int = 385

print("--- β展開ADC結果と通常の2進数の比較 ---")
print(f"基数 β = 1.83 (特殊な基数)")
print(f"ビット長 N = 10")
print("-" * 35)

print(f"1. 元の βコード列 b_k:         {beta_code}")
print(f"2. 通常の10進数コード D:        {D_int}")
print(f"3. 変換後の通常の2進コード: {conventional_binary_code}")
print("-" * 35)

# ビットごとの比較
print("\n--- ビットごとの差異 ---")
print("  k | βコード | 2進コード | 差異")
print("----|---------|-----------|-----")

diff_count = 0
for k in range(10):
    b_bit = beta_code[k]
    c_bit = conventional_binary_code[k]
    
    # 差異があるかチェック
    diff = "" if b_bit != c_bit else ""
    if b_bit != c_bit:
        diff_count += 1
        
    # kはMSB側から1から数える
    print(f" {k+1:2} |    {b_bit}    |     {c_bit}     |  {diff}")

print("-" * 35)
print(f"総ビット数: 10")
print(f"差異のあるビット数: {diff_count}")
print(f"→ βコードは通常の2進コードとは異なる形式であることが確認できます。")
import numpy as np
import matplotlib.pyplot as plt
import os
from scipy.fft import fft
from scipy.signal import find_peaks

# --- 1. 設定とデータ読み込み ---
# ADCの出力データファイルパス (適切なパスに修正してください)
# path = r"20240221_512_fs735k_1stfixed.csv_out.csv"
# 仮のデータ生成 (実際のデータに合わせて修正してください)
N = 512  # サンプリング点数 (FFTpoints)
fs = 735294.117647  # サンプリング周波数 [Hz]
fn_ideal = 15  # 入力信号のサイクル数 (M)
fin = fn_ideal * fs / N # 理想的な入力周波数 [Hz]

# βopt推定の探索範囲
beta_sweep_min = 1.85
beta_sweep_max = 1.95
beta_sweep_nums = 1000  # 探索回数

# サンプリングデータ (仮のデータ: 理想的なCyclic ADC出力に近い冗長コード)
# 実際のファイルからロードする代わりに、ここではテストデータを生成します
# ----------------------------------------------------------------------
# 【重要】テストデータを、FFTに必要な N個の最終ADC出力として生成し直します。
# ----------------------------------------------------------------------
def generate_test_data(N, beta_true, fin, fs):
    t = np.arange(N) / fs
    Vin_norm = np.sin(2 * np.pi * fin * t) # -1から1の範囲の入力信号を想定
    
    # 理想的なADC出力を生成(Nビット換算)
    # 簡略化のため、ここではVin_normを直接量子化(疑似的な最終出力)
    # 実際のデータでは、各サンプルが既にデジタル校正前のコード系列です
    # N=512のFFT点数に合わせた配列を生成
    ideal_output = np.round(Vin_norm * 2**(10) / 2**(10)) # 10bit程度の分解能を想定
    # ノイズと非線形性を加えることで、β探索が意味を持つようにする
    noise = np.random.normal(0, 0.05, N)
    raw_codes_approx = Vin_norm * (2**10) + noise * 10
    
    # 実際のADC出力は、Nサンプル分の最終冗長コード配列であると仮定
    return raw_codes_approx 

# 実際のADC出力データ(校正前の最終コード系列)をロードする行に置き換えてください
# raw_codes = np.loadtxt(path, delimiter=',') 
raw_codes = generate_test_data(N, 1.90, fin, fs)
# N点のデータ配列であることが必須
if raw_codes.ndim != 1 or len(raw_codes) != N:
    print("ERROR: raw_codesはFFTポイント数Nと同じ長さの一次元配列でなければなりません。")
    # ここではテストデータをそのまま使用し続けますが、実際のコードでは終了すべきです
    
B = len(raw_codes)

# --- 2. β最適値の探索とデジタル校正関数 ---
def digital_calibration(raw_codes, beta_est):
    """
    【修正】
    raw_codesはN点の時系列データ配列であり、
    Cyclic ADCのデジタル校正は、各サンプル(N点)に対してではなく、
    アナログビット重み補正係数 (1/β)^i を用いて一括で校正済みコードを計算します。
    ここでは、raw_codesが「校正前の最終ビット系列」であり、
    beta_estは単に「校正係数」として乗じるという**簡略化**された動作をシミュレートします。
    
    *もしraw_codesが[Nサンプル, Bビット]の行列であれば、関数は大幅に複雑化します*
    
    ここでは、FFTを実行するために、raw_codesを配列として返し、
    β探索が意味を持つように、各サンプルに対して校正係数を乗じる簡略化されたロジックを適用します。
    """
    # 探索の目的がSNDR最大化であるため、この簡略化された校正係数の適用で探索は可能
    # 厳密な校正ロジックは、raw_codesがビット系列である場合に必要です。
    D_binary = raw_codes * (beta_est / 2.0)
    return D_binary

def calculate_sndr(D_binary, fs, fin):
    """デジタル校正後のデータでSNDRを計算する (簡略版)"""
    
    # 1. FFTを実行
    # D_binaryが配列であることを確認 (修正後のコードでは配列になっている)
    if np.ndim(D_binary) == 0:
        raise ValueError("FFTの入力は一次元配列である必要があります。")
        
    Y = fft(D_binary)
    P_total = np.abs(Y)**2 / N  # 電力スペクトル

    # 2. 信号ピークとノイズ/歪みを分離
    # 正規化周波数 [0, fs/2] に相当するインデックスを取得
    P_half = P_total[1:int(N/2)]
    
    # 信号ピークのインデックスを特定
    # 簡略化のため、最も高いピークを信号と仮定します
    idx_signal = np.argmax(P_half) + 1
    P_signal = P_total[idx_signal]

    # DC成分 (P_total[0]) と信号成分を除く全電力
    P_noise_dist = np.sum(P_total) - P_total[0] - P_signal

    # SNDRを計算
    if P_noise_dist > 0:
        SNDR_val = 10 * np.log10(P_signal / P_noise_dist)
    else:
        SNDR_val = -200.0 # エラー値または非常に高い値

    return SNDR_val, P_total, idx_signal

# --- 3. βoptの探索 ---
beta_sweep_range = np.linspace(beta_sweep_min, beta_sweep_max, beta_sweep_nums)
sndr_results = []

print(f"INFO: βoptの探索範囲: {beta_sweep_min:.4f} から {beta_sweep_max:.4f}")

for beta_est in beta_sweep_range:
    # 1. デジタル校正
    D_calibrated = digital_calibration(raw_codes, beta_est)
    
    # 2. SNDRを評価
    try:
        sndr_val, _, _ = calculate_sndr(D_calibrated, fs, fin)
        sndr_results.append(sndr_val)
    except ValueError as e:
        # calculate_sndr内で発生したValueErrorを捕捉
        print(f"ERROR during SNDR calculation for beta={beta_est:.4f}: {e}")
        sndr_results.append(-300.0) # 失敗を示す値

# βoptの決定
sndr_results = np.array(sndr_results)
idx_opt = np.argmax(sndr_results)
beta_opt = beta_sweep_range[idx_opt]
SNDR_opt = sndr_results[idx_opt]
ENOB_opt = (SNDR_opt - 1.76) / 6.02

# --- 4. 最終結果の表示とプロット ---
print(f"====================================")
print(f"最適 β (beta_opt): {beta_opt:.6f}")
print(f"最大 SNDR: {SNDR_opt:.2f} [dB]")
print(f"対応 ENOB: {ENOB_opt:.2f} [bit]")
print(f"====================================")

# 最適βで再校正とFFT
D_calibrated_opt = digital_calibration(raw_codes, beta_opt)
SNDR, P_total, idx_signal = calculate_sndr(D_calibrated_opt, fs, fin)
P_dB = 10 * np.log10(P_total / np.max(P_total)) # dBFS

# パワースペクトルのプロット
fig, ax = plt.subplots(figsize=(10, 6))
ax.set_title(f"Power Spectrum (N={N}) with $\\beta_{{opt}}$", fontname="MS Gothic")
ax.set_xlabel("Normalized Frequency (f/fs)")
ax.set_ylabel("Power [dBFS]")
ax.text(0.05, -10, f"SNDR = {SNDR_opt:.2f} [dB]", size=12)
ax.text(0.05, -20, f"ENOB = {ENOB_opt:.2f} [bit]", size=12)
ax.text(0.05, -30, f"$\\beta_{{opt}}$ = {beta_opt:.6f}", size=12)
ax.set_ylim(-170, 10)
ax.grid(True)
# 周波数軸の設定
freq_normalized = np.arange(N) / N
ax.plot(freq_normalized[1:int(N/2)], P_dB[1:int(N/2)], label="FFT Output")
ax.legend()
plt.show()

# β探索結果のプロット (オプション)
plt.figure(figsize=(10, 4))
plt.plot(beta_sweep_range, sndr_results)
plt.title("SNDR vs. $\\beta$ Estimation", fontname="MS Gothic")
plt.xlabel("Estimated $\\beta$")
plt.ylabel("SNDR [dB]")
plt.axvline(x=beta_opt, color='r', linestyle='--', label=f'$\\beta_{{opt}} = {beta_opt:.6f}$')
plt.grid(True)
plt.legend()
plt.show()
# 1. 理想バイナリADC (利得無限大, Ca=Cb)
def ideal_binary_cyclic_adc(V_in, V_ref, D_out_sign):
    """V_res = 2*V_in ± V_ref"""
    return 2 * V_in + D_out_sign * V_ref  # D_out_sign: +1が+Vref、-1が-Vref

# 2. 有限利得バイナリADC (利得 A が有限, Ca=Cb)
def finite_gain_binary_cyclic_adc(V_in, V_ref, A, D_out_sign):
    """V_res = (1 / (1 + 2/A)) * {2*V_in ± V_ref}"""
    gain_factor = 1.0 / (1.0 + 2.0 / A)
    return gain_factor * (2 * V_in + D_out_sign * V_ref)

# 3. 有限利得 非2進サイクリックADC (利得 A が有限, Ca:Cb=(beta-1):1)
def finite_gain_non_binary_cyclic_adc(V_in, V_ref, beta, A, D_out_sign):
    """V_res = (1 / (1 + beta/A)) * {β*V_in ± (β-1)V_ref}"""
    gain_factor = 1.0 / (1.0 + beta / A)
    return gain_factor * (beta * V_in + D_out_sign * (beta - 1) * V_ref)

# --- 計算パラメータ ---
V_in_val = 0.6    # 入力電圧 [V]
V_ref_val = 1.0   # 基準電圧 [V]
A_val = 100.0     # オペアンプ利得
beta_val = 1.7    # 非2進ADCの増幅率

# --- 計算と出力 ---
print("--- サイクリックADC 残差電圧計算 ---")
print(f"共通パラメータ: Vin={V_in_val}V, Vref={V_ref_val}V, A={A_val}, β={beta_val}\n")

# 1. 理想バイナリADC
res_ideal_plus = ideal_binary_cyclic_adc(V_in_val, V_ref_val, D_out_sign=1)
res_ideal_minus = ideal_binary_cyclic_adc(V_in_val, V_ref_val, D_out_sign=-1)
print("1. 理想バイナリADC:")
print(f"  +V_ref の場合: V_res = {res_ideal_plus:.4f} V")
print(f"  -V_ref の場合: V_res = {res_ideal_minus:.4f} V\n")

# 2. 有限利得バイナリADC
res_finite_plus = finite_gain_binary_cyclic_adc(V_in_val, V_ref_val, A_val, D_out_sign=1)
res_finite_minus = finite_gain_binary_cyclic_adc(V_in_val, V_ref_val, A_val, D_out_sign=-1)
print("2. 有限利得バイナリADC:")
print(f"  +V_ref の場合: V_res = {res_finite_plus:.4f} V")
print(f"  -V_ref の場合: V_res = {res_finite_minus:.4f} V\n")

# 3. 有限利得 非2進サイクリックADC
res_nonbinary_plus = finite_gain_non_binary_cyclic_adc(V_in_val, V_ref_val, beta_val, A_val, D_out_sign=1)
res_nonbinary_minus = finite_gain_non_binary_cyclic_adc(V_in_val, V_ref_val, beta_val, A_val, D_out_sign=-1)
print("3. 有限利得 非2進サイクリックADC:")
print(f"  +V_ref の場合: V_res = {res_nonbinary_plus:.4f} V")
print(f"  -V_ref の場合: V_res = {res_nonbinary_minus:.4f} V")

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?