ngspice の壁、sudo 無しで越えた — PySpice で本物の Bode 線図が出るまで
- python
- spice
- ngspice
- 電子回路
- conda
前回、シミュレーションは「壁」で止まっていた
前回の記事で、PySpice はネットリスト生成までは動くが、肝心のシミュレーションは libngspice.so が無くて止まる、と正直に書きました。私の環境は管理者権限がなく、sudo apt install ngspice が叩けなかったからです。
書いたあと、ずっと引っかかっていました。「sudo が無いと、本当に詰みなのか?」。現場では珍しくない状況です。共用の計算機、権限の絞られた開発環境、CI のコンテナ——「ツールは動くはずなのに、入れる権限がない」。あの不毛さに、20 年で何度もぶつかってきました。
なので続きをやりました。詰みではありませんでした。
なぜ ngspice は「別に必要」なのか
おさらいです。PySpice は回路を Python オブジェクトとして組み立て、ネットリストを吐くところまでを担います。しかし実際に方程式を解くのは ngspice という別物で、これは Python パッケージではなくシステムの共有ライブラリ(libngspice.so)です。pip install PySpice はこの計算エンジンまでは持ってきません。
ここを「OS のパッケージマネージャで入れる」と説明する記事がほとんどですが、それは root 権限がある前提の話です。権限が無い環境では、別の入口が要ります。
「動くのに入れられない」が一番つらい
ハードウェア寄りの開発を長くやってきて、回路シミュレーションそのものより消耗したのは、しばしば環境を用意するところでした。ツールに罪はなく、ロジックも分かっている。それでも、権限・依存・バージョンの壁で「動かせない」。あの時間が一番もったいない、という感覚が体に染みついています。
だから今回も、本題(Bode 線図を出す)より先に、権限の無い環境で計算エンジンをどう入れるかを現実解として確かめたかった。
sudo 無しで ngspice を通す
結論の手順はこれだけです。conda-forge には libngspice 込みの ngspice があり、micromamba(単体バイナリ、root 不要)で userspace に展開できます。
# micromamba を userspace に取得(root 不要)
mkdir -p .tools && cd .tools
curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xj bin/micromamba
cd ..
# conda-forge から ngspice を専用 prefix に入れる(root 不要)
export MAMBA_ROOT_PREFIX=$PWD/.tools/mamba-root
./.tools/bin/micromamba create -y -p ./.ngspice-env -c conda-forge ngspice
# -> .ngspice-env/lib/libngspice.so が手に入る
あとは PySpice(別の venv 側)に、この共有ライブラリの在り処を教えるだけです。
export LD_LIBRARY_PATH="$PWD/.ngspice-env/lib:$LD_LIBRARY_PATH"
python examples/04_pyspice_bode.py
ここで一つ、現場目線の補足。ソースからビルドしなかったのは判断です。この環境には bison / flex が無く、ngspice をソースビルドするにはそれらが要る。権限が無いと結局そこでまた詰む。conda-forge 経路はビルドツールの依存を丸ごと回避できるのが効きました。「権限が無い時ほど、ビルドより配布物」というのが今回の学びです。
実際に Bode 線図が出た
前回と同じ RC ローパス(R=1kΩ, C=1µF)で AC 解析を回しました。理論カットオフは
fc = 1 / (2πRC) = 1 / (2π·1000·1e-6) ≈ 159.15 Hz
実行コードの核心はこれだけです。
from PySpice.Spice.Netlist import Circuit
from PySpice.Unit import u_V, u_kOhm, u_uF, u_Hz
circuit = Circuit("RC low-pass (AC)")
circuit.SinusoidalVoltageSource("input", "vin", circuit.gnd, amplitude=1 @ u_V)
circuit.R(1, "vin", "vout", 1 @ u_kOhm)
circuit.C(1, "vout", circuit.gnd, 1 @ u_uF)
analysis = circuit.simulator().ac(
start_frequency=1 @ u_Hz, stop_frequency=1_000_000 @ u_Hz,
number_of_points=20, variation="dec",
)
出てきた Bode 線図がこれです。

そして「本当に正しく回っているか」の答え合わせ。実測値はこうでした。
| 指標 | 値 |
|---|---|
| 理論カットオフ fc | 159.15 Hz |
| 実測 −3dB 点 | ≈ 158.49 Hz(理論と 0.4% 差) |
| DC ゲイン | −0.00 dB |
| 1 MHz ゲイン | −76 dB(−20dB/dec ロールオフ) |
| 位相 | 0° → fc で −45° → 高域 −90° |
理論値と実測がほぼ一致。これでようやく「PySpice が、私の権限の無い環境で、正しく回った」と言い切れます。前回の宿題は、ここで回収できました。
正直に書いておく注意点
実行時にこの警告が出ます。
Unsupported Ngspice version 41
PySpice 1.5 は ngspice 41 を「正式サポート」とは宣言していません。動きはする(上の結果がその証拠)が、将来の挙動保証は別問題です。再現性を固めるなら、conda-forge で ngspice のバージョンを固定(例: ngspice=xx)し、PySpice 側の対応バージョンと突き合わせるのが堅い。「動いた」と「保証された」は違う、というのは現場では常に意識する線です。
結論 — 壁の正体は「権限」、現実解は配布物
今回分かったのは、ngspice の壁の正体は技術ではなく 権限 だった、ということです。そして権限が無いときの現実解は「ソースからビルド」ではなく「conda-forge のような配布物を userspace に落とす」だった。これは回路シミュレーションに限らず、権限の絞られた環境で計算系ツールを動かすとき、そのまま使える型です。環境の壁の越え方そのものが、再利用できる資産になりました。
次は、この lab-circuit-python を Atelier Lab に育てます。skidl で回路を組み、PySpice で検証し、波形を出す——前回からの 3 つのライブラリが、ここで初めて一本につながります。将来的には STM32(Renode)や FPGA と同じターミナルで観測できる統合ラボへ。コードは MIT で公開します。
この記事は Zenn に初出したものを加筆・補足したものです ── Zenn の元記事を見る