ngspice开发配置与指引

ngspice开发配置与指引

社蕙 10 2024-06-21

1. 编译

全局编译

./autogen.sh
  cd release/
  ./reconfigure
  make -j8

1.1 新建编译

mkdir src/zhy
  touch sobar.h sobar.c # 创建需要的源文件

然后创建一个Makefile.am:

noinst_LTLIBRARIES = libsobar.la

libsobar_la_SOURCES = \
                    sobar.c

AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/rcr
AM_CFLAGS = $(STATIC)

MAINTAINERCLEANFILES = Makefile.in
  1. 去外层的 src/Makefile.amSUBDIRS = 后添加上zhy等需要的子文件夹;
  2. 继续在这个文件的某个地方增加一行 ngspice_LDADD += zhy/libsobar.la,把zhy这个文件夹中的库编译进来;
  3. 去根目录的 configure.ac找到 AC_CONFIG_FILES,在其中加上 src/zhy/Makefile,确保能生成 Makefile.in文件;
  4. 重新跑一次编译。

1.2 新建联合编译

如果是使用c++写的,则内容上还需要另行修改:

noinst_LTLIBRARIES = libsobar.la

libsobar_la_SOURCES = \
                    sobar.cpp

# libsobar_la_LDFLAGS = -larmadillo

AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
AM_CXXFLAGS = -std=c++11 -fpermissive -larmadillo
AM_CFLAGS = $(STATIC)

MAINTAINERCLEANFILES = Makefile.in

主要是需要加上CXXFLAGS,另外需要注意,所有cpp中的函数定义必须用 extern "C"包裹,否则函数被改名后编译器会报符号错误。

2. 开发

.h 里面尽量不要include其他文件。

2.1 总函数入口

src/frontend/inp.c inp_source()抓取 ft_curckt

2.2 数据结构

  • 节点链表:ft_curckt->ci_ckt->CKTnodes,使用next遍历。
  • 器件列表比较复杂,以电容为例:
ccode = CKTtypelook("Capacitor");

  for (CAPmodel* model = (CAPmodel*)ft_curckt->ci_ckt->CKThead[ccode]; model;
             model = CAPnextModel(model)){
             // 这里首先需要用CKThead[ccode]找出一个全局的编码

// CKThead是一个GENmodel类型的指针,要强制转换成CAPModel,有一种C强行实现继承的味道
             ...
             }
  • 电流源的分类在 isrcload.c中,参考一下。
  • 在cp_evloop中,control这个wordlist存储了控制命令。

2.3 仿真入口

  • main.c:115:定义了一个 IFsimulator *ft_sim,这是一个包含了大量空壳函数指针的结构体,也就是一个仿真器的原型,在正常默认编译中它被 SIMinfo 初始化。

  • ngspice.c:29:SIMinfo在此处定义,CKTdoJob 就是仿真函数。

  • cktdojob.c:28:其第一部分将task中的参数搬运到ckt中,第二部分从217:for开始,作者指出, /* Analysis order is important */,这个循环本质上是将job按照 analInfo 这个数组的顺序做事,这个数组在analysis.c中定义,例如前五个仿真按顺序是:

    SPICEanalysis *analInfo[] = {
    &OPTinfo,
    &ACinfo,
    &DCTinfo,
    &DCOinfo,
    &TRANinfo,
    ...
    

    那么它的意思就是必须先做完DCO(Peration)仿真,才会去做TRAN(sient)仿真。接下来在:222做一次an_init,在:238做一次an_func,以tran为例,首先初始化会进 traninit.c,在这里会得到tran仿真最重要的一系列时间参数。

数学

\begin{bmatrix} G & E \\ -E^T & 0 \end{bmatrix} \begin{bmatrix} V(s)\\I(s) \end{bmatrix} + \begin{bmatrix} C \\ & H \end{bmatrix} \begin{bmatrix} sV(s)\\sI(s) \end{bmatrix} = \begin{bmatrix} B\\0 \end{bmatrix}U(s)
\begin{aligned} GV(s)+EI(s)+sCV(s)&=BU(s)\\ -E^TV(s)+sHI(s)&=0 \end{aligned}

假设电感矩阵H可逆,才有:

(sC+G+\frac{1}{s}EH^{-1}E^T)V(s)=BU(s)

然而需要注意到,对于一般的,由于电压源的存在,H矩阵是奇异的。

更一般的NMA

因此提出一个想法,即调换MNA的构成方式,将电感电流放在最后一行,如

\begin{bmatrix} G & F & E \\ -F^T \\ -E^T \end{bmatrix} \begin{bmatrix} V(s)\\I_s(s)\\I_L(s) \end{bmatrix} + \begin{bmatrix} C \\ &0 \\&& H \end{bmatrix} \begin{bmatrix} sV(s)\\sI_s(s)\\sI_L(s) \end{bmatrix} = \begin{bmatrix} B_1\\B_2\\0 \end{bmatrix}U(s)

这里还要检查一个部分,就是B最后那里是个0,这是否意味着还是没法插入一些电流相关的量?

其他

  1. pinv的作用是什么?
  2. pinv算起来很慢,有没有办法优化?