update vdmos with self-heating network and tj and tcase terminal

This commit is contained in:
dwarning 2020-01-25 16:12:05 +01:00
parent 35dbc7a725
commit f53462dfd8
23 changed files with 1273 additions and 774 deletions

View File

@ -4009,7 +4009,7 @@ static int get_number_terminals(char *c)
char *inst = gettok_instance(&c);
strncpy(nam_buf, inst, sizeof(nam_buf) - 1);
txfree(inst);
if (strstr(nam_buf, "off") || strchr(nam_buf, '='))
if (strstr(nam_buf, "off") || strchr(nam_buf, '=') || strstr(nam_buf, "tnodeout"))
break;
i++;
}

View File

@ -620,7 +620,7 @@ http://ltwiki.org/index.php5?title=Undocumented_LTspice#VDMOS:_Breakdown_and_Sub
void
DevCapVDMOS(double vgd, double cgdmin,
double cgdmax, double a, double cgs,
double *capgs, double *capgd, double *capgb)
double *capgs, double *capgd)
{
double s = (cgdmax - cgdmin) / (1 + M_PI / 2);
double y = cgdmax - s;
@ -629,7 +629,6 @@ DevCapVDMOS(double vgd, double cgdmin,
else
*capgd = 0.5 * (s * atan(a * vgd) + y);
*capgs = 0.5 * cgs;
*capgb = 0;
}
/* Compute the MOS overlap capacitances as functions of the device

View File

@ -22,6 +22,7 @@ libvdmos_la_SOURCES = \
vdmospar.c \
vdmospzld.c \
vdmosset.c \
vdmossoachk.c \
vdmostemp.c \
vdmostrun.c

View File

@ -2,7 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1987 Thomas L. Quarles
Modified: 2000 AlansFixes
VDMOS Model: 2018 Holger Vogt
VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#include "ngspice/ngspice.h"
@ -12,35 +12,36 @@ VDMOS Model: 2018 Holger Vogt
#include "ngspice/suffix.h"
IFparm VDMOSpTable[] = { /* parameters */
IOPU("mu", VDMOS_M, IF_REAL, "Multiplier"),
IOPU("l", VDMOS_L, IF_REAL, "Length"),
IOPU("w", VDMOS_W, IF_REAL, "Width"),
IP("off", VDMOS_OFF, IF_FLAG, "Device initially off"),
IOPU("icvds", VDMOS_IC_VDS, IF_REAL, "Initial D-S voltage"),
IOPU("icvgs", VDMOS_IC_VGS, IF_REAL, "Initial G-S voltage"),
IOPU("temp", VDMOS_TEMP, IF_REAL, "Instance temperature"),
IOPU("dtemp", VDMOS_DTEMP, IF_REAL, "Instance temperature difference"),
IP( "ic", VDMOS_IC, IF_REALVEC, "Vector of D-S, G-S voltages"),
IOPU("m", VDMOS_M, IF_REAL, "Multiplier"),
IOPU("l", VDMOS_L, IF_REAL, "Length"),
IOPU("w", VDMOS_W, IF_REAL, "Width"),
IP("off", VDMOS_OFF, IF_FLAG, "Device initially off"),
IOPU("icvds", VDMOS_IC_VDS, IF_REAL, "Initial D-S voltage"),
IOPU("icvgs", VDMOS_IC_VGS, IF_REAL, "Initial G-S voltage"),
IOPU("temp", VDMOS_TEMP, IF_REAL, "Instance temperature"),
IOPU("dtemp", VDMOS_DTEMP, IF_REAL, "Instance temperature difference"),
IP( "ic", VDMOS_IC, IF_REALVEC, "Vector of D-S, G-S voltages"),
OP( "id", VDMOS_CD, IF_REAL, "Drain current"),
OP( "is", VDMOS_CS, IF_REAL, "Source current"),
OP( "ig", VDMOS_CG, IF_REAL, "Gate current "),
OP( "vgs", VDMOS_VGS, IF_REAL, "Gate-Source voltage"),
OP( "vds", VDMOS_VDS, IF_REAL, "Drain-Source voltage"),
OP( "cgs", VDMOS_CAPGS, IF_REAL, "Gate-Source capacitance"),
OP( "cgd", VDMOS_CAPGD, IF_REAL, "Gate-Drain capacitance"),
OP( "cds", VDMOS_CAPDS, IF_REAL, "Drain-Source capacitance"),
IOP("tnodeout", VDMOS_TNODEOUT, IF_FLAG, "Thermal model switch on/off"),
OP( "id", VDMOS_CD, IF_REAL, "Drain current"),
OP( "is", VDMOS_CS, IF_REAL, "Source current"),
OP( "ig", VDMOS_CG, IF_REAL, "Gate current"),
OP( "vgs", VDMOS_VGS, IF_REAL, "Gate-Source voltage"),
OP( "vds", VDMOS_VDS, IF_REAL, "Drain-Source voltage"),
OP( "cgs", VDMOS_CAPGS, IF_REAL, "Gate-Source capacitance"),
OP( "cgd", VDMOS_CAPGD, IF_REAL, "Gate-Drain capacitance"),
OP( "cds", VDMOS_CAPDS, IF_REAL, "Drain-Source capacitance"),
OPU( "dnode", VDMOS_DNODE, IF_INTEGER, "Number of the drain node "),
OPU( "gnode", VDMOS_GNODE, IF_INTEGER, "Number of the gate node "),
OPU( "snode", VDMOS_SNODE, IF_INTEGER, "Number of the source node "),
OPU( "tempnode", VDMOS_TNODE, IF_INTEGER, "Number of temperature node"),
OPU( "tcasenode", VDMOS_TCASE, IF_INTEGER, "Number of 2nd temperature node"),
OPU( "dnodeprime", VDMOS_DNODEPRIME, IF_INTEGER, "Number of int. drain node"),
OPU( "snodeprime", VDMOS_SNODEPRIME, IF_INTEGER, "Number of int. source node "),
OP( "von", VDMOS_VON, IF_REAL, " "),
OP( "vdsat", VDMOS_VDSAT, IF_REAL, "Saturation drain voltage"),
OPU( "sourcevcrit", VDMOS_SOURCEVCRIT, IF_REAL, "Critical source voltage"),
OPU( "drainvcrit", VDMOS_DRAINVCRIT, IF_REAL, "Critical drain voltage"),
OP( "von", VDMOS_VON, IF_REAL, "Device on state voltage"),
OP( "rs", VDMOS_SOURCERESIST, IF_REAL, "Source resistance"),
OPU("sourceconductance", VDMOS_SOURCECONDUCT, IF_REAL, "Conductance of source"),
OP( "rd", VDMOS_DRAINRESIST, IF_REAL, "Drain conductance"),
@ -54,13 +55,14 @@ IFparm VDMOSpTable[] = { /* parameters */
OPU( "qgs", VDMOS_QGS, IF_REAL, "Gate-Source charge storage"),
OPU( "qgd", VDMOS_QGD, IF_REAL, "Gate-Drain charge storage"),
OPU( "p", VDMOS_POWER, IF_REAL, "Instaneous power"),
OPU( "p", VDMOS_POWER, IF_REAL, "Instantaneous power"),
};
IFparm VDMOSmPTable[] = { /* model parameters */
/* basic device */
OP("type", VDMOS_MOD_TYPE, IF_STRING, "N-channel or P-channel MOS"),
IOP("vto", VDMOS_MOD_VTO, IF_REAL, "Threshold voltage"),
IOP("vto", VDMOS_MOD_VTH, IF_REAL, "Threshold voltage"),
IOPR("vth0", VDMOS_MOD_VTH, IF_REAL, "Threshold voltage"),
IOP("kp", VDMOS_MOD_KP, IF_REAL, "Transconductance parameter"),
IOP("phi", VDMOS_MOD_PHI, IF_REAL, "Surface potential"),
IOP("lambda",VDMOS_MOD_LAMBDA,IF_REAL, "Channel length modulation"),
@ -80,10 +82,17 @@ IFparm VDMOSmPTable[] = { /* model parameters */
IOP("vq", VDMOS_MOD_VQ, IF_REAL, "Quasi saturation voltage fitting parameter"),
IOP("mtriode", VDMOS_MOD_MTRIODE, IF_REAL, "Conductance multiplier in triode region"),
/* temperature dependency */
IOP( "tcvth", VDMOS_MOD_TCVTH, IF_REAL, "Linear Vth0 temperature coefficient"),
IOPR("vtotc", VDMOS_MOD_TCVTH, IF_REAL, "Linear Vth0 temperature coefficient"),
IOP( "mu", VDMOS_MOD_MU, IF_REAL, "Exponent of gain temperature dependency"),
IOPR("bex", VDMOS_MOD_MU, IF_REAL, "Exponent of gain temperature dependency"),
IOP( "texp0", VDMOS_MOD_TEXP0, IF_REAL, "Drain resistance rd0 temperature exponent"),
IOP( "texp1", VDMOS_MOD_TEXP1, IF_REAL, "Drain resistance rd1 temperature exponent"),
/* weak inversion */
IOP("subslope", VDMOS_MOD_SUBSLOPE, IF_REAL, "Slope of weak inversion log current versus vgs - vth"),
IOP("subshift", VDMOS_MOD_SUBSHIFT, IF_REAL, "Shift of weak inversion plot on the vgs axis"),
IOP("ksubthres", VDMOS_MOD_KSUBTHRES, IF_REAL, "Shift of weak inversion plot on the vgs axis"),
IOP("ksubthres", VDMOS_MOD_KSUBTHRES, IF_REAL, "Slope of weak inversion log current versus vgs"),
/* body diode */
IOP("bv", VDMOS_MOD_BV, IF_REAL, "Vds breakdown voltage"),
@ -94,7 +103,7 @@ IFparm VDMOSmPTable[] = { /* model parameters */
IOP("n", VDMOS_MOD_N, IF_REAL, "Body diode emission coefficient"),
IOP("tt", VDMOS_MOD_TT, IF_REAL, "Body diode transit time"),
IOP("eg", VDMOS_MOD_EG, IF_REAL, "Body diode activation energy for temperature effect on Is"),
IOP("Xti", VDMOS_MOD_XTI, IF_REAL, "Body diode saturation current temperature exponent"),
IOP("xti", VDMOS_MOD_XTI, IF_REAL, "Body diode saturation current temperature exponent"),
IOP("is", VDMOS_MOD_IS, IF_REAL, "Body diode saturation current"),
IOP("vj", VDMOS_MOD_VJ, IF_REAL, "Body diode junction potential"),
@ -108,16 +117,30 @@ IFparm VDMOSmPTable[] = { /* model parameters */
IOPA("cgdmax", VDMOS_MOD_CGDMAX, IF_REAL, "Maximum non-linear G-D capacitance"),
IOPA("a", VDMOS_MOD_A, IF_REAL, "Non-linear Cgd capacitance parameter"),
IOPA("cgs", VDMOS_MOD_CGS, IF_REAL, "Gate-source capacitance"),
/* self heating */
IOP("rthjc", VDMOS_MOD_RTHJC, IF_REAL, "Self-heating thermal resistance"),
IOP("rthca", VDMOS_MOD_RTHCA, IF_REAL, "Self-heating thermal resistance"),
IOP("cthj", VDMOS_MOD_CTHJ, IF_REAL, "Self-heating thermal capacitance"),
/* soa check */
IOP("vgs_max", VDMOS_MOD_VGS_MAX, IF_REAL, "maximum voltage G-S branch"),
IOP("vgd_max", VDMOS_MOD_VGD_MAX, IF_REAL, "maximum voltage G-D branch"),
IOP("vds_max", VDMOS_MOD_VDS_MAX, IF_REAL, "maximum voltage D-S branch"),
IOP("vgsr_max", VDMOS_MOD_VGSR_MAX, IF_REAL, "maximum voltage G-S branch"),
IOP("vgdr_max", VDMOS_MOD_VGDR_MAX, IF_REAL, "maximum voltage G-D branch"),
};
char *VDMOSnames[] = {
"Drain",
"Gate",
"Source"
"Source",
"Temp",
"Tcase"
};
int VDMOSnSize = NUMELEMS(VDMOSnames);
int VDMOSpTSize = NUMELEMS(VDMOSpTable);
int VDMOSmPTSize = NUMELEMS(VDMOSmPTable);
int VDMOSiSize = sizeof(VDMOSinstance);
int VDMOSmSize = sizeof(VDMOSmodel);
int VDMOSnSize = NUMELEMS(VDMOSnames);
int VDMOSpTSize = NUMELEMS(VDMOSpTable);
int VDMOSmPTSize = NUMELEMS(VDMOSmPTable);
int VDMOSiSize = sizeof(VDMOSinstance);
int VDMOSmSize = sizeof(VDMOSmodel);

View File

@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
/*
*/
@ -20,15 +21,21 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
VDMOSinstance *here;
int xnrm;
int xrev;
double xgs;
double xgd;
double capgs;
double capgd;
double xgs, xcgT;
double xgd, xcdT;
double capgs, cgT;
double capgd, cdT;
double cTt, gTtt, gTtg, gTtdp, gTtsp;
double GmT;
double xcsT, xcTt;
register int selfheat;
for( ; model != NULL; model = VDMOSnextModel(model)) {
for(here = VDMOSinstances(model); here!= NULL;
here = VDMOSnextInstance(here)) {
selfheat = (here->VDMOStnodeoutGiven) && (model->VDMOSrthjc != 0.0);
if (here->VDMOSmode < 0) {
xnrm=0;
xrev=1;
@ -36,6 +43,27 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
xnrm=1;
xrev=0;
}
if (here->VDMOSmode >= 0) {
GmT = model->VDMOStype * here->VDMOSgmT;
cgT = model->VDMOStype * here->VDMOScgT;
cdT = model->VDMOStype * here->VDMOScdT;
cTt = model->VDMOScthj;
gTtg = here->VDMOSgtempg;
gTtdp = here->VDMOSgtempd;
gTtt = here->VDMOSgtempT;
gTtsp = - (gTtg + gTtdp);
} else {
GmT = -model->VDMOStype * here->VDMOSgmT;
cgT = -model->VDMOStype * here->VDMOScgT;
cdT = -model->VDMOStype * here->VDMOScdT;
cTt = -model->VDMOScthj;
gTtg = -here->VDMOSgtempg;
gTtdp = -here->VDMOSgtempd;
gTtt = -here->VDMOSgtempT;
gTtsp = gTtg + gTtdp;
}
/*
* VDMOS cap model parameters
*/
@ -46,7 +74,12 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
xgs = capgs * ckt->CKTomega;
xgd = capgd * ckt->CKTomega;
/* bulk diode */
xcgT = cgT * ckt->CKTomega;
xcdT = cdT * ckt->CKTomega;
xcsT = -(cgT + cdT) * ckt->CKTomega;
xcTt = cTt * ckt->CKTomega;
/* body diode */
double gspr, geq, xceq;
gspr = here->VDIOtConductance;
geq = *(ckt->CKTstate0 + here->VDIOconduct);
@ -62,6 +95,7 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
*(here->VDMOSGPspPtr +1) -= xgs;
*(here->VDMOSDPgpPtr +1) -= xgd;
*(here->VDMOSSPgpPtr +1) -= xgs;
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance;
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance;
*(here->VDMOSDPdpPtr) += here->VDMOSdrainConductance+
@ -78,10 +112,10 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
*(here->VDMOSSPdpPtr) -= here->VDMOSgds+xrev*(here->VDMOSgm);
/* gate resistor */
*(here->VDMOSGgPtr) += (here->VDMOSgateConductance);
*(here->VDMOSGPgpPtr) += (here->VDMOSgateConductance)/* + ?? FIXME */;
*(here->VDMOSGPgpPtr) += (here->VDMOSgateConductance);
*(here->VDMOSGgpPtr) -= here->VDMOSgateConductance;
*(here->VDMOSGPgPtr) -= here->VDMOSgateConductance;
/* bulk diode */
/* body diode */
*(here->VDMOSSsPtr) += gspr;
*(here->VDMOSDdPtr) += geq;
*(here->VDMOSDdPtr +1) += xceq;
@ -93,6 +127,29 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
*(here->VDIORPsPtr) -= gspr;
*(here->VDIORPdPtr) -= geq;
*(here->VDIORPdPtr +1) -= xceq;
if (selfheat)
{
*(here->VDMOSDPtempPtr) += GmT;
*(here->VDMOSSPtempPtr) += -GmT;
*(here->VDMOSTemptempPtr) += gTtt + 1/model->VDMOSrthjc;
*(here->VDMOSTempgpPtr) += gTtg;
*(here->VDMOSTempdpPtr) += gTtdp;
*(here->VDMOSTempspPtr) += gTtsp;
*(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc;
*(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc;
*(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca;
*(here->VDMOSTptpPtr) += 1/model->VDMOSrthca;
*(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca;
*(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca;
*(here->VDMOSCktTtpPtr) += 1.0;
*(here->VDMOSTpcktTPtr) += 1.0;
*(here->VDMOSTemptempPtr + 1) += xcTt;
*(here->VDMOSDPtempPtr + 1) += xcdT;
*(here->VDMOSSPtempPtr + 1) += xcsT;
*(here->VDMOSGPtempPtr + 1) += xcgT;
}
}
}
return(OK);

View File

@ -43,19 +43,22 @@ VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
return(OK);
case VDMOS_L:
value->rValue = here->VDMOSl;
return(OK);
return(OK);
case VDMOS_W:
value->rValue = here->VDMOSw;
return(OK);
return(OK);
case VDMOS_OFF:
value->rValue = here->VDMOSoff;
return(OK);
value->iValue = here->VDMOSoff;
return(OK);
case VDMOS_TNODEOUT:
value->iValue = here->VDMOStnodeout;
return(OK);
case VDMOS_IC_VDS:
value->rValue = here->VDMOSicVDS;
return(OK);
return(OK);
case VDMOS_IC_VGS:
value->rValue = here->VDMOSicVGS;
return(OK);
return(OK);
case VDMOS_DNODE:
value->iValue = here->VDMOSdNode;
return(OK);
@ -65,6 +68,9 @@ VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
case VDMOS_SNODE:
value->iValue = here->VDMOSsNode;
return(OK);
case VDMOS_TNODE:
value->iValue = here->VDMOStempNode;
return(OK);
case VDMOS_SNODEPRIME:
value->iValue = here->VDMOSsNodePrime;
return(OK);
@ -89,15 +95,6 @@ VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
case VDMOS_VON:
value->rValue = here->VDMOSvon;
return(OK);
case VDMOS_VDSAT:
value->rValue = here->VDMOSvdsat;
return(OK);
case VDMOS_SOURCEVCRIT:
value->rValue = here->VDMOSsourceVcrit;
return(OK);
case VDMOS_DRAINVCRIT:
value->rValue = here->VDMOSdrainVcrit;
return(OK);
case VDMOS_CD:
value->rValue = here->VDMOScd;
return(OK);

View File

@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#ifndef VDMOS
@ -41,10 +42,15 @@ typedef struct sVDMOSinstance {
const int VDMOSdNode; /* number of the gate node of the mosfet */
const int VDMOSgNode; /* number of the gate node of the mosfet */
const int VDMOSsNode; /* number of the source node of the mosfet */
const int VDMOStempNode; /* number of the temperature node of the mosfet */
const int VDMOStcaseNode; /* number of the 2nd temperature node of the mosfet */
int VDMOSdNodePrime; /* number of the internal drain node of the mosfet */
int VDMOSsNodePrime; /* number of the internal source node of the mosfet */
int VDMOSgNodePrime; /* number of the internal gate node of the mosfet */
int VDIOposPrimeNode; /* number of the internal node of the bulk diode */
int VDMOStNodePrime; /* number of the internal temp node between voltage source and Rthca */
int VDIOposPrimeNode; /* number of the internal node of the body diode */
int VDMOSvcktTbranch; /* equation number of branch equation added for cktTemp source */
double VDMOSm; /* parallel device multiplier */
@ -52,42 +58,37 @@ typedef struct sVDMOSinstance {
double VDMOSw; /* the width of the channel region */
double VDMOSsourceConductance; /*conductance of source(or 0):set in setup*/
double VDMOSdrainConductance; /*conductance of drain(or 0):set in setup*/
double VDMOSdrainResistance; /*resistance of drain(or 0): set in temp*/
double VDMOSqsResistance; /*resistance of drain: set in temp*/
double VDMOSgateConductance; /*conductance of gate(or 0):set in setup*/
double VDMOSdsConductance; /*conductance of drain to source:set in setup*/
double VDMOStemp; /* operating temperature of this instance */
double VDMOSdtemp; /* operating temperature of the instance relative to circuit temperature*/
int VDMOStnodeout; /* flag indicate self heating on */
double VDMOStTransconductance; /* temperature corrected transconductance*/
double VDMOStPhi; /* temperature corrected Phi */
double VDMOStVto; /* temperature corrected Vto */
double VDMOStSatCur; /* temperature corrected saturation Cur. */
double VDMOStVth; /* temperature corrected Vth */
double VDMOSicVDS; /* initial condition D-S voltage */
double VDMOSicVGS; /* initial condition G-S voltage */
double VDMOSvon;
double VDMOSvdsat;
double VDMOSsourceVcrit; /* Vcrit for pos. vds */
double VDMOSdrainVcrit; /* Vcrit for pos. vds */
double VDMOScd;
double VDMOSgm;
double VDMOSgds;
double VDMOSf2d;
double VDMOSf3d;
double VDMOSf4d;
double VDMOSf2s;
double VDMOSf3s;
double VDMOSf4s;
double VDIOcap;
double VDIOtSatCur; /* temperature corrected saturation Cur. density*/
double VDIOtSatCur; /* temperature corrected saturation Cur. density*/
double VDIOinitCond;
double VDIOtVcrit;
double VDIOconductance;
double VDIOtConductance;
double VDIOtBrkdwnV;
double VDIOtJctCap;
double VDIOtDepCap; /* temperature adjusted transition point in */
/* the cureve matching Fc * Vj */
double VDIOtJctPot; /* temperature corrected Bulk potential */
/* the curve matching Fc * Vj */
double VDIOtJctPot; /* temperature corrected junction potential */
double VDIOtGradingCoeff;
double VDIOtTransitTime;
@ -95,6 +96,16 @@ typedef struct sVDMOSinstance {
double VDIOtF2;
double VDIOtF3;
double VDMOSTempSH; /* for portability of SH temp to noise analysis */
double VDMOSgmT;
double VDMOSgtempg;
double VDMOSgtempd;
double VDMOSgtempT;
double VDMOScgT;
double VDMOScdT;
double VDMOScth; /* current alias power */
/*
* naming convention:
* x = vgs
@ -135,21 +146,20 @@ typedef struct sVDMOSinstance {
int VDMOSmode; /* device mode : 1 = normal, -1 = inverse */
unsigned VDMOSoff:1; /* non-zero to indicate device is off for dc analysis*/
unsigned VDMOStempGiven :1; /* instance temperature specified */
unsigned VDMOSdtempGiven :1; /* instance delta temperature specified */
unsigned VDMOSmGiven :1;
unsigned VDMOSlGiven :1;
unsigned VDMOSwGiven :1;
unsigned VDMOSdNodePrimeSet :1;
unsigned VDMOSsNodePrimeSet :1;
unsigned VDMOSdNodePrimeSet :1;
unsigned VDMOSsNodePrimeSet :1;
unsigned VDMOSicVDSGiven :1;
unsigned VDMOSicVGSGiven :1;
unsigned VDMOSvonGiven :1;
unsigned VDMOStnodeoutGiven : 1; /* flag indicate self heating on */
unsigned VDMOSvonGiven : 1;
unsigned VDMOSvdsatGiven :1;
unsigned VDMOSmodeGiven :1;
unsigned VDMOSmodeGiven :1;
double *VDMOSDdPtr; /* pointer to sparse matrix element at
* (Drain node,drain node) */
@ -201,7 +211,7 @@ typedef struct sVDMOSinstance {
* (source node, drain node) */
double *VDMOSSdPtr; /* pointer to sparse matrix element at
* (drain node, source node) */
/* bulk diode */
/* body diode */
double *VDIORPdPtr; /* pointer to sparse matrix element at
* (diode prime node, drain node) */
double *VDIODrpPtr; /* pointer to sparse matrix element at
@ -212,32 +222,57 @@ typedef struct sVDMOSinstance {
* (source node, diode prime node) */
double *VDIORPsPtr; /* pointer to sparse matrix element at
* (diode prime node, source node) */
/* self heating */
double *VDMOSTemptempPtr;
double *VDMOSTempdpPtr;
double *VDMOSTempspPtr;
double *VDMOSTempgpPtr;
double *VDMOSGPtempPtr;
double *VDMOSDPtempPtr;
double *VDMOSSPtempPtr;
double *VDMOSTcasetcasePtr; /* for Rthjc */
double *VDMOSTcasetempPtr;
double *VDMOSTemptcasePtr;
double *VDMOSTptpPtr; /* for Rthca */
double *VDMOSTptcasePtr;
double *VDMOSTcasetpPtr;
double *VDMOSCktTcktTPtr; /* for VcktTemp */
double *VDMOSCktTtpPtr;
double *VDMOSTpcktTPtr;
} VDMOSinstance ;
#define VDMOSvgs VDMOSstates+ 0 /* gate-source voltage */
#define VDMOSvds VDMOSstates+ 1 /* drain-source voltage */
#define VDMOSdeltemp VDMOSstates+ 2
#define VDMOScapgs VDMOSstates+2 /* gate-source capacitor value */
#define VDMOSqgs VDMOSstates+ 3 /* gate-source capacitor charge */
#define VDMOScqgs VDMOSstates+ 4 /* gate-source capacitor current */
#define VDMOScapgs VDMOSstates+3 /* gate-source capacitor value */
#define VDMOSqgs VDMOSstates+ 4 /* gate-source capacitor charge */
#define VDMOScqgs VDMOSstates+ 5 /* gate-source capacitor current */
#define VDMOScapgd VDMOSstates+ 5 /* gate-drain capacitor value */
#define VDMOSqgd VDMOSstates+ 6 /* gate-drain capacitor charge */
#define VDMOScqgd VDMOSstates+ 7 /* gate-drain capacitor current */
#define VDMOScapgd VDMOSstates+ 6 /* gate-drain capacitor value */
#define VDMOSqgd VDMOSstates+ 7 /* gate-drain capacitor charge */
#define VDMOScqgd VDMOSstates+ 8 /* gate-drain capacitor current */
#define VDIOvoltage VDMOSstates+ 8
#define VDIOcurrent VDMOSstates+ 9
#define VDIOconduct VDMOSstates+ 10
#define VDIOcapCharge VDMOSstates+ 11
#define VDIOcapCurrent VDMOSstates+ 12
#define VDIOvoltage VDMOSstates+ 9
#define VDIOcurrent VDMOSstates+ 10
#define VDIOconduct VDMOSstates+ 11
#define VDIOcapCharge VDMOSstates+ 12
#define VDIOcapCurrent VDMOSstates+ 13
#define VDMOSnumStates 13
#define VDMOScapth VDMOSstates+ 14 /* thermal capacitor value */
#define VDMOSqth VDMOSstates+ 15 /* thermal capacitor charge */
#define VDMOScqth VDMOSstates+ 16 /* thermal capacitor current */
#define VDMOSnumStates 17
/* per model data */
/* NOTE: parameters marked 'input - use xxxx' are paramters for
/* NOTE: parameters marked 'input - use xxxx' are parameters for
* which a temperature correction is applied in VDMOStemp, thus
* the VDMOSxxxx value in the per-instance structure should be used
* instead in all calculations
@ -262,7 +297,7 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */
double VDMOSqsVoltage;
double VDMOStransconductance; /* input - use tTransconductance */
double VDMOSoxideCapFactor;
double VDMOSvt0; /* input - use tVto */
double VDMOSvth0; /* input - use tVth */
double VDMOSphi; /* input - use tPhi */
double VDMOSlambda;
double VDMOStheta;
@ -273,34 +308,44 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */
double VDMOScgdmax;
double VDMOSa;
double VDMOScgs;
double VDMOSsubsl;
double VDMOSsubshift;
double VDMOSksubthres;
double VDMOSmtr;
/* bulk diode */
/* body diode */
double VDIOjunctionCap; /* input - use tCj */
double VDIOjunctionPot; /* input - use tBulkPot */
double VDIOjunctionPot; /* input - use tJctPot */
double VDIOdepletionCapCoeff;
double VDIOjctSatCur; /* input - use tSatCur */
double VDMOSDbv;
double VDMOSDibv;
double VDMOSbv;
double VDMOSibv;
double VDIObrkdEmissionCoeff;
double VDIOresistance;
double VDIOresistTemp1;
double VDIOresistTemp2;
double VDIOconductance;
double VDMOSrds;
double VDMOSDn;
double VDMOSn;
double VDIOtransitTime;
double VDIOtranTimeTemp1;
double VDIOtranTimeTemp2;
double VDMOSDeg;
double VDMOSDxti;
double VDMOSeg;
double VDMOSxti;
double VDIOgradCoeff;
double VDIOgradCoeffTemp1;
double VDIOgradCoeffTemp2;
double VDMOSrthjc;
double VDMOSrthca;
double VDMOScthj;
double VDMOSmu;
double VDMOStexp0;
double VDMOStexp1;
double VDMOStcvth;
double VDMOSvgsMax;
double VDMOSvgdMax;
double VDMOSvdsMax;
double VDMOSvgsrMax;
double VDMOSvgdrMax;
unsigned VDMOStypeGiven :1;
unsigned VDIOjctSatCurGiven :1;
unsigned VDMOSdrainResistanceGiven :1;
@ -310,7 +355,7 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */
unsigned VDMOSqsVoltageGiven :1;
unsigned VDMOSqsGiven :1;
unsigned VDMOStransconductanceGiven :1;
unsigned VDMOSvt0Given :1;
unsigned VDMOSvth0Given :1;
unsigned VDIOgradCoeffGiven :1;
unsigned VDIOdepletionCapCoeffGiven :1;
unsigned VDMOSphiGiven :1;
@ -324,23 +369,35 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */
unsigned VDMOScgdmaxGiven :1;
unsigned VDMOScgsGiven :1;
unsigned VDMOSaGiven :1;
unsigned VDMOSsubslGiven :1;
unsigned VDMOSsubshiftGiven :1;
unsigned VDMOSksubthresGiven :1;
unsigned VDMOSmtrGiven :1;
unsigned VDMOSDbvGiven :1;
unsigned VDMOSDibvGiven :1;
unsigned VDMOSbvGiven :1;
unsigned VDMOSibvGiven :1;
unsigned VDIOjunctionCapGiven :1;
unsigned VDIOjunctionPotGiven :1;
unsigned VDIObrkdEmissionCoeffGiven :1;
unsigned VDIOresistanceGiven :1;
unsigned VDMOSrdsGiven :1;
unsigned VDMOSDnGiven :1;
unsigned VDMOSnGiven :1;
unsigned VDIOtransitTimeGiven :1;
unsigned VDMOSDegGiven :1;
unsigned VDMOSDxtiGiven :1;
unsigned VDMOSegGiven :1;
unsigned VDMOSxtiGiven :1;
unsigned VDMOSrthjcGiven :1;
unsigned VDMOSrthcaGiven :1;
unsigned VDMOScthjGiven :1;
unsigned VDMOSmuGiven :1;
unsigned VDMOStexp0Given :1;
unsigned VDMOStexp1Given :1;
unsigned VDMOStcvthGiven :1;
unsigned VDMOSvgsMaxGiven :1;
unsigned VDMOSvgdMaxGiven :1;
unsigned VDMOSvdsMaxGiven :1;
unsigned VDMOSvgsrMaxGiven :1;
unsigned VDMOSvgdrMaxGiven :1;
} VDMOSmodel;
#ifndef NMOS
@ -362,11 +419,12 @@ enum {
VDMOS_TEMP,
VDMOS_M,
VDMOS_DTEMP,
VDMOS_TNODEOUT,
};
/* model paramerers */
/* model parameters */
enum {
VDMOS_MOD_VTO = 101,
VDMOS_MOD_VTH = 101,
VDMOS_MOD_KP,
VDMOS_MOD_PHI,
VDMOS_MOD_LAMBDA,
@ -394,7 +452,6 @@ enum {
VDMOS_MOD_CGS,
VDMOS_MOD_RB,
VDMOS_MOD_MTRIODE,
VDMOS_MOD_SUBSLOPE,
VDMOS_MOD_SUBSHIFT,
VDMOS_MOD_KSUBTHRES,
VDMOS_MOD_BV,
@ -405,6 +462,18 @@ enum {
VDMOS_MOD_TT,
VDMOS_MOD_EG,
VDMOS_MOD_XTI,
VDMOS_MOD_RTHJC,
VDMOS_MOD_RTHCA,
VDMOS_MOD_CTHJ,
VDMOS_MOD_MU,
VDMOS_MOD_TEXP0,
VDMOS_MOD_TEXP1,
VDMOS_MOD_TCVTH,
VDMOS_MOD_VGS_MAX,
VDMOS_MOD_VGD_MAX,
VDMOS_MOD_VDS_MAX,
VDMOS_MOD_VGSR_MAX,
VDMOS_MOD_VGDR_MAX,
};
/* device questions */
@ -415,14 +484,13 @@ enum {
VDMOS_DNODE,
VDMOS_GNODE,
VDMOS_SNODE,
VDMOS_TNODE,
VDMOS_TCASE,
VDMOS_DNODEPRIME,
VDMOS_SNODEPRIME,
VDMOS_SOURCECONDUCT,
VDMOS_DRAINCONDUCT,
VDMOS_VON,
VDMOS_VDSAT,
VDMOS_SOURCEVCRIT,
VDMOS_DRAINVCRIT,
VDMOS_CD,
VDMOS_GM,
VDMOS_GDS,

View File

@ -21,8 +21,7 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
VDMOSmodel *model = (VDMOSmodel *) inModel;
VDMOSinstance *here;
double Beta;
double DrainSatCur;
double SourceSatCur;
double OxideCap;
double gm;
double gds;
double vgst;
@ -52,11 +51,10 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
vt = CONSTKoverQ * here->VDMOStemp;
DrainSatCur = here->VDMOSm * here->VDMOStSatCur;
SourceSatCur = here->VDMOSm * here->VDMOStSatCur;
Beta = here->VDMOStTransconductance;
Beta = here->VDMOStTransconductance * here->VDMOSm *
here->VDMOSw/here->VDMOSl;
OxideCap = model->VDMOSoxideCapFactor * here->VDMOSl *
here->VDMOSm * here->VDMOSw;
vgs = model->VDMOStype * (
*(ckt->CKTrhsOld+here->VDMOSgNode) -
@ -84,7 +82,7 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
/*
* this block of code evaluates the drain current and its
* derivatives using the shichman-hodges model and the
* charges associated with the gate, channel and bulk for
* charges associated with the gate and channel for
* mosfets
*
*/
@ -93,59 +91,50 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
* it is obvious that they can be made global
*/
{
double betap;
double von = here->VDMOStVth * model->VDMOStype;
vgst = (here->VDMOSmode == 1 ? vgs : vgd) - von;
vdsat = MAX(vgst, 0);
double slope = model->VDMOSksubthres;
double lambda = model->VDMOSlambda;
double theta = model->VDMOStheta;
double shift = model->VDMOSsubshift;
double mtr = model->VDMOSmtr;
vgst=(here->VDMOSmode==1?vgs:vgd);
vdsat=MAX(vgst,0);
/* scale vds with mtr (except with lambda) */
double vdss = vds*mtr*here->VDMOSmode;
double t0 = 1 + lambda*vds;
double t1 = 1 + theta*vgs;
double betap = Beta*t0/t1;
double dbetapdvgs = -Beta*theta*t0/(t1*t1);
double dbetapdvds = Beta*lambda/t1;
if (vgst <= 0) {
/*
* cutoff region
*/
/* cdrain = 0 */
gm=0;
gds=0;
gm2=gds2=0;
gmds=0;
gm3=gds3=0;
gm2ds=gmds2=0;
} else {
/*
* saturation region
*/
double t2 = exp((vgst-shift)/slope);
vgst = slope * log(1 + t2);
double dvgstdvgs = t2/(t2+1);
betap=Beta*(1+model->VDMOSlambda*(vds*here->VDMOSmode));
/* cdrain = betap * vgst * vgst * 0.5; */
if (vgst <= (vds*here->VDMOSmode)){
gm=betap*vgst;
gds=model->VDMOSlambda*Beta*vgst*vgst*.5;
if (vgst <= vdss) {
/* saturation region */
gm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst;
gds = .5*dbetapdvds*vgst*vgst;
gm2 = betap;
gds2 = 0;
gmds = vgst*model->VDMOSlambda*Beta;
gmds = Beta*lambda*vgst;
gm3 = 0;
gds3 = 0;
gm2ds = Beta * model->VDMOSlambda;
gm2ds = Beta*lambda;
gmds2 = 0;
} else {
/*
* linear region
*/
/* cdrain = betap * vds * (vgst - vds/2); */
gm=betap*(vds*here->VDMOSmode);
gds= Beta * model->VDMOSlambda*(vgst*
vds*here->VDMOSmode - vds*vds*0.5) +
betap*(vgst - vds*here->VDMOSmode);
}
else {
/* linear region */
gm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss);
gds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr;
gm2 = 0;
gds2 = 2*Beta * model->VDMOSlambda*(vgst -
vds*here->VDMOSmode) - betap;
gmds = Beta * model->VDMOSlambda* vds *
here->VDMOSmode + betap;
gds2 = 2*Beta * lambda*(vgst - vds*here->VDMOSmode) - betap;
gmds = Beta * lambda * vds * here->VDMOSmode + betap;
gm3=0;
gds3 = -Beta*model->VDMOSlambda*3.;
gds3 = -Beta*lambda*3.;
gm2ds=0;
gmds2 = 2*model->VDMOSlambda*Beta;
}
gmds2 = 2*lambda*Beta;
}
/*
* finished
@ -156,15 +145,6 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
/*
* COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
*/
/*
* now we do the hard part of the bulk-drain and bulk-source
* diode - we evaluate the non-linear capacitance and
* charge
*
* the basic equations are not hard, but the implementation
* is somewhat long in an attempt to avoid log/exponential
* evaluations
*/
/*
* meyer's capacitor model
*/
@ -180,7 +160,6 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
* expressions for the charge are available
*/
{
double phi;
@ -191,7 +170,7 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
/* von, vgst and vdsat have already been adjusted for
possible source-drain interchange */
phi = here->VDMOStPhi;
cox = 0;/*FIXME: can we do disto without knowing the oxide thickness?*/
cox = OxideCap; /*FIXME: using a guess for the oxide thickness of 1e-07 in vdmostemp.c */
lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
if (vgst <= 0) {
lcapgs2 = cox/(3*phi);

View File

@ -20,3 +20,4 @@ extern int VDMOSconvTest(GENmodel*,CKTcircuit*);
extern int VDMOSdisto(int,GENmodel*,CKTcircuit*);
extern int VDMOSnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*);
extern int VDMOSdSetup(GENmodel*,CKTcircuit*);
extern int VDMOSsoaCheck(CKTcircuit *, GENmodel *);

View File

@ -58,7 +58,7 @@ SPICEdev VDMOSinfo = {
.DEVsenTrunc = NULL,
.DEVdisto = VDMOSdisto,
.DEVnoise = VDMOSnoise,
.DEVsoaCheck = NULL,
.DEVsoaCheck = VDMOSsoaCheck,
.DEVinstSize = &VDMOSiSize,
.DEVmodSize = &VDMOSmSize,

View File

@ -2,7 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
VDMOS: 2018 Holger Vogt
VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#include "ngspice/ngspice.h"
@ -14,9 +14,35 @@ VDMOS: 2018 Holger Vogt
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
/* VDMOSlimitlog(deltemp, deltemp_old, LIM_TOL, check)
* Logarithmic damping the per-iteration change of deltemp beyond LIM_TOL.
*/
static double
cweakinv2(double sl, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr, double theta);
VDMOSlimitlog(
double deltemp,
double deltemp_old,
double LIM_TOL,
int *check)
{
*check = 0;
if (isnan (deltemp) || isnan (deltemp_old))
{
fprintf(stderr, "Alberto says: YOU TURKEY! The limiting function received NaN.\n");
fprintf(stderr, "New prediction returns to 0.0!\n");
deltemp = 0.0;
*check = 1;
}
/* Logarithmic damping of deltemp beyond LIM_TOL */
if (deltemp > deltemp_old + LIM_TOL) {
deltemp = deltemp_old + LIM_TOL + log10((deltemp-deltemp_old)/LIM_TOL);
*check = 1;
}
else if (deltemp < deltemp_old - LIM_TOL) {
deltemp = deltemp_old - LIM_TOL - log10((deltemp_old-deltemp)/LIM_TOL);
*check = 1;
}
return deltemp;
}
int
VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
@ -27,8 +53,6 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
VDMOSmodel *model = (VDMOSmodel *)inModel;
VDMOSinstance *here;
double Beta;
double DrainSatCur;
double SourceSatCur;
double arg;
double cdhat;
double cdrain;
@ -55,14 +79,18 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
#ifndef PREDICTOR
double xfact = 0.0;
#endif
int xnrm;
int xrev;
int xnrm, xrev;
double capgs = 0.0; /* total gate-source capacitance */
double capgd = 0.0; /* total gate-drain capacitance */
int Check;
double capth = 0.0; /* total thermal capacitance */
int Check_mos, Check_diode;
int error;
double CGBdummy;
register int selfheat;
double rd0T, rd1T, dBeta_dT, drd0T_dT, drd1T_dT, dIds_dT;
double deldelTemp, delTemp, delTemp1, Temp, Vds, Vgs;
double ceqqth=0.0;
double GmT, gTtg, gTtdp, gTtt, gTtsp, gcTt=0.0;
/* loop through all the VDMOS device models */
for (; model != NULL; model = VDMOSnextModel(model)) {
@ -76,34 +104,60 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
for (here = VDMOSinstances(model); here != NULL;
here = VDMOSnextInstance(here)) {
selfheat = (here->VDMOStnodeoutGiven) && (model->VDMOSrthjc != 0.0);
if (selfheat)
Check_mos = 1;
else
Check_mos = 0;
vt = CONSTKoverQ * here->VDMOStemp;
Check = 1;
/* first, we compute a few useful values - these could be
* pre-computed, but for historical reasons are still done
* here. They may be moved at the expense of instance size
*/
DrainSatCur = here->VDMOSm * here->VDMOStSatCur;
SourceSatCur = here->VDMOSm * here->VDMOStSatCur;
Beta = here->VDMOStTransconductance * here->VDMOSm *
here->VDMOSw / here->VDMOSl;
delTemp = 0.0;
if ((ckt->CKTmode & MODEINITSMSIG)) {
vgs = *(ckt->CKTstate0 + here->VDMOSvgs);
vds = *(ckt->CKTstate0 + here->VDMOSvds);
delTemp = *(ckt->CKTstate0 + here->VDMOSdeltemp);
} else if ((ckt->CKTmode & MODEINITTRAN)) {
vgs = *(ckt->CKTstate1 + here->VDMOSvgs);
vds = *(ckt->CKTstate1 + here->VDMOSvds);
delTemp = *(ckt->CKTstate1 + here->VDMOSdeltemp);
} else if ((ckt->CKTmode & MODEINITJCT) && !here->VDMOSoff) {
/* ok - not one of the simple cases, so we have to
* look at all of the possibilities for why we were
* called. We still just initialize the two voltages
*/
vds = model->VDMOStype * here->VDMOSicVDS;
vgs = model->VDMOStype * here->VDMOSicVGS;
delTemp = 0.0;
if ((vds == 0.0) && (vgs == 0.0) &&
((ckt->CKTmode & (MODETRAN | MODEAC|MODEDCOP |
MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC))))
{
vgs = model->VDMOStype * model->VDMOSvth0 + 0.1;
vds = 0.0;
}
} else if ((ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) && (here->VDMOSoff)) {
delTemp = vgs = vds = 0.0;
/*
* ok - now to do the start-up operations
*
* we must get values for vbs, vds, and vgs from somewhere
* we must get values for vds and vgs from somewhere
* so we either predict them or recover them from last iteration
* These are the two most common cases - either a prediction
* step or the general iteration step and they
* share some code, so we put them first - others later on
*/
if ((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG
| MODEINITTRAN)) ||
((ckt->CKTmode & MODEINITFIX) && (!here->VDMOSoff))) {
}
else
{
#ifndef PREDICTOR
if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) {
if (ckt->CKTmode & MODEINITPRED) {
/* predictor step */
@ -116,7 +170,13 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
*(ckt->CKTstate1 + here->VDMOSvds);
vds = (1 + xfact)* (*(ckt->CKTstate1 + here->VDMOSvds))
- (xfact * (*(ckt->CKTstate2 + here->VDMOSvds)));
} else {
*(ckt->CKTstate0 + here->VDMOSdeltemp) =
*(ckt->CKTstate1 + here->VDMOSdeltemp);
delTemp = (1 + xfact)* (*(ckt->CKTstate1 + here->VDMOSdeltemp))
- (xfact * (*(ckt->CKTstate2 + here->VDMOSdeltemp)));
}
else
{
#endif /* PREDICTOR */
/* general iteration */
@ -127,6 +187,10 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
vds = model->VDMOStype * (
*(ckt->CKTrhsOld + here->VDMOSdNodePrime) -
*(ckt->CKTrhsOld + here->VDMOSsNodePrime));
if (selfheat)
delTemp = *(ckt->CKTrhsOld + here->VDMOStempNode);
else
delTemp = 0.0;
#ifndef PREDICTOR
}
#endif /* PREDICTOR */
@ -140,61 +204,73 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
delvds = vds - *(ckt->CKTstate0 + here->VDMOSvds);
delvgd = vgd - vgdo;
deldelTemp = delTemp - *(ckt->CKTstate0 + here->VDMOSdeltemp);
/* these are needed for convergence testing */
if (here->VDMOSmode >= 0) {
cdhat =
here->VDMOScd
+ here->VDMOSgm * delvgs
+ here->VDMOSgds * delvds;
here->VDMOScd
+ here->VDMOSgm * delvgs
+ here->VDMOSgds * delvds
+ here->VDMOSgmT * deldelTemp;
} else {
cdhat =
here->VDMOScd
- here->VDMOSgm * delvgd
+ here->VDMOSgds * delvds;
here->VDMOScd
- here->VDMOSgm * delvgd
+ here->VDMOSgds * delvds
+ here->VDMOSgmT * deldelTemp;
}
#ifndef NOBYPASS
/* now lets see if we can bypass (ugh) */
if ((!(ckt->CKTmode &
(MODEINITPRED | MODEINITTRAN | MODEINITSMSIG))) &&
if ((!(ckt->CKTmode & MODEINITPRED)) &&
(ckt->CKTbypass) &&
(fabs(delvgs) < (ckt->CKTreltol *
MAX(fabs(vgs),
fabs(*(ckt->CKTstate0 +
here->VDMOSvgs))) +
ckt->CKTvoltTol)) &&
(fabs(delvds) < (ckt->CKTreltol *
MAX(fabs(vds),
fabs(*(ckt->CKTstate0 +
here->VDMOSvds))) +
ckt->CKTvoltTol)) &&
(fabs(cdhat - here->VDMOScd) < (ckt->CKTreltol *
MAX(fabs(cdhat),
fabs(here->VDMOScd)) +
ckt->CKTabstol))) {
/* bypass code */
/* nothing interesting has changed since last
* iteration on this device, so we just
* copy all the values computed last iteration out
* and keep going
*/
vgs = *(ckt->CKTstate0 + here->VDMOSvgs);
vds = *(ckt->CKTstate0 + here->VDMOSvds);
vgd = vgs - vds;
cdrain = here->VDMOSmode * (here->VDMOScd);
if (ckt->CKTmode & (MODETRAN | MODETRANOP)) {
capgs = (*(ckt->CKTstate0 + here->VDMOScapgs) +
*(ckt->CKTstate1 + here->VDMOScapgs));
capgd = (*(ckt->CKTstate0 + here->VDMOScapgd) +
*(ckt->CKTstate1 + here->VDMOScapgd));
}
goto bypass;
}
(fabs(delvds) < (ckt->CKTreltol *
MAX(fabs(vds),
fabs(*(ckt->CKTstate0 +
here->VDMOSvds))) +
ckt->CKTvoltTol)) &&
(fabs(cdhat - here->VDMOScd) < (ckt->CKTreltol *
MAX(fabs(cdhat),
fabs(here->VDMOScd)) +
ckt->CKTabstol)) &&
((here->VDMOStempNode == 0) ||
(fabs(deldelTemp) < (ckt->CKTreltol * MAX(fabs(delTemp),
fabs(*(ckt->CKTstate0+here->VDMOSdeltemp)))
+ ckt->CKTvoltTol*1e4))))
{
/* bypass code */
/* nothing interesting has changed since last
* iteration on this device, so we just
* copy all the values computed last iteration out
* and keep going
*/
vgs = *(ckt->CKTstate0 + here->VDMOSvgs);
vds = *(ckt->CKTstate0 + here->VDMOSvds);
vgd = vgs - vds;
delTemp = *(ckt->CKTstate0 + here->VDMOSdeltemp);
/* calculate Vds for temperature conductance calculation
in bypass (used later when filling Temp node matrix) */
Vds = here->VDMOSmode > 0 ? vds : -vds;
cdrain = here->VDMOSmode * (here->VDMOScd);
if (ckt->CKTmode & (MODETRAN | MODETRANOP)) {
capgs = (*(ckt->CKTstate0 + here->VDMOScapgs) +
*(ckt->CKTstate1 + here->VDMOScapgs));
capgd = (*(ckt->CKTstate0 + here->VDMOScapgd) +
*(ckt->CKTstate1 + here->VDMOScapgd));
capth = (*(ckt->CKTstate0 + here->VDMOScapth) +
*(ckt->CKTstate1 + here->VDMOScapth));
}
goto bypass;
}
#endif /*NOBYPASS*/
/* ok - bypass is out, do it the hard way */
von = model->VDMOStype * here->VDMOSvon;
@ -202,7 +278,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
#ifndef NODELIMITING
/*
* limiting
* we want to keep device voltages from changing
* we want to keep device voltages from changing
* so fast that the exponentials churn out overflows
* and similar rudeness
*/
@ -222,31 +298,41 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
}
vgs = vgd + vds;
}
if (selfheat)
delTemp = VDMOSlimitlog(delTemp,
*(ckt->CKTstate0 + here->VDMOSdeltemp),100,&Check_mos);
else
delTemp = 0.0;
#endif /*NODELIMITING*/
} else {
/* ok - not one of the simple cases, so we have to
* look at all of the possibilities for why we were
* called. We still just initialize the three voltages
*/
if ((ckt->CKTmode & MODEINITJCT) && !here->VDMOSoff) {
vds = model->VDMOStype * here->VDMOSicVDS;
vgs = model->VDMOStype * here->VDMOSicVGS;
if ((vds == 0) && (vgs == 0) &&
((ckt->CKTmode &
(MODETRAN | MODEDCOP | MODEDCTRANCURVE)) ||
(!(ckt->CKTmode & MODEUIC)))) {
vgs = model->VDMOStype * here->VDMOStVto;
vds = 0;
}
} else {
vgs = vds = 0;
}
}
Temp = delTemp + here->VDMOStemp;
here->VDMOSTempSH = Temp; /* added for portability of SH Temp for noise analysis */
/* Calculate temperature dependent values for self-heating effect */
if (selfheat) {
double TempRatio = Temp / here->VDMOStemp;
Beta = here->VDMOStTransconductance * pow(TempRatio,model->VDMOSmu);
dBeta_dT = here->VDMOStTransconductance * model->VDMOSmu / (here->VDMOStemp * pow(TempRatio,1-model->VDMOSmu));
rd0T = here->VDMOSdrainResistance * pow(TempRatio, model->VDMOStexp0);
drd0T_dT = rd0T * model->VDMOStexp0 / Temp;
rd1T = 0.0;
drd1T_dT = 0.0;
if (model->VDMOSqsGiven) {
rd1T = here->VDMOSqsResistance * pow(TempRatio, model->VDMOStexp1);
drd1T_dT = rd1T * model->VDMOStexp1 / Temp;
}
} else {
Beta = here->VDMOStTransconductance;
dBeta_dT = 0.0;
rd0T = here->VDMOSdrainResistance;
drd0T_dT = 0.0;
rd1T = 0.0;
if (model->VDMOSqsGiven)
rd1T = here->VDMOSqsResistance;
drd1T_dT = 0.0;
}
/*
* now all the preliminaries are over - we can start doing the
@ -261,125 +347,63 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
if (vds >= 0) {
/* normal mode */
here->VDMOSmode = 1;
Vds = vds;
Vgs = vgs;
} else {
/* inverse mode */
here->VDMOSmode = -1;
Vds = -vds;
Vgs = vgd;
}
{
/*
* this block of code evaluates the drain current and its
* derivatives using the shichman-hodges model and the
* charges associated with the gate, channel and bulk for
* charges associated with the gate and channel for
* mosfets
*
*/
/* the following 2 variables are local to this code block until
* it is obvious that they can be made global
*/
double betap;
double vgst;
von = (model->VDMOSvt0*model->VDMOStype);
vgst = (here->VDMOSmode == 1 ? vgs : vgd) - von;
von = here->VDMOStVth * model->VDMOStype;
double vgst = (here->VDMOSmode == 1 ? vgs : vgd) - von;
vdsat = MAX(vgst, 0);
if (model->VDMOSksubthresGiven) {
/* Alternative simple weak inversion model, according to https://www.anasoft.co.uk/MOS1Model.htm
/* Simple weak inversion model, according to https://www.anasoft.co.uk/MOS1Model.htm
* Scale the voltage overdrive vgst logarithmically in weak inversion.
* Best fits LTSPICE curves with shift=0
* Drain current including subthreshold current */
*/
double slope = model->VDMOSksubthres;
double lambda = model->VDMOSlambda;
double theta = model->VDMOStheta;
double shift = model->VDMOSsubshift;
double mtr = model->VDMOSmtr;
double slope = model->VDMOSksubthres;
double lambda = model->VDMOSlambda;
double theta = model->VDMOStheta;
double shift = model->VDMOSsubshift;
double mtr = model->VDMOSmtr;
/* scale vds with mtr (except with lambda) */
double vdss = vds*mtr*here->VDMOSmode;
double t0 = 1 + lambda*vds;
double t1 = 1 + theta*vgs;
double betap = Beta*t0/t1;
double dbetapdvgs = -Beta*theta*t0/(t1*t1);
double dbetapdvds = Beta*lambda/t1;
double dbetapdT = dBeta_dT*t0/t1;
/* scale vds with mtr (except with lambda) */
double vdss = vds*mtr*here->VDMOSmode;
double t0 = 1 + lambda*vds;
double t1 = 1 + theta*vgs;
betap = Beta*t0/t1;
double dbetapdvgs = -Beta*theta*t0/(t1*t1);
double dbetapdvds = Beta*lambda/t1;
double t2 = exp((vgst-shift)/slope);
vgst = slope * log(1 + t2);
double dvgstdvgs = t2/(t2+1);
double t2 = exp((vgst-shift)/slope);
vgst = slope * log(1 + t2);
double dvgstdvgs = t2/(t2+1);
if (vgst <= vdss) {
/* saturation region */
cdrain = betap*vgst*vgst*.5;
here->VDMOSgm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst;
here->VDMOSgds = .5*dbetapdvds*vgst*vgst;
}
else {
/* linear region */
cdrain = betap * vdss * (vgst - .5 * vdss);
here->VDMOSgm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss);
here->VDMOSgds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr;
}
if (vgst <= vdss) {
/* saturation region */
cdrain = betap * vgst*vgst * .5;
here->VDMOSgm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst;
here->VDMOSgds = .5*dbetapdvds*vgst*vgst;
dIds_dT = dbetapdT * vgst*vgst * .5;
}
else if (model->VDMOSsubslGiven) {
/* numerical differentiation for gd and gm with a delta of 2 mV */
double vdsm = vds * here->VDMOSmode;
double delta = 0.001;
cdrain = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vdsm, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
/* gd */
double vds1 = vdsm + delta;
double cdrp = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
vds1 = vdsm - delta;
double cdrm = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
here->VDMOSgds = (cdrp - cdrm) / (2. * delta);
/* gm */
double vgst1 = vgst + delta;
cdrp = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vdsm, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
vgst1 = vgst - delta;
cdrm = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vdsm, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
here->VDMOSgm = (cdrp - cdrm) / (2. * delta);
} else {
double onfg, fgate, Betam, dfgdvg;
onfg = 1.0+model->VDMOStheta*vgst;
fgate = 1.0/onfg;
Betam = Beta * fgate;
dfgdvg = -model->VDMOStheta*fgate*fgate;
if (vgst <= 0) {
/*
* cutoff region
*/
cdrain = 0;
here->VDMOSgm = 0;
here->VDMOSgds = 0;
} else {
/* scale vds with mtr */
double mtr = model->VDMOSmtr;
betap = Betam*(1 + model->VDMOSlambda*(vds*here->VDMOSmode));
if (vgst <= (vds * here->VDMOSmode) * mtr) {
/*
* saturation region
*/
cdrain = betap*vgst*vgst*.5;
here->VDMOSgm = betap*vgst * fgate + dfgdvg * cdrain;
here->VDMOSgds = model->VDMOSlambda*Betam*vgst*vgst*.5;
} else {
/*
* linear region
*/
cdrain = betap * (vds * here->VDMOSmode) * mtr *
(vgst - .5 * (vds*here->VDMOSmode) * mtr);
here->VDMOSgm = betap * (vds * here->VDMOSmode) * mtr * fgate + dfgdvg * cdrain;
here->VDMOSgds = betap * (vgst - (vds * here->VDMOSmode) * mtr) +
model->VDMOSlambda * Betam *
(vds * here->VDMOSmode) * mtr *
(vgst - .5 * (vds * here->VDMOSmode) * mtr);
}
}
else {
/* linear region */
cdrain = betap * vdss * (vgst - .5 * vdss);
here->VDMOSgm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss);
here->VDMOSgds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr;
dIds_dT = dbetapdT * vdss * (vgst - .5 * vdss);
}
}
@ -398,119 +422,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
*(ckt->CKTstate0 + here->VDMOSvgs) = vgs;
*(ckt->CKTstate0 + here->VDMOSvds) = vds;
/*
* vdmos capacitor model
*/
if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) {
/*
* calculate gate - drain, gate - source capacitors
* drain-source capacitor is evaluated with the bulk diode below
*/
/*
* this just evaluates at the current time,
* expects you to remember values from previous time
* returns 1/2 of non-constant portion of capacitance
* you must add in the other half from previous time
* and the constant part
*/
DevCapVDMOS(vgd, cgdmin, cgdmax, a, cgs,
(ckt->CKTstate0 + here->VDMOScapgs),
(ckt->CKTstate0 + here->VDMOScapgd),
&CGBdummy);
vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs);
vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds);
if (ckt->CKTmode & (MODETRANOP | MODEINITSMSIG)) {
capgs = 2 * *(ckt->CKTstate0 + here->VDMOScapgs);
capgd = 2 * *(ckt->CKTstate0 + here->VDMOScapgd);
} else {
capgs = (*(ckt->CKTstate0 + here->VDMOScapgs) +
*(ckt->CKTstate1 + here->VDMOScapgs));
capgd = (*(ckt->CKTstate0 + here->VDMOScapgd) +
*(ckt->CKTstate1 + here->VDMOScapgd));
}
/*
*/
#ifndef PREDICTOR
if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) {
*(ckt->CKTstate0 + here->VDMOSqgs) =
(1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqgs)
- xfact * *(ckt->CKTstate2 + here->VDMOSqgs);
*(ckt->CKTstate0 + here->VDMOSqgd) =
(1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqgd)
- xfact * *(ckt->CKTstate2 + here->VDMOSqgd);
} else {
#endif /*PREDICTOR*/
if (ckt->CKTmode & MODETRAN) {
*(ckt->CKTstate0 + here->VDMOSqgs) = (vgs - vgs1)*capgs +
*(ckt->CKTstate1 + here->VDMOSqgs);
*(ckt->CKTstate0 + here->VDMOSqgd) = (vgd - vgd1)*capgd +
*(ckt->CKTstate1 + here->VDMOSqgd);
} else {
/* TRANOP only */
*(ckt->CKTstate0 + here->VDMOSqgs) = vgs*capgs;
*(ckt->CKTstate0 + here->VDMOSqgd) = vgd*capgd;
}
#ifndef PREDICTOR
}
#endif /*PREDICTOR*/
}
#ifndef NOBYPASS
bypass :
#endif
if ((ckt->CKTmode & (MODEINITTRAN)) ||
(!(ckt->CKTmode & (MODETRAN)))) {
/*
* initialize to zero charge conductances
* and current
*/
gcgs = 0;
ceqgs = 0;
gcgd = 0;
ceqgd = 0;
} else {
if (capgs == 0) *(ckt->CKTstate0 + here->VDMOScqgs) = 0;
if (capgd == 0) *(ckt->CKTstate0 + here->VDMOScqgd) = 0;
/*
* calculate equivalent conductances and currents for
* meyer"s capacitors
*/
error = NIintegrate(ckt, &gcgs, &ceqgs, capgs, here->VDMOSqgs);
if (error) return(error);
error = NIintegrate(ckt, &gcgd, &ceqgd, capgd, here->VDMOSqgd);
if (error) return(error);
ceqgs = ceqgs - gcgs*vgs + ckt->CKTag[0] *
*(ckt->CKTstate0 + here->VDMOSqgs);
ceqgd = ceqgd - gcgd*vgd + ckt->CKTag[0] *
*(ckt->CKTstate0 + here->VDMOSqgd);
}
/*
* load current vector
*/
if (here->VDMOSmode >= 0) {
xnrm = 1;
xrev = 0;
cdreq = model->VDMOStype*(cdrain - here->VDMOSgds*vds -
here->VDMOSgm*vgs);
} else {
xnrm = 0;
xrev = 1;
cdreq = -(model->VDMOStype)*(cdrain - here->VDMOSgds*(-vds) -
here->VDMOSgm*vgd);
}
*(ckt->CKTrhs + here->VDMOSgNodePrime) -=
(model->VDMOStype * (ceqgs + ceqgd));
*(ckt->CKTrhs + here->VDMOSdNodePrime) +=
(-cdreq + model->VDMOStype * ceqgd);
*(ckt->CKTrhs + here->VDMOSsNodePrime) +=
cdreq + model->VDMOStype * ceqgs;
*(ckt->CKTstate0 + here->VDMOSdeltemp) = delTemp;
/* quasi saturation
* according to Vincenzo d'Alessandro's Quasi-Saturation Model, simplified:
@ -522,17 +434,194 @@ bypass :
double vdsn = model->VDMOStype * (
*(ckt->CKTrhsOld + here->VDMOSdNode) -
*(ckt->CKTrhsOld + here->VDMOSsNode));
double rd = model->VDMOSdrainResistance + model->VDMOSqsResistance *
(vdsn / (vdsn + fabs(model->VDMOSqsVoltage)));
here->VDMOSdrainConductance = 1 / rd;
double rd = rd0T + rd1T * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage)));
if (rd > 0)
here->VDMOSdrainConductance = 1 / rd + ckt->CKTgmin;
else
here->VDMOSdrainConductance = 1 / rd0T;
} else {
if (rd0T > 0)
here->VDMOSdrainConductance = 1 / rd0T;
}
if (selfheat) {
GmT = dIds_dT;
here->VDMOSgmT = GmT;
} else {
GmT = 0.0;
here->VDMOSgmT = 0.0;
}
if (selfheat) {
/* note that sign is switched because power flows out
of device into the temperature node. */
here->VDMOSgtempg = -model->VDMOStype*here->VDMOSgm * Vds;
here->VDMOSgtempT = -GmT * Vds;
here->VDMOSgtempd = -model->VDMOStype* (here->VDMOSgds * Vds + cdrain);
here->VDMOScth = - cdrain * Vds
- 1/here->VDMOSdrainConductance * cdrain*cdrain
- model->VDMOStype * (here->VDMOSgtempg * Vgs + here->VDMOSgtempd * Vds)
- here->VDMOSgtempT * delTemp;
}
/*
* vdmos capacitor model
*/
if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) {
/*
* calculate gate - drain, gate - source capacitors
* drain-source capacitor is evaluated with the body diode below
*/
/*
* this just evaluates at the current time,
* expects you to remember values from previous time
* returns 1/2 of non-constant portion of capacitance
* you must add in the other half from previous time
* and the constant part
*/
DevCapVDMOS(vgd, cgdmin, cgdmax, a, cgs,
(ckt->CKTstate0 + here->VDMOScapgs),
(ckt->CKTstate0 + here->VDMOScapgd));
*(ckt->CKTstate0 + here->VDMOScapth) = model->VDMOScthj; /* always constant */
vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs);
vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds);
delTemp1 = *(ckt->CKTstate1 + here->VDMOSdeltemp);
if (ckt->CKTmode & (MODETRANOP | MODEINITSMSIG)) {
capgs = 2 * *(ckt->CKTstate0 + here->VDMOScapgs);
capgd = 2 * *(ckt->CKTstate0 + here->VDMOScapgd);
capth = 2 * *(ckt->CKTstate0 + here->VDMOScapth);
} else {
capgs = (*(ckt->CKTstate0 + here->VDMOScapgs) +
*(ckt->CKTstate1 + here->VDMOScapgs));
capgd = (*(ckt->CKTstate0 + here->VDMOScapgd) +
*(ckt->CKTstate1 + here->VDMOScapgd));
capth = (*(ckt->CKTstate0 + here->VDMOScapth) +
*(ckt->CKTstate1 + here->VDMOScapth));
}
#ifndef PREDICTOR
if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) {
*(ckt->CKTstate0 + here->VDMOSqgs) =
(1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqgs)
- xfact * *(ckt->CKTstate2 + here->VDMOSqgs);
*(ckt->CKTstate0 + here->VDMOSqgd) =
(1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqgd)
- xfact * *(ckt->CKTstate2 + here->VDMOSqgd);
*(ckt->CKTstate0 + here->VDMOSqth) =
(1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqth)
- xfact * *(ckt->CKTstate2 + here->VDMOSqth);
} else {
#endif /*PREDICTOR*/
if (ckt->CKTmode & MODETRAN) {
*(ckt->CKTstate0 + here->VDMOSqgs) = (vgs - vgs1)*capgs +
*(ckt->CKTstate1 + here->VDMOSqgs);
*(ckt->CKTstate0 + here->VDMOSqgd) = (vgd - vgd1)*capgd +
*(ckt->CKTstate1 + here->VDMOSqgd);
*(ckt->CKTstate0 + here->VDMOSqth) = (delTemp-delTemp1)*capth +
*(ckt->CKTstate1 + here->VDMOSqth);
} else {
/* TRANOP only */
*(ckt->CKTstate0 + here->VDMOSqgs) = vgs*capgs;
*(ckt->CKTstate0 + here->VDMOSqgd) = vgd*capgd;
*(ckt->CKTstate0 + here->VDMOSqth) = delTemp*capth;
}
#ifndef PREDICTOR
}
#endif /*PREDICTOR*/
}
#ifndef NOBYPASS
bypass:
#endif
if ((ckt->CKTmode & (MODEINITTRAN)) ||
(!(ckt->CKTmode & (MODETRAN)))) {
/*
* initialize to zero charge conductances
* and current
*/
gcgs = 0;
ceqgs = 0;
gcgd = 0;
ceqgd = 0;
gcTt = 0.0;
ceqqth = 0.0;
} else {
if (capgs == 0) *(ckt->CKTstate0 + here->VDMOScqgs) = 0;
if (capgd == 0) *(ckt->CKTstate0 + here->VDMOScqgd) = 0;
if (capth == 0) *(ckt->CKTstate0 + here->VDMOScqth) = 0;
/*
* calculate equivalent conductances and currents for
* vdmos capacitors
*/
error = NIintegrate(ckt, &gcgs, &ceqgs, capgs, here->VDMOSqgs);
if (error) return(error);
error = NIintegrate(ckt, &gcgd, &ceqgd, capgd, here->VDMOSqgd);
if (error) return(error);
ceqgs = ceqgs - gcgs*vgs + ckt->CKTag[0] *
*(ckt->CKTstate0 + here->VDMOSqgs);
ceqgd = ceqgd - gcgd*vgd + ckt->CKTag[0] *
*(ckt->CKTstate0 + here->VDMOSqgd);
if (selfheat)
{
error = NIintegrate(ckt, &gcTt, &ceqqth, 0.0, here->VDMOSqth);
gcTt = model->VDMOScthj * ckt->CKTag[0];
ceqqth = *(ckt->CKTstate0 + here->VDMOScqth) - gcTt * delTemp;
}
}
/*
* load current vector
*/
if (selfheat) {
if (here->VDMOSmode >= 0) {
GmT = model->VDMOStype * here->VDMOSgmT;
gTtg = here->VDMOSgtempg;
gTtdp = here->VDMOSgtempd;
gTtt = here->VDMOSgtempT;
gTtsp = - (gTtg + gTtdp);
} else {
GmT = -model->VDMOStype * here->VDMOSgmT;
gTtg = here->VDMOSgtempg;
gTtsp = here->VDMOSgtempd;
gTtt = here->VDMOSgtempT;
gTtdp = - (gTtg + gTtsp);
}
} else {
GmT = 0.0;
gTtg = 0.0;
gTtdp = 0.0;
gTtt = 0.0;
gTtsp = 0.0;
}
if (here->VDMOSmode >= 0) {
xnrm = 1;
xrev = 0;
cdreq = model->VDMOStype*(cdrain - here->VDMOSgds*vds
- here->VDMOSgm*vgs)
- GmT * delTemp;
} else {
xnrm = 0;
xrev = 1;
cdreq = -(model->VDMOStype)*(cdrain - here->VDMOSgds*(-vds)
- here->VDMOSgm*vgd)
- GmT * delTemp;
}
*(ckt->CKTrhs + here->VDMOSgNodePrime) -= (model->VDMOStype * (ceqgs + ceqgd));
*(ckt->CKTrhs + here->VDMOSdNodePrime) += (-cdreq + model->VDMOStype * ceqgd);
*(ckt->CKTrhs + here->VDMOSsNodePrime) += cdreq + model->VDMOStype * ceqgs;
if (selfheat) {
*(ckt->CKTrhs + here->VDMOStempNode) -= here->VDMOScth + ceqqth; /* dissipated power + Cthj current */
*(ckt->CKTrhs + here->VDMOSvcktTbranch) = ckt->CKTtemp-CONSTCtoK; /* ckt temperature */
}
/*
* load y matrix
*/
*(here->VDMOSDdPtr) += (here->VDMOSdrainConductance + here->VDMOSdsConductance);
*(here->VDMOSGgPtr) += (here->VDMOSgateConductance); //((gcgd + gcgs + gcgb));
*(here->VDMOSGgPtr) += (here->VDMOSgateConductance);
*(here->VDMOSSsPtr) += (here->VDMOSsourceConductance + here->VDMOSdsConductance);
*(here->VDMOSDPdpPtr) +=
(here->VDMOSdrainConductance + here->VDMOSgds +
@ -560,26 +649,40 @@ bypass :
*(here->VDMOSDsPtr) += (-here->VDMOSdsConductance);
*(here->VDMOSSdPtr) += (-here->VDMOSdsConductance);
if (selfheat)
{
(*(here->VDMOSDPtempPtr) += GmT);
(*(here->VDMOSSPtempPtr) += -GmT);
(*(here->VDMOSGPtempPtr) += 0.0);
(*(here->VDMOSTemptempPtr) += gTtt + 1/model->VDMOSrthjc + gcTt);
(*(here->VDMOSTempgpPtr) += gTtg);
(*(here->VDMOSTempdpPtr) += gTtdp);
(*(here->VDMOSTempspPtr) += gTtsp);
(*(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc);
(*(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc);
(*(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca);
(*(here->VDMOSTptpPtr) += 1/model->VDMOSrthca);
(*(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca);
(*(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca);
(*(here->VDMOSCktTtpPtr) += 1.0);
(*(here->VDMOSTpcktTPtr) += 1.0);
}
/* bulk diode model
/* body diode model
* Delivers reverse conduction and forward breakdown
* of VDMOS transistor
*/
double vd; /* current diode voltage */
double vdtemp;
double vte;
double vtebrk, vbrknp;
double cd, cdb, csat, cdeq;
double czero;
double czof2;
double capd;
double gd, gdb, gspr;
double delvd; /* change in diode voltage temporary */
double diffcharge, deplcharge, diffcap, deplcap;
double evd, evrev;
double evrev;
#ifndef NOBYPASS
double tol; /* temporary for tolerence calculations */
double tol; /* temporary for tolerance calculations */
#endif
cd = 0.0;
@ -588,11 +691,11 @@ bypass :
gdb = 0.0;
csat = here->VDIOtSatCur;
gspr = here->VDIOtConductance;
vte = model->VDMOSDn * vt;
vte = model->VDMOSn * vt;
vtebrk = model->VDIObrkdEmissionCoeff * vt;
vbrknp = here->VDIOtBrkdwnV;
Check = 1;
Check_diode = 1;
if (ckt->CKTmode & MODEINITSMSIG) {
vd = *(ckt->CKTstate0 + here->VDIOvoltage);
} else if (ckt->CKTmode & MODEINITTRAN) {
@ -646,29 +749,31 @@ bypass :
/*
* limit new junction voltage
*/
if ((model->VDMOSDbvGiven) &&
if ((model->VDMOSbvGiven) &&
(vd < MIN(0, -vbrknp + 10 * vtebrk))) {
double vdtemp;
vdtemp = -(vd + vbrknp);
vdtemp = DEVpnjlim(vdtemp,
-(*(ckt->CKTstate0 + here->VDIOvoltage) +
vbrknp), vtebrk,
here->VDIOtVcrit, &Check);
here->VDIOtVcrit, &Check_diode);
vd = -(vdtemp + vbrknp);
} else {
vd = DEVpnjlim(vd, *(ckt->CKTstate0 + here->VDIOvoltage),
vte, here->VDIOtVcrit, &Check);
vte, here->VDIOtVcrit, &Check_diode);
}
}
/*
* compute dc current and derivatives
*/
if (vd >= -3 * vte) { /* bottom current forward */
double evd;
evd = exp(vd / vte);
cdb = csat*(evd - 1);
gdb = csat*evd / vte;
} else if ((!(model->VDMOSDbvGiven)) ||
} else if ((!(model->VDMOSbvGiven)) ||
vd >= -vbrknp) { /* reverse */
arg = 3 * vte / (vd*CONSTe);
@ -696,6 +801,7 @@ bypass :
/*
* charge storage elements
*/
double czero, czof2, diffcharge, deplcharge, diffcap, deplcap;
czero = here->VDIOtJctCap;
if (vd < here->VDIOtDepCap) {
arg = 1 - vd / here->VDIOtJctPot;
@ -751,7 +857,7 @@ bypass :
* check convergence
*/
if (Check == 1) {
if ((Check_mos == 1) || (Check_diode == 1)) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *)here;
}
@ -761,7 +867,7 @@ bypass :
*(ckt->CKTstate0 + here->VDIOconduct) = gd;
#ifndef NOBYPASS
load :
load:
#endif
/*
* load current vector
@ -789,47 +895,3 @@ load :
}
return(OK);
}
/* scaling function, sine function interpolating between 0 and 1
* nf2: empirical setting of sine 'speed'
*/
static double
scalef(double nf2, double vgst)
{
double vgstsin = vgst / nf2;
if (vgstsin > 1)
return 1;
else if (vgstsin < -1)
return 0;
else
return 0.5 * sin(vgstsin * M_PI / 2) + 0.5;
}
/* Calculate D/S current including weak inversion.
* Uses a single function covering weak-moderate-stong inversion, as well
* as linear and saturation regions, with an interpolation method according to
* Tvividis, McAndrew: "Operation and Modeling of the MOS Transistor", Oxford, 2011, p. 209.
* A single parameter n sets the slope of the weak inversion current. The weak inversion
* current is independent from vds, as in long channel devices.
* The following modification has been added for VDMOS compatibility:
* n and lambda are depending on vgst with a sine function interpolating between 0 and 1.
*/
static double
cweakinv2(double slope, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr, double theta)
{
double betam = beta / (1.0+theta*vgst);
vgst += shift * (1 - scalef(0.5, vgst));
double n = slope / 2.3 / 0.0256; /* Tsividis, p. 208 */
double n1 = n + (1 - n) * scalef(0.7, vgst); /* n < n1 < 1 */
double first = log(1 + exp(vgst / (2 * n1 * vt)));
double second = log(1 + exp((vgst - vds * mtr * n1) / (2 * n1 * vt)));
double cds =
betam * n1 * 2 * vt * vt * (1 + scalef(1, vgst) * lambda * vds) *
(first * first - second * second);
return cds;
}

View File

@ -24,8 +24,8 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
case VDMOS_MOD_TNOM:
value->rValue = model->VDMOStnom-CONSTCtoK;
return(OK);
case VDMOS_MOD_VTO:
value->rValue = model->VDMOSvt0;
case VDMOS_MOD_VTH:
value->rValue = model->VDMOSvth0;
return(OK);
case VDMOS_MOD_KP:
value->rValue = model->VDMOStransconductance;
@ -57,9 +57,6 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
case VDMOS_MOD_MTRIODE:
value->rValue = model->VDMOSmtr;
return(OK);
case VDMOS_MOD_SUBSLOPE:
value->rValue = model->VDMOSsubsl;
return(OK);
case VDMOS_MOD_SUBSHIFT:
value->rValue = model->VDMOSsubshift;
return(OK);
@ -93,7 +90,7 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
value->rValue = model->VDIOjctSatCur;
return(OK);
case VDMOS_MOD_N:
value->rValue = model->VDMOSDn;
value->rValue = model->VDMOSn;
return(OK);
case VDMOS_MOD_VJ:
value->rValue = model->VDIOjunctionPot;
@ -105,10 +102,10 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
value->rValue = model->VDIOgradCoeff;
return(OK);
case VDMOS_MOD_BV:
value->rValue = model->VDMOSDbv;
value->rValue = model->VDMOSbv;
return(OK);
case VDMOS_MOD_IBV:
value->rValue = model->VDMOSDibv;
value->rValue = model->VDMOSibv;
return(OK);
case VDMOS_MOD_NBV:
value->rValue = model->VDIObrkdEmissionCoeff;
@ -123,10 +120,46 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
value->rValue = model->VDIOtransitTime;
return(OK);
case VDMOS_MOD_EG:
value->rValue = model->VDMOSDeg;
value->rValue = model->VDMOSeg;
return(OK);
case VDMOS_MOD_XTI:
value->rValue = model->VDMOSDxti;
value->rValue = model->VDMOSxti;
return(OK);
case VDMOS_MOD_RTHJC:
value->rValue = model->VDMOSrthjc;
return(OK);
case VDMOS_MOD_RTHCA:
value->rValue = model->VDMOSrthca;
return(OK);
case VDMOS_MOD_CTHJ:
value->rValue = model->VDMOScthj;
return(OK);
case VDMOS_MOD_MU:
value->rValue = model->VDMOSmu;
return(OK);
case VDMOS_MOD_TEXP0:
value->rValue = model->VDMOStexp0;
return(OK);
case VDMOS_MOD_TEXP1:
value->rValue = model->VDMOStexp1;
return(OK);
case VDMOS_MOD_TCVTH:
value->rValue = model->VDMOStcvth;
return(OK);
case VDMOS_MOD_VGS_MAX:
value->rValue = model->VDMOSvgsMax;
return(OK);
case VDMOS_MOD_VGD_MAX:
value->rValue = model->VDMOSvgdMax;
return(OK);
case VDMOS_MOD_VDS_MAX:
value->rValue = model->VDMOSvdsMax;
return(OK);
case VDMOS_MOD_VGSR_MAX:
value->rValue = model->VDMOSvgsrMax;
return(OK);
case VDMOS_MOD_VGDR_MAX:
value->rValue = model->VDMOSvgdrMax;
return(OK);
default:
return(E_BADPARM);

View File

@ -1,6 +1,7 @@
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#include "ngspice/ngspice.h"
@ -19,9 +20,9 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDMOStnom = value->rValue + CONSTCtoK;
model->VDMOStnomGiven = TRUE;
break;
case VDMOS_MOD_VTO:
model->VDMOSvt0 = value->rValue;
model->VDMOSvt0Given = TRUE;
case VDMOS_MOD_VTH:
model->VDMOSvth0 = value->rValue;
model->VDMOSvth0Given = TRUE;
break;
case VDMOS_MOD_KP:
model->VDMOStransconductance = value->rValue;
@ -54,20 +55,14 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
case VDMOS_MOD_RQ:
model->VDMOSqsResistance = value->rValue;
model->VDMOSqsResistanceGiven = TRUE;
if (model->VDMOSqsVoltageGiven)
model->VDMOSqsGiven = TRUE;
break;
case VDMOS_MOD_VQ:
model->VDMOSqsVoltage = value->rValue;
model->VDMOSqsVoltageGiven = TRUE;
if (model->VDMOSqsResistanceGiven)
model->VDMOSqsGiven = TRUE;
break;
case VDMOS_MOD_RB:
model->VDIOresistance = value->rValue;
model->VDIOresistanceGiven = TRUE;
model->VDIOresistTemp1 = 0;
model->VDIOresistTemp2 = 0;
break;
case VDMOS_MOD_IS:
model->VDIOjctSatCur = value->rValue;
@ -137,10 +132,6 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDMOSmtr = value->rValue;
model->VDMOSmtrGiven = TRUE;
break;
case VDMOS_MOD_SUBSLOPE:
model->VDMOSsubsl = value->rValue;
model->VDMOSsubslGiven = TRUE;
break;
case VDMOS_MOD_SUBSHIFT:
model->VDMOSsubshift = value->rValue;
model->VDMOSsubshiftGiven = TRUE;
@ -150,12 +141,12 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDMOSksubthresGiven = TRUE;
break;
case VDMOS_MOD_BV:
model->VDMOSDbv = value->rValue;
model->VDMOSDbvGiven = TRUE;
model->VDMOSbv = value->rValue;
model->VDMOSbvGiven = TRUE;
break;
case VDMOS_MOD_IBV:
model->VDMOSDibv = value->rValue;
model->VDMOSDibvGiven = TRUE;
model->VDMOSibv = value->rValue;
model->VDMOSibvGiven = TRUE;
break;
case VDMOS_MOD_NBV:
model->VDIObrkdEmissionCoeff = value->rValue;
@ -166,8 +157,8 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDMOSrdsGiven = TRUE;
break;
case VDMOS_MOD_N:
model->VDMOSDn = value->rValue;
model->VDMOSDnGiven = TRUE;
model->VDMOSn = value->rValue;
model->VDMOSnGiven = TRUE;
break;
case VDMOS_MOD_TT:
model->VDIOtransitTime = value->rValue;
@ -176,12 +167,60 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDIOtranTimeTemp2 = 0;
break;
case VDMOS_MOD_EG:
model->VDMOSDeg = value->rValue;
model->VDMOSDegGiven = TRUE;
model->VDMOSeg = value->rValue;
model->VDMOSegGiven = TRUE;
break;
case VDMOS_MOD_XTI:
model->VDMOSDxti = value->rValue;
model->VDMOSDxtiGiven = TRUE;
model->VDMOSxti = value->rValue;
model->VDMOSxtiGiven = TRUE;
break;
case VDMOS_MOD_RTHJC:
model->VDMOSrthjc = value->rValue;
model->VDMOSrthjcGiven = TRUE;
break;
case VDMOS_MOD_RTHCA:
model->VDMOSrthca = value->rValue;
model->VDMOSrthcaGiven = TRUE;
break;
case VDMOS_MOD_CTHJ:
model->VDMOScthj = value->rValue;
model->VDMOScthjGiven = TRUE;
break;
case VDMOS_MOD_MU:
model->VDMOSmu = value->rValue;
model->VDMOSmuGiven = TRUE;
break;
case VDMOS_MOD_TEXP0:
model->VDMOStexp0 = value->rValue;
model->VDMOStexp0Given = TRUE;
break;
case VDMOS_MOD_TEXP1:
model->VDMOStexp1 = value->rValue;
model->VDMOStexp1Given = TRUE;
break;
case VDMOS_MOD_TCVTH:
model->VDMOStcvth = value->rValue;
model->VDMOStcvthGiven = TRUE;
break;
case VDMOS_MOD_VGS_MAX:
model->VDMOSvgsMax = value->rValue;
model->VDMOSvgsMaxGiven = TRUE;
break;
case VDMOS_MOD_VGD_MAX:
model->VDMOSvgdMax = value->rValue;
model->VDMOSvgdMaxGiven = TRUE;
break;
case VDMOS_MOD_VDS_MAX:
model->VDMOSvdsMax = value->rValue;
model->VDMOSvdsMaxGiven = TRUE;
break;
case VDMOS_MOD_VGSR_MAX:
model->VDMOSvgsrMax = value->rValue;
model->VDMOSvgsrMaxGiven = TRUE;
break;
case VDMOS_MOD_VGDR_MAX:
model->VDMOSvgdrMax = value->rValue;
model->VDMOSvgdrMaxGiven = TRUE;
break;
default:
return(E_BADPARM);

View File

@ -36,6 +36,7 @@ VDMOSnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
double noizDens[VDMOSNSRCS];
double lnNdens[VDMOSNSRCS];
int i;
double tempRatioSH;
/* define the names of the noise sources */
@ -90,17 +91,21 @@ VDMOSnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
switch (mode) {
case N_DENS:
if ((inst->VDMOStnodeoutGiven) && (model->VDMOSrthjc != 0.0))
tempRatioSH = inst->VDMOSTempSH / ckt->CKTtemp;
else
tempRatioSH = 1.0;
NevalSrc(&noizDens[VDMOSRDNOIZ],&lnNdens[VDMOSRDNOIZ],
ckt,THERMNOISE,inst->VDMOSdNodePrime,inst->VDMOSdNode,
inst->VDMOSdrainConductance);
inst->VDMOSdrainConductance * tempRatioSH);
NevalSrc(&noizDens[VDMOSRSNOIZ],&lnNdens[VDMOSRSNOIZ],
ckt,THERMNOISE,inst->VDMOSsNodePrime,inst->VDMOSsNode,
inst->VDMOSsourceConductance);
inst->VDMOSsourceConductance * tempRatioSH);
NevalSrc(&noizDens[VDMOSIDNOIZ],&lnNdens[VDMOSIDNOIZ],
ckt,THERMNOISE,inst->VDMOSdNodePrime,inst->VDMOSsNodePrime,
(2.0/3.0 * fabs(inst->VDMOSgm)));
(2.0/3.0 * fabs(inst->VDMOSgm)) * tempRatioSH);
NevalSrc(&noizDens[VDMOSFLNOIZ], NULL, ckt,
N_GAIN,inst->VDMOSdNodePrime, inst->VDMOSsNodePrime,

View File

@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
/*
*/
@ -60,6 +61,10 @@ VDMOSparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select)
here->VDMOSicVGS = value->rValue;
here->VDMOSicVGSGiven = TRUE;
break;
case VDMOS_TNODEOUT:
here->VDMOStnodeout = (value->iValue != 0);
here->VDMOStnodeoutGiven = TRUE;
break;
case VDMOS_IC:
switch(value->v.numValue){
case 2:

View File

@ -44,8 +44,13 @@ VDMOSpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
capgd = ( 2* *(ckt->CKTstate0+here->VDMOScapgd));
xgs = capgs;
xgd = capgd;
/*printf("vdmos: xgs=%g, xgd=%g\n",
xgs,xgd);*/
/* body diode */
double gspr, geq, xceq;
gspr = here->VDIOtConductance;
geq = *(ckt->CKTstate0 + here->VDIOconduct);
xceq = *(ckt->CKTstate0 + here->VDIOcapCurrent);
/*
* load matrix
*/
@ -67,21 +72,34 @@ VDMOSpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance;
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance;
*(here->VDMOSDPdpPtr) += here->VDMOSdrainConductance+
here->VDMOSgds+
xrev*(here->VDMOSgm);
here->VDMOSgds+xrev*(here->VDMOSgm);
*(here->VDMOSSPspPtr) += here->VDMOSsourceConductance+
here->VDMOSgds+
xnrm*(here->VDMOSgm);
here->VDMOSgds+xnrm*(here->VDMOSgm);
*(here->VDMOSDdpPtr) -= here->VDMOSdrainConductance;
*(here->VDMOSSspPtr) -= here->VDMOSsourceConductance;
*(here->VDMOSDPdPtr) -= here->VDMOSdrainConductance;
*(here->VDMOSDPgPtr) += (xnrm-xrev)*here->VDMOSgm;
*(here->VDMOSDPspPtr) -= here->VDMOSgds+
xnrm*(here->VDMOSgm);
*(here->VDMOSSPgPtr) -= (xnrm-xrev)*here->VDMOSgm;
*(here->VDMOSDPgpPtr) += (xnrm-xrev)*here->VDMOSgm;
*(here->VDMOSDPspPtr) -= here->VDMOSgds+xnrm*(here->VDMOSgm);
*(here->VDMOSSPgpPtr) -= (xnrm-xrev)*here->VDMOSgm;
*(here->VDMOSSPsPtr) -= here->VDMOSsourceConductance;
*(here->VDMOSSPdpPtr) -= here->VDMOSgds+
xrev*(here->VDMOSgm);
*(here->VDMOSSPdpPtr) -= here->VDMOSgds+xrev*(here->VDMOSgm);
/* gate resistor */
*(here->VDMOSGgPtr) += (here->VDMOSgateConductance);
*(here->VDMOSGPgpPtr) += (here->VDMOSgateConductance);
*(here->VDMOSGgpPtr) -= here->VDMOSgateConductance;
*(here->VDMOSGPgPtr) -= here->VDMOSgateConductance;
/* body diode */
*(here->VDMOSSsPtr) += gspr;
*(here->VDMOSDdPtr) += geq + xceq * s->real;
*(here->VDMOSDdPtr +1 ) += xceq * s->imag;
*(here->VDIORPrpPtr) += geq + gspr + xceq * s->real;
*(here->VDIORPrpPtr +1) += xceq * s->imag;
*(here->VDIOSrpPtr) -= gspr;
*(here->VDIODrpPtr) -= geq + xceq * s->real;
*(here->VDIODrpPtr +1) -= xceq * s->imag;
*(here->VDIORPsPtr) -= gspr;
*(here->VDIORPdPtr) -= geq + xceq * s->real;
*(here->VDIORPdPtr +1 ) -= xceq * s->imag;
}
}

View File

@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
/* load the VDMOS device structure with those pointers needed later
@ -27,87 +28,136 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
/* loop through all the VDMOS device models */
for (; model != NULL; model = VDMOSnextModel(model)) {
if (!model->VDMOStypeGiven) {
if (!model->VDMOStypeGiven)
model->VDMOStype = NMOS;
}
if (!model->VDIOjctSatCurGiven) {
if (!model->VDIOjctSatCurGiven)
model->VDIOjctSatCur = 1e-14;
}
if (!model->VDMOStransconductanceGiven) {
if (!model->VDMOStransconductanceGiven)
model->VDMOStransconductance = 1;
}
if (!model->VDMOSvt0Given) {
model->VDMOSvt0 = 0;
}
if (!model->VDIOjunctionPotGiven) {
if (!model->VDMOSvth0Given)
model->VDMOSvth0 = 0;
if (!model->VDIOjunctionPotGiven)
model->VDIOjunctionPot = .8;
}
if (!model->VDIOgradCoeffGiven) {
if (!model->VDIOgradCoeffGiven)
model->VDIOgradCoeff = .5;
}
if (!model->VDIOdepletionCapCoeffGiven) {
if (!model->VDIOdepletionCapCoeffGiven)
model->VDIOdepletionCapCoeff = .5;
}
if (!model->VDMOSphiGiven) {
if (!model->VDMOSphiGiven)
model->VDMOSphi = .6;
}
if (!model->VDMOSlambdaGiven) {
if (!model->VDMOSlambdaGiven)
model->VDMOSlambda = 0;
}
if (!model->VDMOSthetaGiven) {
if (!model->VDMOSthetaGiven)
model->VDMOStheta = 0;
}
if (!model->VDMOSfNcoefGiven) {
if (!model->VDMOSfNcoefGiven)
model->VDMOSfNcoef = 0;
}
if (!model->VDMOSfNexpGiven) {
if (!model->VDMOSfNexpGiven)
model->VDMOSfNexp = 1;
}
if (!model->VDMOScgdminGiven) {
if (!model->VDMOScgdminGiven)
model->VDMOScgdmin = 0;
}
if (!model->VDMOScgdmaxGiven) {
if (!model->VDMOScgdmaxGiven)
model->VDMOScgdmax = 0;
}
if (!model->VDMOScgsGiven) {
if (!model->VDMOScgsGiven)
model->VDMOScgs = 0;
}
if (!model->VDMOSaGiven) {
if (!model->VDMOSaGiven)
model->VDMOSa = 1.;
}
if (!model->VDMOSsubslGiven) {
model->VDMOSsubsl = 0;
}
if (!model->VDMOSsubshiftGiven) {
if (!model->VDMOSsubshiftGiven)
model->VDMOSsubshift = 0;
}
if (!model->VDMOSksubthresGiven) {
model->VDMOSksubthres = 0;
}
if (!model->VDMOSmtrGiven) {
if (!model->VDMOSksubthresGiven)
model->VDMOSksubthres = 0.1;
if (!model->VDMOSmtrGiven)
model->VDMOSmtr = 1.;
}
if (!model->VDMOSDbvGiven) {
model->VDMOSDbv = 1.0e30;
}
if (!model->VDMOSDibvGiven) {
model->VDMOSDibv = 1.0e-10;
}
if (!model->VDIObrkdEmissionCoeffGiven) {
if (!model->VDMOSbvGiven)
model->VDMOSbv = 1.0e30;
if (!model->VDMOSibvGiven)
model->VDMOSibv = 1.0e-10;
if (!model->VDIObrkdEmissionCoeffGiven)
model->VDIObrkdEmissionCoeff = 1.;
}
if (!model->VDMOSrdsGiven) {
model->VDMOSrds = 1.0e30;
}
if (!model->VDMOSDnGiven) {
model->VDMOSDn = 1.;
}
if (!model->VDIOtransitTimeGiven) {
if (!model->VDMOSdrainResistanceGiven)
model->VDMOSdrainResistance = 1.0e-03;
if (!model->VDMOSsourceResistanceGiven)
model->VDMOSsourceResistance = 1.0e-03;
if (!model->VDMOSgateResistanceGiven)
model->VDMOSgateResistance = 1.0e-03;
if (!model->VDMOSrdsGiven)
model->VDMOSrds = 1.0e+15;
if (!model->VDIOresistanceGiven)
model->VDIOresistance = 1.0e-03;
if (!model->VDMOSnGiven)
model->VDMOSn = 1.;
if (!model->VDIOtransitTimeGiven)
model->VDIOtransitTime = 0.;
}
if (!model->VDMOSDegGiven) {
model->VDMOSDeg = 1.11;
}
if (!model->VDMOSegGiven)
model->VDMOSeg = 1.11;
if (!model->VDMOSrthjcGiven)
model->VDMOSrthjc = 0;
if (!model->VDMOSrthcaGiven)
model->VDMOSrthca = 100;
if (!model->VDMOScthjGiven)
model->VDMOScthj = 10e-06;
if (!model->VDMOSmuGiven)
model->VDMOSmu = -1.5;
if (!model->VDMOStcvthGiven)
model->VDMOStcvth = 0.0;
if (!model->VDMOStexp0Given)
model->VDMOStexp0 = 1.5;
if (!model->VDMOStexp1Given)
model->VDMOStexp1 = 0.3;
if (!model->VDMOSvgsMaxGiven)
model->VDMOSvgsMax = 1e99;
if (!model->VDMOSvgdMaxGiven)
model->VDMOSvgdMax = 1e99;
if (!model->VDMOSvdsMaxGiven)
model->VDMOSvdsMax = 1e99;
if (!model->VDMOSvgsrMaxGiven)
model->VDMOSvgsrMax = 1e99;
if (!model->VDMOSvgdrMaxGiven)
model->VDMOSvgdrMax = 1e99;
if ((model->VDMOSqsResistanceGiven) && (model->VDMOSqsVoltageGiven))
model->VDMOSqsGiven = 1;
else
model->VDMOSqsGiven = 0;
/* loop through all the instances of the model */
for (here = VDMOSinstances(model); here != NULL;
@ -129,6 +179,45 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
if (!here->VDMOSvonGiven) {
here->VDMOSvon = 0;
}
if(!here->VDMOSmGiven) {
here->VDMOSm = 1;
}
if(!here->VDMOSlGiven) {
here->VDMOSl = 1;
}
if(!here->VDMOSwGiven) {
here->VDMOSw = 1;
}
if (model->VDMOSdrainResistance != 0) {
here->VDMOSdrainConductance = here->VDMOSm / model->VDMOSdrainResistance;
} else {
here->VDMOSdrainConductance = here->VDMOSm / 1.0e-03;
}
if (model->VDMOSsourceResistance != 0) {
here->VDMOSsourceConductance = here->VDMOSm / model->VDMOSsourceResistance;
} else {
here->VDMOSsourceConductance = here->VDMOSm / 1.0e-03;
}
if (model->VDMOSgateResistance != 0) {
here->VDMOSgateConductance = here->VDMOSm / model->VDMOSgateResistance;
} else {
here->VDMOSgateConductance = here->VDMOSm / 1.0e-03;
}
if (model->VDMOSrdsGiven) {
if (model->VDMOSrds != 0) {
here->VDMOSdsConductance = here->VDMOSm / model->VDMOSrds;
} else {
here->VDMOSdsConductance = 1e-15;
}
} else {
here->VDMOSdsConductance = 1e-15;
}
if (model->VDIOresistance != 0) {
here->VDIOconductance = here->VDMOSm / model->VDIOresistance;
} else {
here->VDIOconductance = here->VDMOSm / 1.0e-03;
}
if (model->VDMOSdrainResistance != 0) {
if (here->VDMOSdNodePrime == 0) {
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "drain");
@ -153,6 +242,29 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
here->VDMOSdNodePrime = here->VDMOSdNode;
}
if (model->VDMOSgateResistance != 0 ) {
if (here->VDMOSgNodePrime == 0) {
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "gate");
if (error) return(error);
here->VDMOSgNodePrime = tmp->number;
if (ckt->CKTcopyNodesets) {
CKTnode *tmpNode;
IFuid tmpName;
if (CKTinst2Node(ckt, here, 2, &tmpNode, &tmpName) == OK) {
if (tmpNode->nsGiven) {
tmp->nodeset = tmpNode->nodeset;
tmp->nsGiven = tmpNode->nsGiven;
}
}
}
}
}
else {
here->VDMOSgNodePrime = here->VDMOSgNode;
}
if (model->VDMOSsourceResistance != 0) {
if (here->VDMOSsNodePrime == 0) {
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "source");
@ -177,32 +289,9 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
here->VDMOSsNodePrime = here->VDMOSsNode;
}
if (model->VDMOSgateResistance != 0 ) {
if (here->VDMOSgNodePrime == 0) {
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "gate");
if (error) return(error);
here->VDMOSgNodePrime = tmp->number;
if (ckt->CKTcopyNodesets) {
CKTnode *tmpNode;
IFuid tmpName;
if (CKTinst2Node(ckt, here, 3, &tmpNode, &tmpName) == OK) {
if (tmpNode->nsGiven) {
tmp->nodeset = tmpNode->nodeset;
tmp->nsGiven = tmpNode->nsGiven;
}
}
}
}
}
else {
here->VDMOSgNodePrime = here->VDMOSgNode;
}
if (model->VDIOresistance != 0 ) {
if (here->VDIOposPrimeNode == 0) {
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "bulk diode");
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "body diode");
if (error) return(error);
here->VDIOposPrimeNode = tmp->number;
@ -223,6 +312,18 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
here->VDIOposPrimeNode = here->VDMOSsNode;
}
if ((here->VDMOStnodeoutGiven) && (model->VDMOSrthjc!=0.0)) {
if(here->VDMOSvcktTbranch == 0) {
error = CKTmkCur(ckt,&tmp,here->VDMOSname,"VcktTemp");
if(error) return(error);
here->VDMOSvcktTbranch = tmp->number;
}
if (here->VDMOStNodePrime == 0) {
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "thermal node");
if (error) return(error);
here->VDMOStNodePrime = tmp->number;
}
}
/* macro to make elements with built in test for out of memory */
#define TSTALLOC(ptr,first,second) \
@ -230,6 +331,25 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
return(E_NOMEM);\
} } while(0)
if ((here->VDMOStnodeoutGiven) && (model->VDMOSrthjc!=0.0)) {
TSTALLOC(VDMOSTemptempPtr, VDMOStempNode, VDMOStempNode);
TSTALLOC(VDMOSTempdpPtr, VDMOStempNode, VDMOSdNodePrime);
TSTALLOC(VDMOSTempspPtr, VDMOStempNode, VDMOSsNodePrime);
TSTALLOC(VDMOSTempgpPtr, VDMOStempNode, VDMOSgNodePrime);
TSTALLOC(VDMOSGPtempPtr, VDMOSgNodePrime, VDMOStempNode);
TSTALLOC(VDMOSDPtempPtr, VDMOSdNodePrime, VDMOStempNode);
TSTALLOC(VDMOSSPtempPtr, VDMOSsNodePrime, VDMOStempNode);
TSTALLOC(VDMOSTcasetcasePtr, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/
TSTALLOC(VDMOSTcasetempPtr, VDMOStcaseNode, VDMOStempNode);
TSTALLOC(VDMOSTemptcasePtr, VDMOStempNode, VDMOStcaseNode);
TSTALLOC(VDMOSTptpPtr, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */
TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStempNode);
TSTALLOC(VDMOSTcasetpPtr, VDMOStempNode, VDMOStNodePrime);
TSTALLOC(VDMOSCktTcktTPtr, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */
TSTALLOC(VDMOSCktTtpPtr, VDMOSvcktTbranch, VDMOStNodePrime);
TSTALLOC(VDMOSTpcktTPtr, VDMOStNodePrime, VDMOSvcktTbranch);
}
TSTALLOC(VDMOSDdPtr, VDMOSdNode, VDMOSdNode);
TSTALLOC(VDMOSGgPtr, VDMOSgNode, VDMOSgNode);
TSTALLOC(VDMOSSsPtr, VDMOSsNode, VDMOSsNode);
@ -294,6 +414,16 @@ VDMOSunsetup(GENmodel *inModel, CKTcircuit *ckt)
&& here->VDIOposPrimeNode != here->VDMOSsNode)
CKTdltNNum(ckt, here->VDIOposPrimeNode);
here->VDIOposPrimeNode = 0;
if ((here->VDMOStnodeoutGiven) && (model->VDMOSrthjc!=0.0)) {
if (here->VDMOStNodePrime > 0)
CKTdltNNum(ckt, here->VDMOStNodePrime);
here->VDMOStNodePrime = 0;
if (here->VDMOSvcktTbranch > 0)
CKTdltNNum(ckt, here->VDMOSvcktTbranch);
here->VDMOSvcktTbranch = 0;
}
}
}
return OK;

View File

@ -0,0 +1,142 @@
/**********
Copyright 2013 Dietmar Warning. All rights reserved.
Author: 2013 Dietmar Warning
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "vdmosdefs.h"
#include "ngspice/trandefs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
#include "ngspice/cpdefs.h"
int
VDMOSsoaCheck(CKTcircuit *ckt, GENmodel *inModel)
{
VDMOSmodel *model = (VDMOSmodel *) inModel;
VDMOSinstance *here;
double vgs, vgd, vds; /* actual mos voltages */
int maxwarns;
static int warns_vgs = 0, warns_vgd = 0, warns_vds = 0;
if (!ckt) {
warns_vgs = 0;
warns_vgd = 0;
warns_vds = 0;
return OK;
}
maxwarns = ckt->CKTsoaMaxWarns;
for (; model; model = VDMOSnextModel(model)) {
for (here = VDMOSinstances(model); here; here = VDMOSnextInstance(here)) {
vgs = ckt->CKTrhsOld [here->VDMOSgNode] -
ckt->CKTrhsOld [here->VDMOSsNodePrime];
vgd = ckt->CKTrhsOld [here->VDMOSgNode] -
ckt->CKTrhsOld [here->VDMOSdNodePrime];
vds = ckt->CKTrhsOld [here->VDMOSdNodePrime] -
ckt->CKTrhsOld [here->VDMOSsNodePrime];
if (!model->VDMOSvgsrMaxGiven) {
if (fabs(vgs) > model->VDMOSvgsMax)
if (warns_vgs < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgs=%g has exceeded Vgs_max=%g\n",
vgs, model->VDMOSvgsMax);
warns_vgs++;
}
} else {
if (model->VDMOStype > 0) {
if (vgs > model->VDMOSvgsMax)
if (warns_vgs < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgs=%g has exceeded Vgs_max=%g\n",
vgs, model->VDMOSvgsMax);
warns_vgs++;
}
if (-1*vgs > model->VDMOSvgsrMax)
if (warns_vgs < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgs=%g has exceeded Vgsr_max=%g\n",
vgs, model->VDMOSvgsrMax);
warns_vgs++;
}
} else {
if (vgs > model->VDMOSvgsrMax)
if (warns_vgs < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgs=%g has exceeded Vgsr_max=%g\n",
vgs, model->VDMOSvgsrMax);
warns_vgs++;
}
if (-1*vgs > model->VDMOSvgsMax)
if (warns_vgs < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgs=%g has exceeded Vgs_max=%g\n",
vgs, model->VDMOSvgsMax);
warns_vgs++;
}
}
}
if (!model->VDMOSvgdrMaxGiven) {
if (fabs(vgd) > model->VDMOSvgdMax)
if (warns_vgd < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgd=%g has exceeded Vgd_max=%g\n",
vgd, model->VDMOSvgdMax);
warns_vgd++;
}
} else {
if (model->VDMOStype > 0) {
if (vgd > model->VDMOSvgdMax)
if (warns_vgd < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgd=%g has exceeded Vgd_max=%g\n",
vgd, model->VDMOSvgdMax);
warns_vgd++;
}
if (-1*vgd > model->VDMOSvgdrMax)
if (warns_vgd < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgd=%g has exceeded Vgdr_max=%g\n",
vgd, model->VDMOSvgdrMax);
warns_vgd++;
}
} else {
if (vgd > model->VDMOSvgdrMax)
if (warns_vgd < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgd=%g has exceeded Vgdr_max=%g\n",
vgd, model->VDMOSvgdrMax);
warns_vgd++;
}
if (-1*vgd > model->VDMOSvgdMax)
if (warns_vgd < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vgd=%g has exceeded Vgd_max=%g\n",
vgd, model->VDMOSvgdMax);
warns_vgd++;
}
}
}
if (fabs(vds) > model->VDMOSvdsMax)
if (warns_vds < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"Vds=%g has exceeded Vds_max=%g\n",
vds, model->VDMOSvdsMax);
warns_vds++;
}
}
}
return OK;
}

