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?

PythonでわかるAD変換と二分探索アルゴリズム

Last updated at Posted at 2025-04-04

はじめに

本記事では、逐次比較型ADC(SAR ADC)風のアルゴリズムを用いて、
入力信号(サイン波)に対して 比較 → ビット出力 → 残差生成 → 再帰処理 を行う
Pythonコードについて詳しく解説します。

このコードを使うことで、以下のような処理が視覚的に確認できます:

各ステップでのビット判定(0 or 1)

各ステップで生成される残差電圧の推移

最終的なデジタル出力の再構成

すべてのビット・残差を時間軸に沿ってプロット表示

逐次比較型ADCの学習や可視化、シミュレーションに最適な内容となっております。

Pythonコード

import numpy as np
import matplotlib.pyplot as plt

def comparator_and_residue(Vin, Vref):
    """
    コンパレータと残差出力
    Comparator and residue output
    """
    if Vin > Vref:
        Bit = 1
        Vout = 2 * (Vin - Vref)
    else:
        Bit = 0
        Vout = 2 * Vin
    return Bit, Vout

# ---- 初期設定 / Initialization ----
fs = 1000                           # サンプリング周波数 [Hz]
f = 5                               # サイン波周波数 [Hz]
t = np.arange(0, 1, 1/fs)           # 時間軸
Vin_all = 0.5 * np.sin(2 * np.pi * f * t) + 0.5  # [0,1]範囲のサイン波
Vref = 0.5                          # 比較用基準電圧
n_steps = 8                         # 8ビット比較ステップ

# ---- データ記録用 / Data storage ----
bits_matrix = []
residues_matrix = []
digital_values = []

# ---- SAR処理: ビット生成 + 各残差を記録 ----
for Vin in Vin_all:
    current_Vin = Vin
    bits = []
    residues = []

    for _ in range(n_steps):
        bit, current_Vin = comparator_and_residue(current_Vin, Vref)
        bits.append(bit)
        residues.append(current_Vin)

    bits_matrix.append(bits)
    residues_matrix.append(residues)
    digital = int("".join(map(str, bits)), 2)
    digital_values.append(digital)

# ---- NumPy配列に変換 / Convert to arrays ----
bits_array = np.array(bits_matrix)            # shape: (samples, 8)
residues_array = np.array(residues_matrix)    # shape: (samples, 8)

# ---- プロット / Plot section ----
plt.figure(figsize=(16, 18))

# 元の入力とデジタル値のプロット / Input and reconstructed value
plt.subplot(n_steps + 2, 1, 1)
plt.plot(t, Vin_all, label='Input (sine wave)')
plt.plot(t, np.array(digital_values) / (2**n_steps - 1), label='Reconstructed Digital Value')
plt.title("Input and Reconstructed Digital Output (8-bit)")
plt.ylabel("Voltage")
plt.legend()
plt.grid(True)

# 各残差ステップのプロット / Plot all residues
for i in range(n_steps):
    plt.subplot(n_steps + 2, 1, i + 2)
    plt.plot(t, residues_array[:, i], label=f"Residue after Step {i+1}", color='C' + str(i % 10))
    plt.ylabel(f"Vout {i+1}")
    plt.grid(True)
    plt.legend()

plt.xlabel("Time [s]")
plt.tight_layout()
plt.show()

# ---- 最初の数個の残差を表示 / Print first 10 residues ----
print("First 10 samples (residues per step):")
for i in range(10):
    residue_str = ', '.join(f"{r:.4f}" for r in residues_matrix[i])
    print(f"t = {t[i]:.4f}s, Vin = {Vin_all[i]:.3f}, Residues = [{residue_str}]")

# ---- プロット / Plot section ----
plt.figure(figsize=(14, 14))

# 元の入力とデジタル出力の比較 / Input vs Digital Output
plt.subplot(n_steps + 2, 1, 1)
plt.plot(t, Vin_all, label='Input (sine wave)')
plt.plot(t, np.array(digital_values) / (2**n_steps - 1), label='Reconstructed Digital Value')
plt.title("Input and Reconstructed Digital Output (8-bit)")
plt.ylabel("Voltage")
plt.legend()
plt.grid(True)

# 各ビットのプロット / Bit plot
for i in range(n_steps):
    plt.subplot(n_steps + 2, 1, i + 2)
    plt.plot(t, bits_array[:, i], drawstyle='steps-post')
    plt.ylim(-0.2, 1.2)
    plt.ylabel(f"Bit {n_steps - 1 - i}")
    plt.grid(True)

# 最終段の下に残差の最終値をプロット / Last residue
plt.subplot(n_steps + 2, 1, n_steps + 2)
plt.plot(t, residues_array[:, -1], label='Final Residue', color='purple')
plt.ylabel("Residue (Step 8)")
plt.xlabel("Time [s]")
plt.grid(True)
plt.legend()

plt.tight_layout()
plt.show()


結果
image.png

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?