2
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でアナログ回路設計しよう!~ソースフォロワ回路~

2
Posted at

こんにちは、アナログ回路勉強中のよしあきです。

このシリーズではPythonを使って回路設計・シミュレーションを行うということで、前回はそのために必要なPySpicengspiceのインストールを行いました。

環境構築が完了したため、ここではMOSFETを使った簡単な回路としてソースフォロワを設計&シミュレーションしていきます。

ソースフォロワについての復習

こちらのサイトを元に、まずはソースフォロワ回路について復習しておきます。

そもそもソースフォロワとはドレイン接地回路と呼ばれ、MOSFETのドレイン側を電源電圧Vdd(固定電位)、ソース側を出力端子とします。
すると出力端子であるソース電圧が、入力端子であるゲート電圧に追従(Follow)して動くため、ソースフォロワと呼ばれています。

他にもドレイン共通回路(Common Drain)や電圧フォロワ回路(Voltage Follower)と呼ばれます。

回路図と入力電圧vin, 出力電圧voutの関係を以下に示します。

image.png

原理を簡単に説明すると、vinが上昇した時にはMOSFETがONになり、Vddから電流idを流します。

すると出力抵抗Rdとidの積によりvoutは決まるため、この値が上昇します。
これがvinが上昇するとvoutも追従して上昇するといった流れです。

image.png

この回路の特徴は、ゲートで受けるため入力インピーダンスが高く、出力インピーダンスが低い点です。
このようなインピーダンス変換により、優秀なバッファとして働きます。

また、出力であるソース電圧が上がるとゲートソース間電圧vgsが小さくなって、電流を抑えようとします。
この自己帰還バイアスにより、波形の歪みが小さくなります。

ソースフォロワ回路のシミュレーション

それでは、回路シミュレーションを行うプログラムを書いていきましょう。

初めにモジュールのインストールです。
シミュレータであるngspiceを呼び出すためのPySpiceと、グラフ描画用のmatplotlibをインポートします。

from PySpice.Spice.Netlist import Circuit
from PySpice.Unit import *
import matplotlib.pyplot as plt

続いてそれぞれの素子を定義&結線していきます。
素子の引数に端子ごとのノード名を入力していくのですが、ノード名が一致する端子が結線されていくイメージです。

# 回路作成
circuit = Circuit('Source Follower')

# 電源('素子名の識別子', '正極のノード名', '負極のノード名', 電圧値)
circuit.V('dd', 'vdd', circuit.gnd, 1.8@u_V)

# 正弦波入力(素子名、正極ノード、負極ノード、直流オフセット、振幅、周波数)
circuit.SinusoidalVoltageSource(
    'input', 'vin', circuit.gnd,
    dc_offset=0.9@u_V,
    offset=0.9@u_V,
    amplitude=0.9@u_V,
    frequency=100@u_Hz
)

# 簡易NMOSモデルの定義('モデル名', '素子タイプ', 'レベル', 'パラメータ1=値1', 'パラメータ2=値2', ...)
circuit.model('nmos', 'NMOS', LEVEL=1, KP=20*10**-6, VTO=1@u_V, LAMBDA_=0.02)

# MOSFETを置くための関数('素子名', 'ドレイン', 'ゲート', 'ソース', 'ボディ', model='モデル名', l=チャネル長, w=チャネル幅)
circuit.M('m1', 'vdd', 'vin', 'out', 'out', model='nmos', l=1@u_um, w=10@u_um)

# ソース側の負荷('素子名', '接続ノード1', '接続ノード2', 抵抗値)
circuit.R('load', 'out', circuit.gnd, 1@u_kOhm)

ここでは、電源電圧1.8Vで動作している回路に、0-1.8Vの正弦波入力を与えるシミュレーションを行います。
各引数はコメントで記載していますが、特筆すべきは簡易NMOSを定義するコマンド circuit.model()でしょう。

引数にLEVELKP, VTOといった見慣れない文字がありますので、以下で解説します。

  • nmos: モデル名の定義、モデルを配置する際にmodel=で参照する
  • NMOS: モデルの種類、n-ch MOSFETを意味する
  • LEVEL=1: 古典的なShichman-Hodgesモデルを使う指定、高速でわかりやすい反面、短チャネル効果などはほぼ入らない
  • KP=220*10**-6: トランスコンダクタンスgmを決める係数、だいたい180uプロセスnmosでこのくらいの値
  • VTO=1@u_V: しきい値電圧、Vgsがこの値を超えるとスイッチとしてのMOSFETがONになる
  • LAMBDA_=0.02: チャネル長変調係数

