Jupyter Notebook上でLTSpiceのシミュレーションを動かす方法

#はじめに
こんにちは。アナログ回路シミュレーションソフトであるLTSpiceをJupyter Notebook上から回して、
結果を取得する方法を紹介します。
LTSpiceには、コマンドラインによるバッチ処理モードが用意されており、
そちらを使ってネットリストの生成とシミュレーションの実行を行います。
#なぜやろうと思ったか
機械学習でアナログ回路設計を行うことを試みるために、自動シミュレーションを行う必要があったため。
こちらの記事で紹介しています。 → https://qiita.com/dl10yr/items/fe100b3aeb18045d3ff5
#動作環境
OS: Ubuntu 18.04.2 LTS
ubuntuでLTSpiceを動かすためにwineを使っています。
Jupyter Notebook: 5.7.8
Python: 3.7.3
#シミュレーションを回す
基本的にはこれです。
シミュレーションを行うネットリストのあるフォルダまで移動して、これで実行できます。

```
$ wine /hogehoge/LTSpice/XVIIx64.exe -b XXX.net
```
/hogehoge/LTSpice/XVIIx64.exe: XVIIx64.exeのあるLTSpiceのフォルダ
-b: バッチモードでのシミュレーションを行うことを指定するオプション
XXX.net: シミュレーションを行いたいネットリスト
#結果の取得
結果の取得は、自分が使っているものは2パターンあります。
###.logファイルから取得
大体のものはこっちです。.logファイルをテキスト処理して欲しい数字を抽出します。
上手くテキスト処理するのが難しいですね。。。

```python
import codecs
with codecs.open(file + ".log", "r", "Shift-JIS", "ignore") as file:
  s = file.read()
```
そして、重要なポイントは、codecsモジュールを使用することです。
"ignore"を指定することでエラーを無視して力技で読んでくれます。
###.rawファイルから取得
.rawファイルに結果が記載されるシミュレーションがあります。
これは[ltspiceモジュール](https://pypi.org/project/ltspice/)を利用して読み込みます。
pythonにはLTSpiceのデータを読み込むモジュールがあるんです！

```python
import ltspice
l = ltspice.Ltspice(file + ".raw") 
l.parse()
r0_sim = l.getData("output_impedance_at_V(output)")[0]
```

#Jupyter Notebookにおける具体的な実装例
具体例を上げて紹介します。
今回は上で紹介した記事で行ったオペアンプ回路のCMRRの解析と出力抵抗の解析部分について紹介します。
シミュレーションの実行し、結果を返却する関数の実装例です。
コードは[Githubに上げたここ](https://github.com/dl10yr/DesignOpAmp_ML)のJupyter Notebookのコードから抜粋しています。
コードが汚く不必要な記述もあるかもしれません。。。
Jupyter Notebook上からコマンドを実行するので、subprocessモジュールを利用しています。

###CMRR
こっちは.logファイルから結果の取得をしています。

```python
import ltspice
import os
import subprocess
import shutil
import codecs
import re
    def analysis_CMRR(self): ##CMRR
        try:
            os.mkdir(self.wk_dir + "/CMRR")
            shutil.copy(self.wk_dir + "/tsmc018.lib", self.wk_dir + "/CMRR/tsmc018.lib")
        except:
            pass

        os.chdir(self.wk_dir + "/CMRR")
        file = self.wk_dir + "/CMRR/test-OpAmp-CMRR"
        shutil.copyfile(self.wk_dir + "/test-OpAmp-CMRR.net", file + ".net")

        output = subprocess.run(["wine", "/hogehoge/LTSpice/XVIIx64.exe", "-b","test-OpAmp-CMRR.net"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        with codecs.open(file + ".log", "r", "Shift-JIS", "ignore") as file:
            s = file.read()
        lines = s.split("\n")
        for line in lines:
            if "cmrr:" in line:
                cmrr = line
        words = re.split('[|(|)|,|]| |\r',cmrr)
        words = [x for x in words if x]
        for word in words:
            if "dB" in word:
                CMRR_value = float(word.strip("dB"))
        os.chdir(self.wk_dir)
        return CMRR_value
```

###出力抵抗
こっちは.rawファイルからの結果取得をしています。

```python
import ltspice
import os
import subprocess
import shutil
import codecs
import re
    def analysis_Out_R(self):
        ##出力抵抗
        try:
            os.mkdir(self.wk_dir + "/Out_R")
            shutil.copy(self.wk_dir + "/tsmc018.lib", self.wk_dir + "/Out_R/tsmc018.lib")
        except:
            pass

        os.chdir(self.wk_dir + "/Out_R")
        file = self.wk_dir + "/Out_R/test-OpAmp-Out_R"
        shutil.copyfile(self.wk_dir + "/test-OpAmp-Out_R.net", file + ".net")
        tf_con = ".tf V(OUTPUT) VIN"

        with open(file + ".net", "r") as f:
            s = f.read()
        line = s.split("\n")
        line.insert(-3, tf_con)
        wr_s = "\n".join(line)
        with open(file + ".net", "w") as f:
            f.write(wr_s)
        output = subprocess.run(["wine", "/hogehoge/LTSpice/XVIIx64.exe", "-b","test-OpAmp-Out_R.net"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        l = ltspice.Ltspice(file + ".raw") 
        l.parse()
        r0_sim = l.getData("output_impedance_at_V(output)")[0]
        os.chdir(self.wk_dir)
        return r0_sim
```


#ネットリストを生成する
余談になりますが、バッチモードでは、回路図ファイル（asc）からネットリストを生成することもできます。

```
$ wine /hogehoge/LTSpice/XVIIx64.exe -netlist test-OpAmp-CMRR.asc
```