Tcl SpiceGenTcl package (v0.61)

TipsTop, Main, Index

This page contains different tips that help you to use SpiceGenTcl more efficiently.

Define custom elementTop, Main, Index

To define custom element class we should use ::SpiceGenTcl::Device class as a superclass. Why we need this? One simple example is custom Verilog-A device, that could have arbitary number of pins and parameters. Let's try to define new element for next Verilog-A device:

// Jiles/Atherton Magnetic Core Model
// Enhanced as described in "Simulation and MOdeling of Nonlinear Magnetics"
// by Williams, Vogelsong, and Kundert, as found on www.designers-guide.org.
`include "discipline.h"
`include "constants.h"

//
// Core Model
//
module coreja(p,n);

magnetic p, n;
inout p, n;
(* type = "instance" *) parameter real len=0.1 from (0:1000);   // effective magnetic length of core
(* type = "instance" *) parameter real area=1 from (0:inf);     // magnetic cross-sectional area of core
parameter real ms=1.6M from (0:inf);    // saturation magnetization
parameter real a=1100 from (0:inf);     // 
parameter real k=2000 from (0:inf);     // bulk coupliing coefficient
parameter real alpha=1.6m from (0:inf); // interdomain coupling coef.
parameter real c=0.2 from [0:1];        // coef. for reversable magnetization

magnetic Hdot;          // internal Hdot node
real H;                 // field intensity
real B;                 // flux density
real Manh;              // anhysteric magnetization
real Mirr;              // irreversible magnetization
real dMirr;             // dMirr/dH
real M;                 // total magnetization
real Heff;              // effective field intensity
integer delta;          // direction of the input MMF
integer migrating;      // flag indicating that the pinning sites are moving

// sign function
    analog function integer sign;
    input arg;
    real arg;
    sign = (arg >= 0.0 ? 1 : -1);
    endfunction

// hyperbolic cotangent function
    analog function real coth;
    input arg;
    real arg;
    real x;
    begin
        x = exp(min(80,max(-80,arg)));
        coth = (x+1/x)/(x-1/x);
    end
    endfunction

// core model
    analog begin
    H = MMF(p,n) / len;
    MMF(Hdot) <+ ddt(H);
    delta = sign(MMF(Hdot));
    B = Phi(p,n)/area;
    M = B/`P_U0 - H;
    Heff = H + alpha * M;
    if (abs(Heff) > 0.001 * a) 
        Manh = ms * (coth(Heff/a) - a/Heff);
    else
        Manh = ms * Heff/(3.0*a);       // Taylor series expansion of coth()
    dMirr = (Manh - M)/(delta*k - alpha*(Manh - M)) * MMF(Hdot);
    migrating = (delta > 0) ^ (M > Manh);
    Mirr = idt( migrating * dMirr, Manh );

    M = (1-c)*Mirr + c*Manh;
    Phi(p,n) <+ area*`P_U0*(H+M);
    end
endmodule

This model is taken from designers-guide, that contains many Verilog-AMS models.

oo::class create Core {
    superclass Device
    constructor {name pNode nNode args} {
        set arguments [argparse -inline {
            {-model= -required}
            {-len= -default 0.1}
            {-area= -default 1}
        }]
        lappend paramList "model [dget $arguments model] -posnocheck"
        dict for {paramName value} $arguments {
            if {$paramName ni {model}} {
                lappend paramList "$paramName $value"
            }
        }
        next n$name [list "p $pNode" "n $nNode"] $paramList
    }
}

In this block of code we define instance class of core. Let's go through the each line. First line is class definition:

oo::class create Core

It is good convention to start class name from capital letter.

Superclass for new element is ::SpiceGenTcl::Device:

superclass SpiceGenTcl::Device

In next line we define arguments for constructor:

constructor {name pNode nNode args}

First argument is name of instance, then positive node and negative node names, args accepts model value after -model key and all instance parameters of device.

In these few lines we process args variable with argparse package:

set arguments [argparse -inline "
    {-model= -required}
    {-len= -default 0.1}
    {-area= -default 1}
"]

Here we define required -model argument, and optional instance arguments -len and -area with default values. Due to these lines we can pass parameters to element in forms -paramName $paramValue $paramQual, for example: -area 1e-4 or -area l*m -eq.

Possible qualificator is -eq - it means that parameter should be inserted into SPICE netlist as paramName={expression}

In the next few lines we build parameter list that will be passed to ::SpiceGenTcl::Device constructor:

lappend paramList "model [dget $arguments model] -posnocheck"
dict for {paramName value} $arguments {
    if {$paramName ni {model}} {
        lappend paramList "$paramName $value"
    }
}

The last but not the least is step of passing arguments to ::SpiceGenTcl::Device constructor:

next n$name [list "p $pNode" "n $nNode"] $params

This superclass accept arguments in form constructor {name pins modelName instParams}. So, we pass string n$name as device name, n is reference designator for Verilog-a devices in Ngspice. Secondly we pass list of nodes [list "p $pNode" "n $nNode"] in form of {{Name0 NodeName} {Name1 NodeName} {Name2 NodeName} ...}. And the last is list of parameters in form {{model Value -posnocheck} {Name Value ?-eq?} {Name Value ?-eq?} {Name Value ?-eq?} ...}.

So, after that we can create a new instance of newly created class:

set coreInst [Core new 1 p n -model coreModel -area 1e-4 -len {l*5 -eq}]
puts [$coreInst genSPICEString]

Resulted SPICE string is:

n1 p n coremodel area=1e-4 len={l*5}

Verilog-A devices in Ngspice demand corresponding model being instantiated in the netlist. For that purpose we create CoreModel class:

oo::class create CoreModel {
    superclass Model
    constructor {name args} {
        set paramsNames [list ms a k alpha c]
        next $name coreja [my argsPreprocess $paramsNames {*}$args]
    }
}

Here we use as superclass ::SpiceGenTcl::Model for new element. Next we define constructor for model, first argument is name of model and args that accepts model value all instance parameters of device. To process optional arguments, we use special method ::SpiceGenTcl::KeyArgsBuilder::argsPreprocess, that process optional args arguments and produces string for ::SpiceGenTcl::Model constructor.

set paramsNames [list ms a k alpha c]
next $name coreja [my argsPreprocess $paramsNames {*}$args]

We set model parameters in list paramsNames, and after that we pass arguments to superclass's constructor. The name coreja corresponds to name of Verilog-A module.

We use ::SpiceGenTcl::KeyArgsBuilder::argsPreprocess procedure here, but we can go the same way we do with Core class, and add, for example, default values, or use some complex logic of elements initialization:

oo::class create CoreModel {
    superclass Model
    constructor {name args} {
        set arguments [argparse -inline {
            -ms=
            {-a= -default 1000}
            -k=
            -alpha=
            -c=
        }]
        dict for {paramName value} $arguments {
            lappend paramList "$paramName $value"
        }
        next $name coreja $paramList
    }
}

Finally, we initialize model instance and print SPICE string:

set coreModel [CoreModel new coremodel -ms 1.7meg -a 1100 -k 2000 -alpha 1.6m -c 0.2]
puts [$coreModel genSPICEString]

The result is:

.model coremodel coreja(ms=1.7meg a=1100 k=2000 alpha=1.6m c=0.2)

If you want to see the simulation example with that model, please look at /examples/ngspice/advanced/verilog_a_magnetic.tcl.