View File

@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#include "ngspice/ngspice.h"
@ -21,7 +22,7 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
double fact1,fact2;
double kt,kt1;
double arg1;
double ratio,ratio4;
double ratio;
double phio;
double pbfact1,pbfact;
double vt,vtnom;
@ -45,22 +46,21 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
pbfact1 = -2*vtnom *(1.5*log(fact1)+CHARGE*arg1);
/* now model parameter preprocessing */
if (model->VDMOSphi <= 0.0) {
SPfrontEnd->IFerrorf(ERR_FATAL,
"%s: Phi is not positive.", model->VDMOSmodName);
return(E_BADPARM);
}
model->VDMOSoxideCapFactor = 0;
model->VDMOSoxideCapFactor = 3.9 * 8.854214871e-12 / 1e-07; /* use default Tox of 100nm */
/* bulk diode model */
/* body diode model */
/* limit activation energy to min of .1 */
if (model->VDMOSDeg<.1) {
if (model->VDMOSeg<.1) {
SPfrontEnd->IFerrorf(ERR_WARNING,
"%s: bulk diode activation energy too small, limited to 0.1",
"%s: body diode activation energy too small, limited to 0.1",
model->VDMOSmodName);
model->VDMOSDeg = .1;
model->VDMOSeg = .1;
}
/* limit depletion cap coeff to max of .95 */
if (model->VDIOdepletionCapCoeff>.95) {
@ -72,12 +72,7 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
/* set lower limit of saturation current */
if (model->VDIOjctSatCur < ckt->CKTepsmin)
model->VDIOjctSatCur = ckt->CKTepsmin;
if ((!model->VDIOresistanceGiven) || (model->VDIOresistance == 0)) {
model->VDIOconductance = 0.0;
}
else {
model->VDIOconductance = 1 / model->VDIOresistance;
}
xfc = log(1 - model->VDIOdepletionCapCoeff);
/* loop through all instances of the model */
@ -86,15 +81,29 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
double arg; /* 1 - fc */
/* perform the parameter defaulting */
if(!here->VDMOSdtempGiven) {
here->VDMOSdtemp = 0.0;
}
if(!here->VDMOStempGiven) {
here->VDMOStemp = ckt->CKTtemp + here->VDMOSdtemp;
}
vt = here->VDMOStemp * CONSTKoverQ;
double dt = here->VDMOStemp - model->VDMOStnom;
/* vdmos temperature model */
ratio = here->VDMOStemp/model->VDMOStnom;
here->VDMOStTransconductance = model->VDMOStransconductance
* here->VDMOSm * here->VDMOSw / here->VDMOSl
* pow(ratio, model->VDMOSmu);
here->VDMOStVth = model->VDMOSvth0 - model->VDMOStype * model->VDMOStcvth * dt;
here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * pow(ratio, model->VDMOStexp0);
if (model->VDMOSqsGiven)
here->VDMOSqsResistance = model->VDMOSqsResistance / here->VDMOSm * pow(ratio, model->VDMOStexp1);
vt = here->VDMOStemp * CONSTKoverQ;
fact2 = here->VDMOStemp/REFTEMP;
kt = here->VDMOStemp * CONSTboltz;
egfet = 1.16-(7.02e-4*here->VDMOStemp*here->VDMOStemp)/
@ -102,82 +111,15 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP));
pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg);
if(!here->VDMOSmGiven) {
here->VDMOSm = 1;
}
if(!here->VDMOSlGiven) {
here->VDMOSl = 1;
}
if(!here->VDMOSwGiven) {
here->VDMOSw = 1;
}
ratio4 = ratio * sqrt(ratio);
here->VDMOStTransconductance = model->VDMOStransconductance / ratio4;
phio = (model->VDMOSphi - pbfact1) / fact1;
here->VDMOStPhi = fact2 * phio + pbfact;
here->VDMOStVto = model->VDMOSvt0;
here->VDMOStPhi = fact2 * phio + pbfact; /* needed for distortion analysis */
here->VDMOSf2d = 0;
here->VDMOSf3d = 0;
here->VDMOSf4d = 0;
here->VDMOSf2s = 0;
here->VDMOSf3s = 0;
here->VDMOSf4s = 0;
if (model->VDMOSdrainResistanceGiven) {
if (model->VDMOSdrainResistance != 0) {
here->VDMOSdrainConductance = here->VDMOSm /
model->VDMOSdrainResistance;
}
else {
here->VDMOSdrainConductance = 0;
}
} else {
here->VDMOSdrainConductance = 0;
}
if(model->VDMOSsourceResistanceGiven) {
if(model->VDMOSsourceResistance != 0) {
here->VDMOSsourceConductance = here->VDMOSm /
model->VDMOSsourceResistance;
} else {
here->VDMOSsourceConductance = 0;
}
} else {
here->VDMOSsourceConductance = 0;
}
if (model->VDMOSgateResistanceGiven) {
if (model->VDMOSgateResistance != 0) {
here->VDMOSgateConductance = here->VDMOSm /
model->VDMOSgateResistance;
} else {
here->VDMOSgateConductance = 0;
}
} else {
here->VDMOSgateConductance = 0;
}
if (model->VDMOSrdsGiven) {
if (model->VDMOSrds != 0) {
here->VDMOSdsConductance = here->VDMOSm /
model->VDMOSrds;
}
else {
here->VDMOSdsConductance = 0;
}
}
else {
here->VDMOSdsConductance = 0;
}
/* bulk diode model */
/* body diode temperature model */
double pbo, gmaold;
double gmanew, factor;
double tBreakdownVoltage, vte, cbv;
double xbv, xcbv, tol, iter, dt;
double xbv, xcbv, tol, iter;
dt = here->VDMOStemp - model->VDMOStnom;
/* Junction grading temperature adjust */
factor = 1.0 + (model->VDIOgradCoeffTemp1 * dt)
+ (model->VDIOgradCoeffTemp2 * dt * dt);
@ -185,7 +127,7 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
pbo = (model->VDIOjunctionPot - pbfact1) / fact1;
gmaold = (model->VDIOjunctionPot - pbo) / pbo;
here->VDIOtJctCap = model->VDIOjunctionCap /
here->VDIOtJctCap = here->VDMOSm * model->VDIOjunctionCap /
(1 + here->VDIOtGradingCoeff*
(400e-6*(model->VDMOStnom - REFTEMP) - gmaold));
here->VDIOtJctPot = pbfact + fact2*pbo;
@ -193,10 +135,10 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
here->VDIOtJctCap *= 1 + here->VDIOtGradingCoeff*
(400e-6*(here->VDMOStemp - REFTEMP) - gmanew);
here->VDIOtSatCur = model->VDIOjctSatCur * exp(
here->VDIOtSatCur = here->VDMOSm * model->VDIOjctSatCur * exp(
((here->VDMOStemp / model->VDMOStnom) - 1) *
model->VDMOSDeg / (model->VDMOSDn*vt) +
model->VDMOSDxti / model->VDMOSDn *
model->VDMOSeg / (model->VDMOSn*vt) +
model->VDMOSxti / model->VDMOSn *
log(here->VDMOStemp / model->VDMOStnom));
/* the defintion of f1, just recompute after temperature adjusting
@ -209,14 +151,14 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
here->VDIOtJctPot;
/* and Vcrit */
vte = model->VDMOSDn*vt;
vte = model->VDMOSn*vt;
here->VDIOtVcrit = vte * log(vte / (CONSTroot2*here->VDIOtSatCur));
/* limit junction potential to max of 1/FC */
if (here->VDIOtDepCap > 1.0) {
here->VDIOtJctPot = 1.0 / model->VDMOSDn;
here->VDIOtDepCap = model->VDMOSDn*here->VDIOtJctPot;
if (here->VDIOtDepCap > 2.5) {
here->VDIOtJctPot = 2.5 / model->VDMOSn;
here->VDIOtDepCap = model->VDMOSn*here->VDIOtJctPot;
SPfrontEnd->IFerrorf(ERR_WARNING,
"%s: junction potential VJ too large, limited to %f",
model->VDMOSmodName, here->VDIOtJctPot);
@ -224,16 +166,16 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
/* and now to compute the breakdown voltage, again, using
* temperature adjusted basic parameters */
if (model->VDMOSDbvGiven) {
if (model->VDMOSbvGiven) {
/* tlev == 0 */
tBreakdownVoltage = fabs(model->VDMOSDbv);
tBreakdownVoltage = fabs(model->VDMOSbv);
cbv = model->VDMOSDibv;
cbv = model->VDMOSibv;
if (cbv < here->VDIOtSatCur * tBreakdownVoltage / vt) {
cbv = here->VDIOtSatCur * tBreakdownVoltage / vt;
#ifdef TRACE
SPfrontEnd->IFerrorf(ERR_WARNING, "%s: breakdown current increased to %g to resolve", here->DIOname, cbv);
SPfrontEnd->IFerrorf(ERR_WARNING, "%s: breakdown current increased to %g to resolve", here->VDMOSname, cbv);
SPfrontEnd->IFerrorf(ERR_WARNING,
"incompatibility with specified saturation current");
#endif
@ -252,7 +194,7 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
if (fabs(xcbv - cbv) <= tol) goto matched;
}
#ifdef TRACE
SPfrontEnd->IFerrorf(ERR_WARNING, "%s: unable to match forward and reverse diode regions: bv = %g, ibv = %g", here->DIOname, xbv, xcbv);
SPfrontEnd->IFerrorf(ERR_WARNING, "%s: unable to match forward and reverse diode regions: bv = %g, ibv = %g", here->VDMOSname, xbv, xcbv);
#endif
}
matched:
@ -264,13 +206,8 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
+ (model->VDIOtranTimeTemp2 * dt * dt);
here->VDIOtTransitTime = model->VDIOtransitTime * factor;
/* Series resistance temperature adjust */
here->VDIOtConductance = model->VDIOconductance;
if (model->VDIOresistanceGiven && model->VDIOresistance != 0.0) {
factor = 1.0 + (model->VDIOresistTemp1) * dt
+ (model->VDIOresistTemp2 * dt * dt);
here->VDIOtConductance = model->VDIOconductance / factor;
}
/* Series resistance temperature adjust (not implemented yet) */
here->VDIOtConductance = here->VDIOconductance;
here->VDIOtF2 = exp((1 + here->VDIOtGradingCoeff)*xfc);
here->VDIOtF3 = 1 - model->VDIOdepletionCapCoeff*

View File

@ -33,7 +33,7 @@ model_numnodes(int type)
if (type == INPtypelook("VDMOS")) /* 3 ; VDMOSnames */
{
return 3;
return 5;
}
return 4;

View File

@ -2106,6 +2106,7 @@
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmospar.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmospzld.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmosset.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmossoachk.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmostemp.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmostrun.c" />
<ClCompile Include="..\src\spicelib\devices\vsrc\vsrc.c" />

View File

@ -2547,6 +2547,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmospar.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmospzld.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmosset.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmossoachk.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmostemp.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmostrun.c" />
<ClCompile Include="..\src\spicelib\devices\vsrc\vsrc.c" />

View File

@ -2555,6 +2555,7 @@
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmospar.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmospzld.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmosset.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmossoachk.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmostemp.c" />
<ClCompile Include="..\src\spicelib\devices\vdmos\vdmostrun.c" />
<ClCompile Include="..\src\spicelib\devices\vsrc\vsrc.c" />