Diode model with selfheating option

This commit is contained in:
dwarning 2021-04-11 11:28:57 +02:00 committed by Holger Vogt
parent 48acb10929
commit b1bf7ea0ad
16 changed files with 651 additions and 341 deletions

View File

@ -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':

View File

@ -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':

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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*/

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -5,7 +5,7 @@ Modified: 2000 AlansFixes
Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
**********/
/* perform the temperature update to the diode */
/* perform the temperature update to the diode */
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
@ -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 */

View File

@ -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 */
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,21 +42,40 @@ 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"))
#endif
){
) {
LITERR("incorrect model type");
return;
}
@ -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");