RやCといった受動素子は、ノード名と値を定義するだけで良いのですが、MOSFETのような能動素子はこのように事前にモデルの定義を行う必要があります。

その次の行では、circuit.M()で定義したモデルの配置配線とW/Lの定義を行います。
このようにモデル定義と実際にそれを使う(配置する)コマンドが分けられていることが、初めは少し慣れないポイントかもしれません。


続いてシミュレーションを回します。

simulator = circuit.simulator(temperature=25, nominal_temperature=25)
analysis = simulator.transient(step_time=0.1@u_ms, end_time=50@u_ms)

一行目はsimulatorのセットで、実行時のパラメータを決めています。
(ここではシミュレーション温度のみ設定しています)

二行目はシミュレーションの実行です。
simulatorに対して過渡解析(transient)を行う指定と、それに必要なシミュレーション時間と時間ステップを入力しています。


最後に、実行したシミュレーション結果をmatplotlibでプロットします。

# 波形表示用
# x軸:時間(time)、y軸:電圧(vin, vout)
time = analysis.time.as_ndarray()
vin = analysis['vin'].as_ndarray()
vout = analysis['out'].as_ndarray()

plt.figure(figsize=(10, 5))
plt.plot(time, vin, label='Vin', color='blue')
plt.plot(time, vout, label='Vout', color='red')
plt.xlabel('Time [s]')
plt.ylabel('Voltage [V]')
plt.legend()
plt.grid(True)
plt.show()

シミュレーションした結果はanalysisに保存されています。
実行した結果がこちら。

image.png

vinの入力波形は0~1.8Vの正弦波となっており、voutはvinと同相かつ下がっていますが…
それぞれのPeak電圧が1.8V vs 0.5V以下と1.3V以上の差があり、下側の波形は潰れています。
なぜこのような波形になるのでしょうか?

ソースフォロワの駆動能力

voutが歪んでいる原因はNMOSの駆動能力に対して負荷抵抗1kΩが重すぎるためです。

そもそもvout = vin - vgsはMOSFETが十分な電流を供給できる場合の目安です。

今回、抵抗を1kΩとしているため、仮にvout = 1.0Vまで出力を出したいとなるとMOSFETが供給する必要電流は

I_R = \frac{V_{out}}{R_L} = \frac{1.0V}{1kΩ} = 1mA 

になります。
一方、現在のMOSモデルでは、

K_P = 220\times10^{-6}, \frac{W}{L} = \frac{10\mu m}{1\mu m} = 10

なので、

\beta = K_P \frac{W}{L} = 220 \mu A/V^2 \times 10 = 2200 \mu A/V^2

です。

しきい値電圧Vthは0.7V、入力が1.8VのときのVgsは1.3Vであるため飽和領域ではおよそ以下の電流が流れます。

I_D \approx \frac{1}{2} \beta (V_{gs}-V{th})^2 
I_D \approx \frac{1}{2} \times 2200 \mu A/V^2 \times (1.3V - 0.6V)^2 \approx 540 \mu A

これでは必要電流の1mAの半分しかありません。

実際には、MOSFETの駆動する電流と、抵抗に流れる電流が一致する点で出力が決まるため、

\frac{v_{out}}{1kΩ} \approx \frac{1}{2} \beta ((1.8V-v_{out})-0.7V)^2
\frac{v_{out}}{1000} \approx \frac{1}{2} \times 2200 \times 10^{-6} (1.1-v_{out})^2

となり、voutについて解くと

v_{out} \approx 0.46V

シミュレーションで得られたvin=1.8V時にvout=0.5V未満という結果と一致します。

つまり、この回路ではしきい値電圧分だけ出力が下がっているのではなく、MOSFETが負荷に必要な電流を流せないため、出力電圧がほとんど上がらない という現象が起きています。

この場合、解決策は大きく以下の2つです。

  1. 出力の負荷抵抗を大きくする
  2. MOSFETの駆動能力を上げる

この二つはそれぞれ負荷抵抗を1kΩから100kΩにする、MOSのW/Lを10倍にする、といったパラメータの調整でも実現できますが、いずれも上限が存在します。

そのときは、このサイトにある改良版ソースフォロワやスーパーソースフォロワといった回路トポロジーを試すのもおすすめです。

ここでは最後に、出力抵抗を1MΩ、MOSFETのW/Lを100にした結果をお見せして、ソースフォロワの動作を確認します。
(下側がつぶれないよう、入力の正弦波もオフセット電圧1.0V, 振幅0.3Vにしています)

image.png

voutの波形がvinと同相かつVth分(0.7V)下がっていることがわかります。

本日の設計はここまで、ご覧いただきありがとうございました。

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