1
2

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で学ぶCMOSアナログ回路入門【2段オペアンプ設計方法】

Last updated at Posted at 2025-03-29

はじめに

本プログラムでは、OPアンプ設計に必要な基本パラメータ(ゲイン、スルーレート、帯域、電源電圧など)をもとに、
CMOSトランジスタのW/L比、トランスコンダクタンスgm、入力・出力範囲、電圧利得A0などをPythonで簡易計算します。

参考リンクまとめ

Pythonコード

2段CMOSアンプ設計をしてみよう
image.png

設計条件

項目 記号
電源電圧 ( 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

下コードは、オペアンプ回路の設計に関連する計算を行うためのものです。具体的には、オペアンプのゲイン、トランジスタの設計、入力・出力電圧範囲の計算、そして利得や周波数特性などのパラメータを求めています。主な内容としては:

  1. パラメータ設定: 回路設計に必要な基本的な定数やパラメータを設定。
  2. テール電流 (I₅) の計算: スルーレートに基づいて設計。
  3. ゲインの計算: 単位利得帯域幅からgm(相互コンダクタンス)を算出。
  4. W/L 比の設計: トランジスタのW/L比を計算。
  5. 最小入力電圧の計算: 入力電圧範囲の最小値を求める。
  6. 高利得のためのgm₆の設定: 高利得回路に対応するgm₆の計算。
  7. 出力電圧範囲の計算: 出力電圧の最小値と最大値を計算。
  8. 電圧利得 (A₀) の計算: 出力信号に対する増幅度を計算し、そのdB値を求める。
  9. 周波数特性の解析: ゼロ点やポール周波数の計算。

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]")

結果

image.png

追加のコード

image.png

こちらの計算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")

結果
image.png

追加のコード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}")

結果

image.png

実践

「実際のSPICEシミュレーションとの比較を求める意見を受けて、この動画を参考にしながら考察と計算を進めていきたいと思います。基本はCMOSアナログ回路入門(谷口本)と同じです。

image.png

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?