Unifagfのブログ

間違った情報が多いです

sky130のnmosのvds-ids特性を描く

設計ことはじめとしてnmosのvds-ids特性を描きたい。 Vgsに対してパラメトリック解析を行いたいが、ngspiceの機能として備えていないためpythonスクリプトで対応してみた。

実際にやってみた感想としては、記述量が多くなってしまいあまり良い方法でないと思った。 良い方法があれば教えてほしいです。

回路図

f:id:Unifagf:20220205230901p:plain

ネットリスト

** sch_path: /home/unifagf/work/xschem/tutor/test2/test2.sch
**.subckt test2
XM1 net2 net1 GND GND sky130_fd_pr__nfet_01v8 L=0.15 W=1 nf=1 ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
+ sa=0 sb=0 sd=0 mult=1 m=1
V1 net2 GND 1.8
V2 net1 GND VG
**** begin user architecture code


.lib /home/unifagf/skywater/skywater-pdk/libraries/sky130_fd_pr_ngspice/latest/models/sky130.lib.spice tt
.dc V1 0 1.8 0.1
.parameter VG=1.8
.save all
.control
set filetype=ASCII
.endc


**** end user architecture code
**.ends
.GLOBAL GND
.end

set filetype=ASCIIは、rawファイルをbinaryではなくASCIIで出力させるためのコマンド。 spyci(https://pypi.org/project/spyci/)でrawファイルを読み込むために必要。

グラフ

f:id:Unifagf:20220205233631p:plain

ゲート幅が1umより小さいので、チャネル長変調効果が強く出ている。

スクリプト

処理のフロー f:id:Unifagf:20220206095935p:plain

スクリプト本体(run.py)

#!/usr/bin/env python

import argparse
import subprocess
import itertools
import os
import os.path
import numpy as np
import pandas as pd
import sys
import re
from spyci import spyci
import matplotlib.pyplot as plt
import shutil

#
print(' '.join([f'"{s}"' for s in sys.argv]))
scriptdir = os.path.dirname(sys.argv[0])  # pythonスクリプトがおいてあるディレクトリ

# 引数の設定解析
parser = argparse.ArgumentParser(
    description='Run parametric analysis from xschem file.')
parser.add_argument('schema', help='Original xschem file.')
parser.add_argument('-c', '--clean', action='store_true',
    help='Clean previous work directories.')
parser.add_argument('-n', '--netlist', action='store_true', help='Generate parameterized netlists.')
parser.add_argument('-s', '--simulation', action='store_true', help='Run simulations.')
parser.add_argument('-r', '--result', action='store_true', help='Export results.')
parser.add_argument('-o', '--output', nargs='?', default=scriptdir, help='Specify output directory')
args = parser.parse_args()


# ディレクトリ生成
schname = os.path.splitext(os.path.basename(args.schema))[0]  # 拡張子なしのファイル名を取得
netdir = os.path.join(args.output, 'tmp')
rawdir = os.path.join(args.output, 'tmp')
logdir = os.path.join(args.output, 'tmp')
retdir = os.path.join(args.output, 'result')

if args.netlist:
    os.makedirs(netdir, exist_ok=True)
if args.simulation:
    os.makedirs(rawdir, exist_ok=True)
    os.makedirs(logdir, exist_ok=True)
if args.result:
    os.makedirs(retdir, exist_ok=True)

# パラメータ設定
params = {'VG': ['{:01.1f}'.format(n) for n in np.linspace(0, 1.8, 10)]}


# パラメータの組み合わせ生成
keys = list()
param_comb = list()
df = pd.DataFrame()

if len(params) >= 0:  # パラメータがある場合
    keys = list(params.keys())
    param_comb = list(itertools.product(*[params[k] for k in keys]))
    df = pd.DataFrame(param_comb, columns=keys)
    df['ngspice_net'] = '-'
    df['ngspice_raw'] = '-'
    df['ngspice_out'] = '-'
    for index, row in df.iterrows():
        filename = f'{schname}_' + "_".join([f'{k}{str(row[k])}' for k in keys])
        df.at[index, 'ngspice_net'] = os.path.join(netdir, f'{filename}.net')
        df.at[index, 'ngspice_raw'] = os.path.join(rawdir, f'{filename}.raw')
        df.at[index, 'ngspice_out'] = os.path.join(logdir, f'{filename}.out')
else:  # パラメータがない場合
    filename = f'{schname}'
    _d = {'ngspice_net': os.path.join(netdir, f'{filename}_.net'),
          'ngspice_raw': os.path.join(rawdir, f'{filename}_.raw'),
          'ngspice_out': os.path.join(logdir, f'{filename}_.out')}
    df = pd.DataFrame(_d)


def subprocess_run(cmd):
    """
    サブプロセスを実行する関数
    """
    result = subprocess.run(cmd, stdout=subprocess.PIPE, encoding='utf-8', shell=True)
    return result


# ファイル削除
if args.clean:
    shutil.rmtree(netdir)
    shutil.rmtree(rawdir)
    shutil.rmtree(logdir)
    shutil.rmtree(retdir)


# ネットリスト生成
if args.netlist:
    original_netlist = os.path.join(netdir, f'orig_{schname}.net.spice')  # 回路図から生成したネットリスト
    cmd = 'xschem --netlist ' + \
          f'--netlist_path "{netdir}" ' + \
          f'--netlist_filename "{original_netlist}" ' + \
          f'--quit "{os.path.abspath(args.schema)}"'
    print(cmd)
    proc = subprocess_run(cmd)

    # パラメータを変更したネットリストを生成
    with open(original_netlist, 'r', newline='') as rf:
        print()
        orig_lines = rf.readlines()
        for index, row in df.iterrows():
            with open(row['ngspice_net'], 'w') as wf:
                for line in orig_lines:
                    s = line
                    for k in params.keys():
                        m = re.match(r'^\.parameter\s+' + k + r'=', s)  # 「.parameter hoge=...」という行を置換
                        if m is not None:
                            v = row[k]
                            s = f'.parameter {k}={v}\n'
                    wf.write(s)
                print('{} generated.'.format(row['ngspice_net']))

# simulation実行
if args.simulation:
    print('run simulation')
    for index, row in df.iterrows():
        cmd = 'ngspice --autorun --batch ' + \
            '--output="{}" '.format(row['ngspice_out']) + \
            '--rawfile="{}" "{}"'.format(row['ngspice_raw'], row['ngspice_net'])
        print(cmd)
        result = subprocess_run(cmd)

# グラフを描画
if args.result:
    print(df)  # パラメータ一覧を表示
    print(spyci.list_vars(df.at[0, 'ngspice_raw']))  # 信号名一覧を表示
    fig, ax = plt.subplots()
    for index, row in df.iterrows():
        data = spyci.load_raw(row['ngspice_raw'])
        x = np.real(data['values']['v(v-sweep)'])
        y = -np.real(data['values']['i(v1)'])
        ax.plot(x, y, label='VG={}'.format(row['VG']))
    ax.set_xlabel('Vds (V)')
    ax.set_ylabel('Ids (A)')
    ax.legend(loc='upper right')
    ax.grid(visible=True)
    ax.set_xlim([0, 1.8])
    graphimg = os.path.join(retdir, 'nmos_idsvds.png')
    plt.savefig(graphimg)

使い方

./run.py -nsr test2.sch

sky130のセットアップ

目的

skywaterのフリーなPDK(sky130)で回路のお勉強をするためにspiceの実行環境を整えたい。

参考にしたサイト

https://github.com/bluecmd/learn-sky130/blob/main/schematic/xschem/getting-started.md https://github.com/mabrains/sky130_ubuntu_setup

セットアップ

mkdir -p ~/build/sky130_ubuntu_setup
cd ~/build/sky130_ubuntu_setup
git clone https://github.com/mabrains/sky130_ubuntu_setup.git
sudo ./install_pdk.sh

xschemのインストール

sudo apt-get install libx11-6 libx11-dev  libxrender1 libxrender-dev libxcb1  libx11-xcb-dev libcairo2 libcairo2-dev tcl8.6 tcl8.6-dev tk8.6 tk8.6-dev flex bison libxpm4 libxpm-dev gawk git
mkdir ~/build
cd ~/build
git clone https://github.com/StefanSchippers/xschem.git
cd xschem
./configure
make -j4
sudo make install

起動確認

xschem

PDKのモデルをngspiceで読み込めるようにパッチを当てる。

mkdir -p ~/.xschem/xschem_library
cd ~/.xschem/xschem_library
git clone https://github.com/StefanSchippers/xschem_sky130.git xschem_sky130

cd ~/skywater/skywater-pdk/libraries
cp -a ./sky130_fd_pr ./sky130_fd_pr_ngspice
cd ./sky130_fd_pr_ngspice/latest/
patch -p2 < ~/.xschem/xschem_library/xschem_sky130/sky130_fd_pr.patch

xschemrcの編集

gedit ~/.xschem/xschem_library/xschem_sky130/xschemrc

SKYWATER_MODELSとSKYWATER_STDCELLSを置き換える

set SKYWATER_MODELS ~/skywater/skywater-pdk/libraries/sky130_fd_pr_ngspice/latest$
set SKYWATER_STDCELLS ~/skywater/skywater-pdk/libraries/sky130_fd_sc_hd/latest

ngspiceインストール

sudo apt install ngspice

gawインストール(不要だった)

mkdir -p ~/build/gaw
cd ~/build/gaw
sudo apt install libgtk-3-dev build-essential
wget http://download.tuxfamily.org/gaw/download/gaw3-20200922.tar.gz
tar -xf gaw3-20200922.tar.gz
cd gaw3-20200922
./configure
make -j$(nproc)
sudo make install

gawを起動して閉じる。

gaw

gawrcを開く。

gedit ~/.gaw/gawrc

以下のように編集

up_listenPort = 2020

動作確認

適当な作業ディレクトリに移動してxschemを実行

mkdir -p ~/work/xschem/test1
cd ~/work/xschem/test1
xschem

INSを押して、階層をたどっていきnfet_01v8.symを選択 f:id:Unifagf:20220123222005p:plain

回路図を描く。 f:id:Unifagf:20220123230957p:plain

簡単な操作説明

  • 部品配置はINS
    • nfetは「/home/unifagf/.xschem/xschem_library/xschem_sky130/sky130_fd_pr/nfet_01v8.sym」
    • 電圧源は「/usr/local/xschem/schem_library_devices/vsource.sym」
    • GNDは「/usr/local/xschem/schem_library_devices/gnd.sym」
  • ワイヤはw、w中にwで折れ曲がり点追加、ダブルクリックで終了
  • xschem公式のビデオがわかりやすいhttps://xschem.sourceforge.io/stefan/xschem_man/video_tutorials/editing_and_sim.mp4

s1のコマンドは以下の通り f:id:Unifagf:20220123231117p:plain

.lib /home/unifagf/skywater/skywater-pdk/libraries/sky130_fd_pr_ngspice/latest/models/sky130.lib.spice tt .dc V1 0 1.8 0.1 .save all

Options>Show netlist winにチェック Simulation>Configure simulators and toolsでspice>Ngspiceとなっていることを確認

画面右上のNetlistをクリック、閉じる 画面右上のSimulateをクリック、少し待つ

プロット可能な信号一覧を表示 display

電流を表示 f:id:Unifagf:20220123232215p:plain plot v1#branch

Id-Vd特性が確認できた。

ラズパイをNAS化する。

はじめに

Raspberry Pi 4B 4GBをdperson/sambaでNAS化した。

参考にしたサイト

raspberrypi.mongonta.com

qiita.com

matsudamper.hatenablog.com

mugeek.hatenablog.com

www.indoorcorgielec.com

qiita.com

jorublog.site

mrs.suzu841.com

qiita.com

qiita.com

ラズパイのヘッドレスセットアップ

  • SDカードへのOSのインストールRaspberry Pi Imager v1.6.2でRASPBERRY PI OS(32-BIT)(RELEASED2021-10-30)をインストールする。
  • SSHの有効化。Mobaxterm上で下記コマンドを実行。
touch /cygdrive/g/ssh
※gドライブはSDカードの/bootディレクト
  • SDカードをラズパイに挿入して起動。
  • ラズパイのIPを探す。Mobaxterm上で下記コマンドを実行。私の場合、MACアドレスはdc-a6から始まっていた。
for i in {0..255}; do
ping -w 1 -n 1 192.168.3.$i
done
arp -a
  • SSH接続。
    • パスワードはraspberry
ssh pi@192.168.3.11
ssh-keygen
ssh-copy-id Unifagf@192.168.3.129

HDDのセットアップ

力尽きたので以降は簡潔に。

  • パーテーション作成
  • フォーマット
  • 自動マウント

sambaのセットアップ

Raspberry Pi 3 b+にsambaをdockerで入れてファイルサーバ化する - Qiitaに従って進める。

オペアンプの増幅回路と高精度ネットワーク抵抗

オペアンプの増幅回路

下記回路が基本構成。

f:id:Unifagf:20220101101148p:plain
オペアンプの増幅回路の基本構成

\displaystyle{
V_o=\frac{R_4}{R_1}\frac{R_1+R_3}{R_2+R_4}V_2-\frac{R_3}{R_1}V_1+\frac{R_2}{R_1}\frac{R_1+R_3}{R_2+R_4}V_3
}

作動増幅回路

\displaystyle{
V_1=V_{in-}, V_2=V_{in+}, V_3=V_{ref}, R_1=R_2=R_a, R_3=R_4=R_b
}

f:id:Unifagf:20220101103741p:plain
オペアンプの作動増幅回路

\displaystyle{
V_o=\frac{R_b}{R_a}(V_{in+}-V_{in-})+V_{ref}
}

反転増幅回路

\displaystyle{
V_1=V_{in}, V_2=open, V_3=V_{ref}, R_1=R_a, R_2=\infty, R_3=R_b, R_4=0
}

f:id:Unifagf:20220101104218p:plain
オペアンプの反転増幅回路

\displaystyle{
V_o=-\frac{R_b}{R_a}(V_{in}-V_{ref})+V_{ref}
}

非反転増幅回路

\displaystyle{
V_1=V_{ref}, V_2=V_{in}, V_3=open, R_1=R_a, R_2=0, R_3=R_b, R_r=\infty
}

f:id:Unifagf:20220101104300p:plain
オペアンプの非反転増幅回路

\displaystyle{
V_o=(1+\frac{R_b}{R_a})(V_{in}-V_{ref})+V_{ref}
}

高精度ネットワーク抵抗

増幅回路は抵抗の比で回路のゲインが決まる。ネットワーク抵抗は抵抗値の比精度がよいと言われるが、特性として保証している製品はあまり多くない。増幅回路向きの高精度ネットワーク抵抗のメモ。

微小電流測定用のアンプ

微小電流測定用のアンプについて勉強したメモ

参考文献

測定限界

ja.wikipedia.org

熱雑音による測定限界を考える。 熱雑音は以下の式で表される。kBはボルツマン定数1.308e-23 J/K。

\displaystyle{
V_n=\sqrt{4k_BTR\Delta f}
}
\displaystyle{
I_n=\sqrt{\frac{4k_BT\Delta f}{R}}
}

グラフ化すると以下のようになる。

f:id:Unifagf:20211231143606p:plain
熱雑音(電圧)

f:id:Unifagf:20211231143610p:plain
熱雑音(電流)

信号源のインピーダンスを1GΩとして、熱雑音は10fA/√Hzと非常に低い値となる。 電圧測定では測定限界が熱雑音に制限されることが多いが、 電流測定では熱雑音は無視してよく、ケースレーの資料にあるように「摩擦電気効果」「圧電効果」「電気化学効果」が支配的で10nA程度が限界となるようだ。

電流測定IC

シャント式

Current Sense Amplifier icで検索するとヒットするものは大体こちら。 電源電流測定などでメジャーな方式だが、微小電流には向いていないようだ。

フィードバック式

「Transimpedance Amplifier IC」で検索するとヒットする。

積分