はじめに
本プログラムでは、OPアンプ設計に必要な基本パラメータ(ゲイン、スルーレート、帯域、電源電圧など)をもとに、
CMOSトランジスタのW/L比、トランスコンダクタンスgm、入力・出力範囲、電圧利得A0などをPythonで簡易計算します。
参考リンクまとめ
Pythonコード
設計条件
| 項目 | 記号 | 値 |
|---|---|---|
| 電源電圧 | ( V_{DD} ) | 3.0 V |
| 利得 | ( A ) | 1000 より大きい |
| 利得帯域幅 | ( \omega_u ) | 200 MHz |
| スルー・レート | ( SR ) | 150 V/μs |
| 負荷容量 | ( C_L ) | 1 pF |
| 入力範囲 | ― | 1.3 ~ 2.5 V |
| 出力範囲 | ― | 0.5 ~ 2.5 V |
下コードは、オペアンプ回路の設計に関連する計算を行うためのものです。具体的には、オペアンプのゲイン、トランジスタの設計、入力・出力電圧範囲の計算、そして利得や周波数特性などのパラメータを求めています。主な内容としては:
- パラメータ設定: 回路設計に必要な基本的な定数やパラメータを設定。
- テール電流 (I₅) の計算: スルーレートに基づいて設計。
- ゲインの計算: 単位利得帯域幅からgm(相互コンダクタンス)を算出。
- W/L 比の設計: トランジスタのW/L比を計算。
- 最小入力電圧の計算: 入力電圧範囲の最小値を求める。
- 高利得のためのgm₆の設定: 高利得回路に対応するgm₆の計算。
- 出力電圧範囲の計算: 出力電圧の最小値と最大値を計算。
- 電圧利得 (A₀) の計算: 出力信号に対する増幅度を計算し、そのdB値を求める。
- 周波数特性の解析: ゼロ点やポール周波数の計算。
from IPython.display import display, Math, Markdown
import numpy as np
# ----------------------------
# パラメータ設定 / Parameter Settings
# ----------------------------
display(Markdown("## 1. パラメータ設定 / Parameter Settings"))
Cc = 0.3e-12 # [F]
SR = 150e6 # [V/s]
Cout = 1e-12 # [F]
VDD = 3.0 # [V]
Vin_max = 2.5 # [V]
Vtn = 0.7 # [V]
beta_n = 200e-6 # [A/V^2]
beta_p = 100e-6 # [A/V^2]
lambda_n = 0.1 # [1/V]
lambda_p = 0.1 # [1/V]
omega_u = 2 * np.pi * 200e6 # [rad/s]
VT = 0.7 # [V]
delta_Vov1 = 0.2 # [V]
# ----------------------------
# 計算1:I5 = SR × Cc
# ----------------------------
display(Markdown("## 2. I₅ の算出:スルーレートによるテール電流の設計"))
display(Math(r"I_5 = SR \times C_C"))
I5 = SR * Cc
print(f"I5 = {I5:.2e} [A]")
# ----------------------------
# 計算2:gm1 = ωu × Cc
# ----------------------------
display(Markdown("## 3. gm₁の算出:単位利得帯域幅から"))
display(Math(r"g_{m1} = \omega_u \cdot C_C"))
gm1 = omega_u * Cc
print(f"gm1 = {gm1:.2e} [S]")
# ----------------------------
# 計算3:M1のW/L
# ----------------------------
display(Markdown("## 4. M₁のW/Lの設計"))
display(Math(r"\left( \frac{W}{L} \right)_1 = \frac{g_{m1}^2}{2 \beta_n I_1}"))
I1 = I5 / 2
WL1 = gm1**2 / (2 * beta_n * I1)
print(f"(W/L)_1 = {WL1:.2f}")
# ----------------------------
# 計算4:Vin_min
# ----------------------------
display(Markdown("## 5. 最小入力電圧 Vin_min の設計"))
display(Math(r"V_{in,\min} = \sqrt{\frac{2 I_3}{\beta_n (W/L)_3}} + V_{tn} + \Delta V_{ov1}"))
WL3 = 2
I3 = I5
Vin_min = np.sqrt(2 * I3 / (beta_n * WL3)) + Vtn + delta_Vov1
print(f"Vin_min = {Vin_min:.2f} [V]")
# ----------------------------
# 計算5:gm6 = 10 × gm1
# ----------------------------
display(Markdown("## 6. gm₆ の設計:高利得のための設定"))
display(Math(r"g_{m6} = 10 \cdot g_{m1}"))
gm6 = 10 * gm1
print(f"gm6 = {gm6:.2e} [S]")
# ----------------------------
# 計算6:M6のW/L
# ----------------------------
display(Markdown("## 7. M₆のW/Lの設計"))
display(Math(r"\left( \frac{W}{L} \right)_6 = \frac{g_{m6}^2}{2 \beta_p I_6}"))
I6 = I5
WL6 = gm6**2 / (2 * beta_p * I6)
print(f"(W/L)_6 = {WL6:.2f}")
# ----------------------------
# 出力電圧範囲
# ----------------------------
display(Markdown("## 8. 出力電圧範囲の計算"))
display(Math(r"V_{out,\min} = V_{DS(sat)7}, \quad V_{out,\max} = V_{DD} - V_{DS(sat)6}"))
WL7_given = 40
VT_sat = np.sqrt(2 * 900e-6 / (2 * beta_p * WL7_given)) # M7 saturation
Vout_min = VT_sat
print(f"Vout_min = {Vout_min:.2f} [V]")
VD6sat = np.sqrt(2 * 900e-6 / (beta_p * WL6)) # M6 saturation
Vout_max = VDD - VD6sat
print(f"Vout_max = {Vout_max:.2f} [V]")
# ----------------------------
# 電圧利得 A0 の計算
# ----------------------------
display(Markdown("## 9. 改良版電圧利得 A₀ の計算"))
display(Math(r"A_0 \approx \left( \frac{g_{m1}}{I_5/2 \cdot \lambda} \right) \left( \frac{g_{m6}}{I_7 \cdot \lambda} \right)"))
gm1_new = 380e-6
gm6_new = 4000e-6
I5_new = 45e-6
I7_new = 900e-6
lambda_sum = lambda_n + lambda_p
A0 = (gm1_new / ((I5_new / 2) * lambda_sum)) * (gm6_new / (I7_new * lambda_sum))
A0_dB = 20 * np.log10(A0)
print(f"Voltage Gain A0 ≈ {A0:.0f} [V/V]")
print(f"Voltage Gain A0_dB ≈ {A0_dB:.2f} [dB]")
# 改良版 A0 計算 / Improved Voltage Gain A0
display(Markdown("## 10. 改良版電圧利得 A₀ の再計算"))
display(Markdown("A₀は差動対と2段目のトランジスタのgm、および出力抵抗に基づいて以下の式で表されます:"))
display(Math(r"A_0 \approx \left( \frac{g_{m1}}{(I_5/2) \cdot \lambda} \right) \left( \frac{g_{m6}}{I_7 \cdot \lambda} \right)"))
gm1_new = 380e-6
gm6_new = 4000e-6
I5_new = 45e-6
I7_new = 900e-6
lambda_sum = lambda_n + lambda_p
A0 = (gm1_new / ((I5_new / 2) * lambda_sum)) * (gm6_new / (I7_new * lambda_sum))
A0_dB = 20 * np.log10(A0)
print("\n=== OP Amp Voltage Gain Calculation ===")
print(f"gm1 = {gm1_new:.2e} [S]")
print(f"gm6 = {gm6_new:.2e} [S]")
print(f"I5 = {I5_new:.2e} [A]")
print(f"I7 = {I7_new:.2e} [A]")
print(f"λn + λp = {lambda_sum:.1f}")
print(f"Voltage Gain A0 ≈ {A0:.0f} [V/V]")
print(f"Voltage Gain A0_dB ≈ {A0_dB:.2f} [dB]")
# 設計式に基づく W/L の設計
display(Markdown("## 11. 設計式 (11.25)-(11.32) に基づくトランジスタ設計"))
display(Math(r"(W/L)_5 = \frac{2 I_5}{\beta_n (V_{in,\min} - V_{tn} - \sqrt{\frac{2 I_1}{\beta_n (W/L)_1}})^2}"))
display(Math(r"(W/L)_6 = \frac{g_{m6}}{g_{m4}} \cdot (W/L)_4"))
display(Math(r"(W/L)_7 = \frac{(W/L)_6 \cdot (W/L)_5}{(W/L)_4}"))
gm4 = 1e-4
WL4 = 2
Vin_min = 1.3
delta_Vov1 = 0.2
term2 = np.sqrt(2 * I1 / (beta_n * WL1))
term1 = Vin_min - Vtn - term2
WL5 = 2 * I5 / (beta_n * term1**2)
WL6 = gm6 / gm4 * WL4
WL7 = WL6 * WL5 / WL4
print("\n=== OP Amp Design: Equations (11.25) to (11.32) ===")
print(f"(W/L)_1 = {round(WL1)}")
print(f"term1 for (W/L)_5 calculation = {term1:.3f}")
print(f"(W/L)_5 = {round(WL5)}")
print(f"gm6 = {gm6:.2e} [S]")
# アスペクト比による再計算
display(Markdown("## 12. アスペクト比による (W/L)_7 の再計算"))
display(Math(r"(W/L)_7 = \left( \frac{(W/L)_6}{(W/L)_4} \right) \div 2 \cdot (W/L)_5"))
WL6 = 80
WL4 = 2
WL5 = 2
WL7 = (WL6 / WL4) / 2 * WL5
print("\n=== Aspect Ratio Calculation for (W/L)_7 ===")
print(f"(W/L)_6 = {WL6}")
print(f"(W/L)_4 = {WL4}")
print(f"(W/L)_5 = {WL5}")
print(f"(W/L)_7 = {WL7:.2f}")
# DCゲインと周波数特性の計算
display(Markdown("## 13. DC利得・ゼロ点・ポール周波数の解析"))
display(Math(r"A_v = g_{m2} \cdot g_{m6} \cdot R_1 \cdot R_2"))
display(Math(r"z = \frac{g_{m6}}{C_C}, \quad p_1 = -\frac{1}{g_{m6} R_1 R_2 C_C}, \quad p_2 = -\frac{g_{m6}}{C_2}"))
R1 = 1e3
R2 = 1e3
gm2 = gm1
C2 = 1e-12
Av = R1 * R2 * gm2 * gm6
z = gm6 / Cc
p1 = -1 / (gm6 * R1 * R2 * Cc)
p2 = -gm6 / C2
print("\n=== DC Gain Calculation ===")
print(f"DC Gain (Av) = {Av:.2f} [V/V]")
print("\n=== Zero Frequency Calculation ===")
print(f"Zero frequency (z) = {z:.2e} [rad/s]")
print("\n=== Pole Frequency p1 Calculation ===")
print(f"First pole (p1) = {p1:.2e} [rad/s]")
print("\n=== Pole Frequency p2 Calculation ===")
print(f"Second pole (p2) = {p2:.2e} [rad/s]")
# ----------------------------
# 消費電流・消費電力
# ----------------------------
I_total = I5 + I6 + I7 # 簡易合計
P_total = VDD * I_total
print(f"Total Current = {I_total:.2e} [A]")
print(f"Power Dissipation = {P_total:.2e} [W]")
# ----------------------------
# 出力スイング幅
# ----------------------------
Vout_swing = Vout_max - Vout_min
print(f"Output Swing = {Vout_swing:.2f} [V]")
# ----------------------------
# 位相余裕の簡易評価
# ----------------------------
PM = 180 - (np.arctan(z/omega_u) + np.arctan(omega_u/abs(p2))) * 180/np.pi
print(f"Phase Margin ≈ {PM:.2f} [deg]")
# ============================================================
# Program Name: two_stage_opamp_numeric_v4.0.py
# Purpose: Full 10^N input & 10^N output OpAmp calculator
# ============================================================
!pip install numpy matplotlib ipywidgets numba
import numpy as np
import matplotlib.pyplot as plt
import ipywidgets as widgets
from numba import njit
from IPython.display import display, clear_output
# ============================================================
# 10^N formatter
# ============================================================
def format_exp(x, unit=""):
if x == 0:
return f"0 {unit}"
exp = int(np.floor(np.log10(abs(x))))
coef = x / (10**exp)
return f"{coef:.3f} × 10^{exp} {unit}"
# ============================================================
# safe float(eval)
# ============================================================
def parse_num(txt):
try:
return float(eval(txt))
except:
raise ValueError(f"Invalid numeric input: {txt}")
# ============================================================
# gm/Id model
# ============================================================
def gm_from_ratio(Id, gm_Id_ratio):
return Id * gm_Id_ratio
@njit
def mos_gds(Id, VA):
return Id / VA
# ============================================================
# AC computation
# ============================================================
def compute_ac(gm1, gm2, gm6, gds2, gds4, gds6, gds7, Cc, CL, ISS):
Av1 = gm1 / (gds2 + gds4)
Av2 = gm6 / (gds6 + gds7)
Av_total = Av1 * Av2
GBW = gm1 / Cc
p1 = - gm1 / (Cc * (gm6 / gds2))
p2 = - gm6 / (CL * (gm2 / gm1))
z1 = gm6 / Cc
SR = ISS / Cc
return Av1, Av2, Av_total, GBW, p1, p2, z1, SR
# ============================================================
# Bode plot
# ============================================================
def bode_plot(A0, p1, p2, z1):
w = np.logspace(1, 8, 500)
jw = 1j * w
A = A0 * (1 - jw/z1) / ((1 + jw/p1)*(1 + jw/p2))
mag = 20 * np.log10(np.abs(A))
phase = np.angle(A, deg=True)
fig, ax = plt.subplots(2,1, figsize=(6,8))
ax[0].semilogx(w, mag)
ax[0].set_ylabel("Magnitude [dB]")
ax[0].grid()
ax[1].semilogx(w, phase)
ax[1].set_ylabel("Phase [deg]")
ax[1].set_xlabel("ω [rad/s]")
ax[1].grid()
plt.show()
# ============================================================
# UI(10^N入力)
# ============================================================
W1 = widgets.Text(value="1e-5", description="W1 [m]")
W3 = widgets.Text(value="2e-5", description="W3 [m]")
W5 = widgets.Text(value="1.2e-5", description="W5 [m]")
W6 = widgets.Text(value="3e-5", description="W6 [m]")
gm_Id = widgets.Text(value="10", description="gm/Id [1/V]")
ISS = widgets.Text(value="1e-4", description="ISS [A]")
Cc = widgets.Text(value="3e-13", description="Cc [F]")
CL = widgets.Text(value="5e-12", description="CL [F]")
button = widgets.Button(description="Calculate")
out = widgets.Output()
# ============================================================
# callback
# ============================================================
def on_calculate(btn):
with out:
clear_output(wait=True)
# ----- parse 10^N inputs -----
p = {}
p["W1"] = parse_num(W1.value)
p["W3"] = parse_num(W3.value)
p["W5"] = parse_num(W5.value)
p["W6"] = parse_num(W6.value)
p["gm_Id"] = parse_num(gm_Id.value)
p["ISS"] = parse_num(ISS.value)
p["Cc"] = parse_num(Cc.value)
p["CL"] = parse_num(CL.value)
p["VA_n"] = 20
p["VA_p"] = 30
# currents
Id1 = p["ISS"]/2
Id2 = Id1
Id6 = Id1 * 10
gm1 = gm_from_ratio(Id1, p["gm_Id"])
gm2 = gm1
gm6 = gm_from_ratio(Id6, p["gm_Id"])
gds2 = mos_gds(Id2, p["VA_n"])
gds4 = mos_gds(Id2, p["VA_p"])
gds6 = mos_gds(Id6, p["VA_n"])
gds7 = mos_gds(Id6, p["VA_p"])
Av1, Av2, Av_total, GBW, p1, p2, z1, SR = compute_ac(
gm1, gm2, gm6, gds2, gds4, gds6, gds7,
p["Cc"], p["CL"], p["ISS"]
)
# ----- output (10^N) -----
print("====== Results (10^N format) ======")
print(f"gm1 = {format_exp(gm1,' S')}")
print(f"gm6 = {format_exp(gm6,' S')}")
print("")
print(f"Av_total = {Av_total:.2f} ({20*np.log10(Av_total):.2f} dB)")
print("")
print(f"GBW = {format_exp(GBW,' Hz')}")
print("")
print(f"p1 = {format_exp(p1,' rad/s')} ({abs(p1)/(2*np.pi):.3f} Hz)")
print(f"p2 = {format_exp(p2,' rad/s')} ({abs(p2)/(2*np.pi):.3f} Hz)")
print("")
print(f"z1 = {format_exp(z1,' rad/s')} ({z1/(2*np.pi):.3f} Hz)")
print("")
print(f"SR = {format_exp(SR,' V/s')} ({SR/1e6:.3f} V/us)")
print("")
bode_plot(Av_total, p1, p2, z1)
button.on_click(on_calculate)
display(W1, W3, W5, W6, gm_Id, ISS, Cc, CL, button, out)
# ============================================================
# Program Name: two_stage_opamp_numeric_v5.0.py
# Purpose: 10^N input + correct A0 physical model
# ============================================================
!pip install numpy matplotlib ipywidgets numba
import numpy as np
import matplotlib.pyplot as plt
import ipywidgets as widgets
from numba import njit
from IPython.display import display, clear_output
# ============================================================
# 10^N formatter
# ============================================================
def format_exp(x, unit=""):
if x == 0:
return f"0 {unit}"
exp = int(np.floor(np.log10(abs(x))))
coef = x / (10**exp)
return f"{coef:.3f} × 10^{exp} {unit}"
# ============================================================
# safe float(eval)
# ============================================================
def parse_num(txt):
try:
return float(eval(txt))
except:
raise ValueError(f"Invalid numeric input: {txt}")
# ============================================================
# gm/Id model
# ============================================================
def gm_from_ratio(Id, gm_Id_ratio):
return Id * gm_Id_ratio
@njit
def mos_gds(Id, VA):
return Id / VA # 1/ro = λ·Id
# ============================================================
# AC computation
# ============================================================
def compute_ac(gm1, gm2, gm6, gds2, gds4, gds6, gds7, Cc, CL, ISS):
# low-frequency gain
Av1 = gm1 / (gds2 + gds4)
Av2 = gm6 / (gds6 + gds7)
Av_total = Av1 * Av2
# GBW
GBW = gm1 / Cc
# dominant pole
p1 = - gm1 / (Cc * (gm6 / gds2))
# second pole
p2 = - gm6 / (CL * (gm2 / gm1))
# RHP zero
z1 = gm6 / Cc
# slew rate
SR = ISS / Cc
return Av1, Av2, Av_total, GBW, p1, p2, z1, SR
# ============================================================
# Correct A0 model (gm·ro model)
# ============================================================
def compute_A0_correct(gm1, gm6, I1, I6, lambda_n, lambda_p):
ro1 = 1 / (lambda_n * I1)
ro6 = 1 / (lambda_p * I6)
A0 = gm1 * ro1 * gm6 * ro6
A0_dB = 20 * np.log10(A0)
return A0, A0_dB
# ============================================================
# Bode Plot
# ============================================================
def bode_plot(A0, p1, p2, z1):
w = np.logspace(1, 8, 500)
jw = 1j * w
A = A0 * (1 - jw/z1) / ((1 + jw/p1)*(1 + jw/p2))
mag = 20 * np.log10(np.abs(A))
phase = np.angle(A, deg=True)
fig, ax = plt.subplots(2,1, figsize=(6,8))
ax[0].semilogx(w, mag)
ax[0].set_ylabel("Magnitude [dB]")
ax[0].grid()
ax[1].semilogx(w, phase)
ax[1].set_ylabel("Phase [deg]")
ax[1].set_xlabel("ω [rad/s]")
ax[1].grid()
plt.show()
# ============================================================
# UI(10^N入力)
# ============================================================
W1 = widgets.Text(value="1e-5", description="W1 [m]")
W3 = widgets.Text(value="2e-5", description="W3 [m]")
W5 = widgets.Text(value="1.2e-5", description="W5 [m]")
W6 = widgets.Text(value="3e-5", description="W6 [m]")
gm_Id = widgets.Text(value="10", description="gm/Id [1/V]")
ISS = widgets.Text(value="1e-4", description="ISS [A]")
Cc = widgets.Text(value="3e-13", description="Cc [F]")
CL = widgets.Text(value="5e-12", description="CL [F]")
lambda_n = widgets.Text(value="0.1", description="λn [1/V]")
lambda_p = widgets.Text(value="0.1", description="λp [1/V]")
button = widgets.Button(description="Calculate")
out = widgets.Output()
# ============================================================
# callback
# ============================================================
def on_calculate(btn):
with out:
clear_output(wait=True)
# ----- parse 10^N inputs -----
p = {}
p["W1"] = parse_num(W1.value)
p["W3"] = parse_num(W3.value)
p["W5"] = parse_num(W5.value)
p["W6"] = parse_num(W6.value)
p["gm_Id"] = parse_num(gm_Id.value)
p["ISS"] = parse_num(ISS.value)
p["Cc"] = parse_num(Cc.value)
p["CL"] = parse_num(CL.value)
p["lambda_n"] = parse_num(lambda_n.value)
p["lambda_p"] = parse_num(lambda_p.value)
p["VA_n"] = 1/p["lambda_n"]
p["VA_p"] = 1/p["lambda_p"]
# currents
Id1 = p["ISS"]/2
Id2 = Id1
Id6 = Id1 * 10
gm1 = gm_from_ratio(Id1, p["gm_Id"])
gm2 = gm1
gm6 = gm_from_ratio(Id6, p["gm_Id"])
gds2 = mos_gds(Id2, p["VA_n"])
gds4 = mos_gds(Id2, p["VA_p"])
gds6 = mos_gds(Id6, p["VA_n"])
gds7 = mos_gds(Id6, p["VA_p"])
Av1, Av2, Av_total, GBW, p1, p2, z1, SR = compute_ac(
gm1, gm2, gm6, gds2, gds4, gds6, gds7,
p["Cc"], p["CL"], p["ISS"]
)
# ----- correct A0 (gm·ro model) -----
A0, A0_dB = compute_A0_correct(
gm1, gm6,
Id1, Id6,
p["lambda_n"], p["lambda_p"]
)
# ----- output -----
print("====== Results (10^N format, v5.0 correct physics) ======")
print(f"gm1 = {format_exp(gm1,' S')}")
print(f"gm6 = {format_exp(gm6,' S')}")
print("")
print(f"Av_total (AC small-signal) = {Av_total:.2f} ({20*np.log10(Av_total):.2f} dB)")
print("")
print(f"GBW = {format_exp(GBW,' Hz')}")
print("")
print(f"Dominant pole p1 = {format_exp(p1,' rad/s')}")
print(f"Second pole p2 = {format_exp(p2,' rad/s')}")
print(f"RHP zero z1 = {format_exp(z1,' rad/s')}")
print("")
print(f"Slew Rate = {format_exp(SR,' V/s')}")
print("")
print("=== Correct DC Gain Model ===")
print(f"DC Gain A0 = {A0:.2e} [V/V]")
print(f"DC Gain A0 (dB) = {A0_dB:.2f} [dB]")
bode_plot(Av_total, p1, p2, z1)
button.on_click(on_calculate)
display(W1, W3, W5, W6, gm_Id, ISS, Cc, CL, lambda_n, lambda_p, button, out)
結果
MOSFET の基本動作説明まとめ
1. 電圧と電流の関係
-
VGS (ゲート–ソース間電圧)
→ MOSFETをONさせる電圧。- NMOS: $V_{GS} > V_{th}$ でチャネル形成(電流が流れる)。
- PMOS: $V_{SG} > |V_{th}|$ でON。
-
VDS (ドレイン–ソース間電圧)
→ MOSFET両端の電圧差。動作領域を決める。- 小さいとき: 線形領域(抵抗のようにふるまう)。
- 大きいとき: 飽和領域(電流源のようにふるまう)。
-
ID (ドレイン電流)
-
線形領域(抵抗的動作)
$$
I_D \approx \mu C_{ox} \frac{W}{L} \big[ (V_{GS}-V_{th}) V_{DS} - \tfrac{1}{2} V_{DS}^2 \big]
$$ -
飽和領域(電流源的動作)
$$
I_D \approx \tfrac{1}{2} \mu C_{ox} \frac{W}{L} (V_{GS}-V_{th})^2
$$
-
2. 抵抗としてのMOSFET
-
小さい VDS で動作する場合、電流はほぼオームの法則に従う。
→ 可変抵抗器として使える。- アナログスイッチ、ボルテージコントロールドレジスタに利用。
3. 電流源としてのMOSFET
-
大きい VDS (飽和領域) では、IDがほぼVDSに依存しなくなる。
→ 理想的な 定電流源 のようにふるまう。- 電流は $V_{GS}$ のみに依存。
- 電流ミラー回路で利用される。
4. MOSFETを使った典型回路要素
-
抵抗の代用
- 小 $V_{DS}$ でバイアス → 可変抵抗として使える。
-
電流源
- 飽和領域にバイアス → 電流一定。
- OPアンプの差動対やミラー回路に利用。
-
増幅素子
- 入力:ゲートに印加する $V_{GS}$
- 出力:ドレイン電流変化 $\Delta I_D$
- 抵抗負荷と組み合わせて電圧増幅器を実現。
5. 図解イメージ(文章版)
- 抵抗的動作
VGS > Vth
VDS 小さい → ID ≈ k (VGS - Vth) * VDS
- 電流源的動作
VGS > Vth
VDS 大きい → ID ≈ (1/2) k (VGS - Vth)^2
一定電流を流す
MOSFET増幅器の条件
1. 増幅器が成り立つ条件
-
MOSFETが飽和領域で動作していることが必須です。
→ 飽和領域では 電流源のようにふるまい、トランスコンダクタンス (gm) が安定するからです。 -
飽和条件は:
$$
V_{DS} \geq V_{GS} - V_{th}
$$
ここで
- $V_{DS}$ : ドレイン–ソース間電圧
- $V_{GS}$ : ゲート–ソース間電圧
- $V_{th}$ : 閾値電圧
2. 入力電圧が 0 のとき
例えば差動増幅器(オペアンプの入力ステージ)の場合:
- 入力が $V_{in+} = V_{in-} = 0$ のとき、両方のMOSFETに同じバイアス電圧がかかる。
- このとき、左右のMOSFETは対称的に 飽和状態で動作して、テール電流が均等に分配される。
- これが バイアス点 (operating point) になります。
→ 増幅はこの「入力0のバイアス点」からの小信号変化に応答して行われます。
3. 増幅器が動かない場合
-
MOSFETが 線形領域 (抵抗動作) に入ると、ドレイン電流が $V_{DS}$ に依存してしまい、
電流源としての性質が失われます。
→ 増幅器としては使えません(非線形・歪み大)。 -
MOSFETが カットオフ (VGS < Vth) の場合も、電流が流れないので増幅はできません。
4. まとめ
- MOSFETを使った増幅器は「すべてのMOSFETが飽和状態」にあるときに正常に動作する。
- 入力電圧 0 は「基準バイアス点」であり、この点を中心に小信号を与えることでリニアな増幅が実現する。
1. W/L の意味
MOSFETの電流式(飽和領域):
$$
I_D = \tfrac{1}{2} \mu C_{ox} \frac{W}{L} (V_{GS}-V_{th})^2
$$
-
W(チャネル幅) を大きくすると ID が大きくなり、gm も大きくなる。 → 高速化・高利得化
-
L(チャネル長) を大きくすると λ(チャネル長変調)が小さくなり、出力抵抗 ro が大きくなる。 → 高ゲイン・低オフセット
-
したがって 2段オペアンプでは:
- 入力差動対(M1, M2) → 大きな gm が欲しい → W/L を大きく
- ミラー負荷やカレントミラー(M3, M4) → 出力抵抗を稼ぐため Lを長めに
- 出力段(M6, M7) → 大電流駆動のため Wを広く
2. マルチフィンガー(Multi-finger)の調整
-
実際のICレイアウトでは、1つの大きなWを持つMOSFETを複数のフィンガーに分割して配置します。
- 例: W = 100 µm, L = 0.5 µm → 10 µm × 10 finger
-
メリット:
- パラジティック容量低減(ゲート抵抗を下げて高速化)。
- マッチング改善(シンメトリ配置で差動入力M1, M2の誤差を小さくできる)。
- レイアウトの柔軟性(広いトランジスタをコンパクトに配置可能)。
3. 2段オペアンプでの調整指針
(1) 第1段(差動入力 M1, M2)
- gm を大きくしたい → Wを大きく、Lは最小寸法に近い値。
- マルチフィンガーにして左右対称配置 → オフセット低減。
(2) ミラー負荷(M3, M4)
- 高い出力抵抗が必要 → Lを長く。
- gm は差動対に比べ小さくてもよい。
- マルチフィンガーはあまり使わず、長いチャネルで安定性を優先。
(3) 第2段(増幅用 M6)
- 大きな gm が必要 → Wをさらに大きく。
- ゼロキャンセルやRHPゼロ対策で Cc と関係。
- マルチフィンガーでゲート容量を分散。
(4) 出力段(M7, M8)
- 電流駆動能力が必要 → Wを広く、マルチフィンガーでIR dropと寄生を低減。
4. 設計上の注意
- W/L比は回路性能を決めるが、レイアウト時はマルチフィンガー配置で寄生とマッチングを制御する。
- 入力差動対 → シンメトリ配置
- カレントミラー → 共通センター配置(common-centroid layout)
- 出力段 → 電流ドライブ重視で多フィンガー化
追加のコード
こちらの計算Pythonコードも載せていきます。
from IPython.display import display, Math, Markdown
import numpy as np
# タイトルと式表示
display(Markdown("## 2段構成 CMOS Op-Amp の各特性式"))
# 数式の表示(省略せず継続)
display(Markdown("### 電圧利得 (Voltage Gain)"))
display(Math(r"A_V = g_{md} \cdot R_{O1} \cdot g_{m6} \cdot R_{O2}"))
display(Markdown("### 利得帯域幅積 (Gain Bandwidth Product)"))
display(Math(r"GBW = \frac{g_{md}}{2\pi C_C}"))
display(Markdown("### 同相分除去比 (Common-Mode Rejection Ratio, CMRR)"))
display(Math(r"CMRR = 2 r_{o5} \cdot g_{m3,4} \cdot g_{md} \cdot R_{O1}"))
display(Markdown("### 出力抵抗 (Output Resistance)"))
display(Math(r"R_O = R_{O2} = r_{o6} \parallel r_{o7}"))
display(Math(r"R_{O1} = r_{o4} \parallel r_{o2}"))
display(Markdown("## 安定動作条件 (Stability Conditions)"))
display(Math(r"g_{m6} = 10 \cdot g_{md}"))
display(Math(r"C_C > 0.22 \cdot C_L"))
display(Markdown("### gm の定義 (Transconductance Definitions)"))
display(Math(r"g_{m6} = \sqrt{2 \beta_6 I_6}"))
display(Math(r"g_{md} = \sqrt{\beta_{1,2} I_{SS}}"))
display(Markdown("### MOSFET 飽和領域での一般式"))
display(Math(r"g_m = \frac{\partial I_D}{\partial V_{GS}} = \sqrt{2 \beta I_D}"))
# ==========================
# 数値計算とプリント
# ==========================
# パラメータ設定
beta_6 = 200e-6 # M6のβ [A/V^2]
I6 = 100e-6 # M6のドレイン電流 [A]
beta_md = 180e-6 # 差動ペアのβ [A/V^2]
ISS = 100e-6 # 差動ペアの電流源 [A]
CC = 1e-12 # 補償容量 [F]
RO1 = 100e3 # 1段目出力抵抗 [Ω]
RO2 = 100e3 # 2段目出力抵抗 [Ω]
# 計算
gm6 = np.sqrt(2 * beta_6 * I6)
gmd = np.sqrt(beta_md * ISS)
GBW = gmd / (2 * np.pi * CC)
Av = gmd * RO1 * gm6 * RO2
Av_dB = 20 * np.log10(Av)
# 結果出力
print("=== 数値計算結果 ===")
print(f"g_m6 = {gm6:.3e} S")
print(f"g_md = {gmd:.3e} S")
print(f"GBW = {GBW:.2e} Hz")
print(f"A_v = {Av:.2e} V/V")
print(f"A_v [dB] = {Av_dB:.2f} dB")
追加のコード2
こちらの計算Pythonコードも載せていきます。
from sympy import symbols, sqrt, Eq, latex
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import display, Math, Markdown
# ------------------------
# シンボル定義 / Define symbols
# ------------------------
C_L, C_c, SR = symbols('C_L C_c SR')
I5, I6 = symbols('I_5 I_6')
V_DD, V_SS = symbols('V_{DD} V_{SS}')
Vin_max, Vin_min = symbols('V_{in(max)} V_{in(min)}')
VT03_max, VT1_min, VT1_max = symbols('V_{T03(max)} V_{T1(min)} V_{T1(max)}')
VDS5_sat = symbols('V_{DS5(sat)}')
g_m1, g_m2, g_m3, g_m4, g_m6 = symbols('g_{m1} g_{m2} g_{m3} g_{m4} g_{m6}')
K1, K3, K5, K6 = symbols('K_1 K_3 K_5 K_6')
S1, S2, S3, S4, S5, S6, S7 = symbols('S_1 S_2 S_3 S_4 S_5 S_6 S_7')
lambda2, lambda4, lambda6, lambda7 = symbols('\\lambda_2 \\lambda_4 \\lambda_6 \\lambda_7')
Av = symbols('A_v')
P_diss = symbols('P_{diss}')
b1, b3 = symbols('b_1 b_3')
GB = symbols('GB')
# ------------------------
# Step表示関数 / Function to display steps
# ------------------------
def step(title, equation):
# ステップのタイトルと式を表示する関数 / Function to display title and equation
display(Markdown(f"### {title}"))
display(Math(latex(equation)))
# ------------------------
# シンボリックな式の表示 / Display symbolic expressions step-by-step
# ------------------------
step("Step 1: Compensation Capacitor Condition", Eq(C_c, 0.22 * C_L))
step("Step 2: Tail Current", Eq(I5, SR * C_c))
denom3 = (V_DD - Vin_max - abs(VT03_max) + VT1_min)**2
step("Step 3: S₃ from Input Maximum Voltage", Eq(S3, I5 / (K3 * denom3)))
step("Step 4: Ensure M₃ Pole is Non-Dominant", Eq(g_m3 / (2 * symbols('C_{gs3}')), 10 * GB))
step("Step 5: S₂ from gₘ₁ and I₅", Eq(S2, g_m1**2 / (K1 * I5)))
VDS_expr = Vin_min - V_SS - sqrt(I5 / b1) - VT1_max
step("Step 6-1: V_{DS5(sat)}", Eq(VDS5_sat, VDS_expr))
step("Step 6-2: S₅ from V_{DS5(sat)}", Eq(S5, 2 * I5 / (K5 * VDS5_sat**2)))
step("Step 7-1: gₘ₆ for Phase Margin", Eq(g_m6, 2.2 * g_m2 * (C_L / C_c)))
step("Step 7-2: S₆ from gₘ₆ and S₄", Eq(S6, (g_m6 / g_m4) * S4))
step("Step 8: I₆ Calculation", Eq(I6, g_m6**2 / (2 * K6 * S6)))
step("Step 9: S₇ from Current Ratio", Eq(S7, (I6 / I5) * S5))
gain_denom = I5 * (lambda2 + lambda4) * I6 * (lambda6 + lambda7)
step("Step 10-1: Voltage Gain", Eq(Av, 2 * g_m2 * g_m6 / gain_denom))
step("Step 10-2: Power Dissipation", Eq(P_diss, (I5 + I6) * (V_DD + abs(V_SS))))
Vin_max_expr = V_DD - sqrt(I5 / b3) - abs(VT03_max) - VT1_min
Vin_min_expr = V_SS + sqrt(I5 / b1) + VT1_max + VDS5_sat
step("ICMR Maximum", Eq(Vin_max, Vin_max_expr))
step("ICMR Minimum", Eq(Vin_min, Vin_min_expr))
step("Balance Condition for M4 Saturation", Eq(S6 / S4, 2 * S7 / S5))
# ------------------------
# 数値計算 / Numerical Calculations
# ------------------------
# 数値パラメータの定義 / Define numerical values for the parameters
values = {
C_L: 10e-12, # Load capacitance (F) / 負荷容量
SR: 1e6, # Slew rate (V/s) / スルーレート
V_DD: 5, # Positive supply voltage (V) / 正の電源電圧
V_SS: -5, # Negative supply voltage (V) / 負の電源電圧
VT03_max: -1, # Maximum threshold voltage for VT03 (V) / VT03の最大閾値
VT1_min: 0.7, # Minimum threshold voltage for VT1 (V) / VT1の最小閾値
VT1_max: 1, # Maximum threshold voltage for VT1 (V) / VT1の最大閾値
b1: 1e-3, # Parameter b1 / パラメータ b1
b3: 1e-3, # Parameter b3 / パラメータ b3
g_m1: 2e-3, # Transconductance of M1 (S) / M1のトランスコンダクタンス
g_m2: 2e-3, # Transconductance of M2 (S) / M2のトランスコンダクタンス
g_m3: 2e-3, # Transconductance of M3 (S) / M3のトランスコンダクタンス
g_m4: 2e-3, # Transconductance of M4 (S) / M4のトランスコンダクタンス
K1: 1, # Constant K1 / 定数 K1
K3: 1, # Constant K3 / 定数 K3
K5: 1, # Constant K5 / 定数 K5
K6: 1, # Constant K6 / 定数 K6
S4: 1, # S₄ value (assumed) / 仮定されたS₄の値
lambda2: 1, # Parameter lambda2 / パラメータ lambda2
lambda4: 1, # Parameter lambda4 / パラメータ lambda4
lambda6: 1, # Parameter lambda6 / パラメータ lambda6
lambda7: 1, # Parameter lambda7 / パラメータ lambda7
VDS5_sat: 0.2 # Given V_{DS5(sat)} (V) / 指定されたV_{DS5(sat)}
}
# ------------------------
# 各式の数値評価 / Evaluate each expression numerically
# ------------------------
# Step 1: Compensation Capacitor / 補償用コンデンサ
C_c_val = (0.22 * values[C_L])
# Step 2: Tail Current / テール電流
I5_val = values[SR] * C_c_val
# ICMRの評価 / Evaluate ICMR expressions:
# ICMR Maximum: Vin_max = V_DD - sqrt(I5/b3) - abs(VT03_max) - VT1_min
Vin_max_val = values[V_DD] - np.sqrt(I5_val/values[b3]) - abs(values[VT03_max]) - values[VT1_min]
# ICMR Minimum: Vin_min = V_SS + sqrt(I5/b1) + VT1_max + VDS5_sat
Vin_min_val = values[V_SS] + np.sqrt(I5_val/values[b1]) + values[VT1_max] + values[VDS5_sat]
# Denom3 for S₃ calculation: (sqrt(I5/b3) + 2*VT1_min)^2 / S₃の分母計算
denom3_val = (np.sqrt(I5_val/values[b3]) + 2*values[VT1_min])**2
# Step 3: S₃ from Input Maximum Voltage / 入力最大電圧からS₃を計算
S3_val = I5_val / (values[K3] * denom3_val)
# Step 5: S₂ from gₘ₁ and I₅ / gₘ₁とI₅からS₂を計算
S2_val = values[g_m1]**2 / (values[K1] * I5_val)
# Step 6-2: S₅ from V_DS5(sat) / V_{DS5(sat)}からS₅を計算
S5_val = 2 * I5_val / (values[K5] * values[VDS5_sat]**2)
# Step 7-1: gₘ₆ for Phase Margin / 位相余裕のためのgₘ₆を計算
g_m6_val = 2.2 * values[g_m2] * (values[C_L] / C_c_val)
# Note: This simplifies to 10*g_m2 because C_c = 0.22*C_L / 注: C_c = 0.22*C_L のため、10*g_m2に簡略化
# Step 7-2: S₆ from gₘ₆ and S₄ / gₘ₆とS₄からS₆を計算
S6_val = (g_m6_val / values[g_m4]) * values[S4]
# Step 8: I₆ Calculation / I₆を計算
I6_val = g_m6_val**2 / (2 * values[K6] * S6_val)
# Step 9: S₇ from Current Ratio / 電流比からS₇を計算
S7_val = (I6_val / I5_val) * S5_val
# Step 10-1: Voltage Gain / 電圧利得を計算
Av_val = 2 * values[g_m2] * g_m6_val / (I5_val * (values[lambda2] + values[lambda4]) * I6_val * (values[lambda6] + values[lambda7]))
# Step 10-2: Power Dissipation / 消費電力を計算
P_diss_val = (I5_val + I6_val) * (values[V_DD] + abs(values[V_SS]))
# ------------------------
# 数値結果の表示 / Print numerical results
# ------------------------
print("\n### Numerical Calculated Values / 数値計算結果")
print(f"Compensation Capacitor (C_c): {C_c_val:.3e} F")
print(f"Tail Current (I5): {I5_val:.3e} A")
print(f"ICMR Maximum (Vin_max): {Vin_max_val:.3f} V")
print(f"ICMR Minimum (Vin_min): {Vin_min_val:.3f} V")
print(f"S₃ from Input Maximum Voltage: {S3_val:.3e}")
print(f"S₂ from gₘ₁ and I5: {S2_val:.3f}")
print(f"S₅ from V_DS5(sat): {S5_val:.3e}")
print(f"gₘ₆ for Phase Margin: {g_m6_val:.3e} S")
print(f"S₆ from gₘ₆ and S₄: {S6_val:.3f}")
print(f"I₆ Calculation: {I6_val:.3e} A")
print(f"S₇ from Current Ratio: {S7_val:.3e}")
print(f"Voltage Gain (A_v): {Av_val:.3e}")
print(f"Power Dissipation (P_diss): {P_diss_val:.3e} W")
# ------------------------
# バランス条件のチェック / Check balance condition for M4 saturation
# ------------------------
balance_LHS = S6_val / values[S4]
balance_RHS = 2 * S7_val / S5_val
print(f"\nBalance Condition (S6/S4): {balance_LHS:.3f}")
print(f"Balance Condition (2*S7/S5): {balance_RHS:.3f}")
結果
実践
「実際のSPICEシミュレーションとの比較を求める意見を受けて、この動画を参考にしながら考察と計算を進めていきたいと思います。基本はCMOSアナログ回路入門(谷口本)と同じです。
計手順①】スルーレートSRからバイアス電流 $I_5$ を決定する
目的:
出力段トランジスタ(M5)が**一定以上のスルーレート(立ち上がり速度)**を保証するために、必要な電流 $I_5$ を決める。
式:
$$
SR = \frac{I_5}{C_L} \Rightarrow I_5 = SR \cdot C_L
$$
- $SR$:スルーレート [V/μs]
- $C_L$:負荷容量 [F]
- $I_5$:出力段の電流
数値代入:
$$
I_5 = 1,\text{V}/\mu\text{s} \times 5,\text{pF} = 5,\mu\text{A}
$$
さらに消費電力制約:
$$
P_{\text{bias}} = V_{DD} \cdot I_5 \leq 1,\text{mW}
\Rightarrow I_5 \leq \frac{1,\text{mW}}{1.8,\text{V}} = 278,\mu\text{A}
$$
結論:
設計的に余裕をもたせて「100μAを選定」
【設計手順②】帯域幅 $f_{-3dB}$ から負荷抵抗 $R_{\text{out}}$ を決定
目的:
出力帯域が仕様(100kHz)になるように、出力インピーダンス(M4のドレイン)を決める。
式:
$$
f_{-3dB} = \frac{1}{2\pi R_{\text{out}} C_L} \Rightarrow
R_{\text{out}} = \frac{1}{2\pi f_{-3dB} C_L}
$$
$$
R_{\text{out}} = \frac{1}{2\pi \cdot 10^5 \cdot 5 \times 10^{-12}} \approx 318,\text{k}\Omega
$$
実際のMOS回路に適用:
$$
R_{\text{out}} = \left(1 + \frac{1}{A_{vA}} \right) \cdot \frac{1}{g_{ds4}}
$$
- $A_{vA}$:M4の出力抵抗を増幅する効果
- $g_{ds4}$:M4のドレイン-ソースコンダクタンス
使うパラメータ(例):
- $\mu C_{ox} = 220,\mu\text{A}/\text{V}^2$
- $V_{TN} = 0.45,\text{V}$
- $V_{AN} = 2.7,\text{V}$
- $I_{D} = 50,\mu\text{A}$
- $W/L = 24/0.24 = 100$
【設計手順③】VIC(max) から M3 の W/L 比を決定
目的:
差動対M1が飽和動作するために、入力共通モード最大値 $V_{IC(\max)}$ に対して、M3のゲート電圧が制限内になるようにする。
飽和条件:
$$
V_{IC(\max)} = V_{DD} - V_{SG3} + V_{TN}
\Rightarrow V_{SG3} \leq V_{DD} - V_{IC(\max)} + V_{TN}
$$
数値代入:
$$
V_{SG3} \leq 1.8 - 0.4 + 0.45 = 0.95,\text{V}
\Rightarrow V_{SG3} = 0.7,\text{V} \text{(仮定)}
$$
P24の式から:
$$
V_{GS} = \sqrt{ \frac{2 \cdot I_{D5}}{\mu C_{ox}} \cdot \left(1 + \frac{V_{DS}}{V_A} \right) } + V_T
$$
W3/L3 の式導出:
$$
V_{SG3} = 0.7 = \sqrt{ \frac{2 \cdot 50\mu}{220\mu} \cdot \left( \frac{W_3}{L_3} \right) \cdot \left( 1 + \frac{0.7}{5.3} \right) } + 0.45
\Rightarrow \frac{W_3}{L_3} = 19.9
$$
設計手順
4)$A_v$ から $\frac{W_1}{L_1}$ または $\frac{W_2}{L_2}$ を求める
$$
32V/\sqrt{V(30,\text{dB})} = g_{m1} R_{\text{out}} = \frac{g_{m1}}{g_{ds2} + g_{ds4}}
$$
$$
= \frac{\sqrt{2 \mu C_{ox} \frac{W_1}{L_1} I_D} \left(1 + \frac{V_{DS}}{V_A} \right)}{(1/V_{A2} + 1/V_{A4}) I_D}
$$
$$
= \frac{\sqrt{2 \cdot 200,\mu A/V^2 \cdot \frac{W_1}{L_1} \cdot 50,\mu A} \left(1 + \frac{0.6}{27.4} \right)}{(1/30 + 1/20) \cdot 50,\mu A}
$$
$$
\approx 5.9 \cdot \sqrt{\frac{W_1}{L_1}} \Rightarrow \frac{W_1}{L_1} = \frac{W_2}{L_2} = 28.7
$$
設計手順
5)$V_{IC(min)}$ から $\frac{W_5}{L_5}$ を求める
M1 が動作するための条件式:
$$
V_{DS5(sat)} = V_{IC(min)} - V_{SS} - V_{GS1}
$$
$$
= -0.4 + 0.9 - \sqrt{\frac{2 \cdot 50,\mu A}{220,\mu A/V^2 \cdot 28.7 \cdot (1 + \frac{0.6}{27.4})}} < 0.39
$$
∴ $V_{DS5(sat)} = 0.25,\text{V}$ を採用
M5 のパラメータ設定:
$$
V_{DS} = 0.25,\text{V}, \quad I_D = 100,\mu A, \quad L = 0.5,\mu m, \quad V_{eff} = 0.2,\text{V}
$$
$$
V_A = 6.9,\text{V}, \quad V_T = 0.46,\text{V}, \quad \mu C_{ox} = 220,\mu A/V^2
$$
しきい値式(スライド内右下 P24より)を用いて:
$$
\frac{W_5}{L_5} = \frac{2 \cdot 100,\mu A}{220,\mu A/V^2 \cdot (0.2)^2} \cdot \left(1 + \frac{0.25}{6.9} \right) \approx 21.9
$$
設計手順
6)R と M5, M8 の $L, W$ を求める
M1(M2) の $V_{eff} = 0.2,\text{V}$
M5 と M8 の $V_{GS} = V_{DS} = 0.7,\text{V}$
$$
R = \frac{V_{DD} - V_{GS}}{I} = \frac{1.8 - 0.7}{100,\mu A} = 11,k\Omega
$$
電流:$I = 100,\mu A$
$$
V_{GS} = V_{DS} = 0.7,\text{V} \Rightarrow V_{eff} = 0.25,\text{V}
$$
$$
\frac{W_5}{L_5} \approx 21.9 \Rightarrow L = 0.5,\mu m \Rightarrow W = 11.0,\mu m
$$
結論
M5, M8 のトランジスタのサイズは:
$$
L = 0.5,\mu m, \quad W = 11.0,\mu m
$$
【2段構成の演算増幅器の設計例】
差動増幅回路 + ソース接地増幅回路 + 位相補償
【仕様】
- 電源電圧:3V
- 利得 $A_v$:60dB
- 位相余裕:60度
- 利得帯域幅積 GB:50MHz
- スルーレート SR:5V/μs
- 同相入力範囲 CMR:-0.7V~1V
- 出力電圧範囲:-1.1V~0.9V
- 消費電力 $P_{bias}$:1mW
【条件】
- $g_{m1} = g_{m2} = g_m1$
- $g_{ds2} + g_{ds4} = g_{o1}$
- $g_{ds6} + g_{ds7} = g_{o2}$
【解析式まとめ】
この回路の解析結果(青枠内)
-
Common-mode Range (CMR)
-
Positive:
$$
V_{in(max)} = V_{DD} - \sqrt{\frac{2 I_5}{\beta_3}} - |V_{T3}| + V_{TN}
$$ -
Negative:
$$
V_{in(min)} = V_{SS} - \sqrt{\frac{2 I_5}{\beta_1}} + |V_{T1}| + V_{DS5(\text{sat})}
$$
-
-
利得
$$
A_{v1} = \frac{-g_{m1}}{g_{ds2} + g_{ds4}} = \frac{-2g_{m1}}{I_5(1/V_{A2} + 1/V_{A4})}
$$$$
A_{v2} = \frac{-g_{m6}}{g_{ds6} + g_{ds7}} = \frac{-g_{m6}}{I_6(1/V_{A6} + 1/V_{A7})}
$$ -
スルーレートとGB
$$
SR = \frac{I_5}{C_c}, \quad GB = \frac{g_{m1}}{C_c}
$$ -
零点(RHP zero)
$$
RHP , zero, z_1 = \frac{g_{m6}}{C_c}
$$
【補償容量の決定】
位相補償容量を挿入
-
ミラー効果により Q1 ノードに
$$
\left(1 + \frac{g_{m6}}{g_{o2}}\right) C_c \approx \left(\frac{g_{m6}}{g_{o2}}\right) C_c
$$の容量が等価的に付加される
→ 1st pole $p_1$ が決まる -
高周波では $C_c$ のインピーダンスが低下し、M6 がダイオード接続とみなされる
→ Qノードから 2nd pole $p_2$ が決まる -
さらに高周波ではミラー効果による近似が成り立たなくなり、$C_c$ によるゼロ点が生成される
【極とゼロの周波数配置と位相余裕】
極とゼロの配置式
-
$p_1 = \frac{-g_{o1} \cdot g_{o2}}{g_{m6} C_c}$
-
$p_2 = \frac{-g_{m6}}{C_L}$
-
RHPゼロ:
$$
z_1 = \frac{g_{m6}}{C_c}
$$ -
GB:
$$
GB = \frac{g_{m1}}{C_c}
$$
設計指針
-
このゼロ点と $p_2$ と GB の位置で位相余裕が決まる
- $z_1 > 10GB$ かつ位相余裕45度:$|p_2| \geq 1.22GB$
- $z_1 > 10GB$ かつ位相余裕60度:$|p_2| \geq 2.2GB$
2段構成の演算増幅器の設計例
補償容量の決定
-
ゼロ点制約:
$$
z_1 > 10 GB より \frac{g_{m6}}{C_c} > 10 \cdot \frac{g_{m1}}{C_c} \Rightarrow g_{m6} > 10 g_{m1}
$$ -
極制約:
$$
|p_2| \geq 2.2 GB より \frac{g_{m6}}{C_L} > 2.2 \cdot \frac{g_{m1}}{C_c}
\Rightarrow C_c > \frac{2.2 C_L}{10} = 0.22 C_L
$$ -
今回 $C_L$ は負荷として用いないので出力端子に付く寄生容量の値を仮定する:
$$
C_L = 1 \text{pF} として, \quad C_c = 0.3 \text{pF}
$$
2段構成の演算増幅器の設計例
M5のドレイン電流の決定
-
M5のドレイン電流はスルーレートから決まる:
$$
SR = \frac{I_5}{C_c} より
$$$$
I_5 \geq SR \times C_c = 5,\text{V}/\mu\text{s} \times 0.3,\text{pF} = 1.5,\mu\text{A}
\Rightarrow I_5 = 25,\mu\text{A} とする
$$ -
[tips]
もしスルーレートが分からない場合は、セトリングタイム10倍程度で代用する
SRはなぜ $I_5/C_c$ となるのか? → Appendix に説明あり
2段構成の演算増幅器の設計例
M3(M4)のW/Lの決定
- M3のW/Lは同相入力範囲の正側から決まる:
$$
\text{Positive CMR} \quad V_{\text{in(max)}} = V_{DD} - \sqrt{\frac{I_5}{\beta_3}} - |V_{T3}| + V_{T1}
$$
$$
= 1.5,\text{V} - \sqrt{\frac{25,\mu\text{A}}{60,\mu\text{A}/\text{V}^2 \cdot \frac{W_3}{L_3}}} - 0.4 + 0.4 = 1.0,\text{V}
$$
$$
\Rightarrow \frac{W_3}{L_3} = \frac{W_4}{L_4} = 1.6
$$
- [tips]
ここで、大きすぎたり小さすぎる値になったら変更して調整する
これが成り立たず $L_3 = L_1$ しかない理由
おおまかな設計ではゲート容量を大きくして位相補償に影響を与える
2段構成の演算増幅器の設計例
M1(M2)のW/Lの決定
- M1のW/Lは利得帯域積から決まる:
$$
GB = \frac{g_{m1}}{C_c} \Rightarrow g_{m1} = GB \times C_c
$$
$$
g_{m1} = \sqrt{2\mu C_{ox} \frac{W_1}{L_1} I_D} \Rightarrow \frac{W_1}{L_1} = \frac{g_{m1}^2}{2\mu C_{ox} I_D}
$$
$$
= \frac{(50 \times 10^6 \cdot 2\pi \cdot 0.3 \times 10^{-12})^2}{2 \cdot 220 \times 10^{-6} \cdot 12.5 \times 10^{-6}} \Rightarrow \frac{W_1}{L_1} = \frac{W_2}{L_2} \approx 1.6
$$
2段構成の演算増幅器の設計例
差動増幅回路 + カレントミラーによる負荷
M5のW/Lの決定
M5 の W/L は同相入力範囲の負側から決まる
Negative CMR
$$
V_{in(min)} = V_{SS} - \sqrt{\frac{I_5}{\beta_1}} + |V_{T1}| + V_{DS5(sat)}
$$
$$
V_{DS5} = V_{in(min)} - V_{SS} - \sqrt{\frac{I_5}{\beta_1}} - |V_{T1}|
$$
$$
= (-0.7) - (-1.5) - \sqrt{\frac{25 \times 10^{-6}}{220 \times 10^{-6} \cdot 1.6}} - 0.4 = 0.13,\text{V}
$$
よって:
$$
\frac{W_5}{L_5} = \frac{2 I_5}{\mu C_{ox} V_{DS5}} = \frac{2 \cdot 25 \times 10^{-6}}{220 \times 10^{-6} \cdot (0.13)^2} \simeq 13.5
$$
M6 の W/L の決定
M6 の W/L は位相余裕の条件から決まる
- ここで電位を揃える:$V_{SC4} = V_{SG6}$
$$
g_m = \mu C_{ox} \frac{W}{L} (V_{GS} - V_T)
\Rightarrow \frac{W_6}{L_6} = \frac{W_4}{L_4} \cdot \frac{g_{m6}}{g_{m4}}
$$
- 条件:
$$
\frac{g_{m6}}{C_c} > 10 \cdot \frac{g_{m2}}{C_c}
\Rightarrow g_{m6} > 10 \cdot g_{m1} = 10 \cdot 94.25,\mu A = 942.5,\mu A
$$
$$
g_{m4} \simeq 49.0,\mu A
\Rightarrow \frac{W_6}{L_6} = \frac{1.6 \cdot 942.5}{49.0} \simeq 30.8
$$
$$
I_6 = \frac{g_{m6}^2}{2 \mu C_{ox}} \cdot \frac{L_6}{W_6} = \frac{(942.5 \times 10^{-6})^2}{2 \cdot 60 \times 10^{-6}} \cdot \frac{1.6}{30.8} \simeq 241,\mu A
$$
出力電圧範囲(最大値)の確認
$$
V_{DS(sat)} = \sqrt{\frac{2 I_D}{\beta}} \quad (I_6 \simeq 241,\mu A)
$$
$$
V_{DS6(sat)} = \sqrt{\frac{2 \cdot 241,\mu A}{60,\mu A/V^2 \cdot 30.8}} \simeq 0.51,\text{V}
\Rightarrow \text{満たしている}
$$
M7のW/Lの決定と出力電圧範囲(最小値)の確認
M7 の W/L はM6も電流とM5の電流から決まる
$$
\frac{W_7}{L_7} = \frac{W_5}{L_5} \cdot \frac{I_6}{I_5} = 13.5 \cdot \frac{241,\mu A}{25,\mu A} \simeq 130
$$
$$
V_{DS7(sat)} = \sqrt{\frac{2 \cdot 241,\mu A}{220,\mu A/V^2 \cdot 130}} \simeq 0.13
\Rightarrow \text{満たしている}
$$
Rの決定
M5のV_{DS5}は0.13V
$$
V_{GS5} = V_{DS5} = V_{GSS} = V_{DSS} = 0.13,\text{V}
$$
$$
R = \frac{2.87,\text{V}}{25,\mu A} = 114.8,\text{k}\Omega \simeq 115,\text{k}\Omega
$$
消費電力と利得の確認
$$
P_{diss} = 3,\text{V} \times (25,\mu A + 242,\mu A) \simeq 0.798,\text{mW}
$$
利得:
$$
A_{v1} = \frac{-g_{m1}}{g_{ds2} + g_{ds4}} = \frac{-2 g_{m1}}{(1/V_{A2} + 1/V_{A4}) I_5}
$$
$$
A_{v2} = \frac{-g_{m6}}{g_{ds6} + g_{ds7}} = \frac{-g_{m6}}{(1/V_{A6} + 1/V_{A7}) I_6}
$$
$$
= \frac{2 \cdot 94.25 \times 10^{-6} \cdot 942.5 \times 10^{-6}}{(1/20 + 1/30) \cdot 25 \times 10^{-6} \cdot (1/20 + 1/30) \cdot 242 \times 10^{-6}} = 4246 \Rightarrow 73,\text{dB}
$$
2段構成の演算増幅器の設計例
差動増幅回路 + ソース接地増幅回路 + 位相補償
図中の等式:
- $\beta = \mu C_{ox} \cdot \frac{W}{L}$
- $V_{GS} = \sqrt{\frac{2I_D}{\beta}} + V_T$
- $V_D > V_G - V_T$
- $V_{DS(\text{sat})} = \sqrt{\frac{2I_D}{\beta}}$
この回路の解析結果:
Common-Mode Range(CMR)
- Positive CMR:
$$
V_{in(\text{max})} = V_{DD} - \sqrt{\frac{I_5}{\beta_3}} - |V_{T3}| + V_{T1}
$$
- Negative CMR:
$$
V_{in(\text{min})} = V_{SS} - \sqrt{\frac{I_5}{\beta_1}} + |V_{T1}| + V_{DS5(\text{sat})}
$$
利得(Gain)
- 第1段の利得 $A_{v1}$:
$$
A_{v1} = \frac{-g_{m1}}{g_{ds2} + g_{ds4}} = \frac{-2g_{m1}}{(1/V_{A2} + 1/V_{A4}) I_5}
$$
- 第2段の利得 $A_{v2}$:
$$
A_{v2} = \frac{-g_{m6}}{g_{ds6} + g_{ds7}} = \frac{-g_{m6}}{(1/V_{A6} + 1/V_{A7}) I_6}
$$
その他のパラメータ
- スルーレート(Slew Rate):
$$
SR = \frac{I_5}{C_c}
$$
- 利得帯域積(GB, Gain Bandwidth):
$$
GB = \frac{g_{m1}}{C_c}
$$
周波数特性(ポール・ゼロ)
- 第1ポール:
$$
p_1 \simeq \frac{-g_{o1} \cdot g_{o2}}{g_{m6} C_c}
$$
- 第2ポール:
$$
p_2 = \frac{-g_{m6}}{C_L}
$$
- RHP(右半平面)ゼロ:
$$
z_1 = \frac{g_{m6}}{C_c}
$$
# Program Name: opamp_design_calc.py
# Creation Date: 20250809
# Overview: Design calculation script for 2-stage operational amplifier
# Usage: Run this script to compute key transistor parameters for a 2-stage op-amp
# 必要なライブラリのインストール
!pip install numpy
import numpy as np
# ----------------------------
# 各種パラメータ(定数)定義
# ----------------------------
# スルーレート [V/μs]
SR = 5 # [V/μs]
# 負荷容量 [F]
C_c = 0.3e-12 # [F]
C_L = 1e-12 # [F]
# 消費電力制約 [W], 電源電圧 [V]
P_bias = 1e-3 # [W]
V_DD = 3.0 # [V]
# トランジスタ定数
mu_Cox = 220e-6 # [A/V^2]
V_TN = 0.45 # [V]
V_AN = 2.7 # [V]
I_D = 50e-6 # [A]
V_eff = 0.2 # [V]
L_5 = 0.5e-6 # [m]
W_by_L_guess = 1.6
# ----------------------------
# 計算1:I5の決定 (スルーレートより)
# ----------------------------
# 日本語:SR = I5 / Cc より I5 = SR * Cc
# English: From SR = I5 / Cc, calculate I5
I5 = SR * C_c # [A]
# 消費電力制約での最大 I5
I5_max = P_bias / V_DD
# 設計的に余裕をもって選定
I5_selected = 25e-6 # [A]
# ----------------------------
# 計算2:GBよりgm1を計算 → W1/L1
# ----------------------------
# GB = gm1 / Cc → gm1 = GB * Cc
GB = 50e6 # [Hz]
gm1 = GB * C_c # [S]
# gm1 = sqrt(2 * mu_Cox * W/L * ID) より W/Lを解く
W_by_L_1 = gm1**2 / (2 * mu_Cox * I_D)
# ----------------------------
# 計算3:出力段 M5 のW/L
# ----------------------------
# V_DS = 0.13 V より
V_DS5 = 0.13 # [V]
W_by_L_5 = 2 * I5_selected / (mu_Cox * V_DS5**2)
# ----------------------------
# 計算4:M6のgm, W/L, I6計算 (RHPゼロより)
# ----------------------------
gm6 = 10 * gm1
gm4 = 49e-6
W_by_L_6 = W_by_L_guess * gm6 / gm4
I6 = gm6**2 / (2 * mu_Cox) * (1 / W_by_L_6)
# ----------------------------
# 計算5:出力スイング制限 V_DS6
# ----------------------------
V_DS6 = np.sqrt(2 * I6 / (mu_Cox * W_by_L_6))
# ----------------------------
# 計算6:M7 の W/L
# ----------------------------
W_by_L_7 = W_by_L_5 * (I6 / I5_selected)
V_DS7 = np.sqrt(2 * I6 / (mu_Cox * W_by_L_7))
# ----------------------------
# 計算7:抵抗 R の決定
# ----------------------------
V_GS5 = V_DS5
R_load = (V_DD - V_GS5) / I5_selected
# ----------------------------
# 結果出力
# ----------------------------
print(f"I5 (from SR): {I5*1e6:.2f} μA")
print(f"I5 selected: {I5_selected*1e6:.2f} μA")
print(f"gm1 (from GB): {gm1*1e6:.2f} μS")
print(f"W1/L1: {W_by_L_1:.2f}")
print(f"W5/L5: {W_by_L_5:.2f}")
print(f"W6/L6: {W_by_L_6:.2f}")
print(f"I6: {I6*1e6:.2f} μA")
print(f"V_DS6(sat): {V_DS6:.2f} V")
print(f"W7/L7: {W_by_L_7:.2f}")
print(f"V_DS7(sat): {V_DS7:.2f} V")
print(f"R_load: {R_load/1e3:.2f} kΩ")
# Program Name: two_stage_opamp_fullcalc.py
# Creation Date: 20250923
# Overview: Full 2-stage op-amp design including transistor sizing, gm, GB, SR, gain, and power check
# Usage: Run this script in Python to compute W/L, gm, SR, GB, Av(dB), and power dissipation
!pip install numpy
import numpy as np
# ----------------------------
# Parameters
# ----------------------------
# Supply
V_DD = 3.0 # [V]
P_bias = 1e-3 # [W]
# Slew Rate and Capacitors
SR = 5 # [V/us]
C_c = 0.3e-12 # [F]
C_L = 1e-12 # [F]
# MOS parameters
mu_Cox = 220e-6 # [A/V^2]
V_TN = 0.45 # [V]
V_AN = 2.7 # [V]
# Bias assumptions
I_D = 50e-6 # [A]
V_DS5 = 0.13 # [V]
W_by_L_guess = 1.6
GB = 50e6 # [Hz]
# ----------------------------
# Step1: I5 calculation (from SR and power constraint)
# ----------------------------
I5_from_SR = SR * 1e6 * C_c # [A], SR unit conversion: V/us → V/s
I5_max = P_bias / V_DD
I5_selected = 25e-6 # [A], design choice
# ----------------------------
# Step2: gm1 and W/L1 (from GB)
# ----------------------------
gm1 = GB * C_c
W_by_L_1 = gm1**2 / (2 * mu_Cox * I_D)
# ----------------------------
# Step3: Output stage M5 sizing
# ----------------------------
W_by_L_5 = 2 * I5_selected / (mu_Cox * V_DS5**2)
# ----------------------------
# Step4: M6 sizing (RHP zero + gm6 > 10 gm1)
# ----------------------------
gm6 = 10 * gm1
gm4 = 49e-6
W_by_L_6 = W_by_L_guess * gm6 / gm4
I6 = gm6**2 / (2 * mu_Cox) * (1 / W_by_L_6)
V_DS6 = np.sqrt(2 * I6 / (mu_Cox * W_by_L_6))
# ----------------------------
# Step5: M7 sizing
# ----------------------------
W_by_L_7 = W_by_L_5 * (I6 / I5_selected)
V_DS7 = np.sqrt(2 * I6 / (mu_Cox * W_by_L_7))
# ----------------------------
# Step6: Load resistor
# ----------------------------
V_GS5 = V_DS5
R_load = (V_DD - V_GS5) / I5_selected
# ----------------------------
# Step7: Gain and power check
# ----------------------------
VA2, VA4, VA6, VA7 = 20, 30, 20, 30
P_diss = V_DD * (I5_selected + I6)
den1 = (1 / VA2 + 1 / VA4) * I5_selected
Av1 = -2 * gm1 / den1
den2 = (1 / VA6 + 1 / VA7) * I6
Av2 = -gm6 / den2
Av_total = Av1 * Av2
Av_total_dB = 20 * np.log10(abs(Av_total))
# ----------------------------
# Results
# ----------------------------
print("=== 2-Stage Op-Amp Full Calculation ===")
print(f"I5 (from SR): {I5_from_SR*1e6:.2f} μA, I5 max: {I5_max*1e6:.2f} μA, I5 selected: {I5_selected*1e6:.2f} μA")
print(f"gm1: {gm1*1e6:.2f} μS, W1/L1: {W_by_L_1:.2f}")
print(f"W5/L5: {W_by_L_5:.2f}")
print(f"W6/L6: {W_by_L_6:.2f}, I6: {I6*1e6:.2f} μA, V_DS6(sat): {V_DS6:.2f} V")
print(f"W7/L7: {W_by_L_7:.2f}, V_DS7(sat): {V_DS7:.2f} V")
print(f"R_load: {R_load/1e3:.2f} kΩ")
print(f"Power Dissipation: {P_diss*1e3:.3f} mW")
print(f"Av1: {Av1:.1f}, Av2: {Av2:.1f}, Total Gain: {Av_total:.1f}")
print(f"Total Gain (dB): {Av_total_dB:.1f} dB")
# Program Name: two_stage_opamp_full_design.py
# Creation Date: 20250923
# Overview: Full design calculator for 2-stage op-amp including sizing, gain, power, CMR, SR, GB, poles and zeros
# Usage: Run this script in Python to compute W/L, gm, gain (dB), power, CMR, SR, GB, poles and zeros
!pip install numpy
import numpy as np
# ----------------------------
# Parameters
# ----------------------------
# Supply
V_DD = 3.0 # [V]
V_SS = -1.5 # [V]
P_bias = 1e-3 # [W]
# Slew Rate and Capacitors
SR = 5 # [V/us]
C_c = 0.3e-12 # [F]
C_L = 1e-12 # [F]
# MOS parameters
mu_Cox = 220e-6 # [A/V^2]
V_TN = 0.45 # [V]
V_AN = 2.7 # [V]
# Bias assumptions
I_D = 50e-6 # [A]
V_DS5 = 0.13 # [V]
W_by_L_guess = 1.6
GB = 50e6 # [Hz]
# ----------------------------
# Step1: I5 calculation (from SR and power constraint)
# ----------------------------
I5_from_SR = SR * 1e6 * C_c # [A], SR unit conversion V/us → V/s
I5_max = P_bias / V_DD
I5_selected = 25e-6 # [A], design choice
# ----------------------------
# Step2: gm1 and W/L1 (from GB)
# ----------------------------
gm1 = GB * C_c
W_by_L_1 = gm1**2 / (2 * mu_Cox * I_D)
# ----------------------------
# Step3: Output stage M5 sizing
# ----------------------------
W_by_L_5 = 2 * I5_selected / (mu_Cox * V_DS5**2)
# ----------------------------
# Step4: M6 sizing (RHP zero + gm6 > 10 gm1)
# ----------------------------
gm6 = 10 * gm1
gm4 = 49e-6
W_by_L_6 = W_by_L_guess * gm6 / gm4
I6 = gm6**2 / (2 * mu_Cox) * (1 / W_by_L_6)
V_DS6 = np.sqrt(2 * I6 / (mu_Cox * W_by_L_6))
# ----------------------------
# Step5: M7 sizing
# ----------------------------
W_by_L_7 = W_by_L_5 * (I6 / I5_selected)
V_DS7 = np.sqrt(2 * I6 / (mu_Cox * W_by_L_7))
# ----------------------------
# Step6: Load resistor
# ----------------------------
V_GS5 = V_DS5
R_load = (V_DD - V_GS5) / I5_selected
# ----------------------------
# Step7: Gain and power check
# ----------------------------
VA2, VA4, VA6, VA7 = 20, 30, 20, 30
P_diss = V_DD * (I5_selected + I6)
den1 = (1 / VA2 + 1 / VA4) * I5_selected
Av1 = -2 * gm1 / den1
den2 = (1 / VA6 + 1 / VA7) * I6
Av2 = -gm6 / den2
Av_total = Av1 * Av2
Av_total_dB = 20 * np.log10(abs(Av_total))
# ----------------------------
# Step8: CMR (common-mode range)
# ----------------------------
beta3 = mu_Cox * W_by_L_6
beta1 = mu_Cox * W_by_L_1
V_in_max = V_DD - np.sqrt(I5_selected / beta3) - V_TN + V_TN
V_in_min = V_SS - np.sqrt(I5_selected / beta1) + V_TN + V_DS5
# ----------------------------
# Step9: Frequency response (poles, zeros, SR, GB)
# ----------------------------
g_o1 = 1 / VA2 + 1 / VA4
g_o2 = 1 / VA6 + 1 / VA7
p1 = -(g_o1 * g_o2) / (gm6 * C_c)
p2 = -gm6 / C_L
z1 = gm6 / C_c
SR_check = I5_selected / C_c
GB_check = gm1 / C_c
# ----------------------------
# Results
# ----------------------------
print("=== 2-Stage Op-Amp Full Design Calculation ===")
print(f"I5 (from SR): {I5_from_SR*1e6:.2f} μA, I5 max: {I5_max*1e6:.2f} μA, I5 selected: {I5_selected*1e6:.2f} μA")
print(f"gm1: {gm1*1e6:.2f} μS, W1/L1: {W_by_L_1:.2f}")
print(f"W5/L5: {W_by_L_5:.2f}")
print(f"W6/L6: {W_by_L_6:.2f}, I6: {I6*1e6:.2f} μA, V_DS6(sat): {V_DS6:.2f} V")
print(f"W7/L7: {W_by_L_7:.2f}, V_DS7(sat): {V_DS7:.2f} V")
print(f"R_load: {R_load/1e3:.2f} kΩ")
print("---")
print(f"Power Dissipation: {P_diss*1e3:.3f} mW")
print(f"Av1: {Av1:.1f}, Av2: {Av2:.1f}, Total Gain: {Av_total:.1f}")
print(f"Total Gain (dB): {Av_total_dB:.1f} dB")
print("---")
print(f"CMR+ (Vin max): {V_in_max:.2f} V, CMR- (Vin min): {V_in_min:.2f} V")
print(f"SR (calc): {SR_check/1e6:.2f} V/us, GB (calc): {GB_check/1e6:.2f} MHz")
print(f"p1: {p1:.2e} Hz, p2: {p2:.2e} Hz, z1: {z1:.2e} Hz")





