1. 光電変換
Q_ph = q * N_ph
N_ph = (η * P_opt * t_int) / (hν)
V_sig = Q_ph / C_FD
光子数 (N_{ph}) は入射光パワー (P_{opt})、露光時間 (t_{int})、および光子エネルギー (h\nu) から決まる。
量子効率 (\eta) を考慮すると、発生電荷 (Q_{ph}) は光の強さに比例。
その電荷がフローティング拡散容量 (C_{FD}) に蓄積され、信号電圧 (V_{sig}) が生じる。
これはCMOSイメージセンサーの1ピクセル出力電圧の基本式。
2. 画素読み出しとADC要求速度
f_s = (M * N) / T_frame
1フレームあたり (M×N) 画素を (T_{frame}) 秒で読み出す必要がある。
例:100万画素を30fpsで出力 → 約30 Msps。
このためCCD時代は高速パイプラインADCが必要だった。
3. シングルスロープADCの基本構造
V_ramp(t) = (V_ref / T_ramp) * t
V_in = S * t_conv
S = V_ref / T_ramp
t_conv = V_in / S = T_ramp * (V_in / V_ref)
D = N_clk * (V_in / V_ref)
- 入力電圧 (V_{in}) と線形ランプ電圧 (V_{ramp}(t)) を比較。
- 比較器出力が切り替わる時刻 (t_{conv}) が電圧に比例。
- この時間をクロックでカウントしてデジタル値 (D) を生成。
つまり「電圧 → 時間 → カウント数」に変換する積分型(計数型)A/D変換。
4. 方式別ADC動作速度
f_ADC(CCD) ≥ (M * N) / T_frame
f_ADC(CMOS) ≥ N / T_frame
- CCDでは出力1系統 → 1個の高速ADCが全画素を逐次処理。
- CMOSではカラムごとにADCを配置(列並列)。
よって1列あたりの処理速度で済み、必要速度は約 (1/M) に低減。
5. まとめ
- 光→電荷→電圧変換は (V = Q/C)。
- CCDは単一高速パイプラインADC方式。
- CMOSは多並列シングルスロープADC方式で、低消費・高並列化。
- 基本関係は全て時間変換式 (t_{conv} = T_{ramp}(V_{in}/V_{ref})) に基づく。
import numpy as np
import matplotlib.pyplot as plt
# ==============================
# 定数 / Constants
# ==============================
q = 1.602e-19 # 電子電荷 [C]
h = 6.626e-34 # プランク定数 [J*s]
c = 3.0e8 # 光速 [m/s]
λ = 550e-9 # 光の波長 [m]
ν = c / λ # 光の周波数 [Hz]
η = 0.6 # 量子効率 (Quantum Efficiency)
C_FD = 10e-15 # フローティング拡散容量 [F]
P_opt = 1e-9 # 入射光パワー [W]
t_int = 10e-3 # 露光時間 [s]
V_ref = 1.0 # 参照電圧 [V]
T_ramp = 10e-6 # ランプ期間 [s]
N_clk = 1024 # クロック数
# ==============================
# 1. 光電変換 / Photoelectric Conversion
# ==============================
N_ph = (η * P_opt * t_int) / (h * ν)
Q_ph = q * N_ph
V_sig = Q_ph / C_FD
print("=== Photoelectric Conversion ===")
print(f"Photon count N_ph = {N_ph:.2e}")
print(f"Generated charge Q_ph = {Q_ph:.2e} [C]")
print(f"Signal voltage V_sig = {V_sig:.3f} [V]")
# ==============================
# 2. 画素読み出しとADC速度要求 / Frame readout speed
# ==============================
M, N = 1000, 1000 # Pixels (1M)
T_frame = 1 / 30 # 30 fps
f_s_CCD = (M * N) / T_frame
f_s_CMOS = N / T_frame
print("\n=== ADC Speed Requirement ===")
print(f"CCD ADC speed ≥ {f_s_CCD/1e6:.1f} Msps")
print(f"CMOS ADC speed ≥ {f_s_CMOS/1e3:.1f} ksps (per column)")
# ==============================
# 3. シングルスロープADC動作 / Single-Slope ADC
# ==============================
S = V_ref / T_ramp
V_in_values = np.linspace(0, V_ref, 5)
t_conv_values = T_ramp * (V_in_values / V_ref)
D_values = N_clk * (V_in_values / V_ref)
print("\n=== Single-Slope ADC ===")
for Vin, tconv, D in zip(V_in_values, t_conv_values, D_values):
print(f"V_in={Vin:.2f} V → t_conv={tconv*1e6:.2f} μs → D={int(D)}")
# ==============================
# 4. 可視化 / Visualization
# ==============================
t = np.linspace(0, T_ramp, 200)
V_ramp = S * t
V_in_demo = 0.7 * V_ref
t_cross = T_ramp * (V_in_demo / V_ref)
plt.figure()
plt.plot(t * 1e6, V_ramp, label="Ramp Voltage V_ramp(t)")
plt.axhline(V_in_demo, color="r", linestyle="--", label="Input Voltage V_in")
plt.axvline(t_cross * 1e6, color="g", linestyle=":", label="t_conv (cross point)")
plt.xlabel("Time [μs]")
plt.ylabel("Voltage [V]")
plt.title("Single-Slope ADC Conversion (Voltage → Time)")
plt.legend()
plt.grid(True)
plt.show()