Diode model with selfheating option
This commit is contained in:
parent
48acb10929
commit
b1bf7ea0ad
|
|
@ -4277,7 +4277,17 @@ int get_number_terminals(char *c)
|
|||
case 'v':
|
||||
case 'i':
|
||||
case 'd':
|
||||
return 2;
|
||||
i = 0;
|
||||
/* find the first token with "off" or "=" in the line*/
|
||||
while ((i < 10) && (*c != '\0')) {
|
||||
char *inst = gettok_instance(&c);
|
||||
strncpy(nam_buf, inst, sizeof(nam_buf) - 1);
|
||||
txfree(inst);
|
||||
if (strstr(nam_buf, "off") || strstr(nam_buf, "thermal") || strchr(nam_buf, '='))
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
return i - 2;
|
||||
break;
|
||||
case 'u':
|
||||
case 'j':
|
||||
|
|
|
|||
|
|
@ -1648,7 +1648,7 @@ numnodes(const char *line, struct subs *subs, wordlist const *modnames)
|
|||
|
||||
/* If model names equal node names, this code will fail! */
|
||||
|
||||
if ((c == 'm') || (c == 'p') || (c == 'q')) { /* IF this is a mos, cpl or bjt*/
|
||||
if ((c == 'm') || (c == 'p') || (c == 'q') || (c == 'd')) { /* IF this is a mos, cpl, bjt or diode */
|
||||
char *s = nexttok(line); /* Skip the instance name */
|
||||
int gotit = 0;
|
||||
int i = 0;
|
||||
|
|
@ -1926,9 +1926,29 @@ devmodtranslate(struct card *s, char *subname, wordlist * const orig_modnames)
|
|||
bxx_printf(&buffer, "%s ", name);
|
||||
tfree(name);
|
||||
name = gettok_node(&t); /* get second attached netname */
|
||||
bxx_printf(&buffer, "%s ", name);
|
||||
tfree(name);
|
||||
name = gettok_node(&t); /* this can be either a model name or a node name. */
|
||||
if (name == NULL) {
|
||||
name = copy(""); /* allow 'tfree' */
|
||||
} else {
|
||||
found = 0;
|
||||
while (!found) {
|
||||
wlsub = wl_find(name, orig_modnames);
|
||||
if (wlsub) {
|
||||
found = 1;
|
||||
break;
|
||||
} else {
|
||||
bxx_printf(&buffer, "%s ", name);
|
||||
tfree(name);
|
||||
name = gettok(&t);
|
||||
if (name == NULL) { /* No token anymore - leave */
|
||||
name = copy(""); /* allow 'tfree' */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* while */
|
||||
}
|
||||
|
||||
translate_mod_name(&buffer, name, subname, orig_modnames);
|
||||
|
||||
|
|
@ -2162,7 +2182,7 @@ inp_numnodes(char c)
|
|||
case 'c':
|
||||
return (2);
|
||||
case 'd':
|
||||
return (2);
|
||||
return (3);
|
||||
case 'e':
|
||||
return (2); /* changed from 4 to 2 by SDB on 4.22.2003 to enable POLY */
|
||||
case 'f':
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ IFparm DIOpTable[] = { /* parameters */
|
|||
IOPU("lp", DIO_LP, IF_REAL, "Length of polysilicon capacitor (level=3)"),
|
||||
IOPU("wm", DIO_WM, IF_REAL, "Width of metal capacitor (level=3)"),
|
||||
IOPU("wp", DIO_WP, IF_REAL, "Width of polysilicon capacitor (level=3)"),
|
||||
IOP("thermal",DIO_THERMAL, IF_FLAG, "Self heating mode selector"),
|
||||
|
||||
IP("sens_area",DIO_AREA_SENS,IF_FLAG,"flag to request sensitivity WRT area"),
|
||||
OP("vd", DIO_VOLTAGE,IF_REAL, "Diode voltage"),
|
||||
|
|
@ -112,7 +113,10 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
IOP( "bv_max", DIO_MOD_BV_MAX, IF_REAL, "maximum voltage in reverse direction"),
|
||||
IOP( "isr", DIO_MOD_ISR, IF_REAL, "Recombination saturation current"),
|
||||
IOP( "nr", DIO_MOD_NR, IF_REAL, "Recombination current emission coefficient"),
|
||||
|
||||
/* self heating */
|
||||
IOP("rth0", DIO_MOD_RTH0, IF_REAL, "Self-heating thermal resistance"),
|
||||
IOP("cth0", DIO_MOD_CTH0, IF_REAL, "Self-heating thermal capacitance"),
|
||||
/* scaled parasitic capacitances level 3 model */
|
||||
IOP( "lm", DIO_MOD_LM, IF_REAL, "Length of metal capacitor (level=3)"),
|
||||
IOP( "lp", DIO_MOD_LP, IF_REAL, "Length of polysilicon capacitor (level=3)"),
|
||||
IOP( "wm", DIO_MOD_WM, IF_REAL, "Width of metal capacitor (level=3)"),
|
||||
|
|
@ -127,7 +131,8 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
|
||||
char *DIOnames[] = {
|
||||
"D+",
|
||||
"D-"
|
||||
"D-",
|
||||
"Tj"
|
||||
};
|
||||
|
||||
int DIOnSize = NUMELEMS(DIOnames);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
/* loop through all the instances of the model */
|
||||
for (here = DIOinstances(model); here != NULL ;
|
||||
here=DIOnextInstance(here)) {
|
||||
gspr=here->DIOtConductance*here->DIOarea;
|
||||
gspr=here->DIOtConductance;
|
||||
geq= *(ckt->CKTstate0 + here->DIOconduct);
|
||||
xceq= *(ckt->CKTstate0 + here->DIOcapCurrent) * ckt->CKTomega;
|
||||
*(here->DIOposPosPtr ) += gspr;
|
||||
|
|
@ -42,6 +42,25 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(here->DIOposPrimePosPtr ) -= gspr;
|
||||
*(here->DIOposPrimeNegPtr ) -= geq;
|
||||
*(here->DIOposPrimeNegPtr +1 ) -= xceq;
|
||||
int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given));
|
||||
if (selfheat) {
|
||||
double dIth_dVrs = here->DIOdIth_dVrs;
|
||||
double dIth_dVdio = here->DIOdIth_dVdio;
|
||||
double dIth_dT = here->DIOdIth_dT;
|
||||
double gcTt = here->DIOgcTt;
|
||||
double dIrs_dT = here->DIOdIrs_dT;
|
||||
double dIdio_dT = *(ckt->CKTstate0 + here->DIOdIdio_dT);
|
||||
(*(here->DIOtempPosPtr) += -dIth_dVrs);
|
||||
(*(here->DIOtempPosPrimePtr) += -dIth_dVdio + dIth_dVrs);
|
||||
(*(here->DIOtempNegPtr) += dIth_dVdio);
|
||||
(*(here->DIOtempTempPtr) += -dIth_dT + 1/model->DIOrth0 + gcTt);
|
||||
(*(here->DIOposTempPtr) += dIrs_dT);
|
||||
(*(here->DIOposPrimeTempPtr) += dIdio_dT - dIrs_dT);
|
||||
(*(here->DIOnegTempPtr) += -dIdio_dT);
|
||||
|
||||
double xgcTt= *(ckt->CKTstate0 + here->DIOcqth) * ckt->CKTomega;
|
||||
(*(here->DIOtempTempPtr + 1) += xgcTt);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ DIOask (CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
|
|||
case DIO_M:
|
||||
value->rValue = here->DIOm;
|
||||
return(OK);
|
||||
case DIO_THERMAL:
|
||||
value->iValue = here->DIOthermal;
|
||||
return(OK);
|
||||
|
||||
case DIO_TEMP:
|
||||
value->rValue = here->DIOtemp-CONSTCtoK;
|
||||
|
|
@ -81,7 +84,9 @@ DIOask (CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
|
|||
return(E_ASKPOWER);
|
||||
} else {
|
||||
value->rValue = *(ckt->CKTstate0 + here->DIOcurrent) *
|
||||
*(ckt->CKTstate0 + here->DIOvoltage);
|
||||
*(ckt->CKTstate0 + here->DIOvoltage) +
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) *
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) / here->DIOtConductance;
|
||||
}
|
||||
return(OK);
|
||||
case DIO_QUEST_SENS_DC:
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
DIOinstance *here;
|
||||
double delvd,vd,cdhat,cd;
|
||||
double tol;
|
||||
double delTemp, deldelTemp;
|
||||
/* loop through all the diode models */
|
||||
for( ; model != NULL; model = DIOnextModel(model)) {
|
||||
|
||||
|
|
@ -36,8 +37,17 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(ckt->CKTrhsOld + here->DIOnegNode);
|
||||
|
||||
delvd=vd- *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
|
||||
int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given));
|
||||
if (selfheat)
|
||||
delTemp = *(ckt->CKTrhsOld + here->DIOtempNode);
|
||||
else
|
||||
delTemp = 0.0;
|
||||
deldelTemp = delTemp - *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
|
||||
cdhat= *(ckt->CKTstate0 + here->DIOcurrent) +
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd +
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp;
|
||||
|
||||
cd= *(ckt->CKTstate0 + here->DIOcurrent);
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ typedef struct sDIOinstance {
|
|||
|
||||
const int DIOposNode; /* number of positive node of diode */
|
||||
const int DIOnegNode; /* number of negative node of diode */
|
||||
const int DIOtempNode; /* number of the temperature node of the diode */
|
||||
int DIOposPrimeNode; /* number of positive prime node of diode */
|
||||
|
||||
double *DIOposPosPrimePtr; /* pointer to sparse matrix at
|
||||
|
|
@ -55,6 +56,15 @@ typedef struct sDIOinstance {
|
|||
double *DIOposPrimePosPrimePtr; /* pointer to sparse matrix at
|
||||
* (positive prime,positive prime) */
|
||||
|
||||
/* self heating */
|
||||
double *DIOtempPosPtr;
|
||||
double *DIOtempPosPrimePtr;
|
||||
double *DIOtempNegPtr;
|
||||
double *DIOtempTempPtr;
|
||||
double *DIOposTempPtr;
|
||||
double *DIOposPrimeTempPtr;
|
||||
double *DIOnegTempPtr;
|
||||
|
||||
double DIOcap; /* stores the diode capacitance */
|
||||
|
||||
double *DIOsens; /* stores the perturbed values of geq and ceq in ac
|
||||
|
|
@ -86,6 +96,7 @@ typedef struct sDIOinstance {
|
|||
double DIOw; /* width for the diode */
|
||||
double DIOl; /* length for the diode */
|
||||
double DIOm; /* multiplier for the diode */
|
||||
int DIOthermal; /* flag indicate self heating on */
|
||||
|
||||
double DIOlengthMetal; /* Length of metal capacitor (level=3) */
|
||||
double DIOlengthPoly; /* Length of polysilicon capacitor (level=3) */
|
||||
|
|
@ -102,15 +113,20 @@ typedef struct sDIOinstance {
|
|||
double DIOtTransitTime; /* temperature adjusted transit time */
|
||||
double DIOtGradingCoeff; /* temperature adjusted grading coefficient (MJ) */
|
||||
double DIOtConductance; /* temperature adjusted series conductance */
|
||||
double DIOtConductance_dT; /* temperature adjusted series conductance temperature derivative */
|
||||
|
||||
double DIOtDepCap; /* temperature adjusted transition point in */
|
||||
/* the curve matching (Fc * Vj ) */
|
||||
double DIOtDepSWCap; /* temperature adjusted transition point in */
|
||||
/* the curve matching (Fcs * Vjs ) */
|
||||
double DIOtSatCur; /* temperature adjusted saturation current */
|
||||
double DIOtSatCur_dT; /* temperature adjusted saturation current temperature derivative */
|
||||
double DIOtSatSWCur; /* temperature adjusted side wall saturation current */
|
||||
double DIOtSatSWCur_dT; /* temperature adjusted side wall saturation current temperature derivative */
|
||||
double DIOtTunSatCur; /* tunneling saturation current */
|
||||
double DIOtTunSatCur_dT; /* tunneling saturation current temperature derivative */
|
||||
double DIOtTunSatSWCur; /* sidewall tunneling saturation current */
|
||||
double DIOtTunSatSWCur_dT; /* sidewall tunneling saturation current temperature derivative */
|
||||
|
||||
double DIOtVcrit; /* temperature adjusted V crit */
|
||||
double DIOtF1; /* temperature adjusted f1 */
|
||||
|
|
@ -126,6 +142,14 @@ typedef struct sDIOinstance {
|
|||
double DIOjunctionCap; /* geometry adjusted junction capacitance */
|
||||
double DIOjunctionSWCap; /* geometry adjusted junction sidewall capacitance */
|
||||
double DIOtRecSatCur; /* temperature adjusted recombination saturation current */
|
||||
double DIOtRecSatCur_dT; /* temperature adjusted recombination saturation current */
|
||||
|
||||
double DIOdIth_dVrs;
|
||||
double DIOdIth_dVdio;
|
||||
double DIOdIth_dT;
|
||||
double DIOgcTt;
|
||||
double DIOdIrs_dT;
|
||||
double DIOdIdio_dT;
|
||||
|
||||
double DIOcmetal; /* parasitic metal overlap capacitance */
|
||||
double DIOcpoly; /* parasitic polysilicon overlap capacitance */
|
||||
|
|
@ -175,10 +199,16 @@ typedef struct sDIOinstance {
|
|||
#define DIOcapCharge DIOstate+3
|
||||
#define DIOcapCurrent DIOstate+4
|
||||
|
||||
#define DIOnumStates 5
|
||||
#define DIOqth DIOstate+5 /* thermal capacitor charge */
|
||||
#define DIOcqth DIOstate+6 /* thermal capacitor current */
|
||||
|
||||
#define DIOsensxp DIOstate+5 /* charge sensitivities and their derivatives.
|
||||
* +6 for the derivatives - pointer to the
|
||||
#define DIOdeltemp DIOstate+7 /* thermal voltage over rth0 */
|
||||
#define DIOdIdio_dT DIOstate+8
|
||||
|
||||
#define DIOnumStates 9
|
||||
|
||||
#define DIOsensxp DIOstate+9 /* charge sensitivities and their derivatives.
|
||||
* +10 for the derivatives - pointer to the
|
||||
* beginning of the array */
|
||||
|
||||
#define DIOnumSenStates 2
|
||||
|
|
@ -248,6 +278,9 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
unsigned DIOrecSatCurGiven : 1;
|
||||
unsigned DIOrecEmissionCoeffGiven : 1;
|
||||
|
||||
unsigned DIOrth0Given :1;
|
||||
unsigned DIOcth0Given :1;
|
||||
|
||||
unsigned DIOlengthMetalGiven : 1; /* Length of metal capacitor (level=3) */
|
||||
unsigned DIOlengthPolyGiven : 1; /* Length of polysilicon capacitor (level=3) */
|
||||
unsigned DIOwidthMetalGiven : 1; /* Width of metal capacitor (level=3) */
|
||||
|
|
@ -312,6 +345,9 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
double DIOrecSatCur; /* Recombination saturation current */
|
||||
double DIOrecEmissionCoeff; /* Recombination emission coefficient */
|
||||
|
||||
double DIOrth0;
|
||||
double DIOcth0;
|
||||
|
||||
double DIOlengthMetal; /* Length of metal capacitor (level=3) */
|
||||
double DIOlengthPoly; /* Length of polysilicon capacitor (level=3) */
|
||||
double DIOwidthMetal; /* Width of metal capacitor (level=3) */
|
||||
|
|
@ -348,6 +384,7 @@ enum {
|
|||
DIO_L,
|
||||
DIO_M,
|
||||
DIO_DTEMP,
|
||||
DIO_THERMAL,
|
||||
DIO_LM,
|
||||
DIO_LP,
|
||||
DIO_WM,
|
||||
|
|
@ -407,6 +444,8 @@ enum {
|
|||
DIO_MOD_BV_MAX,
|
||||
DIO_MOD_ISR,
|
||||
DIO_MOD_NR,
|
||||
DIO_MOD_RTH0,
|
||||
DIO_MOD_CTH0,
|
||||
|
||||
DIO_MOD_LM,
|
||||
DIO_MOD_LP,
|
||||
|
|
@ -418,5 +457,7 @@ enum {
|
|||
DIO_MOD_XP,
|
||||
};
|
||||
|
||||
void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit *ckt);
|
||||
|
||||
#include "dioext.h"
|
||||
#endif /*DIO*/
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double arg;
|
||||
double argsw;
|
||||
double capd;
|
||||
double cd, cdb, cdsw;
|
||||
double cd, cdb, cdsw, cdb_dT, cdsw_dT;
|
||||
double cdeq;
|
||||
double cdhat;
|
||||
double ceq;
|
||||
|
|
@ -46,7 +46,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double evd;
|
||||
double evrev;
|
||||
double gd, gdb, gdsw, gen_fac, gen_fac_vd;
|
||||
double t1, evd_rec, cdb_rec, gdb_rec;
|
||||
double t1, evd_rec, cdb_rec, gdb_rec, cdb_rec_dT;
|
||||
double geq;
|
||||
double gspr; /* area-scaled conductance */
|
||||
double sarg;
|
||||
|
|
@ -56,13 +56,17 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double vd; /* current diode voltage */
|
||||
double vdtemp;
|
||||
double vt; /* K t / Q */
|
||||
double vte, vtesw, vtetun;
|
||||
double vtebrk;
|
||||
int Check = 0;
|
||||
double vte, vtesw, vtetun, vtebrk;
|
||||
int Check_dio=0, Check_th;
|
||||
int error;
|
||||
int SenCond=0; /* sensitivity condition */
|
||||
double diffcharge, diffchargeSW, deplcharge, deplchargeSW, diffcap, diffcapSW, deplcap, deplcapSW;
|
||||
|
||||
double deldelTemp, delTemp, Temp;
|
||||
double ceqqth=0.0, Ith=0.0, gcTt=0.0, vrs=0.0;
|
||||
double dIdio_dT, dIth_dVdio=0.0, dIrs_dT=0.0, dIth_dVrs=0.0, dIth_dT=0.0;
|
||||
double argsw_dT, csat_dT, csatsw_dT;
|
||||
|
||||
/* loop through all the diode models */
|
||||
for( ; model != NULL; model = DIOnextModel(model)) {
|
||||
|
||||
|
|
@ -70,10 +74,16 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
for (here = DIOinstances(model); here != NULL ;
|
||||
here=DIOnextInstance(here)) {
|
||||
|
||||
int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given));
|
||||
|
||||
/*
|
||||
* this routine loads diodes for dc and transient analyses.
|
||||
*/
|
||||
|
||||
if (selfheat)
|
||||
Check_th = 1;
|
||||
else
|
||||
Check_th = 0;
|
||||
|
||||
if(ckt->CKTsenInfo){
|
||||
if((ckt->CKTsenInfo->SENstatus == PERTURBATION)
|
||||
|
|
@ -88,15 +98,15 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
cd = 0.0;
|
||||
cdb = 0.0;
|
||||
cdsw = 0.0;
|
||||
cdsw_dT = 0.0;
|
||||
gd = 0.0;
|
||||
gdb = 0.0;
|
||||
gdsw = 0.0;
|
||||
csat = here->DIOtSatCur;
|
||||
csatsw = here->DIOtSatSWCur;
|
||||
gspr = here->DIOtConductance * here->DIOarea;
|
||||
delTemp = 0.0;
|
||||
vt = CONSTKoverQ * here->DIOtemp;
|
||||
vte = model->DIOemissionCoeff * vt;
|
||||
vtebrk = model->DIObrkdEmissionCoeff * vt;
|
||||
gspr = here->DIOtConductance;
|
||||
/*
|
||||
* initialization
|
||||
*/
|
||||
|
|
@ -110,8 +120,10 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
if((ckt->CKTsenInfo->SENmode == TRANSEN)&&
|
||||
(ckt->CKTmode & MODEINITTRAN)) {
|
||||
vd = *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
} else{
|
||||
vd = *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
}
|
||||
|
||||
#ifdef SENSDEBUG
|
||||
|
|
@ -120,20 +132,25 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
goto next1;
|
||||
}
|
||||
|
||||
Check=1;
|
||||
Check_dio=1;
|
||||
if(ckt->CKTmode & MODEINITSMSIG) {
|
||||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
} else if (ckt->CKTmode & MODEINITTRAN) {
|
||||
vd= *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) &&
|
||||
(ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) {
|
||||
vd=here->DIOinitCond;
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) {
|
||||
vd=0;
|
||||
delTemp = 0.0;
|
||||
} else if ( ckt->CKTmode & MODEINITJCT) {
|
||||
vd=here->DIOtVcrit;
|
||||
delTemp = 0.0;
|
||||
} else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) {
|
||||
vd=0;
|
||||
delTemp = 0.0;
|
||||
} else {
|
||||
#ifndef PREDICTOR
|
||||
if (ckt->CKTmode & MODEINITPRED) {
|
||||
|
|
@ -144,16 +161,34 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(ckt->CKTstate1 + here->DIOcurrent);
|
||||
*(ckt->CKTstate0 + here->DIOconduct) =
|
||||
*(ckt->CKTstate1 + here->DIOconduct);
|
||||
*(ckt->CKTstate0 + here->DIOdeltemp) =
|
||||
*(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
delTemp = DEVpred(ckt,here->DIOdeltemp);
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) =
|
||||
*(ckt->CKTstate1 + here->DIOdIdio_dT);
|
||||
*(ckt->CKTstate0+here->DIOqth) =
|
||||
*(ckt->CKTstate1+here->DIOqth);
|
||||
} else {
|
||||
#endif /* PREDICTOR */
|
||||
vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->DIOnegNode);
|
||||
if (selfheat)
|
||||
delTemp = *(ckt->CKTrhsOld + here->DIOtempNode);
|
||||
else
|
||||
delTemp = 0.0;
|
||||
*(ckt->CKTstate0+here->DIOqth) = model->DIOcth0 * delTemp;
|
||||
if((ckt->CKTmode & MODEINITTRAN)) {
|
||||
*(ckt->CKTstate1+here->DIOqth) =
|
||||
*(ckt->CKTstate0+here->DIOqth);
|
||||
}
|
||||
#ifndef PREDICTOR
|
||||
}
|
||||
#endif /* PREDICTOR */
|
||||
delvd=vd- *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
deldelTemp = delTemp - *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
cdhat= *(ckt->CKTstate0 + here->DIOcurrent) +
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd +
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp;
|
||||
/*
|
||||
* bypass if solution has not changed
|
||||
*/
|
||||
|
|
@ -167,13 +202,20 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
ckt->CKTabstol;
|
||||
if (fabs(cdhat- *(ckt->CKTstate0 + here->DIOcurrent))
|
||||
< tol) {
|
||||
if ((here->DIOtempNode == 0) ||
|
||||
(fabs(deldelTemp) < (ckt->CKTreltol * MAX(fabs(delTemp),
|
||||
fabs(*(ckt->CKTstate0+here->DIOdeltemp)))+
|
||||
ckt->CKTvoltTol*1e4))) {
|
||||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
cd= *(ckt->CKTstate0 + here->DIOcurrent);
|
||||
gd= *(ckt->CKTstate0 + here->DIOconduct);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
dIdio_dT= *(ckt->CKTstate0 + here->DIOdIdio_dT);
|
||||
goto load;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* NOBYPASS */
|
||||
/*
|
||||
* limit new junction voltage
|
||||
|
|
@ -184,17 +226,39 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
vdtemp = DEVpnjlim(vdtemp,
|
||||
-(*(ckt->CKTstate0 + here->DIOvoltage) +
|
||||
here->DIOtBrkdwnV),vtebrk,
|
||||
here->DIOtVcrit,&Check);
|
||||
here->DIOtVcrit,&Check_dio);
|
||||
vd = -(vdtemp+here->DIOtBrkdwnV);
|
||||
} else {
|
||||
vd = DEVpnjlim(vd,*(ckt->CKTstate0 + here->DIOvoltage),
|
||||
vte,here->DIOtVcrit,&Check);
|
||||
vte,here->DIOtVcrit,&Check_dio);
|
||||
}
|
||||
if (selfheat)
|
||||
delTemp = DEVlimitlog(delTemp,
|
||||
*(ckt->CKTstate0 + here->DIOdeltemp), 100, &Check_th);
|
||||
else
|
||||
delTemp = 0.0;
|
||||
}
|
||||
/*
|
||||
* compute dc current and derivitives
|
||||
*/
|
||||
next1: if (model->DIOsatSWCurGiven) { /* sidewall current */
|
||||
next1:
|
||||
if (selfheat) {
|
||||
Temp = here->DIOtemp + delTemp;
|
||||
DIOtempUpdate(model, here, Temp, ckt);
|
||||
} else {
|
||||
Temp = here->DIOtemp;
|
||||
}
|
||||
|
||||
csat = here->DIOtSatCur;
|
||||
csat_dT = here->DIOtSatCur_dT;
|
||||
csatsw = here->DIOtSatSWCur;
|
||||
csatsw_dT = here->DIOtSatSWCur_dT;
|
||||
gspr = here->DIOtConductance;
|
||||
vt = CONSTKoverQ * Temp;
|
||||
vte = model->DIOemissionCoeff * vt;
|
||||
vtebrk = model->DIObrkdEmissionCoeff * vt;
|
||||
|
||||
if (model->DIOsatSWCurGiven) { /* sidewall current */
|
||||
|
||||
if (model->DIOswEmissionCoeffGiven) { /* current with own characteristic */
|
||||
|
||||
|
|
@ -205,61 +269,87 @@ next1: if (model->DIOsatSWCurGiven) { /* sidewall current */
|
|||
evd = exp(vd/vtesw);
|
||||
cdsw = csatsw*(evd-1);
|
||||
gdsw = csatsw*evd/vtesw;
|
||||
cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vd * evd / (vtesw * Temp);
|
||||
|
||||
} else if((!(model->DIObreakdownVoltageGiven)) ||
|
||||
vd >= -here->DIOtBrkdwnV) { /* reverse */
|
||||
|
||||
argsw = 3*vtesw/(vd*CONSTe);
|
||||
argsw = argsw * argsw * argsw;
|
||||
argsw_dT = 3 * argsw / Temp;
|
||||
cdsw = -csatsw*(1+argsw);
|
||||
gdsw = csatsw*3*argsw/vd;
|
||||
cdsw_dT = -csatsw_dT - (csatsw_dT*argsw + csatsw*argsw_dT);
|
||||
|
||||
} else { /* breakdown */
|
||||
double evrev_dT;
|
||||
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk);
|
||||
evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp);
|
||||
cdsw = -csatsw*evrev;
|
||||
gdsw = csatsw*evrev/vtebrk;
|
||||
cdsw_dT = -(csatsw_dT*evrev + csatsw*evrev_dT);
|
||||
|
||||
}
|
||||
|
||||
} else { /* merge saturation currents and use same characteristic as bottom diode */
|
||||
|
||||
csat = csat + csatsw;
|
||||
csat_dT = csat_dT + csatsw_dT;
|
||||
cdsw_dT = 0.0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* temperature dependent diode saturation current and derivative
|
||||
*/
|
||||
|
||||
if (vd >= -3*vte) { /* bottom current forward */
|
||||
|
||||
evd = exp(vd/vte);
|
||||
cdb = csat*(evd-1);
|
||||
gdb = csat*evd/vte;
|
||||
cdb_dT = csat_dT * (evd - 1) - csat * vd * evd / (vte * Temp);
|
||||
if (model->DIOrecSatCurGiven) { /* recombination current */
|
||||
evd_rec = exp(vd/(model->DIOrecEmissionCoeff*vt));
|
||||
double vterec = model->DIOrecEmissionCoeff*vt;
|
||||
evd_rec = exp(vd/(vterec));
|
||||
cdb_rec = here->DIOtRecSatCur*(evd_rec-1);
|
||||
gdb_rec = here->DIOtRecSatCur*evd_rec/vt;
|
||||
gdb_rec = here->DIOtRecSatCur*evd_rec/vterec;
|
||||
cdb_rec_dT = here->DIOtRecSatCur_dT * (evd_rec - 1)
|
||||
-here->DIOtRecSatCur * vd * evd_rec / (vterec*Temp);
|
||||
t1 = pow((1-vd/here->DIOtJctPot), 2) + 0.005;
|
||||
gen_fac = pow(t1, here->DIOtGradingCoeff/2);
|
||||
gen_fac_vd = here->DIOtGradingCoeff * (1-vd/here->DIOtJctPot) * pow(t1, (here->DIOtGradingCoeff/2-1));
|
||||
gen_fac_vd = -here->DIOtGradingCoeff * (1-vd/here->DIOtJctPot)
|
||||
* pow(t1, (here->DIOtGradingCoeff/2-1));
|
||||
cdb_rec = cdb_rec * gen_fac;
|
||||
gdb_rec = gdb_rec * gen_fac + cdb_rec * gen_fac_vd;
|
||||
cdb = cdb + cdb_rec;
|
||||
gdb = gdb + gdb_rec;
|
||||
cdb_dT = cdb_dT + cdb_rec_dT*gen_fac;
|
||||
}
|
||||
|
||||
} else if((!(model->DIObreakdownVoltageGiven)) ||
|
||||
vd >= -here->DIOtBrkdwnV) { /* reverse */
|
||||
|
||||
double darg_dT;
|
||||
|
||||
arg = 3*vte/(vd*CONSTe);
|
||||
arg = arg * arg * arg;
|
||||
darg_dT = 3 * arg / Temp;
|
||||
cdb = -csat*(1+arg);
|
||||
gdb = csat*3*arg/vd;
|
||||
cdb_dT = -csat_dT - (csat_dT*arg + csat*darg_dT);
|
||||
|
||||
} else { /* breakdown */
|
||||
double evrev_dT;
|
||||
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk);
|
||||
evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp);
|
||||
cdb = -csat*evrev;
|
||||
gdb = csat*evrev/vtebrk;
|
||||
cdb_dT = -(csat_dT*evrev + csat*evrev_dT);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -270,6 +360,8 @@ next1: if (model->DIOsatSWCurGiven) { /* sidewall current */
|
|||
|
||||
cdsw = cdsw - here->DIOtTunSatSWCur * (evd - 1);
|
||||
gdsw = gdsw + here->DIOtTunSatSWCur * evd / vtetun;
|
||||
cdsw_dT = cdsw_dT - here->DIOtTunSatSWCur_dT * (evd - 1)
|
||||
- here->DIOtTunSatSWCur * vd * evd / (vtetun * Temp);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -280,11 +372,14 @@ next1: if (model->DIOsatSWCurGiven) { /* sidewall current */
|
|||
|
||||
cdb = cdb - here->DIOtTunSatCur * (evd - 1);
|
||||
gdb = gdb + here->DIOtTunSatCur * evd / vtetun;
|
||||
cdb_dT = cdb_dT - here->DIOtTunSatCur_dT * (evd - 1)
|
||||
- here->DIOtTunSatCur * vd * evd / (vtetun * Temp);
|
||||
|
||||
}
|
||||
|
||||
cd = cdb + cdsw;
|
||||
gd = gdb + gdsw;
|
||||
dIdio_dT = cdb_dT + cdsw_dT;
|
||||
|
||||
if (vd >= -3*vte) { /* limit forward */
|
||||
|
||||
|
|
@ -365,6 +460,7 @@ next1: if (model->DIOsatSWCurGiven) { /* sidewall current */
|
|||
if(SenCond){
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) = gd;
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT;
|
||||
#ifdef SENSDEBUG
|
||||
printf("storing small signal parameters\n");
|
||||
printf("cd = %.7e,vd = %.7e\n",cd,vd);
|
||||
|
|
@ -400,6 +496,15 @@ next1: if (model->DIOsatSWCurGiven) { /* sidewall current */
|
|||
*(ckt->CKTstate1 + here->DIOcapCurrent) =
|
||||
*(ckt->CKTstate0 + here->DIOcapCurrent);
|
||||
}
|
||||
if (selfheat)
|
||||
{
|
||||
error = NIintegrate(ckt, &gcTt, &ceqqth, model->DIOcth0, here->DIOqth);
|
||||
if (error) return(error);
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOcqth) =
|
||||
*(ckt->CKTstate0 + here->DIOcqth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -409,7 +514,7 @@ next1: if (model->DIOsatSWCurGiven) { /* sidewall current */
|
|||
* check convergence
|
||||
*/
|
||||
if ( (!(ckt->CKTmode & MODEINITFIX)) || (!(here->DIOoff)) ) {
|
||||
if (Check == 1) {
|
||||
if ((Check_th == 1) || (Check_dio == 1)) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
}
|
||||
|
|
@ -417,18 +522,44 @@ next1: if (model->DIOsatSWCurGiven) { /* sidewall current */
|
|||
next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) = gd;
|
||||
*(ckt->CKTstate0 + here->DIOdeltemp) = delTemp;
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT;
|
||||
|
||||
if(SenCond) continue;
|
||||
|
||||
#ifndef NOBYPASS
|
||||
load:
|
||||
#endif
|
||||
if (selfheat) {
|
||||
double dIrs_dVrs, dIrs_dgspr, dIth_dIrs;
|
||||
vrs = *(ckt->CKTrhsOld + here->DIOposNode) - *(ckt->CKTrhsOld + here->DIOposPrimeNode);
|
||||
Ith = vd*cd + vrs*vrs*gspr; /* Diode dissipated power */
|
||||
dIrs_dVrs = gspr;
|
||||
dIrs_dgspr = vrs;
|
||||
dIrs_dT = dIrs_dgspr * here->DIOtConductance_dT;
|
||||
dIth_dVrs = vrs*gspr;
|
||||
dIth_dIrs = vrs;
|
||||
dIth_dVrs = dIth_dVrs + dIth_dIrs*dIrs_dVrs;
|
||||
dIth_dT = dIth_dIrs*dIrs_dT + dIdio_dT*vd;
|
||||
dIth_dVdio = cd + vd*gd;
|
||||
here->DIOdIth_dVrs = dIth_dVrs;
|
||||
here->DIOdIth_dVdio = dIth_dVdio;
|
||||
here->DIOdIth_dT = dIth_dT;
|
||||
here->DIOgcTt = gcTt;
|
||||
here->DIOdIrs_dT = dIrs_dT;
|
||||
}
|
||||
/*
|
||||
* load current vector
|
||||
*/
|
||||
cdeq=cd-gd*vd;
|
||||
*(ckt->CKTrhs + here->DIOnegNode) += cdeq;
|
||||
*(ckt->CKTrhs + here->DIOposPrimeNode) -= cdeq;
|
||||
if (selfheat) {
|
||||
*(ckt->CKTrhs + here->DIOposNode) += dIrs_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOposPrimeNode) += dIdio_dT*delTemp - dIrs_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOnegNode) += -dIdio_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOtempNode) += Ith - dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp - ceqqth;
|
||||
}
|
||||
/*
|
||||
* load matrix
|
||||
*/
|
||||
|
|
@ -439,6 +570,15 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
|||
*(here->DIOnegPosPrimePtr) -= gd;
|
||||
*(here->DIOposPrimePosPtr) -= gspr;
|
||||
*(here->DIOposPrimeNegPtr) -= gd;
|
||||
if (selfheat) {
|
||||
(*(here->DIOtempPosPtr) += -dIth_dVrs);
|
||||
(*(here->DIOtempPosPrimePtr) += -dIth_dVdio + dIth_dVrs);
|
||||
(*(here->DIOtempNegPtr) += dIth_dVdio);
|
||||
(*(here->DIOtempTempPtr) += -dIth_dT + 1/model->DIOrth0 + gcTt);
|
||||
(*(here->DIOposTempPtr) += dIrs_dT);
|
||||
(*(here->DIOposPrimeTempPtr) += dIdio_dT - dIrs_dT);
|
||||
(*(here->DIOnegTempPtr) += -dIdio_dT);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -178,6 +178,12 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value)
|
|||
case DIO_MOD_NR:
|
||||
value->rValue = model->DIOrecEmissionCoeff;
|
||||
return(OK);
|
||||
case DIO_MOD_RTH0:
|
||||
value->rValue = model->DIOrth0;
|
||||
return(OK);
|
||||
case DIO_MOD_CTH0:
|
||||
value->rValue = model->DIOcth0;
|
||||
return(OK);
|
||||
|
||||
case DIO_MOD_LM:
|
||||
value->rValue = model->DIOlengthMetal;
|
||||
|
|
|
|||
|
|
@ -217,6 +217,14 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel)
|
|||
model->DIOrecEmissionCoeff = value->rValue;
|
||||
model->DIOrecEmissionCoeffGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_RTH0:
|
||||
model->DIOrth0 = value->rValue;
|
||||
model->DIOrth0Given = TRUE;
|
||||
break;
|
||||
case DIO_MOD_CTH0:
|
||||
model->DIOcth0 = value->rValue;
|
||||
model->DIOcth0Given = TRUE;
|
||||
break;
|
||||
|
||||
case DIO_MOD_LM:
|
||||
model->DIOlengthMetal = value->rValue;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ DIOparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select)
|
|||
here->DIOm = value->rValue;
|
||||
here->DIOmGiven = TRUE;
|
||||
break;
|
||||
case DIO_THERMAL:
|
||||
here->DIOthermal = (value->iValue != 0);
|
||||
break;
|
||||
|
||||
case DIO_TEMP:
|
||||
here->DIOtemp = value->rValue+CONSTCtoK;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ DIOpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
|
|||
/* loop through all the instances of the model */
|
||||
for (here = DIOinstances(model); here != NULL ;
|
||||
here=DIOnextInstance(here)) {
|
||||
gspr=here->DIOtConductance*here->DIOarea;
|
||||
gspr=here->DIOtConductance;
|
||||
geq= *(ckt->CKTstate0 + here->DIOconduct);
|
||||
xceq= *(ckt->CKTstate0 + here->DIOcapCurrent);
|
||||
*(here->DIOposPosPtr ) += gspr;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ DIOsAcLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
geq0 = *(here->DIOsenGeq);
|
||||
xceq0 = *(here->DIOsenCeq) * ckt->CKTomega;
|
||||
A0 = here->DIOarea;
|
||||
gspr0=here->DIOtConductance*A0;
|
||||
gspr0=here->DIOtConductance;
|
||||
cpos0 = gspr0 * vspr;
|
||||
icpos0 = gspr0 * ivspr;
|
||||
cposprm0 = geq0 * vd - xceq0 * ivd - cpos0;
|
||||
|
|
|
|||
|
|
@ -171,6 +171,27 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
model->DIOrecSatCur = 1e-14;
|
||||
}
|
||||
|
||||
/* set lower limit of saturation current */
|
||||
if (model->DIOsatCur < ckt->CKTepsmin)
|
||||
model->DIOsatCur = ckt->CKTepsmin;
|
||||
|
||||
if(!model->DIOnomTempGiven) {
|
||||
model->DIOnomTemp = ckt->CKTnomTemp;
|
||||
}
|
||||
|
||||
if((!model->DIOresistGiven) || (model->DIOresist==0)) {
|
||||
model->DIOconductance = 0.0;
|
||||
} else {
|
||||
model->DIOconductance = 1/model->DIOresist;
|
||||
}
|
||||
|
||||
if (!model->DIOrth0Given) {
|
||||
model->DIOrth0 = 0;
|
||||
}
|
||||
if (!model->DIOcth0Given) {
|
||||
model->DIOcth0 = 1e-5;
|
||||
}
|
||||
|
||||
if(!model->DIOlengthMetalGiven) {
|
||||
model->DIOlengthMetal = 0.0;
|
||||
}
|
||||
|
|
@ -286,6 +307,8 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
}
|
||||
}
|
||||
|
||||
int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given));
|
||||
|
||||
/* macro to make elements with built in test for out of memory */
|
||||
#define TSTALLOC(ptr,first,second) \
|
||||
do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
|
||||
|
|
@ -299,6 +322,17 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
|
|||
TSTALLOC(DIOposPosPtr,DIOposNode,DIOposNode);
|
||||
TSTALLOC(DIOnegNegPtr,DIOnegNode,DIOnegNode);
|
||||
TSTALLOC(DIOposPrimePosPrimePtr,DIOposPrimeNode,DIOposPrimeNode);
|
||||
|
||||
if (selfheat) {
|
||||
TSTALLOC(DIOtempPosPtr, DIOtempNode, DIOposNode);
|
||||
TSTALLOC(DIOtempPosPrimePtr, DIOtempNode, DIOposPrimeNode);
|
||||
TSTALLOC(DIOtempNegPtr, DIOtempNode, DIOnegNode);
|
||||
TSTALLOC(DIOtempTempPtr, DIOtempNode, DIOtempNode);
|
||||
TSTALLOC(DIOposTempPtr, DIOposNode, DIOtempNode);
|
||||
TSTALLOC(DIOposPrimeTempPtr, DIOposPrimeNode, DIOtempNode);
|
||||
TSTALLOC(DIOnegTempPtr, DIOnegNode, DIOtempNode);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -15,85 +15,36 @@ Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
|||
#include "ngspice/suffix.h"
|
||||
#include "ngspice/cpdefs.h"
|
||||
|
||||
int
|
||||
DIOtemp(GENmodel *inModel, CKTcircuit *ckt)
|
||||
{
|
||||
void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit *ckt) {
|
||||
|
||||
DIOmodel *model = (DIOmodel*)inModel;
|
||||
double xfc, xfcs;
|
||||
double vte;
|
||||
double vt, vte, vts, vtt, vtr;
|
||||
double cbv;
|
||||
double xbv;
|
||||
double xcbv;
|
||||
double tol;
|
||||
double vt;
|
||||
double vtnom;
|
||||
DIOinstance *here;
|
||||
int iter;
|
||||
double dt;
|
||||
double factor;
|
||||
double tBreakdownVoltage;
|
||||
|
||||
double egfet1,arg1,fact1,pbfact1,pbo,gmaold,pboSW,gmaSWold;
|
||||
double fact2,pbfact,arg,egfet,gmanew,gmaSWnew;
|
||||
double arg1_dT, arg2, arg2_dT;
|
||||
double gclimit;
|
||||
|
||||
if (!cp_getvar("DIOgradingCoeffMax", CP_REAL, &gclimit, 0))
|
||||
gclimit = 0.9;
|
||||
|
||||
/* loop through all the diode models */
|
||||
for( ; model != NULL; model = DIOnextModel(model)) {
|
||||
if(!model->DIOnomTempGiven) {
|
||||
model->DIOnomTemp = ckt->CKTnomTemp;
|
||||
}
|
||||
vt = CONSTKoverQ * Temp;
|
||||
vte = model->DIOemissionCoeff * vt;
|
||||
vts = model->DIOswEmissionCoeff * vt;
|
||||
vtt = model->DIOtunEmissionCoeff * vt;
|
||||
vtr = model->DIOrecEmissionCoeff * vt;
|
||||
vtnom = CONSTKoverQ * model->DIOnomTemp;
|
||||
/* limit grading coeff to max of .9, set new limit with variable DIOgradingCoeffMax */
|
||||
if(model->DIOgradingCoeff>gclimit) {
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING,
|
||||
"%s: grading coefficient too large, limited to %g",
|
||||
model->DIOmodName, gclimit);
|
||||
model->DIOgradingCoeff=gclimit;
|
||||
}
|
||||
/* limit activation energy to min of .1 */
|
||||
if(model->DIOactivationEnergy<.1) {
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING,
|
||||
"%s: activation energy too small, limited to 0.1",
|
||||
model->DIOmodName);
|
||||
model->DIOactivationEnergy=.1;
|
||||
}
|
||||
/* limit depletion cap coeff to max of .95 */
|
||||
if(model->DIOdepletionCapCoeff>.95) {
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING,
|
||||
"%s: coefficient Fc too large, limited to 0.95",
|
||||
model->DIOmodName);
|
||||
model->DIOdepletionCapCoeff=.95;
|
||||
}
|
||||
/* limit sidewall depletion cap coeff to max of .95 */
|
||||
if(model->DIOdepletionSWcapCoeff>.95) {
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING,
|
||||
"%s: coefficient Fcs too large, limited to 0.95",
|
||||
model->DIOmodName);
|
||||
model->DIOdepletionSWcapCoeff=.95;
|
||||
}
|
||||
/* set lower limit of saturation current */
|
||||
if (model->DIOsatCur < ckt->CKTepsmin)
|
||||
model->DIOsatCur = ckt->CKTepsmin;
|
||||
if((!model->DIOresistGiven) || (model->DIOresist==0)) {
|
||||
model->DIOconductance = 0.0;
|
||||
} else {
|
||||
model->DIOconductance = 1/model->DIOresist;
|
||||
}
|
||||
xfc=log(1-model->DIOdepletionCapCoeff);
|
||||
xfcs=log(1-model->DIOdepletionSWcapCoeff);
|
||||
|
||||
for(here=DIOinstances(model);here;here=DIOnextInstance(here)) {
|
||||
double egfet1,arg1,fact1,pbfact1,pbo,gmaold,pboSW,gmaSWold;
|
||||
double fact2,pbfact,arg,egfet,gmanew,gmaSWnew;
|
||||
/* loop through all the instances */
|
||||
|
||||
if(!here->DIOdtempGiven) here->DIOdtemp = 0.0;
|
||||
|
||||
if(!here->DIOtempGiven)
|
||||
here->DIOtemp = ckt->CKTtemp + here->DIOdtemp;
|
||||
|
||||
dt = here->DIOtemp - model->DIOnomTemp;
|
||||
dt = Temp - model->DIOnomTemp;
|
||||
|
||||
/* Junction grading temperature adjust */
|
||||
factor = 1.0 + (model->DIOgradCoeffTemp1 * dt)
|
||||
|
|
@ -110,13 +61,12 @@ DIOtemp(GENmodel *inModel, CKTcircuit *ckt)
|
|||
here->DIOtGradingCoeff=gclimit;
|
||||
}
|
||||
|
||||
vt = CONSTKoverQ * here->DIOtemp;
|
||||
/* this part gets really ugly - I won't even try to
|
||||
* explain these equations */
|
||||
fact2 = here->DIOtemp/REFTEMP;
|
||||
egfet = 1.16-(7.02e-4*here->DIOtemp*here->DIOtemp)/
|
||||
(here->DIOtemp+1108);
|
||||
arg = -egfet/(2*CONSTboltz*here->DIOtemp) +
|
||||
fact2 = Temp/REFTEMP;
|
||||
egfet = 1.16-(7.02e-4*Temp*Temp)/
|
||||
(Temp+1108);
|
||||
arg = -egfet/(2*CONSTboltz*Temp) +
|
||||
1.1150877/(CONSTboltz*(REFTEMP+REFTEMP));
|
||||
pbfact = -2*vt*(1.5*log(fact2)+CHARGE*arg);
|
||||
egfet1 = 1.16 - (7.02e-4*model->DIOnomTemp*model->DIOnomTemp)/
|
||||
|
|
@ -135,11 +85,11 @@ DIOtemp(GENmodel *inModel, CKTcircuit *ckt)
|
|||
here->DIOtJctPot = pbfact+fact2*pbo;
|
||||
gmanew = (here->DIOtJctPot-pbo)/pbo;
|
||||
here->DIOtJctCap *= 1+here->DIOtGradingCoeff*
|
||||
(400e-6*(here->DIOtemp-REFTEMP)-gmanew);
|
||||
(400e-6*(Temp-REFTEMP)-gmanew);
|
||||
} else if (model->DIOtlevc == 1) {
|
||||
here->DIOtJctPot = model->DIOjunctionPot - model->DIOtpb*(here->DIOtemp-REFTEMP);
|
||||
here->DIOtJctPot = model->DIOjunctionPot - model->DIOtpb*(Temp-REFTEMP);
|
||||
here->DIOtJctCap = here->DIOjunctionCap *
|
||||
(1+model->DIOcta*(here->DIOtemp-REFTEMP));
|
||||
(1+model->DIOcta*(Temp-REFTEMP));
|
||||
}
|
||||
|
||||
if (model->DIOtlevc == 0) {
|
||||
|
|
@ -151,40 +101,55 @@ DIOtemp(GENmodel *inModel, CKTcircuit *ckt)
|
|||
here->DIOtJctSWPot = pbfact+fact2*pboSW;
|
||||
gmaSWnew = (here->DIOtJctSWPot-pboSW)/pboSW;
|
||||
here->DIOtJctSWCap *= 1+model->DIOgradingSWCoeff*
|
||||
(400e-6*(here->DIOtemp-REFTEMP)-gmaSWnew);
|
||||
(400e-6*(Temp-REFTEMP)-gmaSWnew);
|
||||
} else if (model->DIOtlevc == 1) {
|
||||
here->DIOtJctSWPot = model->DIOjunctionSWPot - model->DIOtphp*(here->DIOtemp-REFTEMP);
|
||||
here->DIOtJctSWPot = model->DIOjunctionSWPot - model->DIOtphp*(Temp-REFTEMP);
|
||||
here->DIOtJctSWCap = here->DIOjunctionSWCap *
|
||||
(1+model->DIOctp*(here->DIOtemp-REFTEMP));
|
||||
(1+model->DIOctp*(Temp-REFTEMP));
|
||||
}
|
||||
|
||||
here->DIOtSatCur = model->DIOsatCur * here->DIOarea * exp(
|
||||
((here->DIOtemp/model->DIOnomTemp)-1) *
|
||||
model->DIOactivationEnergy/(model->DIOemissionCoeff*vt) +
|
||||
model->DIOsaturationCurrentExp/model->DIOemissionCoeff *
|
||||
log(here->DIOtemp/model->DIOnomTemp) );
|
||||
here->DIOtSatSWCur = model->DIOsatSWCur * here->DIOpj * exp(
|
||||
((here->DIOtemp/model->DIOnomTemp)-1) *
|
||||
model->DIOactivationEnergy/(model->DIOswEmissionCoeff*vt) +
|
||||
model->DIOsaturationCurrentExp/model->DIOswEmissionCoeff *
|
||||
log(here->DIOtemp/model->DIOnomTemp) );
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOactivationEnergy / vte;
|
||||
arg1_dT = model->DIOactivationEnergy / (vte*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vte*Temp);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOemissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOemissionCoeff / Temp;
|
||||
here->DIOtSatCur = here->DIOm * model->DIOsatCur * here->DIOarea * exp(arg1 + arg2);
|
||||
here->DIOtSatCur_dT = here->DIOm * model->DIOsatCur * here->DIOarea * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
here->DIOtTunSatCur = model->DIOtunSatCur * here->DIOarea * exp(
|
||||
((here->DIOtemp/model->DIOnomTemp)-1) *
|
||||
model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy/vt +
|
||||
model->DIOtunSaturationCurrentExp *
|
||||
log(here->DIOtemp/model->DIOnomTemp) );
|
||||
here->DIOtTunSatSWCur = model->DIOtunSatSWCur * here->DIOpj * exp(
|
||||
((here->DIOtemp/model->DIOnomTemp)-1) *
|
||||
model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy/vt +
|
||||
model->DIOtunSaturationCurrentExp *
|
||||
log(here->DIOtemp/model->DIOnomTemp) );
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOactivationEnergy / vts;
|
||||
arg1_dT = model->DIOactivationEnergy / (vts*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vts*Temp);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOswEmissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOswEmissionCoeff / Temp;
|
||||
here->DIOtSatSWCur = here->DIOm * model->DIOsatSWCur * here->DIOpj * exp(arg1 + arg2);
|
||||
here->DIOtSatSWCur_dT = here->DIOm * model->DIOsatSWCur * here->DIOpj * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
here->DIOtRecSatCur = model->DIOrecSatCur * here->DIOarea * exp(
|
||||
((here->DIOtemp/model->DIOnomTemp)-1) *
|
||||
model->DIOactivationEnergy/(model->DIOrecEmissionCoeff*vt) +
|
||||
model->DIOsaturationCurrentExp/model->DIOrecEmissionCoeff *
|
||||
log(here->DIOtemp/model->DIOnomTemp) );
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / vtt;
|
||||
arg1_dT = model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / (vtt*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vtt*Temp);
|
||||
arg2 = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff / Temp;
|
||||
here->DIOtTunSatCur = here->DIOm * model->DIOtunSatCur * here->DIOarea * exp(arg1 + arg2);
|
||||
here->DIOtTunSatCur_dT = here->DIOm * model->DIOtunSatCur * here->DIOarea * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / vtt;
|
||||
arg1_dT = model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / (vtt*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vtt*Temp);
|
||||
arg2 = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff / Temp;
|
||||
here->DIOtTunSatSWCur = here->DIOm * model->DIOtunSatSWCur * here->DIOpj * exp(arg1 + arg2);
|
||||
here->DIOtTunSatSWCur_dT = here->DIOm * model->DIOtunSatSWCur * here->DIOpj * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOactivationEnergy / vtr;
|
||||
arg1_dT = model->DIOactivationEnergy / (vtr*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vtr*Temp);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOrecEmissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOrecEmissionCoeff / Temp;
|
||||
here->DIOtRecSatCur = here->DIOm * model->DIOrecSatCur * here->DIOarea * exp(arg1 + arg2);
|
||||
here->DIOtRecSatCur_dT = here->DIOm * model->DIOrecSatCur * here->DIOarea * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
xfc=log(1-model->DIOdepletionCapCoeff);
|
||||
xfcs=log(1-model->DIOdepletionSWcapCoeff);
|
||||
|
||||
/* the defintion of f1, just recompute after temperature adjusting
|
||||
* all the variables used in it */
|
||||
|
|
@ -227,9 +192,9 @@ DIOtemp(GENmodel *inModel, CKTcircuit *ckt)
|
|||
tBreakdownVoltage = model->DIObreakdownVoltage * (1 - model->DIOtcv * dt);
|
||||
}
|
||||
if (model->DIOlevel == 1) {
|
||||
cbv = model->DIObreakdownCurrent;
|
||||
cbv = here->DIOm * model->DIObreakdownCurrent;
|
||||
} else { /* level=3 */
|
||||
cbv = model->DIObreakdownCurrent * here->DIOarea;
|
||||
cbv = here->DIOm * model->DIObreakdownCurrent * here->DIOarea;
|
||||
}
|
||||
if (cbv < here->DIOtSatCur * tBreakdownVoltage/vt) {
|
||||
cbv=here->DIOtSatCur * tBreakdownVoltage/vt;
|
||||
|
|
@ -265,11 +230,13 @@ DIOtemp(GENmodel *inModel, CKTcircuit *ckt)
|
|||
here->DIOtTransitTime = model->DIOtransitTime * factor;
|
||||
|
||||
/* Series resistance temperature adjust */
|
||||
here->DIOtConductance = model->DIOconductance;
|
||||
here->DIOtConductance = here->DIOm * model->DIOconductance * here->DIOarea;
|
||||
if(model->DIOresistGiven && model->DIOresist!=0.0) {
|
||||
factor = 1.0 + (model->DIOresistTemp1) * dt
|
||||
+ (model->DIOresistTemp2 * dt * dt);
|
||||
here->DIOtConductance = model->DIOconductance / factor;
|
||||
here->DIOtConductance = here->DIOm * model->DIOconductance * here->DIOarea / factor;
|
||||
here->DIOtConductance_dT = here->DIOm * -model->DIOconductance * here->DIOarea *
|
||||
(model->DIOresistTemp1 + model->DIOresistTemp2 * dt) / (factor*factor);
|
||||
}
|
||||
|
||||
here->DIOtF2=exp((1+here->DIOtGradingCoeff)*xfc);
|
||||
|
|
@ -278,6 +245,26 @@ DIOtemp(GENmodel *inModel, CKTcircuit *ckt)
|
|||
here->DIOtF2SW=exp((1+model->DIOgradingSWCoeff)*xfcs);
|
||||
here->DIOtF3SW=1-model->DIOdepletionSWcapCoeff*
|
||||
(1+model->DIOgradingSWCoeff);
|
||||
}
|
||||
|
||||
int
|
||||
DIOtemp(GENmodel *inModel, CKTcircuit *ckt)
|
||||
{
|
||||
DIOmodel *model = (DIOmodel*)inModel;
|
||||
DIOinstance *here;
|
||||
|
||||
/* loop through all the diode models */
|
||||
for( ; model != NULL; model = DIOnextModel(model)) {
|
||||
|
||||
/* loop through all the instances */
|
||||
for(here=DIOinstances(model);here;here=DIOnextInstance(here)) {
|
||||
|
||||
if(!here->DIOdtempGiven) here->DIOdtemp = 0.0;
|
||||
|
||||
if(!here->DIOtempGiven)
|
||||
here->DIOtemp = ckt->CKTtemp + here->DIOdtemp;
|
||||
|
||||
DIOtempUpdate(model, here, here->DIOtemp, ckt);
|
||||
|
||||
} /* instance */
|
||||
|
||||
|
|
|
|||
|
|
@ -15,25 +15,24 @@ Modified: 2001 Paolo Nenzi (Cider Integration)
|
|||
void INP2D(CKTcircuit *ckt, INPtables * tab, struct card *current)
|
||||
{
|
||||
|
||||
/* Dname <node> <node> <model> [<val>] [OFF] [IC=<val>] */
|
||||
/* Dname <node> <node> [<temp>] <model> [<val>] [OFF] [IC=<val>] */
|
||||
|
||||
int mytype; /* the type we looked up */
|
||||
int type; /* the type the model says it is */
|
||||
char *line; /* the part of the current line left to parse */
|
||||
char *name; /* the resistor's name */
|
||||
char *nname1; /* the first node's name */
|
||||
char *nname2; /* the second node's name */
|
||||
CKTnode *node1; /* the first node's node pointer */
|
||||
CKTnode *node2; /* the second node's node pointer */
|
||||
const int max_i = 3;/* the maximum node count */
|
||||
CKTnode *node[3];
|
||||
int error; /* error code temporary */
|
||||
int numnodes; /* flag indicating 4 or 5 nodes */
|
||||
GENinstance *fast; /* pointer to the actual instance */
|
||||
IFvalue ptemp; /* a value structure to package resistance into */
|
||||
int waslead; /* flag to indicate that funny unlabeled number was found */
|
||||
double leadval; /* actual value of unlabeled number */
|
||||
char *model; /* the name of the model */
|
||||
INPmodel *thismodel;/* pointer to model description for user's model */
|
||||
GENmodel *mdfast; /* pointer to the actual model */
|
||||
IFuid uid; /* uid of default model */
|
||||
int i;
|
||||
|
||||
mytype = INPtypelook("Diode");
|
||||
if (mytype < 0) {
|
||||
|
|
@ -43,16 +42,35 @@ void INP2D(CKTcircuit *ckt, INPtables * tab, struct card *current)
|
|||
line = current->line;
|
||||
INPgetNetTok(&line, &name, 1);
|
||||
INPinsert(&name, tab);
|
||||
INPgetNetTok(&line, &nname1, 1);
|
||||
INPtermInsert(ckt, &nname1, tab, &node1);
|
||||
INPgetNetTok(&line, &nname2, 1);
|
||||
INPtermInsert(ckt, &nname2, tab, &node2);
|
||||
INPgetNetTok(&line, &model, 1);
|
||||
INPinsert(&model, tab);
|
||||
current->error = INPgetMod(ckt, model, &thismodel, tab);
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
char *token;
|
||||
INPgetNetTok(&line, &token, 1);
|
||||
if (i >= 2 && INPlookMod(token)) {
|
||||
INPinsert(&token, tab);
|
||||
txfree(INPgetMod(ckt, token, &thismodel, tab));
|
||||
if (!thismodel) {
|
||||
LITERR ("Unable to find definition of given model");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i >= max_i) {
|
||||
LITERR ("could not find a valid modelname");
|
||||
return;
|
||||
}
|
||||
INPtermInsert(ckt, &token, tab, &node[i]);
|
||||
}
|
||||
|
||||
if (i > max_i) {
|
||||
LITERR("Too many nodes for this model type");
|
||||
return;
|
||||
}
|
||||
|
||||
numnodes = i;
|
||||
|
||||
if (thismodel != NULL) {
|
||||
if ((mytype != thismodel->INPmodType)
|
||||
|
||||
#ifdef CIDER
|
||||
&& (thismodel->INPmodType != INPtypelook("NUMD"))
|
||||
&& (thismodel->INPmodType != INPtypelook("NUMD2"))
|
||||
|
|
@ -72,12 +90,16 @@ void INP2D(CKTcircuit *ckt, INPtables * tab, struct card *current)
|
|||
}
|
||||
mdfast = tab->defDmod;
|
||||
}
|
||||
|
||||
IFC(newInstance, (ckt, mdfast, &fast, name));
|
||||
IFC(bindNode, (ckt, fast, 1, node1));
|
||||
IFC(bindNode, (ckt, fast, 2, node2));
|
||||
for (i = 0; i < max_i; i++)
|
||||
if (i < numnodes)
|
||||
IFC (bindNode, (ckt, fast, i + 1, node[i]));
|
||||
else
|
||||
GENnode(fast)[i] = -1;
|
||||
|
||||
PARSECALL((&line, ckt, type, fast, &leadval, &waslead, tab));
|
||||
if (waslead) {
|
||||
|
||||
#ifdef CIDER
|
||||
if( type == INPtypelook("NUMD2") ) {
|
||||
LITERR(" error: no unlabelled parameter permitted on NUMD2\n");
|
||||
|
|
|
|||
Loading…
Reference in New Issue