diff --git a/src/include/ngspice/devdefs.h b/src/include/ngspice/devdefs.h index ead0d29dd..832aa4751 100644 --- a/src/include/ngspice/devdefs.h +++ b/src/include/ngspice/devdefs.h @@ -16,6 +16,7 @@ Author: 1985 Thomas L. Quarles double DEVlimvds(double,double); double DEVpnjlim(double,double,double,double,int*); double DEVfetlim(double,double,double); +double DEVlimitlog(double, double, double, int*); void DEVcmeyer(double,double,double,double,double,double,double,double,double, double,double,double*,double*,double*,double,double,double,double); void DEVqmeyer(double,double,double,double,double,double*,double*,double*, diff --git a/src/spicelib/devices/bjt/bjt.c b/src/spicelib/devices/bjt/bjt.c index 33374b14f..794b5ff75 100644 --- a/src/spicelib/devices/bjt/bjt.c +++ b/src/spicelib/devices/bjt/bjt.c @@ -154,6 +154,10 @@ IFparm BJTmPTable[] = { /* model parameters */ OPU("excessphasefactor",BJT_MOD_EXCESSPHASEFACTOR,IF_REAL, "Excess phase fact."), IOP("iss", BJT_MOD_ISS, IF_REAL, "Substrate Jct. Saturation Current"), IOP("ns", BJT_MOD_NS, IF_REAL, "Substrate current emission coefficient"), + IOP("rco", BJT_MOD_RCO, IF_REAL, "Intrinsic coll. resistance"), + IOP("vo", BJT_MOD_VO, IF_REAL, "Epi drift saturation voltage"), + IOP("gamma", BJT_MOD_GAMMA, IF_REAL, "Epi doping parameter"), + IOP("qco", BJT_MOD_QCO, IF_REAL, "Epi Charge parameter"), IOP("tlev", BJT_MOD_TLEV, IF_INTEGER, "Temperature equation selector"), IOP("tlevc", BJT_MOD_TLEVC, IF_INTEGER, "Temperature equation selector"), IOP("tbf1", BJT_MOD_TBF1, IF_REAL, "BF 1. temperature coefficient"), @@ -216,6 +220,10 @@ IFparm BJTmPTable[] = { /* model parameters */ IOP("tise2", BJT_MOD_TISE2, IF_REAL, "ISE 2. temperature coefficient"), IOP("tisc1", BJT_MOD_TISC1, IF_REAL, "ISC 1. temperature coefficient"), IOP("tisc2", BJT_MOD_TISC2, IF_REAL, "ISC 2. temperature coefficient"), + IOP("quasimod", BJT_MOD_QUASIMOD, IF_INTEGER, "Temperature equation selector"), + IOP("vg", BJT_MOD_EGQS, IF_REAL, "Energy gap for QS temp. dependency"), + IOP("cn", BJT_MOD_XRCI, IF_REAL, "Temperature exponent of RCI"), + IOP("d", BJT_MOD_XD, IF_REAL, "Temperature exponent of VO"), IOP("vbe_max", BJT_MOD_VBE_MAX, IF_REAL, "maximum voltage B-E junction"), IOP("vbc_max", BJT_MOD_VBC_MAX, IF_REAL, "maximum voltage B-C junction"), IOP("vce_max", BJT_MOD_VCE_MAX, IF_REAL, "maximum voltage C-E branch") diff --git a/src/spicelib/devices/bjt/bjtacld.c b/src/spicelib/devices/bjt/bjtacld.c index fcdfa7cb3..901ad5f57 100644 --- a/src/spicelib/devices/bjt/bjtacld.c +++ b/src/spicelib/devices/bjt/bjtacld.c @@ -36,6 +36,7 @@ BJTacLoad(GENmodel *inModel, CKTcircuit *ckt) double xcsub; double xcmcb; double m; + double Irci_Vrci, Irci_Vbci, Irci_Vbcx, xcbcx; for( ; model != NULL; model = BJTnextModel(model)) { for( here = BJTinstances(model); here!= NULL; @@ -49,6 +50,9 @@ BJTacLoad(GENmodel *inModel, CKTcircuit *ckt) gmu= *(ckt->CKTstate0 + here->BJTgmu); gm= *(ckt->CKTstate0 + here->BJTgm); go= *(ckt->CKTstate0 + here->BJTgo); + Irci_Vrci = *(ckt->CKTstate0 + here->BJTirci_Vrci); + Irci_Vbci = *(ckt->CKTstate0 + here->BJTirci_Vbci); + Irci_Vbcx = *(ckt->CKTstate0 + here->BJTirci_Vbcx); xgm=0; td=model->BJTexcessPhaseFactor; if(td != 0) { @@ -63,21 +67,24 @@ BJTacLoad(GENmodel *inModel, CKTcircuit *ckt) xcbx= *(ckt->CKTstate0 + here->BJTcqbx) * ckt->CKTomega; xcsub= *(ckt->CKTstate0 + here->BJTcqsub) * ckt->CKTomega; xcmcb= *(ckt->CKTstate0 + here->BJTcexbc) * ckt->CKTomega; + xcbcx= *(ckt->CKTstate0 + here->BJTcqbcx) * ckt->CKTomega; + *(here->BJTcolColPtr) += m * (gcpr); *(here->BJTbaseBasePtr) += m * (gx); *(here->BJTbaseBasePtr + 1) += m * (xcbx); *(here->BJTemitEmitPtr) += m * (gepr); - *(here->BJTcolPrimeColPrimePtr) += m * (gmu+go+gcpr); + *(here->BJTcolPrimeColPrimePtr) += m * (gmu+go); + *(here->BJTcollCXcollCXPtr) += m * (gcpr); *(here->BJTcolPrimeColPrimePtr + 1) += m * (xcmu+xcbx); *(here->BJTsubstConSubstConPtr + 1) += m * (xcsub); *(here->BJTbasePrimeBasePrimePtr) += m * (gx+gpi+gmu); *(here->BJTbasePrimeBasePrimePtr + 1) += m * (xcpi+xcmu+xcmcb); *(here->BJTemitPrimeEmitPrimePtr) += m * (gpi+gepr+gm+go); *(here->BJTemitPrimeEmitPrimePtr + 1) += m * (xcpi+xgm); - *(here->BJTcolColPrimePtr) += m * (-gcpr); + *(here->BJTcollCollCXPtr) += m * (-gcpr); *(here->BJTbaseBasePrimePtr) += m * (-gx); *(here->BJTemitEmitPrimePtr) += m * (-gepr); - *(here->BJTcolPrimeColPtr) += m * (-gcpr); + *(here->BJTcollCXCollPtr) += m * (-gcpr); *(here->BJTcolPrimeBasePrimePtr) += m * (-gmu+gm); *(here->BJTcolPrimeBasePrimePtr + 1) += m * (-xcmu+xgm); *(here->BJTcolPrimeEmitPrimePtr) += m * (-gm-go); @@ -97,6 +104,24 @@ BJTacLoad(GENmodel *inModel, CKTcircuit *ckt) *(here->BJTsubstSubstConPtr + 1) += m * (-xcsub); *(here->BJTbaseColPrimePtr + 1) += m * (-xcbx); *(here->BJTcolPrimeBasePtr + 1) += m * (-xcbx); + if (model->BJTintCollResistGiven) { + *(here->BJTcollCXcollCXPtr) += m * Irci_Vrci; + *(here->BJTcollCXColPrimePtr) += m * -Irci_Vrci; + *(here->BJTcollCXBasePrimePtr) += m * Irci_Vbci; + *(here->BJTcollCXColPrimePtr) += m * -Irci_Vbci; + *(here->BJTcollCXBasePrimePtr) += m * Irci_Vbcx; + *(here->BJTcollCXcollCXPtr) += m * -Irci_Vbcx; + *(here->BJTcolPrimeCollCXPtr) += m * -Irci_Vrci; + *(here->BJTcolPrimeColPrimePtr) += m * Irci_Vrci; + *(here->BJTcolPrimeBasePrimePtr) += m * -Irci_Vbci; + *(here->BJTcolPrimeColPrimePtr) += m * Irci_Vbci; + *(here->BJTcolPrimeBasePrimePtr) += m * -Irci_Vbcx; + *(here->BJTcolPrimeCollCXPtr) += m * Irci_Vbcx; + *(here->BJTbasePrimeBasePrimePtr + 1) += m * xcbcx; + *(here->BJTcollCXcollCXPtr + 1) += m * xcbcx; + *(here->BJTbasePrimeCollCXPtr + 1) += m * -xcbcx; + *(here->BJTcollCXBasePrimePtr + 1) += m * -xcbcx; + } } } return(OK); diff --git a/src/spicelib/devices/bjt/bjtask.c b/src/spicelib/devices/bjt/bjtask.c index f40676907..5b1ae876f 100644 --- a/src/spicelib/devices/bjt/bjtask.c +++ b/src/spicelib/devices/bjt/bjtask.c @@ -78,6 +78,9 @@ BJTask(CKTcircuit *ckt, GENinstance *instPtr, int which, IFvalue *value, IFvalue case BJT_QUEST_COLPRIMENODE: value->iValue = here->BJTcolPrimeNode; return(OK); + case BJT_QUEST_COLLCXNODE: + value->iValue = here->BJTcollCXNode; + return(OK); case BJT_QUEST_BASEPRIMENODE: value->iValue = here->BJTbasePrimeNode; return(OK); diff --git a/src/spicelib/devices/bjt/bjtconv.c b/src/spicelib/devices/bjt/bjtconv.c index 515499e81..c30a47cc8 100644 --- a/src/spicelib/devices/bjt/bjtconv.c +++ b/src/spicelib/devices/bjt/bjtconv.c @@ -27,9 +27,10 @@ BJTconvTest(GENmodel *inModel, CKTcircuit *ckt) double cbhat; double vbe; double vbc; + double vbcx; double delvbe; double delvbc; - + double delvbcx; for( ; model != NULL; model = BJTnextModel(model)) { @@ -41,8 +42,12 @@ BJTconvTest(GENmodel *inModel, CKTcircuit *ckt) vbc=model->BJTtype*( *(ckt->CKTrhsOld+here->BJTbasePrimeNode)- *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + vbcx=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbasePrimeNode)- + *(ckt->CKTrhsOld+here->BJTcollCXNode)); delvbe=vbe- *(ckt->CKTstate0 + here->BJTvbe); delvbc=vbc- *(ckt->CKTstate0 + here->BJTvbc); + delvbcx=vbcx- *(ckt->CKTstate0 + here->BJTvbcx); cchat= *(ckt->CKTstate0 + here->BJTcc)+(*(ckt->CKTstate0 + here->BJTgm)+ *(ckt->CKTstate0 + here->BJTgo))*delvbe- (*(ckt->CKTstate0 + here->BJTgo)+*(ckt->CKTstate0 + @@ -58,14 +63,14 @@ BJTconvTest(GENmodel *inModel, CKTcircuit *ckt) tol=ckt->CKTreltol*MAX(fabs(cchat),fabs(cc))+ckt->CKTabstol; if (fabs(cchat-cc) > tol) { ckt->CKTnoncon++; - ckt->CKTtroubleElt = (GENinstance *) here; + ckt->CKTtroubleElt = (GENinstance *) here; return(OK); /* no reason to continue - we've failed... */ } else { tol=ckt->CKTreltol*MAX(fabs(cbhat),fabs(cb))+ ckt->CKTabstol; if (fabs(cbhat-cb) > tol) { ckt->CKTnoncon++; - ckt->CKTtroubleElt = (GENinstance *) here; + ckt->CKTtroubleElt = (GENinstance *) here; return(OK); /* no reason to continue - we've failed... */ } } diff --git a/src/spicelib/devices/bjt/bjtdefs.h b/src/spicelib/devices/bjt/bjtdefs.h index 4d1870763..625db4772 100644 --- a/src/spicelib/devices/bjt/bjtdefs.h +++ b/src/spicelib/devices/bjt/bjtdefs.h @@ -43,6 +43,7 @@ typedef struct sBJTinstance { const int BJTbaseNode; /* number of base node of bjt */ const int BJTemitNode; /* number of emitter node of bjt */ const int BJTsubstNode; /* number of substrate node of bjt */ + int BJTcollCXNode; /* number of internal collector node of bjt */ int BJTcolPrimeNode; /* number of internal collector node of bjt */ int BJTbasePrimeNode; /* number of internal base node of bjt */ int BJTemitPrimeNode; /* number of internal emitter node of bjt */ @@ -100,15 +101,18 @@ typedef struct sBJTinstance { double BJTtjunctionExpBC; /* temperature adjusted MJC */ double BJTtjunctionExpSub; /* temperature adjusted MJS */ double BJTtemissionCoeffS; /* temperature adjusted NS */ + double BJTtintCollResist; /* temperature adjusted QS RO */ + double BJTtepiSatVoltage; /* temperature adjusted QS VO */ + double BJTtepiDoping; /* temperature adjusted QS GAMMA */ - double *BJTcolColPrimePtr; /* pointer to sparse matrix at - * (collector,collector prime) */ + double *BJTcollCollCXPtr; /* pointer to sparse matrix at + * (collector,collector cx) */ double *BJTbaseBasePrimePtr; /* pointer to sparse matrix at * (base,base prime) */ double *BJTemitEmitPrimePtr; /* pointer to sparse matrix at * (emitter,emitter prime) */ - double *BJTcolPrimeColPtr; /* pointer to sparse matrix at - * (collector prime,collector) */ + double *BJTcollCXCollPtr; /* pointer to sparse matrix at + * (collector cx,collector) */ double *BJTcolPrimeBasePrimePtr; /* pointer to sparse matrix at * (collector prime,base prime) */ double *BJTcolPrimeEmitPrimePtr; /* pointer to sparse matrix at @@ -153,6 +157,17 @@ typedef struct sBJTinstance { double *BJTcolPrimeBasePtr; /* pointer to sparse matrix at * (collector prime,base) */ + double *BJTcollCXcollCXPtr; /* pointer to sparse matrix at + * (collector cx,collector cx) */ + double *BJTcollCXBasePrimePtr; /* pointer to sparse matrix at + * (collector cx,base prime) */ + double *BJTbasePrimeCollCXPtr; /* pointer to sparse matrix at + * (base prime,collector cx) */ + double *BJTcolPrimeCollCXPtr; /* pointer to sparse matrix at + * (collector prime,collector cx) */ + double *BJTcollCXColPrimePtr; /* pointer to sparse matrix at + * (collector cx,base prime) */ + unsigned BJToff :1; /* 'off' flag for bjt */ unsigned BJTtempGiven :1; /* temperature given for bjt instance*/ unsigned BJTdtempGiven :1; /* delta temperature given for bjt instance*/ @@ -171,6 +186,7 @@ typedef struct sBJTinstance { double BJTcapbc; double BJTcapsub; double BJTcapbx; + double BJTcapbcx; double *BJTsens; #define BJTsenGpi BJTsens /* stores the perturbed values of gpi */ @@ -297,29 +313,39 @@ typedef struct sBJTinstance { /* entries in the state vector for bjt: */ #define BJTvbe BJTstate #define BJTvbc BJTstate+1 -#define BJTcc BJTstate+2 -#define BJTcb BJTstate+3 -#define BJTgpi BJTstate+4 -#define BJTgmu BJTstate+5 -#define BJTgm BJTstate+6 -#define BJTgo BJTstate+7 -#define BJTqbe BJTstate+8 -#define BJTcqbe BJTstate+9 -#define BJTqbc BJTstate+10 -#define BJTcqbc BJTstate+11 -#define BJTqsub BJTstate+12 -#define BJTcqsub BJTstate+13 -#define BJTqbx BJTstate+14 -#define BJTcqbx BJTstate+15 -#define BJTgx BJTstate+16 -#define BJTcexbc BJTstate+17 -#define BJTgeqcb BJTstate+18 -#define BJTgcsub BJTstate+19 -#define BJTgeqbx BJTstate+20 -#define BJTvsub BJTstate+21 -#define BJTcdsub BJTstate+22 -#define BJTgdsub BJTstate+23 -#define BJTnumStates 24 +#define BJTvbcx BJTstate+2 +#define BJTvrci BJTstate+3 +#define BJTcc BJTstate+4 +#define BJTcb BJTstate+5 +#define BJTgpi BJTstate+6 +#define BJTgmu BJTstate+7 +#define BJTgm BJTstate+8 +#define BJTgo BJTstate+9 +#define BJTqbe BJTstate+10 +#define BJTcqbe BJTstate+11 +#define BJTqbc BJTstate+12 +#define BJTcqbc BJTstate+13 +#define BJTqsub BJTstate+14 +#define BJTcqsub BJTstate+15 +#define BJTqbx BJTstate+16 +#define BJTcqbx BJTstate+17 +#define BJTgx BJTstate+18 +#define BJTcexbc BJTstate+19 +#define BJTgeqcb BJTstate+20 +#define BJTgcsub BJTstate+21 +#define BJTgeqbx BJTstate+22 +#define BJTvsub BJTstate+23 +#define BJTcdsub BJTstate+24 +#define BJTgdsub BJTstate+25 +#define BJTirci BJTstate+26 +#define BJTirci_Vrci BJTstate+27 +#define BJTirci_Vbci BJTstate+28 +#define BJTirci_Vbcx BJTstate+29 +#define BJTqbcx BJTstate+30 +#define BJTcqbcx BJTstate+31 +#define BJTgbcx BJTstate+32 + +#define BJTnumStates 33 #define BJTsensxpbe BJTstate+24 /* charge sensitivities and their derivatives. +25 for the derivatives - @@ -388,6 +414,10 @@ typedef struct sBJTmodel { /* model structure for a bjt */ double BJTfNexp; double BJTsubSatCur; /* input - don't use */ double BJTemissionCoeffS; + double BJTintCollResist; + double BJTepiSatVoltage; + double BJTepiDoping; + double BJTepiCharge; int BJTtlev; int BJTtlevc; double BJTtbf1; @@ -459,6 +489,10 @@ typedef struct sBJTmodel { /* model structure for a bjt */ double BJTtise2; double BJTtisc1; double BJTtisc2; + int BJTquasimod; + double BJTenergyGapQS; + double BJTtempExpRCI; + double BJTtempExpVO; double BJTvbeMax; /* maximum voltage over B-E junction */ double BJTvbcMax; /* maximum voltage over B-C junction */ double BJTvceMax; /* maximum voltage over C-E branch */ @@ -509,6 +543,10 @@ typedef struct sBJTmodel { /* model structure for a bjt */ unsigned BJTfNexpGiven :1; unsigned BJTsubSatCurGiven : 1; unsigned BJTemissionCoeffSGiven : 1; + unsigned BJTintCollResistGiven : 1; + unsigned BJTepiSatVoltageGiven : 1; + unsigned BJTepiDopingGiven : 1; + unsigned BJTepiChargeGiven : 1; unsigned BJTtlevGiven : 1; unsigned BJTtlevcGiven : 1; unsigned BJTtbf1Given : 1; @@ -568,6 +606,10 @@ typedef struct sBJTmodel { /* model structure for a bjt */ unsigned BJTtise2Given : 1; unsigned BJTtisc1Given : 1; unsigned BJTtisc2Given : 1; + unsigned BJTquasimodGiven : 1; + unsigned BJTenergyGapQSGiven : 1; + unsigned BJTtempExpRCIGiven : 1; + unsigned BJTtempExpVOGiven : 1; unsigned BJTvbeMaxGiven : 1; unsigned BJTvbcMaxGiven : 1; unsigned BJTvceMaxGiven : 1; @@ -650,6 +692,10 @@ enum { BJT_MOD_KF, BJT_MOD_ISS, BJT_MOD_NS, + BJT_MOD_RCO, + BJT_MOD_VO, + BJT_MOD_GAMMA, + BJT_MOD_QCO, BJT_MOD_TNOM, BJT_MOD_TLEV, BJT_MOD_TLEVC, @@ -711,6 +757,10 @@ enum { BJT_MOD_TISE2, BJT_MOD_TISC1, BJT_MOD_TISC2, + BJT_MOD_QUASIMOD, + BJT_MOD_EGQS, + BJT_MOD_XRCI, + BJT_MOD_XD, BJT_MOD_VBE_MAX, BJT_MOD_VBC_MAX, BJT_MOD_VCE_MAX, @@ -723,6 +773,7 @@ enum { BJT_QUEST_BASENODE, BJT_QUEST_EMITNODE, BJT_QUEST_SUBSTNODE, + BJT_QUEST_COLLCXNODE, BJT_QUEST_COLPRIMENODE, BJT_QUEST_BASEPRIMENODE, BJT_QUEST_EMITPRIMENODE, diff --git a/src/spicelib/devices/bjt/bjtload.c b/src/spicelib/devices/bjt/bjtload.c index a4cfc8574..1322328cb 100644 --- a/src/spicelib/devices/bjt/bjtload.c +++ b/src/spicelib/devices/bjt/bjtload.c @@ -64,6 +64,7 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) double czbxf2; double czsub; double delvbc; + double delvbcx; double delvbe; double denom; double dqbdvc; @@ -111,6 +112,7 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) double tf; double tr; double vbc; + double vbcx; double vbe; double vbx=0.0; double vce; @@ -137,6 +139,9 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) int error; int SenCond=0; double m; + double vrci=0.0, delvrci; + double Irci=0.0, Irci_Vrci=0.0, Irci_Vbci=0.0, Irci_Vbcx=0.0; + double Qbci=0.0, Qbci_Vbci=0.0, Qbcx, Qbcx_Vbcx=0.0, gbcx, cbcx; /* loop through all the models */ for( ; model != NULL; model = BJTnextModel(model)) { @@ -159,12 +164,13 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) SenCond = here->BJTsenPertFlag; } - gcsub=0; ceqsub=0; geqbx=0; ceqbx=0; geqcb=0; + gbcx=0; + cbcx=0; /* * dc model paramters */ @@ -195,6 +201,8 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) (ckt->CKTmode & MODEINITTRAN)) { vbe = *(ckt->CKTstate1 + here->BJTvbe); vbc = *(ckt->CKTstate1 + here->BJTvbc); + vbcx = *(ckt->CKTstate1 + here->BJTvbcx); + vrci = *(ckt->CKTstate1 + here->BJTvrci); vbx=model->BJTtype*( *(ckt->CKTrhsOp+here->BJTbaseNode)- *(ckt->CKTrhsOp+here->BJTcolPrimeNode)); @@ -205,6 +213,8 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) else{ vbe = *(ckt->CKTstate0 + here->BJTvbe); vbc = *(ckt->CKTstate0 + here->BJTvbc); + vbcx = *(ckt->CKTstate0 + here->BJTvbcx); + vrci = *(ckt->CKTstate0 + here->BJTvrci); if((ckt->CKTsenInfo->SENmode == DCSEN)|| (ckt->CKTsenInfo->SENmode == TRANSEN)){ vbx=model->BJTtype*( @@ -233,6 +243,8 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) if(ckt->CKTmode & MODEINITSMSIG) { vbe= *(ckt->CKTstate0 + here->BJTvbe); vbc= *(ckt->CKTstate0 + here->BJTvbc); + vbcx= *(ckt->CKTstate0 + here->BJTvbcx); + vrci = *(ckt->CKTstate0 + here->BJTvrci); vbx=model->BJTtype*( *(ckt->CKTrhsOld+here->BJTbaseNode)- *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); @@ -242,6 +254,8 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) } else if(ckt->CKTmode & MODEINITTRAN) { vbe = *(ckt->CKTstate1 + here->BJTvbe); vbc = *(ckt->CKTstate1 + here->BJTvbc); + vbcx = *(ckt->CKTstate1 + here->BJTvbcx); + vrci = *(ckt->CKTstate1 + here->BJTvrci); vbx=model->BJTtype*( *(ckt->CKTrhsOld+here->BJTbaseNode)- *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); @@ -256,20 +270,23 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)){ vbe=model->BJTtype*here->BJTicVBE; vce=model->BJTtype*here->BJTicVCE; - vbc=vbe-vce; + vbc=vbcx=vbe-vce; vbx=vbc; vsub=0; + vrci=0.0; } else if((ckt->CKTmode & MODEINITJCT) && (here->BJToff==0)) { vbe=here->BJTtVcrit; - vbc=0; + vbc=vbcx=0; /* ERROR: need to initialize VSUB, VBX here */ vsub=vbx=0; + vrci=0.0; } else if((ckt->CKTmode & MODEINITJCT) || ( (ckt->CKTmode & MODEINITFIX) && (here->BJToff!=0))) { vbe=0; - vbc=0; + vbc=vbcx=0; /* ERROR: need to initialize VSUB, VBX here */ vsub=vbx=0; + vrci=0.0; } else { #ifndef PREDICTOR if(ckt->CKTmode & MODEINITPRED) { @@ -282,6 +299,14 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate1 + here->BJTvbc); vbc = (1+xfact)**(ckt->CKTstate1 + here->BJTvbc)- xfact* *(ckt->CKTstate2 + here->BJTvbc); + *(ckt->CKTstate0 + here->BJTvbcx) = + *(ckt->CKTstate1 + here->BJTvbcx); + vbcx = (1+xfact)**(ckt->CKTstate1 + here->BJTvbcx)- + xfact* *(ckt->CKTstate2 + here->BJTvbcx); + *(ckt->CKTstate0 + here->BJTvrci) = + *(ckt->CKTstate1 + here->BJTvrci); + vrci = (1+xfact) * *(ckt->CKTstate1 + here->BJTvrci)- + xfact * *(ckt->CKTstate2 + here->BJTvrci); *(ckt->CKTstate0 + here->BJTcc) = *(ckt->CKTstate1 + here->BJTcc); *(ckt->CKTstate0 + here->BJTcb) = @@ -296,10 +321,18 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate1 + here->BJTgo); *(ckt->CKTstate0 + here->BJTgx) = *(ckt->CKTstate1 + here->BJTgx); - *(ckt->CKTstate0 + here->BJTvsub) = + *(ckt->CKTstate0 + here->BJTvsub) = *(ckt->CKTstate1 + here->BJTvsub); vsub = (1+xfact)**(ckt->CKTstate1 + here->BJTvsub)- xfact* *(ckt->CKTstate2 + here->BJTvsub); + *(ckt->CKTstate0 + here->BJTirci) = + *(ckt->CKTstate1 + here->BJTirci); + *(ckt->CKTstate0 + here->BJTirci_Vrci) = + *(ckt->CKTstate1 + here->BJTirci_Vrci); + *(ckt->CKTstate0 + here->BJTirci_Vbci) = + *(ckt->CKTstate1 + here->BJTirci_Vbci); + *(ckt->CKTstate0 + here->BJTirci_Vbcx) = + *(ckt->CKTstate1 + here->BJTirci_Vbcx); } else { #endif /* PREDICTOR */ /* @@ -311,6 +344,12 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) vbc=model->BJTtype*( *(ckt->CKTrhsOld+here->BJTbasePrimeNode)- *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + vbcx=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbasePrimeNode)- + *(ckt->CKTrhsOld+here->BJTcollCXNode)); + vrci=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTcollCXNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); vsub=model->BJTtype*model->BJTsubs*( *(ckt->CKTrhsOld+here->BJTsubstNode)- *(ckt->CKTrhsOld+here->BJTsubstConNode)); @@ -319,6 +358,8 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) #endif /* PREDICTOR */ delvbe=vbe- *(ckt->CKTstate0 + here->BJTvbe); delvbc=vbc- *(ckt->CKTstate0 + here->BJTvbc); + delvbcx=vbcx- *(ckt->CKTstate0 + here->BJTvbcx); + delvrci = vrci - *(ckt->CKTstate0 + here->BJTvrci); vbx=model->BJTtype*( *(ckt->CKTrhsOld+here->BJTbaseNode)- *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); @@ -348,6 +389,12 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) if( (fabs(delvbc) < ckt->CKTreltol*MAX(fabs(vbc), fabs(*(ckt->CKTstate0 + here->BJTvbc)))+ ckt->CKTvoltTol) ) + if( (fabs(delvbcx) < ckt->CKTreltol*MAX(fabs(vbcx), + fabs(*(ckt->CKTstate0 + here->BJTvbcx)))+ + ckt->CKTvoltTol) ) + if( (fabs(delvrci) < ckt->CKTreltol*MAX(fabs(vrci), + fabs(*(ckt->CKTstate0 + here->BJTvrci)))+ + ckt->CKTvoltTol) ) if( (fabs(cchat-*(ckt->CKTstate0 + here->BJTcc)) < ckt->CKTreltol* MAX(fabs(cchat), fabs(*(ckt->CKTstate0 + here->BJTcc)))+ @@ -361,6 +408,8 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) */ vbe = *(ckt->CKTstate0 + here->BJTvbe); vbc = *(ckt->CKTstate0 + here->BJTvbc); + vbcx = *(ckt->CKTstate0 + here->BJTvbcx); + vrci = *(ckt->CKTstate0 + here->BJTvrci); cc = *(ckt->CKTstate0 + here->BJTcc); cb = *(ckt->CKTstate0 + here->BJTcb); gpi = *(ckt->CKTstate0 + here->BJTgpi); @@ -374,6 +423,12 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) vsub = *(ckt->CKTstate0 + here->BJTvsub); gdsub = *(ckt->CKTstate0 + here->BJTgdsub); cdsub = *(ckt->CKTstate0 + here->BJTcdsub); + Irci = *(ckt->CKTstate0 + here->BJTirci); + Irci_Vrci = *(ckt->CKTstate0 + here->BJTirci_Vrci); + Irci_Vbci = *(ckt->CKTstate0 + here->BJTirci_Vbci); + Irci_Vbcx = *(ckt->CKTstate0 + here->BJTirci_Vbcx); + gbcx = *(ckt->CKTstate0 + here->BJTgbcx); + cbcx = *(ckt->CKTstate0 + here->BJTcqbcx); goto load; } #endif /*NOBYPASS*/ @@ -389,6 +444,7 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) vsub = DEVpnjlim(vsub,*(ckt->CKTstate0 + here->BJTvsub),vt, here->BJTtSubVcrit,&ichk1); if (ichk1 == 1) icheck=1; + vrci = vbc - vbcx; /* in case vbc was limited */ } /* * determine dc current and derivitives @@ -465,6 +521,65 @@ next1: vtn=vt*here->BJTtemissionCoeffF; gdsub = csubsat*evsub/vts + ckt->CKTgmin; cdsub = csubsat*(evsub-1) + ckt->CKTgmin*vsub; } + + /* + * Kull's Quasi-Saturation model + */ + if (model->BJTintCollResistGiven) { + double Kbci,Kbci_Vbci,Kbcx,Kbcx_Vbcx; + double rKp1,rKp1_Vbci,rKp1_Vbcx,xvar1,xvar1_Vbci,xvar1_Vbcx; + double Vcorr,Vcorr_Vbci,Vcorr_Vbcx,Iohm,Iohm_Vrci,Iohm_Vbci,Iohm_Vbcx; + double quot,quot_Vrci; + if (vrci > 0.) { + Kbci = sqrt(1+here->BJTtepiDoping*exp(vbc/vt)); + Kbci_Vbci = here->BJTtepiDoping*exp(vbc/vt)/(2*vt*Kbci); + Kbcx = sqrt(1+here->BJTtepiDoping*exp(vbcx/vt)); + Kbcx_Vbcx = here->BJTtepiDoping*exp(vbcx/vt)/(2*vt*Kbcx); + + rKp1 = (1+Kbci)/(1+Kbcx); + rKp1_Vbci = Kbci_Vbci/(1+Kbci); + rKp1_Vbcx = -(1+Kbci)*Kbcx_Vbcx/((Kbcx+1)*(Kbcx+1)); + xvar1 = log(rKp1); + xvar1_Vbci = rKp1_Vbci/rKp1; + xvar1_Vbcx = rKp1_Vbcx/rKp1; + + Vcorr = vt*(Kbci - Kbcx - xvar1); + Vcorr_Vbci = vt*(Kbci_Vbci - xvar1_Vbci); + Vcorr_Vbcx = vt*(-Kbcx_Vbcx - xvar1_Vbcx); + + Iohm = (vrci+Vcorr)/here->BJTtintCollResist; + Iohm_Vrci = 1/here->BJTtintCollResist; + Iohm_Vbci = Vcorr_Vbci/here->BJTtintCollResist; + Iohm_Vbcx = Vcorr_Vbcx/here->BJTtintCollResist; + + quot = 1+fabs(vrci)/here->BJTtepiSatVoltage; + quot_Vrci = vrci/(here->BJTtepiSatVoltage*fabs(vrci)); + + Irci = Iohm/quot + ckt->CKTgmin*vrci; + Irci_Vrci = Iohm_Vrci/quot-Iohm*quot_Vrci/(quot*quot) + ckt->CKTgmin; + Irci_Vbci = Iohm_Vbci/quot; + Irci_Vbcx = Iohm_Vbcx/quot; + + Qbci = model->BJTepiCharge*Kbci; + Qbci_Vbci = model->BJTepiCharge*Kbci_Vbci; + Qbcx = model->BJTepiCharge*Kbcx; + Qbcx_Vbcx = model->BJTepiCharge*Kbcx_Vbcx; + *(ckt->CKTstate0 + here->BJTqbcx) = Qbcx; + here->BJTcapbcx = Qbcx_Vbcx; + } else { + Irci = vrci/here->BJTtintCollResist + ckt->CKTgmin*vrci; + Irci_Vrci = 1/here->BJTtintCollResist + ckt->CKTgmin; + Irci_Vbci = 0.0; + Irci_Vbcx = 0.0; + + Qbci = 0.0; + Qbci_Vbci = 0.0; + Qbcx = 0.0; + Qbcx_Vbcx = 0.0; + *(ckt->CKTstate0 + here->BJTqbcx) = Qbcx; + here->BJTcapbcx = Qbcx_Vbcx; + } + } /* * determine base charge terms */ @@ -548,7 +663,7 @@ next1: vtn=vt*here->BJTtemissionCoeffF; cdis=model->BJTbaseFractionBCcap; if (model->BJTsubs == VERTICAL) ctot=here->BJTtBCcap*here->BJTareab; - else + else ctot=here->BJTtBCcap*here->BJTareac; czbc=ctot*cdis; czbx=ctot-czbc; @@ -641,6 +756,11 @@ next1: vtn=vt*here->BJTtemissionCoeffF; } here->BJTcapbe = capbe; here->BJTcapbc = capbc; + if (model->BJTintCollResistGiven) { + *(ckt->CKTstate0 + here->BJTqbc) += Qbci; + here->BJTcapbc += Qbci_Vbci; + capbc += Qbci_Vbci; + } here->BJTcapsub = capsub; here->BJTcapbx = capbx; @@ -655,6 +775,7 @@ next1: vtn=vt*here->BJTtemissionCoeffF; *(ckt->CKTstate0 + here->BJTcqsub) = capsub; *(ckt->CKTstate0 + here->BJTcqbx) = capbx; *(ckt->CKTstate0 + here->BJTcexbc) = geqcb; + *(ckt->CKTstate0 + here->BJTcqbcx) = Qbcx_Vbcx; if(SenCond){ *(ckt->CKTstate0 + here->BJTcc) = cc; *(ckt->CKTstate0 + here->BJTcb) = cb; @@ -663,6 +784,9 @@ next1: vtn=vt*here->BJTtemissionCoeffF; *(ckt->CKTstate0 + here->BJTgm) = gm; *(ckt->CKTstate0 + here->BJTgo) = go; *(ckt->CKTstate0 + here->BJTgx) = gx; + *(ckt->CKTstate0 + here->BJTirci_Vrci) = Irci_Vrci; + *(ckt->CKTstate0 + here->BJTirci_Vbci) = Irci_Vbci; + *(ckt->CKTstate0 + here->BJTirci_Vbcx) = Irci_Vbcx; *(ckt->CKTstate0 + here->BJTgcsub) = gcsub; *(ckt->CKTstate0 + here->BJTgeqbx) = geqbx; } @@ -697,6 +821,8 @@ next1: vtn=vt*here->BJTtemissionCoeffF; *(ckt->CKTstate0 + here->BJTqbx) ; *(ckt->CKTstate1 + here->BJTqsub) = *(ckt->CKTstate0 + here->BJTqsub) ; + *(ckt->CKTstate1 + here->BJTqbcx) = + *(ckt->CKTstate0 + here->BJTqbcx) ; } error = NIintegrate(ckt,&geq,&ceq,capbe,here->BJTqbe); if(error) return(error); @@ -708,11 +834,19 @@ next1: vtn=vt*here->BJTtemissionCoeffF; gmu=gmu+geq; cb=cb+*(ckt->CKTstate0 + here->BJTcqbc); cc=cc-*(ckt->CKTstate0 + here->BJTcqbc); + if (model->BJTintCollResistGiven) { + error = NIintegrate(ckt,&geq,&ceq,Qbcx_Vbcx,here->BJTqbcx); + if(error) return(error); + gbcx = geq; + cbcx = *(ckt->CKTstate0 + here->BJTcqbcx); + } if(ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->BJTcqbe) = *(ckt->CKTstate0 + here->BJTcqbe); *(ckt->CKTstate1 + here->BJTcqbc) = *(ckt->CKTstate0 + here->BJTcqbc); + *(ckt->CKTstate1 + here->BJTcqbcx) = + *(ckt->CKTstate0 + here->BJTcqbcx); } } } @@ -747,6 +881,8 @@ next1: vtn=vt*here->BJTtemissionCoeffF; next2: *(ckt->CKTstate0 + here->BJTvbe) = vbe; *(ckt->CKTstate0 + here->BJTvbc) = vbc; + *(ckt->CKTstate0 + here->BJTvbcx) = vbcx; + *(ckt->CKTstate0 + here->BJTvrci) = vrci; *(ckt->CKTstate0 + here->BJTcc) = cc; *(ckt->CKTstate0 + here->BJTcb) = cb; *(ckt->CKTstate0 + here->BJTgpi) = gpi; @@ -760,6 +896,10 @@ next2: *(ckt->CKTstate0 + here->BJTvsub) = vsub; *(ckt->CKTstate0 + here->BJTgdsub) = gdsub; *(ckt->CKTstate0 + here->BJTcdsub) = cdsub; + *(ckt->CKTstate0 + here->BJTirci) = Irci; + *(ckt->CKTstate0 + here->BJTirci_Vrci) = Irci_Vrci; + *(ckt->CKTstate0 + here->BJTirci_Vbci) = Irci_Vbci; + *(ckt->CKTstate0 + here->BJTirci_Vbcx) = Irci_Vbcx; /* Do not load the Jacobian and the rhs if perturbation is being carried out */ @@ -795,14 +935,15 @@ load: *(here->BJTcolColPtr) += m * (gcpr); *(here->BJTbaseBasePtr) += m * (gx+geqbx); *(here->BJTemitEmitPtr) += m * (gepr); - *(here->BJTcolPrimeColPrimePtr) += m * (gmu+go+gcpr+geqbx); + *(here->BJTcolPrimeColPrimePtr) += m * (gmu+go+geqbx); + *(here->BJTcollCXcollCXPtr) += m * (gcpr); *(here->BJTsubstConSubstConPtr) += m * (geqsub); *(here->BJTbasePrimeBasePrimePtr) += m * (gx +gpi+gmu+geqcb); *(here->BJTemitPrimeEmitPrimePtr) += m * (gpi+gepr+gm+go); - *(here->BJTcolColPrimePtr) += m * (-gcpr); + *(here->BJTcollCollCXPtr) += m * (-gcpr); *(here->BJTbaseBasePrimePtr) += m * (-gx); *(here->BJTemitEmitPrimePtr) += m * (-gepr); - *(here->BJTcolPrimeColPtr) += m * (-gcpr); + *(here->BJTcollCXCollPtr) += m * (-gcpr); *(here->BJTcolPrimeBasePrimePtr) += m * (-gmu+gm); *(here->BJTcolPrimeEmitPrimePtr) += m * (-gm-go); *(here->BJTbasePrimeBasePtr) += m * (-gx); @@ -816,6 +957,34 @@ load: *(here->BJTsubstSubstConPtr) += m * (-geqsub); *(here->BJTbaseColPrimePtr) += m * (-geqbx); *(here->BJTcolPrimeBasePtr) += m * (-geqbx); +/* +c Stamp element: Irci +*/ + if (model->BJTintCollResistGiven) { + double rhs_current = model->BJTtype * m * (Irci - Irci_Vrci*vrci - Irci_Vbci*vbc - Irci_Vbcx*vbcx); + *(ckt->CKTrhs + here->BJTcollCXNode) += -rhs_current; + *(here->BJTcollCXcollCXPtr) += m * Irci_Vrci; + *(here->BJTcollCXColPrimePtr) += m * -Irci_Vrci; + *(here->BJTcollCXBasePrimePtr) += m * Irci_Vbci; + *(here->BJTcollCXColPrimePtr) += m * -Irci_Vbci; + *(here->BJTcollCXBasePrimePtr) += m * Irci_Vbcx; + *(here->BJTcollCXcollCXPtr) += m * -Irci_Vbcx; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += rhs_current; + *(here->BJTcolPrimeCollCXPtr) += m * -Irci_Vrci; + *(here->BJTcolPrimeColPrimePtr) += m * Irci_Vrci; + *(here->BJTcolPrimeBasePrimePtr) += m * -Irci_Vbci; + *(here->BJTcolPrimeColPrimePtr) += m * Irci_Vbci; + *(here->BJTcolPrimeBasePrimePtr) += m * -Irci_Vbcx; + *(here->BJTcolPrimeCollCXPtr) += m * Irci_Vbcx; + + *(ckt->CKTrhs + here->BJTbasePrimeNode) += m * -cbcx; + *(ckt->CKTrhs + here->BJTcollCXNode) += m * cbcx; + *(here->BJTbasePrimeBasePrimePtr) += m * gbcx; + *(here->BJTcollCXcollCXPtr) += m * gbcx; + *(here->BJTbasePrimeCollCXPtr) += m * -gbcx; + *(here->BJTcollCXBasePrimePtr) += m * -gbcx; + } + } } return(OK); diff --git a/src/spicelib/devices/bjt/bjtmask.c b/src/spicelib/devices/bjt/bjtmask.c index 87a22d7fa..2034b1826 100644 --- a/src/spicelib/devices/bjt/bjtmask.c +++ b/src/spicelib/devices/bjt/bjtmask.c @@ -201,6 +201,18 @@ BJTmAsk(CKTcircuit *ckt, GENmodel *instPtr, int which, IFvalue *value) case BJT_MOD_NS: value->rValue = here->BJTemissionCoeffS; return(OK); + case BJT_MOD_RCO: + value->rValue = here->BJTintCollResist; + return(OK); + case BJT_MOD_VO: + value->rValue = here->BJTepiSatVoltage; + return(OK); + case BJT_MOD_GAMMA: + value->rValue = here->BJTepiDoping; + return(OK); + case BJT_MOD_QCO: + value->rValue = here->BJTepiCharge; + return(OK); case BJT_MOD_TLEV: value->iValue = here->BJTtlev; return(OK); @@ -378,6 +390,18 @@ BJTmAsk(CKTcircuit *ckt, GENmodel *instPtr, int which, IFvalue *value) case BJT_MOD_TISC2: value->rValue = here->BJTtisc2; return(OK); + case BJT_MOD_QUASIMOD: + value->iValue = here->BJTquasimod; + return(OK); + case BJT_MOD_EGQS: + value->rValue = here->BJTenergyGapQS; + return(OK); + case BJT_MOD_XRCI: + value->rValue = here->BJTtempExpRCI; + return(OK); + case BJT_MOD_XD: + value->rValue = here->BJTtempExpVO; + return(OK); case BJT_MOD_VBE_MAX: value->rValue = here->BJTvbeMax; return(OK); diff --git a/src/spicelib/devices/bjt/bjtmpar.c b/src/spicelib/devices/bjt/bjtmpar.c index d917aabee..51409905b 100644 --- a/src/spicelib/devices/bjt/bjtmpar.c +++ b/src/spicelib/devices/bjt/bjtmpar.c @@ -218,6 +218,22 @@ BJTmParam(int param, IFvalue *value, GENmodel *inModel) mods->BJTemissionCoeffS = value->rValue; mods->BJTemissionCoeffSGiven = TRUE; break; + case BJT_MOD_RCO: + mods->BJTintCollResist = value->rValue; + mods->BJTintCollResistGiven = TRUE; + break; + case BJT_MOD_VO: + mods->BJTepiSatVoltage = value->rValue; + mods->BJTepiSatVoltageGiven = TRUE; + break; + case BJT_MOD_GAMMA: + mods->BJTepiDoping = value->rValue; + mods->BJTepiDopingGiven = TRUE; + break; + case BJT_MOD_QCO: + mods->BJTepiCharge = value->rValue; + mods->BJTepiChargeGiven = TRUE; + break; case BJT_MOD_TLEV: mods->BJTtlev = value->iValue; mods->BJTtlevGiven = TRUE; @@ -454,6 +470,22 @@ BJTmParam(int param, IFvalue *value, GENmodel *inModel) mods->BJTtisc2 = value->rValue; mods->BJTtisc2Given = TRUE; break; + case BJT_MOD_QUASIMOD: + mods->BJTquasimod = value->iValue; + mods->BJTquasimodGiven = TRUE; + break; + case BJT_MOD_EGQS: + mods->BJTenergyGapQS = value->rValue; + mods->BJTenergyGapQSGiven = TRUE; + break; + case BJT_MOD_XRCI: + mods->BJTtempExpRCI = value->rValue; + mods->BJTtempExpRCIGiven = TRUE; + break; + case BJT_MOD_XD: + mods->BJTtempExpVO = value->rValue; + mods->BJTtempExpVOGiven = TRUE; + break; case BJT_MOD_VBE_MAX: mods->BJTvbeMax = value->rValue; mods->BJTvbeMaxGiven = TRUE; diff --git a/src/spicelib/devices/bjt/bjtnoise.c b/src/spicelib/devices/bjt/bjtnoise.c index 8cbf4b48c..13b7fb384 100644 --- a/src/spicelib/devices/bjt/bjtnoise.c +++ b/src/spicelib/devices/bjt/bjtnoise.c @@ -85,7 +85,7 @@ for (model=firstModel; model != NULL; model=BJTnextModel(model)) { case N_DENS: NevalSrc(&noizDens[BJTRCNOIZ],&lnNdens[BJTRCNOIZ], - ckt,THERMNOISE,inst->BJTcolPrimeNode,inst->BJTcolNode, + ckt,THERMNOISE,inst->BJTcollCXNode,inst->BJTcolNode, inst->BJTtcollectorConduct * inst->BJTarea * inst->BJTm); NevalSrc(&noizDens[BJTRBNOIZ],&lnNdens[BJTRBNOIZ], diff --git a/src/spicelib/devices/bjt/bjtpzld.c b/src/spicelib/devices/bjt/bjtpzld.c index eca48c04f..95f62b322 100644 --- a/src/spicelib/devices/bjt/bjtpzld.c +++ b/src/spicelib/devices/bjt/bjtpzld.c @@ -32,6 +32,7 @@ BJTpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) double xcsub; double xcmcb; double m; + double Irci_Vrci, Irci_Vbci, Irci_Vbcx, xcbcx; for( ; model != NULL; model = BJTnextModel(model)) { for( here = BJTinstances(model); here!= NULL; @@ -45,6 +46,9 @@ BJTpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) gmu= *(ckt->CKTstate0 + here->BJTgmu); gm= *(ckt->CKTstate0 + here->BJTgm); go= *(ckt->CKTstate0 + here->BJTgo); + Irci_Vrci = *(ckt->CKTstate0 + here->BJTirci_Vrci); + Irci_Vbci = *(ckt->CKTstate0 + here->BJTirci_Vbci); + Irci_Vbcx = *(ckt->CKTstate0 + here->BJTirci_Vbcx); xgm=0; gx= *(ckt->CKTstate0 + here->BJTgx); xcpi= *(ckt->CKTstate0 + here->BJTcqbe); @@ -52,13 +56,15 @@ BJTpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) xcbx= *(ckt->CKTstate0 + here->BJTcqbx); xcsub= *(ckt->CKTstate0 + here->BJTcqsub); xcmcb= *(ckt->CKTstate0 + here->BJTcexbc); + xcbcx= *(ckt->CKTstate0 + here->BJTcqbcx); *(here->BJTcolColPtr) += m * (gcpr); *(here->BJTbaseBasePtr) += m * ((gx) + (xcbx) * (s->real)); *(here->BJTbaseBasePtr + 1) += m * ((xcbx) * (s->imag)); *(here->BJTemitEmitPtr) += m * (gepr); - *(here->BJTcolPrimeColPrimePtr) += m * ((gmu+go+gcpr) + (xcmu+xcbx) * (s->real)); + *(here->BJTcolPrimeColPrimePtr) += m * ((gmu+go) + (xcmu+xcbx) * (s->real)); *(here->BJTcolPrimeColPrimePtr + 1) += m * ((xcmu+xcbx) * (s->imag)); + *(here->BJTcollCXcollCXPtr) += m * (gcpr); *(here->BJTsubstConSubstConPtr) += m * (xcsub)* (s->real); *(here->BJTsubstConSubstConPtr + 1) += m * (xcsub)* (s->imag); @@ -67,10 +73,10 @@ BJTpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) *(here->BJTbasePrimeBasePrimePtr + 1) += m * ((xcpi+xcmu+xcmcb) * (s->imag)); *(here->BJTemitPrimeEmitPrimePtr) += m * ((gpi+gepr+gm+go) + (xcpi+xgm) * (s->real)); *(here->BJTemitPrimeEmitPrimePtr + 1) += m * ((xcpi+xgm) * (s->imag)); - *(here->BJTcolColPrimePtr) += m * (-gcpr); + *(here->BJTcollCollCXPtr) += m * (-gcpr); *(here->BJTbaseBasePrimePtr) += m * (-gx); *(here->BJTemitEmitPrimePtr) += m * (-gepr); - *(here->BJTcolPrimeColPtr) += m * (-gcpr); + *(here->BJTcollCXCollPtr) += m * (-gcpr); *(here->BJTcolPrimeBasePrimePtr) += m * ((-gmu+gm) + (-xcmu+xgm) * (s->real)); *(here->BJTcolPrimeBasePrimePtr + 1) += m * ((-xcmu+xgm) * (s->imag)); *(here->BJTcolPrimeEmitPrimePtr) += m * ((-gm-go) + (-xgm) * (s->real)); @@ -95,6 +101,28 @@ BJTpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) *(here->BJTbaseColPrimePtr + 1) += m * ((-xcbx) * (s->imag)); *(here->BJTcolPrimeBasePtr) += m * ((-xcbx) * (s->real)); *(here->BJTcolPrimeBasePtr + 1) += m * ((-xcbx) * (s->imag)); + if (model->BJTintCollResistGiven) { + *(here->BJTcollCXcollCXPtr) += m * Irci_Vrci; + *(here->BJTcollCXColPrimePtr) += m * -Irci_Vrci; + *(here->BJTcollCXBasePrimePtr) += m * Irci_Vbci; + *(here->BJTcollCXColPrimePtr) += m * -Irci_Vbci; + *(here->BJTcollCXBasePrimePtr) += m * Irci_Vbcx; + *(here->BJTcollCXcollCXPtr) += m * -Irci_Vbcx; + *(here->BJTcolPrimeCollCXPtr) += m * -Irci_Vrci; + *(here->BJTcolPrimeColPrimePtr) += m * Irci_Vrci; + *(here->BJTcolPrimeBasePrimePtr) += m * -Irci_Vbci; + *(here->BJTcolPrimeColPrimePtr) += m * Irci_Vbci; + *(here->BJTcolPrimeBasePrimePtr) += m * -Irci_Vbcx; + *(here->BJTcolPrimeCollCXPtr) += m * Irci_Vbcx; + *(here->BJTbasePrimeBasePrimePtr) += m * xcbcx * (s->real); + *(here->BJTbasePrimeBasePrimePtr + 1) += m * xcbcx * (s->imag); + *(here->BJTcollCXcollCXPtr) += m * xcbcx * (s->real); + *(here->BJTcollCXcollCXPtr + 1) += m * xcbcx * (s->imag); + *(here->BJTbasePrimeCollCXPtr) += m * -xcbcx * (s->real); + *(here->BJTbasePrimeCollCXPtr + 1) += m * -xcbcx * (s->imag); + *(here->BJTcollCXBasePrimePtr) += m * -xcbcx * (s->real); + *(here->BJTcollCXBasePrimePtr + 1) += m * -xcbcx * (s->imag); + } } } return(OK); diff --git a/src/spicelib/devices/bjt/bjtsetup.c b/src/spicelib/devices/bjt/bjtsetup.c index 961ea5100..5c615dc1e 100644 --- a/src/spicelib/devices/bjt/bjtsetup.c +++ b/src/spicelib/devices/bjt/bjtsetup.c @@ -140,6 +140,19 @@ BJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->BJTemissionCoeffSGiven) { model->BJTemissionCoeffS = 1.0; } + if((!model->BJTintCollResistGiven) + ||(model->BJTintCollResist<0.01)) { + model->BJTintCollResist = 0.01; + } + if(!model->BJTepiSatVoltageGiven) { + model->BJTepiSatVoltage = 10.0; + } + if(!model->BJTepiDopingGiven) { + model->BJTepiDoping = 1.0e-11; + } + if(!model->BJTepiChargeGiven) { + model->BJTepiCharge = 0.0; + } if(!model->BJTtlevGiven) { model->BJTtlev = 0; } @@ -322,6 +335,24 @@ BJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->BJTtisc2Given) { model->BJTtisc2 = 0.0; } + if(!model->BJTquasimodGiven) { + model->BJTquasimod = 0; + } + if(!model->BJTenergyGapQSGiven) { + model->BJTenergyGapQS = 1.206; + } + if(!model->BJTtempExpRCIGiven) { + if (model->BJTtype == NPN) + model->BJTtempExpRCI = 2.42; + else + model->BJTtempExpRCI = 2.2; + } + if(!model->BJTtempExpVOGiven) { + if (model->BJTtype == NPN) + model->BJTtempExpVO = 0.87; + else + model->BJTtempExpVO = 0.52; + } if(!model->BJTvbeMaxGiven) { model->BJTvbeMax = 1e99; } @@ -370,7 +401,15 @@ BJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } if(model->BJTcollectorResist == 0) { - here->BJTcolPrimeNode = here->BJTcolNode; + here->BJTcollCXNode = here->BJTcolNode; + } else if(here->BJTcollCXNode == 0) { + error = CKTmkVolt(ckt, &tmp, here->BJTname, "collCX"); + if(error) return(error); + here->BJTcollCXNode = tmp->number; + } + + if(!model->BJTintCollResistGiven) { + here->BJTcolPrimeNode = here->BJTcollCXNode; } else if(here->BJTcolPrimeNode == 0) { error = CKTmkVolt(ckt,&tmp,here->BJTname,"collector"); if(error) return(error); @@ -432,10 +471,11 @@ BJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ return(E_NOMEM);\ } } while(0) - TSTALLOC(BJTcolColPrimePtr,BJTcolNode,BJTcolPrimeNode); + + TSTALLOC(BJTcollCollCXPtr,BJTcolNode,BJTcollCXNode); TSTALLOC(BJTbaseBasePrimePtr,BJTbaseNode,BJTbasePrimeNode); TSTALLOC(BJTemitEmitPrimePtr,BJTemitNode,BJTemitPrimeNode); - TSTALLOC(BJTcolPrimeColPtr,BJTcolPrimeNode,BJTcolNode); + TSTALLOC(BJTcollCXCollPtr,BJTcollCXNode,BJTcolNode); TSTALLOC(BJTcolPrimeBasePrimePtr,BJTcolPrimeNode,BJTbasePrimeNode); TSTALLOC(BJTcolPrimeEmitPrimePtr,BJTcolPrimeNode,BJTemitPrimeNode); TSTALLOC(BJTbasePrimeBasePtr,BJTbasePrimeNode,BJTbaseNode); @@ -462,6 +502,15 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(BJTsubstSubstConPtr,BJTsubstNode,BJTsubstConNode); TSTALLOC(BJTbaseColPrimePtr,BJTbaseNode,BJTcolPrimeNode); TSTALLOC(BJTcolPrimeBasePtr,BJTcolPrimeNode,BJTbaseNode); + + TSTALLOC(BJTcollCXcollCXPtr,BJTcollCXNode,BJTcollCXNode); + + if(model->BJTintCollResistGiven) { + TSTALLOC(BJTcollCXBasePrimePtr,BJTcollCXNode,BJTbasePrimeNode); + TSTALLOC(BJTbasePrimeCollCXPtr,BJTbasePrimeNode,BJTcollCXNode); + TSTALLOC(BJTcolPrimeCollCXPtr,BJTcolPrimeNode,BJTcollCXNode); + TSTALLOC(BJTcollCXColPrimePtr,BJTcollCXNode,BJTcolPrimeNode); + } } } return(OK); @@ -481,20 +530,25 @@ BJTunsetup( for (here = BJTinstances(model); here != NULL; here=BJTnextInstance(here)) { - if (here->BJTemitPrimeNode > 0 - && here->BJTemitPrimeNode != here->BJTemitNode) - CKTdltNNum(ckt, here->BJTemitPrimeNode); - here->BJTemitPrimeNode = 0; + if (here->BJTemitPrimeNode > 0 + && here->BJTemitPrimeNode != here->BJTemitNode) + CKTdltNNum(ckt, here->BJTemitPrimeNode); + here->BJTemitPrimeNode = 0; - if (here->BJTbasePrimeNode > 0 - && here->BJTbasePrimeNode != here->BJTbaseNode) - CKTdltNNum(ckt, here->BJTbasePrimeNode); - here->BJTbasePrimeNode = 0; + if (here->BJTbasePrimeNode > 0 + && here->BJTbasePrimeNode != here->BJTbaseNode) + CKTdltNNum(ckt, here->BJTbasePrimeNode); + here->BJTbasePrimeNode = 0; - if (here->BJTcolPrimeNode > 0 - && here->BJTcolPrimeNode != here->BJTcolNode) + if (here->BJTcollCXNode > 0 + && here->BJTcollCXNode != here->BJTcolNode) + CKTdltNNum(ckt, here->BJTcollCXNode); + here->BJTcollCXNode = 0; + + if (here->BJTcolPrimeNode > 0 + && here->BJTcolPrimeNode != here->BJTcollCXNode) CKTdltNNum(ckt, here->BJTcolPrimeNode); - here->BJTcolPrimeNode = 0; + here->BJTcolPrimeNode = 0; } } return OK; diff --git a/src/spicelib/devices/bjt/bjttemp.c b/src/spicelib/devices/bjt/bjttemp.c index 8456eb42f..eb80b50b5 100644 --- a/src/spicelib/devices/bjt/bjttemp.c +++ b/src/spicelib/devices/bjt/bjttemp.c @@ -177,6 +177,22 @@ BJTtemp(GENmodel *inModel, CKTcircuit *ckt) here->BJTtSatCur = pow(model->BJTsatCur,(1+model->BJTtis1*dt+model->BJTtis2*dt*dt)); } + if (model->BJTintCollResistGiven) { + if (model->BJTquasimod == 1) { + double rT=here->BJTtemp/model->BJTtnom; + here->BJTtintCollResist=model->BJTintCollResist*pow(rT,model->BJTtempExpRCI); + here->BJTtepiSatVoltage=model->BJTepiSatVoltage*pow(rT,model->BJTtempExpVO); + double xvar1=pow(rT,model->BJTtempExpIS); + double xvar2=-model->BJTenergyGapQS*(1.0-rT)/vt; + double xvar3=exp(xvar2); + here->BJTtepiDoping=model->BJTepiDoping*xvar1*xvar3; + } else { + here->BJTtintCollResist=model->BJTintCollResist; + here->BJTtepiSatVoltage=model->BJTepiSatVoltage; + here->BJTtepiDoping=model->BJTepiDoping; + } + } + if (model->BJTtlev == 0) { bfactor = exp(ratlog*model->BJTbetaExp); } else if (model->BJTtlev == 1) { diff --git a/src/spicelib/devices/bjt/bjttrunc.c b/src/spicelib/devices/bjt/bjttrunc.c index abee58deb..86e197dcd 100644 --- a/src/spicelib/devices/bjt/bjttrunc.c +++ b/src/spicelib/devices/bjt/bjttrunc.c @@ -30,6 +30,9 @@ BJTtrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep) CKTterr(here->BJTqbe,ckt,timeStep); CKTterr(here->BJTqbc,ckt,timeStep); CKTterr(here->BJTqsub,ckt,timeStep); + if (model->BJTintCollResistGiven) { + CKTterr(here->BJTqbcx,ckt,timeStep); + } } } return(OK); diff --git a/src/spicelib/devices/devsup.c b/src/spicelib/devices/devsup.c index 691009c95..5bc3c684a 100644 --- a/src/spicelib/devices/devsup.c +++ b/src/spicelib/devices/devsup.c @@ -150,6 +150,36 @@ DEVfetlim(double vnew, double vold, double vto) return(vnew); } +/* DEVlimitlog(deltemp, deltemp_old, LIM_TOL, check) + * Logarithmic damping the per-iteration change of deltemp beyond LIM_TOL. + */ +double +DEVlimitlog( + 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 ACM_SourceDrainResistances( int ACM, diff --git a/src/spicelib/devices/vbic/vbicacld.c b/src/spicelib/devices/vbic/vbicacld.c index e896777e0..0844fccd0 100644 --- a/src/spicelib/devices/vbic/vbicacld.c +++ b/src/spicelib/devices/vbic/vbicacld.c @@ -97,14 +97,14 @@ c Stamp element: Itzf /* c Stamp element: Itzr */ - *(here->VBICemitEIBaseBIPtr) += Itzr_Vbci; - *(here->VBICemitEICollCIPtr) += -Itzr_Vbci; *(here->VBICemitEIBaseBIPtr) += Itzr_Vbei; *(here->VBICemitEIEmitEIPtr) += -Itzr_Vbei; - *(here->VBICcollCIBaseBIPtr) += -Itzr_Vbci; - *(here->VBICcollCICollCIPtr) += Itzr_Vbci; + *(here->VBICemitEIBaseBIPtr) += Itzr_Vbci; + *(here->VBICemitEICollCIPtr) += -Itzr_Vbci; *(here->VBICcollCIBaseBIPtr) += -Itzr_Vbei; *(here->VBICcollCIEmitEIPtr) += Itzr_Vbei; + *(here->VBICcollCIBaseBIPtr) += -Itzr_Vbci; + *(here->VBICcollCICollCIPtr) += Itzr_Vbci; /* c Stamp element: Ibc */ @@ -124,12 +124,12 @@ c Stamp element: Ibep *(here->VBICbaseBPBaseBXPtr) += -Ibep_Vbep; *(here->VBICbaseBPBaseBPPtr) += Ibep_Vbep; /* -c Stamp element: Ircx +c Stamp element: Rcx */ - *(here->VBICcollCollPtr) += Ircx_Vrcx; + *(here->VBICcollCollPtr) += Ircx_Vrcx; *(here->VBICcollCXCollCXPtr) += Ircx_Vrcx; - *(here->VBICcollCXCollPtr) += -Ircx_Vrcx; - *(here->VBICcollCollCXPtr) += -Ircx_Vrcx; + *(here->VBICcollCXCollPtr) += -Ircx_Vrcx; + *(here->VBICcollCollCXPtr) += -Ircx_Vrcx; /* c Stamp element: Irci */ @@ -146,12 +146,12 @@ c Stamp element: Irci *(here->VBICcollCIBaseBIPtr) += -Irci_Vbcx; *(here->VBICcollCICollCXPtr) += Irci_Vbcx; /* -c Stamp element: Irbx +c Stamp element: Rbx */ - *(here->VBICbaseBasePtr) += Irbx_Vrbx; + *(here->VBICbaseBasePtr) += Irbx_Vrbx; *(here->VBICbaseBXBaseBXPtr) += Irbx_Vrbx; - *(here->VBICbaseBXBasePtr) += -Irbx_Vrbx; - *(here->VBICbaseBaseBXPtr) += -Irbx_Vrbx; + *(here->VBICbaseBXBasePtr) += -Irbx_Vrbx; + *(here->VBICbaseBaseBXPtr) += -Irbx_Vrbx; /* c Stamp element: Irbi */ @@ -168,12 +168,12 @@ c Stamp element: Irbi *(here->VBICbaseBIBaseBIPtr) += -Irbi_Vbci; *(here->VBICbaseBICollCIPtr) += Irbi_Vbci; /* -c Stamp element: Ire +c Stamp element: Re */ - *(here->VBICemitEmitPtr) += Ire_Vre; + *(here->VBICemitEmitPtr) += Ire_Vre; *(here->VBICemitEIEmitEIPtr) += Ire_Vre; - *(here->VBICemitEIEmitPtr) += -Ire_Vre; - *(here->VBICemitEmitEIPtr) += -Ire_Vre; + *(here->VBICemitEIEmitPtr) += -Ire_Vre; + *(here->VBICemitEmitEIPtr) += -Ire_Vre; /* c Stamp element: Irbp */ @@ -212,12 +212,12 @@ c Stamp element: Iccp *(here->VBICsubsSISubsSIPtr) += -Iccp_Vbcp; *(here->VBICsubsSIBaseBPPtr) += Iccp_Vbcp; /* -c Stamp element: Irs +c Stamp element: Rs */ - *(here->VBICsubsSubsPtr) += Irs_Vrs; + *(here->VBICsubsSubsPtr) += Irs_Vrs; *(here->VBICsubsSISubsSIPtr) += Irs_Vrs; - *(here->VBICsubsSISubsPtr) += -Irs_Vrs; - *(here->VBICsubsSubsSIPtr) += -Irs_Vrs; + *(here->VBICsubsSISubsPtr) += -Irs_Vrs; + *(here->VBICsubsSubsSIPtr) += -Irs_Vrs; /* c The complex part */ @@ -230,50 +230,50 @@ c The complex part XQbep_Vbci = *(ckt->CKTstate0 + here->VBICcqbepci) * ckt->CKTomega; XQbcp_Vbcp = *(ckt->CKTstate0 + here->VBICcqbcp) * ckt->CKTomega; /* -c Stamp element: Qbe +c Stamp element: Qbe */ - *(here->VBICbaseBIBaseBIPtr + 1) += XQbe_Vbei; - *(here->VBICbaseBIEmitEIPtr + 1) += -XQbe_Vbei; - *(here->VBICbaseBIBaseBIPtr + 1) += XQbe_Vbci; - *(here->VBICbaseBICollCIPtr + 1) += -XQbe_Vbci; - *(here->VBICemitEIBaseBIPtr + 1) += -XQbe_Vbei; - *(here->VBICemitEIEmitEIPtr + 1) += XQbe_Vbei; - *(here->VBICemitEIBaseBIPtr + 1) += -XQbe_Vbci; - *(here->VBICemitEICollCIPtr + 1) += XQbe_Vbci; + *(here->VBICbaseBIBaseBIPtr + 1) += XQbe_Vbei; + *(here->VBICbaseBIEmitEIPtr + 1) += -XQbe_Vbei; + *(here->VBICbaseBIBaseBIPtr + 1) += XQbe_Vbci; + *(here->VBICbaseBICollCIPtr + 1) += -XQbe_Vbci; + *(here->VBICemitEIBaseBIPtr + 1) += -XQbe_Vbei; + *(here->VBICemitEIEmitEIPtr + 1) += XQbe_Vbei; + *(here->VBICemitEIBaseBIPtr + 1) += -XQbe_Vbci; + *(here->VBICemitEICollCIPtr + 1) += XQbe_Vbci; /* -c Stamp element: Qbex +c Stamp element: Qbex */ - *(here->VBICbaseBXBaseBXPtr + 1) += XQbex_Vbex; - *(here->VBICbaseBXEmitEIPtr + 1) += -XQbex_Vbex; - *(here->VBICemitEIBaseBXPtr + 1) += -XQbex_Vbex; - *(here->VBICemitEIEmitEIPtr + 1) += XQbex_Vbex; + *(here->VBICbaseBXBaseBXPtr + 1) += XQbex_Vbex; + *(here->VBICbaseBXEmitEIPtr + 1) += -XQbex_Vbex; + *(here->VBICemitEIBaseBXPtr + 1) += -XQbex_Vbex; + *(here->VBICemitEIEmitEIPtr + 1) += XQbex_Vbex; /* -c Stamp element: Qbc +c Stamp element: Qbc */ - *(here->VBICbaseBIBaseBIPtr + 1) += XQbc_Vbci; - *(here->VBICbaseBICollCIPtr + 1) += -XQbc_Vbci; - *(here->VBICcollCIBaseBIPtr + 1) += -XQbc_Vbci; - *(here->VBICcollCICollCIPtr + 1) += XQbc_Vbci; + *(here->VBICbaseBIBaseBIPtr + 1) += XQbc_Vbci; + *(here->VBICbaseBICollCIPtr + 1) += -XQbc_Vbci; + *(here->VBICcollCIBaseBIPtr + 1) += -XQbc_Vbci; + *(here->VBICcollCICollCIPtr + 1) += XQbc_Vbci; /* -c Stamp element: Qbcx +c Stamp element: Qbcx */ - *(here->VBICbaseBIBaseBIPtr + 1) += XQbcx_Vbcx; - *(here->VBICbaseBICollCXPtr + 1) += -XQbcx_Vbcx; - *(here->VBICcollCXBaseBIPtr + 1) += -XQbcx_Vbcx; - *(here->VBICcollCXCollCXPtr + 1) += XQbcx_Vbcx; + *(here->VBICbaseBIBaseBIPtr + 1) += XQbcx_Vbcx; + *(here->VBICbaseBICollCXPtr + 1) += -XQbcx_Vbcx; + *(here->VBICcollCXBaseBIPtr + 1) += -XQbcx_Vbcx; + *(here->VBICcollCXCollCXPtr + 1) += XQbcx_Vbcx; /* -c Stamp element: Qbep +c Stamp element: Qbep */ - *(here->VBICbaseBXBaseBXPtr + 1) += XQbep_Vbep; - *(here->VBICbaseBXBaseBPPtr + 1) += -XQbep_Vbep; - *(here->VBICbaseBXBaseBIPtr + 1) += XQbep_Vbci; - *(here->VBICbaseBXCollCIPtr + 1) += -XQbep_Vbci; - *(here->VBICbaseBPBaseBXPtr + 1) += -XQbep_Vbep; - *(here->VBICbaseBPBaseBPPtr + 1) += XQbep_Vbep; - *(here->VBICbaseBPBaseBIPtr + 1) += -XQbep_Vbci; - *(here->VBICbaseBPCollCIPtr + 1) += XQbep_Vbci; + *(here->VBICbaseBXBaseBXPtr + 1) += XQbep_Vbep; + *(here->VBICbaseBXBaseBPPtr + 1) += -XQbep_Vbep; + *(here->VBICbaseBXBaseBIPtr + 1) += XQbep_Vbci; + *(here->VBICbaseBXCollCIPtr + 1) += -XQbep_Vbci; + *(here->VBICbaseBPBaseBXPtr + 1) += -XQbep_Vbep; + *(here->VBICbaseBPBaseBPPtr + 1) += XQbep_Vbep; + *(here->VBICbaseBPBaseBIPtr + 1) += -XQbep_Vbci; + *(here->VBICbaseBPCollCIPtr + 1) += XQbep_Vbci; /* -c Stamp element: Qbcp +c Stamp element: Qbcp */ *(here->VBICsubsSISubsSIPtr + 1) += XQbcp_Vbcp; *(here->VBICsubsSIBaseBPPtr + 1) += -XQbcp_Vbcp; diff --git a/src/spicelib/devices/vbic/vbicdefs.h b/src/spicelib/devices/vbic/vbicdefs.h index 3b8bf3587..1ed3f31f1 100644 --- a/src/spicelib/devices/vbic/vbicdefs.h +++ b/src/spicelib/devices/vbic/vbicdefs.h @@ -220,13 +220,17 @@ typedef struct sVBICinstance { double *VBICbaseBPtempPtr; double *VBICemitEItempPtr; double *VBICsubsSItempPtr; + double *VBICtempCollPtr; double *VBICtempCollCIPtr; double *VBICtempCollCXPtr; + double *VBICtempBasePtr; double *VBICtempBaseBIPtr; double *VBICtempBaseBXPtr; double *VBICtempBaseBPPtr; + double *VBICtempEmitPtr; double *VBICtempEmitEIPtr; double *VBICtempSubsPtr; + double *VBICtempSubsSIPtr; double *VBICtempTempPtr; unsigned VBICareaGiven :1; /* flag to indicate area was specified */ diff --git a/src/spicelib/devices/vbic/vbicload.c b/src/spicelib/devices/vbic/vbicload.c index bf6757caf..4e4ff407e 100644 --- a/src/spicelib/devices/vbic/vbicload.c +++ b/src/spicelib/devices/vbic/vbicload.c @@ -38,36 +38,6 @@ int vbic_4T_et_cf_fj(double *, double *,double *,double *,double *,double *,double *, double *, double *,double *); -/* VBIClimitlog(deltemp, deltemp_old, LIM_TOL, check) - * Logarithmic damping the per-iteration change of deltemp beyond LIM_TOL. - */ -static double -VBIClimitlog( - 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 VBICload(GENmodel *inModel, CKTcircuit *ckt) /* actually load the current resistance value into the @@ -720,7 +690,7 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) here->VBICtVcrit,&ichk5); if (here->VBIC_selfheat) { ichk6 = 1; - Vrth = VBIClimitlog(Vrth, + Vrth = DEVlimitlog(Vrth, *(ckt->CKTstate0 + here->VBICvrth),100,&ichk6); } if ((ichk1 == 1) || (ichk2 == 1) || (ichk3 == 1) || (ichk4 == 1) || (ichk5 == 1) || (ichk6 == 1)) icheck=1; @@ -1240,7 +1210,11 @@ c Stamp element: Ibep /* c Stamp element: Rcx */ - *(here->VBICcollTempPtr) += Ircx_Vrth; + rhs_current = -Ircx_Vrth * Vrth; + *(ckt->CKTrhs + here->VBICcollNode) += -rhs_current; + *(here->VBICcollTempPtr) += Ircx_Vrth; + *(ckt->CKTrhs + here->VBICcollCXNode) += rhs_current; + *(here->VBICcollCXtempPtr) += -Ircx_Vrth; /* c Stamp element: Irci */ @@ -1252,7 +1226,11 @@ c Stamp element: Irci /* c Stamp element: Rbx */ - *(here->VBICbaseTempPtr) += Irbx_Vrth; + rhs_current = -Irbx_Vrth * Vrth; + *(ckt->CKTrhs + here->VBICbaseNode) += -rhs_current; + *(here->VBICbaseTempPtr) += Irbx_Vrth; + *(ckt->CKTrhs + here->VBICbaseBXNode) += rhs_current; + *(here->VBICbaseBXtempPtr) += -Irbx_Vrth; /* c Stamp element: Irbi */ @@ -1264,7 +1242,11 @@ c Stamp element: Irbi /* c Stamp element: Re */ - *(here->VBICemitTempPtr) += Ire_Vrth; + rhs_current = -Ire_Vrth * Vrth; + *(ckt->CKTrhs + here->VBICemitNode) += -rhs_current; + *(here->VBICemitTempPtr) += Ire_Vrth; + *(ckt->CKTrhs + here->VBICemitEINode) += rhs_current; + *(here->VBICemitEItempPtr) += -Ire_Vrth; /* c Stamp element: Irbp */ @@ -1292,7 +1274,11 @@ c Stamp element: Iccp /* c Stamp element: Rs */ - *(here->VBICsubsTempPtr) += Irs_Vrth; + rhs_current = -Irs_Vrth * Vrth; + *(ckt->CKTrhs + here->VBICsubsNode) += -rhs_current; + *(here->VBICsubsTempPtr) += Irs_Vrth; + *(ckt->CKTrhs + here->VBICsubsSINode) += rhs_current; + *(here->VBICsubsSItempPtr) += -Irs_Vrth; /* c Stamp element: Rth */ @@ -1302,16 +1288,16 @@ c Stamp element: Cth */ *(here->VBICtempTempPtr) += Icth_Vrth; /* -c Stamp element: Ith +c Stamp element: Ith (all values are delivered with (-) sign) */ - rhs_current = - Ith + Ith_Vrth*Vrth + Icth - Icth_Vrth*Vrth - + Ith_Vbei*Vbei + Ith_Vbci*Vbci + Ith_Vcei*Vcei - + Ith_Vbex*Vbex + Ith_Vbep*Vbep + Ith_Vbcp*Vbcp - + Ith_Vcep*Vcep + Ith_Vrci*Vrci + Ith_Vbcx*Vbcx - + Ith_Vrbi*Vrbi + Ith_Vrbp*Vrbp - + Ith_Vrcx*Vrcx + Ith_Vrbx*Vrbx + Ith_Vre*Vre + Ith_Vrs*Vrs; + rhs_current = -Ith - Ith_Vrth*Vrth + Icth - Icth_Vrth*Vrth + - Ith_Vbei*Vbei - Ith_Vbci*Vbci - Ith_Vcei*Vcei + - Ith_Vbex*Vbex - Ith_Vbep*Vbep - Ith_Vbcp*Vbcp + - Ith_Vcep*Vcep - Ith_Vrci*Vrci - Ith_Vbcx*Vbcx + - Ith_Vrbi*Vrbi - Ith_Vrbp*Vrbp + - Ith_Vrcx*Vrcx - Ith_Vrbx*Vrbx - Ith_Vre*Vre - Ith_Vrs*Vrs; - *(ckt->CKTrhs + here->VBICtempNode) -= rhs_current; + *(ckt->CKTrhs + here->VBICtempNode) += rhs_current; *(here->VBICtempTempPtr) += -Ith_Vrth; @@ -1337,11 +1323,14 @@ c Stamp element: Ith *(here->VBICtempBaseBIPtr) += +Ith_Vrbi; *(here->VBICtempBaseBPPtr) += -Ith_Vrbp; *(here->VBICtempCollCXPtr) += +Ith_Vrbp; - + *(here->VBICtempCollPtr) += -Ith_Vrcx; *(here->VBICtempCollCXPtr) += +Ith_Vrcx; + *(here->VBICtempBasePtr) += -Ith_Vrbx; *(here->VBICtempBaseBXPtr) += +Ith_Vrbx; + *(here->VBICtempEmitPtr) += -Ith_Vre; *(here->VBICtempEmitEIPtr) += +Ith_Vre; - *(here->VBICtempSubsPtr) += +Ith_Vrs; + *(here->VBICtempSubsPtr) += -Ith_Vrs; + *(here->VBICtempSubsSIPtr) += +Ith_Vrs; } } diff --git a/src/spicelib/devices/vbic/vbicsetup.c b/src/spicelib/devices/vbic/vbicsetup.c index 1a97c2d54..ef6b238ea 100644 --- a/src/spicelib/devices/vbic/vbicsetup.c +++ b/src/spicelib/devices/vbic/vbicsetup.c @@ -570,13 +570,17 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(VBICbaseBPtempPtr,VBICbaseBPNode,VBICtempNode); TSTALLOC(VBICemitEItempPtr,VBICemitEINode,VBICtempNode); TSTALLOC(VBICsubsSItempPtr,VBICsubsSINode,VBICtempNode); + TSTALLOC(VBICtempCollPtr,VBICtempNode,VBICcollNode); TSTALLOC(VBICtempCollCIPtr,VBICtempNode,VBICcollCINode); TSTALLOC(VBICtempCollCXPtr,VBICtempNode,VBICcollCXNode); TSTALLOC(VBICtempBaseBIPtr,VBICtempNode,VBICbaseBINode); + TSTALLOC(VBICtempBasePtr,VBICtempNode,VBICbaseNode); TSTALLOC(VBICtempBaseBXPtr,VBICtempNode,VBICbaseBXNode); TSTALLOC(VBICtempBaseBPPtr,VBICtempNode,VBICbaseBPNode); + TSTALLOC(VBICtempEmitPtr,VBICtempNode,VBICemitNode); TSTALLOC(VBICtempEmitEIPtr,VBICtempNode,VBICemitEINode); TSTALLOC(VBICtempSubsPtr,VBICtempNode,VBICsubsNode); + TSTALLOC(VBICtempSubsSIPtr,VBICtempNode,VBICsubsSINode); TSTALLOC(VBICtempTempPtr,VBICtempNode,VBICtempNode); } diff --git a/src/spicelib/devices/vdmos/vdmos.c b/src/spicelib/devices/vdmos/vdmos.c index e76c0940b..79d4d9072 100644 --- a/src/spicelib/devices/vdmos/vdmos.c +++ b/src/spicelib/devices/vdmos/vdmos.c @@ -94,8 +94,8 @@ IFparm VDMOSmPTable[] = { /* model parameters */ IOP( "trg2", VDMOS_MOD_TRG2, IF_REAL, "Gate resistance quadratic temperature coefficient"), IOP( "trs1", VDMOS_MOD_TRS1, IF_REAL, "Source resistance linear temperature coefficient"), IOP( "trs2", VDMOS_MOD_TRS2, IF_REAL, "Source resistance quadratic temperature coefficient"), - IOP( "trb1", VDMOS_MOD_TRB1, IF_REAL, "Body resistance linear temperature coefficient"), - IOP( "trb2", VDMOS_MOD_TRB2, IF_REAL, "Body resistance quadratic temperature coefficient"), + IOP( "trb1", VDIO_MOD_TRB1, IF_REAL, "Body resistance linear temperature coefficient"), + IOP( "trb2", VDIO_MOD_TRB2, IF_REAL, "Body resistance quadratic temperature coefficient"), /* weak inversion */ IOP("subshift", VDMOS_MOD_SUBSHIFT, IF_REAL, "Shift of weak inversion plot on the vgs axis"), @@ -104,22 +104,22 @@ IFparm VDMOSmPTable[] = { /* model parameters */ IOP("tksubthres2", VDMOS_MOD_TKSUBTHRES2, IF_REAL, "Quadratic temperature coefficient of ksubthres"), /* body diode */ - IOP("bv", VDMOS_MOD_BV, IF_REAL, "Vds breakdown voltage"), - IOP("ibv", VDMOS_MOD_IBV, IF_REAL, "Current at Vds=bv"), - IOP("nbv", VDMOS_MOD_NBV, IF_REAL, "Vds breakdown emission coefficient"), + IOP("bv", VDIO_MOD_BV, IF_REAL, "Vds breakdown voltage"), + IOP("ibv", VDIO_MOD_IBV, IF_REAL, "Current at Vds=bv"), + IOP("nbv", VDIO_MOD_NBV, IF_REAL, "Vds breakdown emission coefficient"), IOP("rds", VDMOS_MOD_RDS, IF_REAL, "Drain-source shunt resistance"), - IOP("rb", VDMOS_MOD_RB, IF_REAL, "Body diode ohmic resistance"), - 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("is", VDMOS_MOD_IS, IF_REAL, "Body diode saturation current"), - IOP("vj", VDMOS_MOD_VJ, IF_REAL, "Body diode junction potential"), + IOP("rb", VDIO_MOD_RB, IF_REAL, "Body diode ohmic resistance"), + IOP("n", VDIO_MOD_N, IF_REAL, "Body diode emission coefficient"), + IOP("tt", VDIO_MOD_TT, IF_REAL, "Body diode transit time"), + IOP("eg", VDIO_MOD_EG, IF_REAL, "Body diode activation energy for temperature effect on Is"), + IOP("xti", VDIO_MOD_XTI, IF_REAL, "Body diode saturation current temperature exponent"), + IOP("is", VDIO_MOD_IS, IF_REAL, "Body diode saturation current"), + IOP("vj", VDIO_MOD_VJ, IF_REAL, "Body diode junction potential"), /* body diode capacitance (e.g. source-drain capacitance) */ - IOP("fc", VDMOS_MOD_FC, IF_REAL, "Body diode coefficient for forward-bias depletion capacitance formula"), - IOPA("cjo", VDMOS_MOD_CJ, IF_REAL, "Zero-bias body diode junction capacitance"), - IOP("m", VDMOS_MOD_MJ, IF_REAL, "Body diode grading coefficient"), + IOP("fc", VDIO_MOD_FC, IF_REAL, "Body diode coefficient for forward-bias depletion capacitance formula"), + IOPA("cjo", VDIO_MOD_CJ, IF_REAL, "Zero-bias body diode junction capacitance"), + IOP("m", VDIO_MOD_MJ, IF_REAL, "Body diode grading coefficient"), /* gate-source and gate-drain capacitances */ IOPA("cgdmin", VDMOS_MOD_CGDMIN, IF_REAL, "Minimum non-linear G-D capacitance"), diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h index 5b33e7918..7946d187a 100644 --- a/src/spicelib/devices/vdmos/vdmosdefs.h +++ b/src/spicelib/devices/vdmos/vdmosdefs.h @@ -78,11 +78,13 @@ typedef struct sVDMOSinstance { double VDMOSgds; double VDIOcap; - double VDIOtSatCur; /* temperature corrected saturation Cur. density*/ + double VDIOtSatCur; /* temperature corrected saturation Cur. density */ + double VDIOtSatCur_dT; double VDIOinitCond; double VDIOtVcrit; double VDIOconductance; double VDIOtConductance; + double VDIOtConductance_dT; double VDIOtBrkdwnV; double VDIOtJctCap; double VDIOtDepCap; /* temperature adjusted transition point in */ @@ -105,7 +107,6 @@ typedef struct sVDMOSinstance { double VDMOScdT; double VDMOScth; /* current alias power */ -// double VDIOdIth_dVdio; /* * naming convention: * x = vgs @@ -230,9 +231,11 @@ typedef struct sVDMOSinstance { double *VDMOSSPtempPtr; double *VDIOTempposPrimePtr; /* Diode thermal contribution */ - double *VDIOTempnegPtr; + double *VDMOSTempdPtr; double *VDIOPosPrimetempPtr; - double *VDIONegtempPtr; + double *VDMOSDtempPtr; + double *VDMOStempSPtr; + double *VDMOSSTempPtr; double *VDMOSTcasetcasePtr; /* for Rthjc */ double *VDMOSTcasetempPtr; @@ -315,26 +318,28 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ double VDMOSsubshift; double VDMOSksubthres; double VDMOSmtr; + double VDMOSrds; /* body diode */ double VDIOjunctionCap; /* input - use tCj */ double VDIOjunctionPot; /* input - use tJctPot */ double VDIOdepletionCapCoeff; double VDIOjctSatCur; /* input - use tSatCur */ - double VDMOSbv; - double VDMOSibv; + double VDIObv; + double VDIOibv; double VDIObrkdEmissionCoeff; double VDIOresistance; - double VDMOSrds; - double VDMOSn; + double VDIOn; double VDIOtransitTime; double VDIOtranTimeTemp1; double VDIOtranTimeTemp2; - double VDMOSeg; - double VDMOSxti; + double VDIOeg; + double VDIOxti; double VDIOgradCoeff; double VDIOgradCoeffTemp1; double VDIOgradCoeffTemp2; + double VDIOtrb1; + double VDIOtrb2; double VDMOStcvth; double VDMOSrthjc; @@ -349,8 +354,6 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ double VDMOStrg2; double VDMOStrs1; double VDMOStrs2; - double VDMOStrb1; - double VDMOStrb2; double VDMOStksubthres1; double VDMOStksubthres2; @@ -361,7 +364,6 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ double VDMOSvgdrMax; unsigned VDMOStypeGiven :1; - unsigned VDIOjctSatCurGiven :1; unsigned VDMOSdrainResistanceGiven :1; unsigned VDMOSsourceResistanceGiven :1; unsigned VDMOSgateResistanceGiven :1; @@ -370,8 +372,6 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ unsigned VDMOSqsGiven :1; unsigned VDMOStransconductanceGiven :1; unsigned VDMOSvth0Given :1; - unsigned VDIOgradCoeffGiven :1; - unsigned VDIOdepletionCapCoeffGiven :1; unsigned VDMOSphiGiven :1; unsigned VDMOSlambdaGiven :1; unsigned VDMOSthetaGiven :1; @@ -386,18 +386,23 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ unsigned VDMOSsubshiftGiven :1; unsigned VDMOSksubthresGiven :1; unsigned VDMOSmtrGiven :1; + unsigned VDMOSrdsGiven :1; - unsigned VDMOSbvGiven :1; - unsigned VDMOSibvGiven :1; + unsigned VDIOjctSatCurGiven :1; + unsigned VDIOgradCoeffGiven :1; + unsigned VDIOdepletionCapCoeffGiven :1; + unsigned VDIObvGiven :1; + unsigned VDIOibvGiven :1; unsigned VDIOjunctionCapGiven :1; unsigned VDIOjunctionPotGiven :1; unsigned VDIObrkdEmissionCoeffGiven :1; unsigned VDIOresistanceGiven :1; - unsigned VDMOSrdsGiven :1; - unsigned VDMOSnGiven :1; + unsigned VDIOnGiven :1; unsigned VDIOtransitTimeGiven :1; - unsigned VDMOSegGiven :1; - unsigned VDMOSxtiGiven :1; + unsigned VDIOegGiven :1; + unsigned VDIOxtiGiven :1; + unsigned VDIOtrb1Given :1; + unsigned VDIOtrb2Given :1; unsigned VDMOStcvthGiven :1; unsigned VDMOSrthjcGiven :1; @@ -412,8 +417,6 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ unsigned VDMOStrg2Given :1; unsigned VDMOStrs1Given :1; unsigned VDMOStrs2Given :1; - unsigned VDMOStrb1Given :1; - unsigned VDMOStrb2Given :1; unsigned VDMOStksubthres1Given :1; unsigned VDMOStksubthres2Given :1; @@ -456,11 +459,6 @@ enum { VDMOS_MOD_RG, VDMOS_MOD_RQ, VDMOS_MOD_VQ, - VDMOS_MOD_IS, - VDMOS_MOD_VJ, - VDMOS_MOD_CJ, - VDMOS_MOD_MJ, - VDMOS_MOD_FC, VDMOS_MOD_NMOS, VDMOS_MOD_PMOS, VDMOS_MOD_TNOM, @@ -472,18 +470,25 @@ enum { VDMOS_MOD_CGDMAX, VDMOS_MOD_A, VDMOS_MOD_CGS, - VDMOS_MOD_RB, VDMOS_MOD_MTRIODE, VDMOS_MOD_SUBSHIFT, VDMOS_MOD_KSUBTHRES, - VDMOS_MOD_BV, - VDMOS_MOD_IBV, - VDMOS_MOD_NBV, VDMOS_MOD_RDS, - VDMOS_MOD_N, - VDMOS_MOD_TT, - VDMOS_MOD_EG, - VDMOS_MOD_XTI, + VDIO_MOD_IS, + VDIO_MOD_VJ, + VDIO_MOD_CJ, + VDIO_MOD_MJ, + VDIO_MOD_FC, + VDIO_MOD_RB, + VDIO_MOD_BV, + VDIO_MOD_IBV, + VDIO_MOD_NBV, + VDIO_MOD_N, + VDIO_MOD_TT, + VDIO_MOD_EG, + VDIO_MOD_XTI, + VDIO_MOD_TRB1, + VDIO_MOD_TRB2, VDMOS_MOD_TCVTH, VDMOS_MOD_RTHJC, VDMOS_MOD_RTHCA, @@ -497,8 +502,6 @@ enum { VDMOS_MOD_TRG2, VDMOS_MOD_TRS1, VDMOS_MOD_TRS2, - VDMOS_MOD_TRB1, - VDMOS_MOD_TRB2, VDMOS_MOD_TKSUBTHRES1, VDMOS_MOD_TKSUBTHRES2, VDMOS_MOD_VGS_MAX, diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index 2cddca50f..8645997c8 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -14,35 +14,7 @@ VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning #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 -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; -} +void VDMOStempUpdate(VDMOSmodel *inModel, VDMOSinstance *here, double Temp, CKTcircuit *ckt); int VDMOSload(GENmodel *inModel, CKTcircuit *ckt) @@ -88,6 +60,9 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) register int selfheat; double rd0T, rd1T, dBeta_dT, dIds_dT; + double Vrd=0.0, dIth_dVrd=0.0, dIrd_dT=0.0; + double drd0T_dT, drd1T_dT, drd_dT, dgdrain_dT=0.0; + double dIrd_dVrd, dIrd_dgdrain; double deldelTemp=0.0, delTemp, delTemp1, Temp, Vds, Vgs; double ceqqth=0.0; double GmT, gTtg, gTtdp, gTtt, gTtsp, gcTt=0.0; @@ -298,15 +273,20 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) vgs = vgd + vds; } if (selfheat) - delTemp = VDMOSlimitlog(delTemp, - *(ckt->CKTstate0 + here->VDMOSdelTemp),100,&Check_th); + delTemp = DEVlimitlog(delTemp, + *(ckt->CKTstate0 + here->VDMOSdelTemp),30,&Check_th); else delTemp = 0.0; #endif /*NODELIMITING*/ } - Temp = here->VDMOStemp + delTemp; + if (selfheat) { + Temp = here->VDMOStemp + delTemp; + VDMOStempUpdate(model, here, Temp, ckt); + } else { + Temp = here->VDMOStemp; + } here->VDMOSTempSH = Temp; /* added for portability of SH Temp for noise analysis */ /* Calculate temperature dependent values for self-heating effect */ @@ -315,17 +295,23 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) Beta = here->VDMOStTransconductance * pow(TempRatio,model->VDMOSmu); dBeta_dT = Beta * model->VDMOSmu / Temp; 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; + drd1T_dT = 0.0; if (model->VDMOSqsGiven) rd1T = here->VDMOSqsResistance; + drd1T_dT = 0.0; } /* @@ -428,13 +414,19 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTrhsOld + here->VDMOSdNode) - *(ckt->CKTrhsOld + here->VDMOSsNode)); double rd = rd0T + rd1T * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage))); - if (rd > 0) + drd_dT = drd0T_dT + drd1T_dT * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage))); + if (rd > 0) { here->VDMOSdrainConductance = 1 / rd + ckt->CKTgmin; - else + dgdrain_dT = -drd_dT / (rd*rd); + } else { here->VDMOSdrainConductance = 1 / rd0T; + dgdrain_dT = -drd0T_dT / (rd0T*rd0T); + } } else { - if (rd0T > 0) + if (rd0T > 0) { here->VDMOSdrainConductance = 1 / rd0T; + dgdrain_dT = -drd0T_dT / (rd0T*rd0T); + } } if (selfheat) { @@ -446,15 +438,20 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) } 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 + /* power flows from ground 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 - model->VDMOStype * (here->VDMOSgtempg * Vgs + here->VDMOSgtempd * Vds) - here->VDMOSgtempT * delTemp; + + Vrd = *(ckt->CKTrhsOld + here->VDMOSdNode) - *(ckt->CKTrhsOld + here->VDMOSdNodePrime); + dIth_dVrd = here->VDMOSdrainConductance * Vrd; + dIrd_dVrd = here->VDMOSdrainConductance; + dIrd_dgdrain = Vrd; + dIrd_dT = dIrd_dgdrain * dgdrain_dT; + here->VDMOScth += here->VDMOSdrainConductance * Vrd*Vrd - dIth_dVrd*Vrd - dIrd_dT*Vrd*delTemp; } /* @@ -605,9 +602,10 @@ bypass: *(ckt->CKTrhs + here->VDMOSdNodePrime) += (-cdreq + model->VDMOStype * ceqgd); *(ckt->CKTrhs + here->VDMOSsNodePrime) += cdreq + model->VDMOStype * ceqgs; if (selfheat) { - *(ckt->CKTrhs + here->VDMOSdNodePrime) += GmT * delTemp; + *(ckt->CKTrhs + here->VDMOSdNode) += dIrd_dT * delTemp; + *(ckt->CKTrhs + here->VDMOSdNodePrime) += GmT * delTemp - dIrd_dT * delTemp; *(ckt->CKTrhs + here->VDMOSsNodePrime) += -GmT * delTemp; - *(ckt->CKTrhs + here->VDMOStempNode) -= here->VDMOScth + ceqqth; /* MOS dissipated power + Cthj current */ + *(ckt->CKTrhs + here->VDMOStempNode) += here->VDMOScth - ceqqth; double vCktTemp = (ckt->CKTtemp-CONSTCtoK); /* ckt temperature */ if (ckt->CKTmode & MODETRANOP) vCktTemp *= ckt->CKTsrcFact; @@ -648,13 +646,16 @@ bypass: if (selfheat) { - (*(here->VDMOSDPtempPtr) += GmT); + + (*(here->VDMOSDtempPtr) += dIrd_dT); + (*(here->VDMOSDPtempPtr) += GmT - dIrd_dT); (*(here->VDMOSSPtempPtr) += -GmT); (*(here->VDMOSGPtempPtr) += 0.0); - (*(here->VDMOSTemptempPtr) += gTtt + 1/model->VDMOSrthjc + gcTt); - (*(here->VDMOSTempgpPtr) += gTtg); - (*(here->VDMOSTempdpPtr) += gTtdp); - (*(here->VDMOSTempspPtr) += gTtsp); + (*(here->VDMOSTemptempPtr) += -gTtt - dIrd_dT*Vrd + 1/model->VDMOSrthjc + gcTt); + (*(here->VDMOSTempgpPtr) += -gTtg); + (*(here->VDMOSTempdPtr) += -dIth_dVrd); + (*(here->VDMOSTempdpPtr) += -gTtdp + dIth_dVrd); + (*(here->VDMOSTempspPtr) += -gTtsp); (*(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc); (*(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc); (*(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca); @@ -672,14 +673,15 @@ bypass: double vd, cd; double vte; double vtebrk, vbrknp; - double cdb, csat, cdeq; + double cdb, cdeq; double capd; double gd, gdb, gspr; double delvd; /* change in diode voltage temporary */ double evrev; double Ith=0.0, dIth_dT=0.0; double dIdio_dT=0.0, dIth_dVdio=0.0; - double arg1, darg1_dT, arg2, darg2_dT, csat_dT; + double vrs=0.0, dIrs_dT=0.0, dIth_dVrs=0.0; + #ifndef NOBYPASS double tol; /* temporary for tolerance calculations */ #endif @@ -691,7 +693,7 @@ bypass: gspr = here->VDIOtConductance; vt = CONSTKoverQ * Temp; - vte = model->VDMOSn * vt; + vte = model->VDIOn * vt; vtebrk = model->VDIObrkdEmissionCoeff * vt; vbrknp = here->VDIOtBrkdwnV; @@ -758,7 +760,7 @@ bypass: /* * limit new junction voltage */ - if ((model->VDMOSbvGiven) && + if ((model->VDIObvGiven) && (vd < MIN(0, -vbrknp + 10 * vtebrk))) { double vdtemp; vdtemp = -(vd + vbrknp); @@ -773,19 +775,6 @@ bypass: } } - /* - * temperature dependent diode saturation current and derivative - */ - arg1 = ((Temp / model->VDMOStnom) - 1) * model->VDMOSeg / (model->VDMOSn*vt); - darg1_dT = model->VDMOSeg / (vte*model->VDMOStnom) - - model->VDMOSeg*(Temp/model->VDMOStnom -1)/(vte*Temp); - - arg2 = model->VDMOSxti / model->VDMOSn * log(Temp / model->VDMOStnom); - darg2_dT = model->VDMOSxti / model->VDMOSn / Temp; - - csat = here->VDMOSm * model->VDIOjctSatCur * exp(arg1 + arg2); - csat_dT = here->VDMOSm * model->VDIOjctSatCur * exp(arg1 + arg2) * (darg1_dT + darg2_dT); - /* * compute dc current and derivatives */ @@ -793,27 +782,27 @@ bypass: double evd; evd = exp(vd / vte); - cdb = csat*(evd - 1); - dIdio_dT = csat_dT * (evd - 1) - csat * vd * evd / (vte * Temp); - gdb = csat*evd / vte; + cdb = here->VDIOtSatCur*(evd - 1); + dIdio_dT = here->VDIOtSatCur_dT * (evd - 1) - here->VDIOtSatCur * vd * evd / (vte * Temp); + gdb = here->VDIOtSatCur*evd / vte; - } else if ((!(model->VDMOSbvGiven)) || + } else if ((!(model->VDIObvGiven)) || vd >= -vbrknp) { /* reverse */ double arg3, darg3_dT; arg = 3 * vte / (vd*CONSTe); arg3 = arg * arg * arg; darg3_dT = 3 * arg3 / Temp; - cdb = -csat*(1 + arg3); - dIdio_dT = -csat_dT * (arg3 + 1) - csat * darg3_dT; - gdb = csat * 3 * arg / vd; + cdb = -here->VDIOtSatCur*(1 + arg3); + dIdio_dT = -here->VDIOtSatCur_dT * (arg3 + 1) - here->VDIOtSatCur * darg3_dT; + gdb = here->VDIOtSatCur * 3 * arg / vd; } else { /* breakdown */ evrev = exp(-(vbrknp + vd) / vtebrk); - cdb = -csat*evrev; - dIdio_dT = csat * (-vbrknp-vd) * evrev / vtebrk / Temp - csat_dT * evrev; - gdb = csat*evrev / vtebrk; + cdb = -here->VDIOtSatCur*evrev; + dIdio_dT = here->VDIOtSatCur * (-vbrknp-vd) * evrev / vtebrk / Temp - here->VDIOtSatCur_dT * evrev; + gdb = here->VDIOtSatCur*evrev / vtebrk; } @@ -855,7 +844,7 @@ bypass: if (ckt->CKTmode & MODEINITSMSIG) { *(ckt->CKTstate0 + here->VDIOcapCurrent) = capd; - goto load; + continue; } /* @@ -893,9 +882,18 @@ bypass: load: if (selfheat) { - Ith = vd*cd; + double dIrs_dgspr, dIth_dIrs; + vrs = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDIOposPrimeNode); + + Ith = vd*cd + vrs*vrs*gspr; + dIth_dVdio = cd + vd*gd; - dIth_dT = dIdio_dT*vd; + dIth_dVrs = vrs*gspr; + + dIrs_dgspr = vrs; + dIrs_dT = dIrs_dgspr * here->VDIOtConductance_dT; + dIth_dIrs = vrs; + dIth_dT = dIth_dIrs*dIrs_dT + dIdio_dT*vd; } /* * load current vector @@ -909,9 +907,10 @@ load: *(ckt->CKTrhs + here->VDIOposPrimeNode) += cdeq; } if (selfheat) { - *(ckt->CKTrhs + here->VDMOSdNode) += dIdio_dT*delTemp; - *(ckt->CKTrhs + here->VDIOposPrimeNode) -= dIdio_dT*delTemp; - *(ckt->CKTrhs + here->VDMOStempNode) += Ith - model->VDMOStype*dIth_dVdio*vd + dIth_dT*delTemp; /* Diode dissipated power */ + *(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrs_dT*delTemp; + *(ckt->CKTrhs + here->VDMOSdNode) += -dIdio_dT*delTemp; + *(ckt->CKTrhs + here->VDMOSsNode) += dIrs_dT*delTemp; + *(ckt->CKTrhs + here->VDMOStempNode) += Ith - model->VDMOStype*dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp; } /* * load matrix @@ -924,11 +923,13 @@ load: *(here->VDIORPsPtr) -= gspr; *(here->VDIORPdPtr) -= gd; if (selfheat) { - (*(here->VDMOSTemptempPtr) += dIth_dT); - (*(here->VDIOTempposPrimePtr) += -dIth_dVdio); - (*(here->VDIOTempnegPtr) += dIth_dVdio); - (*(here->VDIOPosPrimetempPtr) += -dIdio_dT); - (*(here->VDIONegtempPtr) += dIdio_dT); + (*(here->VDMOStempSPtr) += -dIth_dVrs); + (*(here->VDIOTempposPrimePtr) += -dIth_dVdio + dIth_dVrs); + (*(here->VDMOSTempdPtr) += dIth_dVdio); + (*(here->VDMOSTemptempPtr) += -dIth_dT); + (*(here->VDIOPosPrimetempPtr) += dIdio_dT - dIrs_dT); + (*(here->VDMOSSTempPtr) += dIrs_dT); + (*(here->VDMOSDtempPtr) += -dIdio_dT); } } } diff --git a/src/spicelib/devices/vdmos/vdmosmask.c b/src/spicelib/devices/vdmos/vdmosmask.c index 9b5c1f956..85c78fb9c 100644 --- a/src/spicelib/devices/vdmos/vdmosmask.c +++ b/src/spicelib/devices/vdmos/vdmosmask.c @@ -83,47 +83,47 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) return(OK); /* body diode */ - case VDMOS_MOD_RB: + case VDIO_MOD_RB: value->rValue = model->VDIOresistance; return(OK); - case VDMOS_MOD_IS: + case VDIO_MOD_IS: value->rValue = model->VDIOjctSatCur; return(OK); - case VDMOS_MOD_N: - value->rValue = model->VDMOSn; + case VDIO_MOD_N: + value->rValue = model->VDIOn; return(OK); - case VDMOS_MOD_VJ: + case VDIO_MOD_VJ: value->rValue = model->VDIOjunctionPot; return(OK); - case VDMOS_MOD_CJ: + case VDIO_MOD_CJ: value->rValue = model->VDIOjunctionCap; return(OK); - case VDMOS_MOD_MJ: + case VDIO_MOD_MJ: value->rValue = model->VDIOgradCoeff; return(OK); - case VDMOS_MOD_BV: - value->rValue = model->VDMOSbv; + case VDIO_MOD_BV: + value->rValue = model->VDIObv; return(OK); - case VDMOS_MOD_IBV: - value->rValue = model->VDMOSibv; + case VDIO_MOD_IBV: + value->rValue = model->VDIOibv; return(OK); - case VDMOS_MOD_NBV: + case VDIO_MOD_NBV: value->rValue = model->VDIObrkdEmissionCoeff; return(OK); case VDMOS_MOD_RDS: value->rValue = model->VDMOSrds; return(OK); - case VDMOS_MOD_FC: + case VDIO_MOD_FC: value->rValue = model->VDIOdepletionCapCoeff; return(OK); - case VDMOS_MOD_TT: + case VDIO_MOD_TT: value->rValue = model->VDIOtransitTime; return(OK); - case VDMOS_MOD_EG: - value->rValue = model->VDMOSeg; + case VDIO_MOD_EG: + value->rValue = model->VDIOeg; return(OK); - case VDMOS_MOD_XTI: - value->rValue = model->VDMOSxti; + case VDIO_MOD_XTI: + value->rValue = model->VDIOxti; return(OK); case VDMOS_MOD_TCVTH: value->rValue = model->VDMOStcvth; @@ -164,11 +164,11 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case VDMOS_MOD_TRS2: value->rValue = model->VDMOStrs2; return(OK); - case VDMOS_MOD_TRB1: - value->rValue = model->VDMOStrb1; + case VDIO_MOD_TRB1: + value->rValue = model->VDIOtrb1; return(OK); - case VDMOS_MOD_TRB2: - value->rValue = model->VDMOStrb2; + case VDIO_MOD_TRB2: + value->rValue = model->VDIOtrb2; return(OK); case VDMOS_MOD_TKSUBTHRES1: value->rValue = model->VDMOStksubthres1; diff --git a/src/spicelib/devices/vdmos/vdmosmpar.c b/src/spicelib/devices/vdmos/vdmosmpar.c index 44fa84ccc..ccb3a4cf4 100644 --- a/src/spicelib/devices/vdmos/vdmosmpar.c +++ b/src/spicelib/devices/vdmos/vdmosmpar.c @@ -60,29 +60,29 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDMOSqsVoltage = value->rValue; model->VDMOSqsVoltageGiven = TRUE; break; - case VDMOS_MOD_RB: + case VDIO_MOD_RB: model->VDIOresistance = value->rValue; model->VDIOresistanceGiven = TRUE; break; - case VDMOS_MOD_IS: + case VDIO_MOD_IS: model->VDIOjctSatCur = value->rValue; model->VDIOjctSatCurGiven = TRUE; break; - case VDMOS_MOD_VJ: + case VDIO_MOD_VJ: model->VDIOjunctionPot = value->rValue; model->VDIOjunctionPotGiven = TRUE; break; - case VDMOS_MOD_CJ: + case VDIO_MOD_CJ: model->VDIOjunctionCap = value->rValue; model->VDIOjunctionCapGiven = TRUE; break; - case VDMOS_MOD_MJ: + case VDIO_MOD_MJ: model->VDIOgradCoeff = value->rValue; model->VDIOgradCoeffGiven = TRUE; model->VDIOgradCoeffTemp1 = 0; model->VDIOgradCoeffTemp2 = 0; break; - case VDMOS_MOD_FC: + case VDIO_MOD_FC: model->VDIOdepletionCapCoeff = value->rValue; model->VDIOdepletionCapCoeffGiven = TRUE; break; @@ -140,15 +140,15 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDMOSksubthres = value->rValue; model->VDMOSksubthresGiven = TRUE; break; - case VDMOS_MOD_BV: - model->VDMOSbv = value->rValue; - model->VDMOSbvGiven = TRUE; + case VDIO_MOD_BV: + model->VDIObv = value->rValue; + model->VDIObvGiven = TRUE; break; - case VDMOS_MOD_IBV: - model->VDMOSibv = value->rValue; - model->VDMOSibvGiven = TRUE; + case VDIO_MOD_IBV: + model->VDIOibv = value->rValue; + model->VDIOibvGiven = TRUE; break; - case VDMOS_MOD_NBV: + case VDIO_MOD_NBV: model->VDIObrkdEmissionCoeff = value->rValue; model->VDIObrkdEmissionCoeffGiven = TRUE; break; @@ -156,23 +156,23 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDMOSrds = value->rValue; model->VDMOSrdsGiven = TRUE; break; - case VDMOS_MOD_N: - model->VDMOSn = value->rValue; - model->VDMOSnGiven = TRUE; + case VDIO_MOD_N: + model->VDIOn = value->rValue; + model->VDIOnGiven = TRUE; break; - case VDMOS_MOD_TT: + case VDIO_MOD_TT: model->VDIOtransitTime = value->rValue; model->VDIOtransitTimeGiven = TRUE; model->VDIOtranTimeTemp1 = 0; model->VDIOtranTimeTemp2 = 0; break; - case VDMOS_MOD_EG: - model->VDMOSeg = value->rValue; - model->VDMOSegGiven = TRUE; + case VDIO_MOD_EG: + model->VDIOeg = value->rValue; + model->VDIOegGiven = TRUE; break; - case VDMOS_MOD_XTI: - model->VDMOSxti = value->rValue; - model->VDMOSxtiGiven = TRUE; + case VDIO_MOD_XTI: + model->VDIOxti = value->rValue; + model->VDIOxtiGiven = TRUE; break; case VDMOS_MOD_TCVTH: model->VDMOStcvth = value->rValue; @@ -226,13 +226,13 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDMOStrs2 = value->rValue; model->VDMOStrs2Given = TRUE; break; - case VDMOS_MOD_TRB1: - model->VDMOStrb1 = value->rValue; - model->VDMOStrb1Given = TRUE; + case VDIO_MOD_TRB1: + model->VDIOtrb1 = value->rValue; + model->VDIOtrb1Given = TRUE; break; - case VDMOS_MOD_TRB2: - model->VDMOStrb2 = value->rValue; - model->VDMOStrb2Given = TRUE; + case VDIO_MOD_TRB2: + model->VDIOtrb2 = value->rValue; + model->VDIOtrb2Given = TRUE; break; case VDMOS_MOD_TKSUBTHRES1: model->VDMOStksubthres1 = value->rValue; diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index e83359ec7..3de5c1864 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -85,11 +85,11 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (!model->VDMOSmtrGiven) model->VDMOSmtr = 1.; - if (!model->VDMOSbvGiven) - model->VDMOSbv = 1.0e30; + if (!model->VDIObvGiven) + model->VDIObv = 1.0e30; - if (!model->VDMOSibvGiven) - model->VDMOSibv = 1.0e-10; + if (!model->VDIOibvGiven) + model->VDIOibv = 1.0e-10; if (!model->VDIObrkdEmissionCoeffGiven) model->VDIObrkdEmissionCoeff = 1.; @@ -109,14 +109,14 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (!model->VDIOresistanceGiven) model->VDIOresistance = 10e-03; - if (!model->VDMOSnGiven) - model->VDMOSn = 1.; + if (!model->VDIOnGiven) + model->VDIOn = 1.; if (!model->VDIOtransitTimeGiven) model->VDIOtransitTime = 0.; - if (!model->VDMOSegGiven) - model->VDMOSeg = 1.11; + if (!model->VDIOegGiven) + model->VDIOeg = 1.11; if (!model->VDMOSrthjcGiven) model->VDMOSrthjc = 1.0e-03; @@ -157,11 +157,11 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (!model->VDMOStrs2Given) model->VDMOStrs2 = 0.0; - if (!model->VDMOStrb1Given) - model->VDMOStrb1 = 0.0; + if (!model->VDIOtrb1Given) + model->VDIOtrb1 = 0.0; - if (!model->VDMOStrb2Given) - model->VDMOStrb2 = 0.0; + if (!model->VDIOtrb2Given) + model->VDIOtrb2 = 0.0; if (!model->VDMOStksubthres1Given) model->VDMOStksubthres1 = 0.0; @@ -189,6 +189,38 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, else model->VDMOSqsGiven = 0; + if(!model->VDMOStnomGiven) { + model->VDMOStnom = ckt->CKTnomTemp; + } + + /* 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 = 3.9 * 8.854214871e-12 / 1e-07; /* use default Tox of 100nm */ + + /* body diode model */ + /* limit activation energy to min of .1 */ + if (model->VDIOeg<.1) { + SPfrontEnd->IFerrorf(ERR_WARNING, + "%s: body diode activation energy too small, limited to 0.1", + model->VDMOSmodName); + model->VDIOeg = .1; + } + /* limit depletion cap coeff to max of .95 */ + if (model->VDIOdepletionCapCoeff>.95) { + SPfrontEnd->IFerrorf(ERR_WARNING, + "%s: coefficient Fc too large, limited to 0.95", + model->VDMOSmodName); + model->VDIOdepletionCapCoeff = .95; + } + /* set lower limit of saturation current */ + if (model->VDIOjctSatCur < ckt->CKTepsmin) + model->VDIOjctSatCur = ckt->CKTepsmin; + /* loop through all the instances of the model */ for (here = VDMOSinstances(model); here != NULL; here = VDMOSnextInstance(here)) { @@ -368,58 +400,61 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ return(E_NOMEM);\ } } while(0) - if ((here->VDMOSthermalGiven) && (model->VDMOSrthjcGiven)) { - TSTALLOC(VDMOSTemptempPtr, VDMOStempNode, VDMOStempNode); /* Transistor thermal contribution */ - 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(VDIOTempposPrimePtr, VDMOStempNode, VDIOposPrimeNode);/* Diode thermal contribution */ - TSTALLOC(VDIOTempnegPtr, VDMOStempNode, VDMOSdNode); - TSTALLOC(VDIOPosPrimetempPtr, VDIOposPrimeNode, VDMOStempNode); - TSTALLOC(VDIONegtempPtr, VDMOSdNode, 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); + TSTALLOC(VDMOSDdPtr, VDMOSdNode, VDMOSdNode); + TSTALLOC(VDMOSGgPtr, VDMOSgNode, VDMOSgNode); + TSTALLOC(VDMOSSsPtr, VDMOSsNode, VDMOSsNode); TSTALLOC(VDMOSDPdpPtr, VDMOSdNodePrime, VDMOSdNodePrime); TSTALLOC(VDMOSSPspPtr, VDMOSsNodePrime, VDMOSsNodePrime); TSTALLOC(VDMOSGPgpPtr, VDMOSgNodePrime, VDMOSgNodePrime); - TSTALLOC(VDMOSDdpPtr, VDMOSdNode, VDMOSdNodePrime); + TSTALLOC(VDMOSDdpPtr, VDMOSdNode, VDMOSdNodePrime); TSTALLOC(VDMOSGPdpPtr, VDMOSgNodePrime, VDMOSdNodePrime); TSTALLOC(VDMOSGPspPtr, VDMOSgNodePrime, VDMOSsNodePrime); - TSTALLOC(VDMOSSspPtr, VDMOSsNode, VDMOSsNodePrime); + TSTALLOC(VDMOSSspPtr, VDMOSsNode, VDMOSsNodePrime); TSTALLOC(VDMOSDPspPtr, VDMOSdNodePrime, VDMOSsNodePrime); - TSTALLOC(VDMOSDPdPtr, VDMOSdNodePrime, VDMOSdNode); + TSTALLOC(VDMOSDPdPtr, VDMOSdNodePrime, VDMOSdNode); TSTALLOC(VDMOSDPgpPtr, VDMOSdNodePrime, VDMOSgNodePrime); TSTALLOC(VDMOSSPgpPtr, VDMOSsNodePrime, VDMOSgNodePrime); - TSTALLOC(VDMOSSPsPtr, VDMOSsNodePrime, VDMOSsNode); + TSTALLOC(VDMOSSPsPtr, VDMOSsNodePrime, VDMOSsNode); TSTALLOC(VDMOSSPdpPtr, VDMOSsNodePrime, VDMOSdNodePrime); - TSTALLOC(VDMOSGgpPtr, VDMOSgNode, VDMOSgNodePrime); + TSTALLOC(VDMOSGgpPtr, VDMOSgNode, VDMOSgNodePrime); TSTALLOC(VDMOSGPgPtr, VDMOSgNodePrime, VDMOSgNode); TSTALLOC(VDMOSDsPtr, VDMOSdNode, VDMOSsNode); TSTALLOC(VDMOSSdPtr, VDMOSsNode, VDMOSdNode); - TSTALLOC(VDIORPdPtr, VDIOposPrimeNode, VDMOSdNode); - TSTALLOC(VDIODrpPtr, VDMOSdNode, VDIOposPrimeNode); - TSTALLOC(VDIOSrpPtr, VDMOSsNode, VDIOposPrimeNode); - TSTALLOC(VDIORPsPtr, VDIOposPrimeNode, VDMOSsNode); + TSTALLOC(VDIORPdPtr, VDIOposPrimeNode, VDMOSdNode); + TSTALLOC(VDIODrpPtr, VDMOSdNode, VDIOposPrimeNode); + TSTALLOC(VDIOSrpPtr, VDMOSsNode, VDIOposPrimeNode); + TSTALLOC(VDIORPsPtr, VDIOposPrimeNode, VDMOSsNode); TSTALLOC(VDIORPrpPtr, VDIOposPrimeNode, VDIOposPrimeNode); + + if ((here->VDMOSthermalGiven) && (model->VDMOSrthjcGiven)) { + TSTALLOC(VDMOSTemptempPtr, VDMOStempNode, VDMOStempNode); /* Transistor thermal contribution */ + 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(VDIOTempposPrimePtr, VDMOStempNode, VDIOposPrimeNode);/* Diode thermal contribution */ + TSTALLOC(VDMOSTempdPtr, VDMOStempNode, VDMOSdNode); + TSTALLOC(VDIOPosPrimetempPtr, VDIOposPrimeNode, VDMOStempNode); + TSTALLOC(VDMOSDtempPtr, VDMOSdNode, VDMOStempNode); + TSTALLOC(VDMOStempSPtr, VDMOStempNode, VDMOSsNode); + TSTALLOC(VDMOSSTempPtr, VDMOSsNode, 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); + } } } return(OK); diff --git a/src/spicelib/devices/vdmos/vdmostemp.c b/src/spicelib/devices/vdmos/vdmostemp.c index 46d891392..db1c66e9c 100644 --- a/src/spicelib/devices/vdmos/vdmostemp.c +++ b/src/spicelib/devices/vdmos/vdmostemp.c @@ -5,6 +5,8 @@ Modified: 2000 AlansFixes VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning **********/ + /* perform the temperature update to the vdmos */ + #include "ngspice/ngspice.h" #include "ngspice/cktdefs.h" #include "vdmosdefs.h" @@ -12,11 +14,9 @@ VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning #include "ngspice/sperror.h" #include "ngspice/suffix.h" -int -VDMOStemp(GENmodel *inModel, CKTcircuit *ckt) -{ - VDMOSmodel *model = (VDMOSmodel *)inModel; - VDMOSinstance *here; +void VDMOStempUpdate(VDMOSmodel *inModel, VDMOSinstance *here, double Temp, CKTcircuit *ckt) { + + VDMOSmodel *model = (VDMOSmodel*)inModel; double egfet,egfet1; double fact1,fact2; @@ -28,199 +28,179 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt) double vt,vtnom; double xfc; - /* loop through all the resistor models */ - for( ; model != NULL; model = VDMOSnextModel(model)) { - + fact1 = model->VDMOStnom/REFTEMP; + vtnom = model->VDMOStnom*CONSTKoverQ; + kt1 = CONSTboltz * model->VDMOStnom; + egfet1 = 1.16-(7.02e-4*model->VDMOStnom*model->VDMOStnom)/ + (model->VDMOStnom+1108); + arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact1 = -2*vtnom *(1.5*log(fact1)+CHARGE*arg1); - /* perform model defaulting */ - if(!model->VDMOStnomGiven) { - model->VDMOStnom = ckt->CKTnomTemp; - } + xfc = log(1 - model->VDIOdepletionCapCoeff); - fact1 = model->VDMOStnom/REFTEMP; - vtnom = model->VDMOStnom*CONSTKoverQ; - kt1 = CONSTboltz * model->VDMOStnom; - egfet1 = 1.16-(7.02e-4*model->VDMOStnom*model->VDMOStnom)/ - (model->VDMOStnom+1108); - arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); - pbfact1 = -2*vtnom *(1.5*log(fact1)+CHARGE*arg1); + double arg; /* 1 - fc */ - /* now model parameter preprocessing */ - if (model->VDMOSphi <= 0.0) { - SPfrontEnd->IFerrorf(ERR_FATAL, - "%s: Phi is not positive.", model->VDMOSmodName); - return(E_BADPARM); - } + double dt = Temp - model->VDMOStnom; - model->VDMOSoxideCapFactor = 3.9 * 8.854214871e-12 / 1e-07; /* use default Tox of 100nm */ + /* vdmos temperature model */ + ratio = Temp/model->VDMOStnom; + here->VDMOStTransconductance = model->VDMOStransconductance + * here->VDMOSm * pow(ratio, model->VDMOSmu); - /* body diode model */ - /* limit activation energy to min of .1 */ - if (model->VDMOSeg<.1) { - SPfrontEnd->IFerrorf(ERR_WARNING, - "%s: body diode activation energy too small, limited to 0.1", - model->VDMOSmodName); - model->VDMOSeg = .1; - } - /* limit depletion cap coeff to max of .95 */ - if (model->VDIOdepletionCapCoeff>.95) { - SPfrontEnd->IFerrorf(ERR_WARNING, - "%s: coefficient Fc too large, limited to 0.95", - model->VDMOSmodName); - model->VDIOdepletionCapCoeff = .95; - } - /* set lower limit of saturation current */ - if (model->VDIOjctSatCur < ckt->CKTepsmin) - model->VDIOjctSatCur = ckt->CKTepsmin; + here->VDMOStVth = model->VDMOSvth0 - model->VDMOStype * model->VDMOStcvth * dt; - xfc = log(1 - model->VDIOdepletionCapCoeff); + here->VDMOStksubthres = model->VDMOSksubthres * (1.0 + (model->VDMOStksubthres1 * dt) + (model->VDMOStksubthres2 * dt * dt)); - /* loop through all instances of the model */ - for(here = VDMOSinstances(model); here!= NULL; - here = VDMOSnextInstance(here)) { - double arg; /* 1 - fc */ + if (model->VDMOStexp0Given) + here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * pow(ratio, model->VDMOStexp0); + else + here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * (1.0 + (model->VDMOStrd1 * dt) + (model->VDMOStrd2 * dt * dt)); - /* perform the parameter defaulting */ - if(!here->VDMOSdtempGiven) { - here->VDMOSdtemp = 0.0; - } - if(!here->VDMOStempGiven) { - here->VDMOStemp = ckt->CKTtemp + here->VDMOSdtemp; - } + here->VDMOSgateConductance = here->VDMOSgateConductance / (1.0 + (model->VDMOStrg1 * dt) + (model->VDMOStrg2 * dt * dt)); - double dt = here->VDMOStemp - model->VDMOStnom; + here->VDMOSsourceConductance = here->VDMOSsourceConductance / (1.0 + (model->VDMOStrs1 * dt) + (model->VDMOStrs2 * dt * dt)); - /* vdmos temperature model */ - ratio = here->VDMOStemp/model->VDMOStnom; - here->VDMOStTransconductance = model->VDMOStransconductance - * here->VDMOSm * pow(ratio, model->VDMOSmu); + if (model->VDMOSqsGiven) + here->VDMOSqsResistance = model->VDMOSqsResistance / here->VDMOSm * pow(ratio, model->VDMOStexp1); - here->VDMOStVth = model->VDMOSvth0 - model->VDMOStype * model->VDMOStcvth * dt; + vt = Temp * CONSTKoverQ; + fact2 = Temp/REFTEMP; + kt = Temp * CONSTboltz; + egfet = 1.16-(7.02e-4*Temp*Temp)/ + (Temp+1108); + arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg); - here->VDMOStksubthres = model->VDMOSksubthres * (1.0 + (model->VDMOStksubthres1 * dt) + (model->VDMOStksubthres2 * dt * dt)); + phio = (model->VDMOSphi - pbfact1) / fact1; + here->VDMOStPhi = fact2 * phio + pbfact; /* needed for distortion analysis */ - if (model->VDMOStexp0Given) - here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * pow(ratio, model->VDMOStexp0); - else - here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * (1.0 + (model->VDMOStrd1 * dt) + (model->VDMOStrd2 * dt * dt)); + /* body diode temperature model */ + double pbo, gmaold; + double gmanew, factor; + double tBreakdownVoltage, vte, cbv; + double xbv, xcbv, tol, iter; + double arg1_dT, arg2, arg2_dT; - here->VDMOSgateConductance = here->VDMOSgateConductance / (1.0 + (model->VDMOStrg1 * dt) + (model->VDMOStrg2 * dt * dt)); + /* Junction grading temperature adjust */ + factor = 1.0 + (model->VDIOgradCoeffTemp1 * dt) + + (model->VDIOgradCoeffTemp2 * dt * dt); + here->VDIOtGradingCoeff = model->VDIOgradCoeff * factor; - here->VDMOSsourceConductance = here->VDMOSsourceConductance / (1.0 + (model->VDMOStrs1 * dt) + (model->VDMOStrs2 * dt * dt)); + pbo = (model->VDIOjunctionPot - pbfact1) / fact1; + gmaold = (model->VDIOjunctionPot - pbo) / pbo; + here->VDIOtJctCap = here->VDMOSm * model->VDIOjunctionCap / + (1 + here->VDIOtGradingCoeff* + (400e-6*(model->VDMOStnom - REFTEMP) - gmaold)); + here->VDIOtJctPot = pbfact + fact2*pbo; + gmanew = (here->VDIOtJctPot - pbo) / pbo; + here->VDIOtJctCap *= 1 + here->VDIOtGradingCoeff* + (400e-6*(Temp - REFTEMP) - gmanew); - if (model->VDMOSqsGiven) - here->VDMOSqsResistance = model->VDMOSqsResistance / here->VDMOSm * pow(ratio, model->VDMOStexp1); + vte = model->VDIOn*vt; - vt = here->VDMOStemp * CONSTKoverQ; - fact2 = here->VDMOStemp/REFTEMP; - kt = here->VDMOStemp * CONSTboltz; - egfet = 1.16-(7.02e-4*here->VDMOStemp*here->VDMOStemp)/ - (here->VDMOStemp+1108); - arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); - pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg); + arg1 = ((Temp / model->VDMOStnom) - 1) * model->VDIOeg / vte; + arg1_dT = model->VDIOeg / (vte*model->VDMOStnom) + - model->VDIOeg*(Temp/model->VDMOStnom -1)/(vte*Temp); + arg2 = model->VDIOxti / model->VDIOn * log(Temp / model->VDMOStnom); + arg2_dT = model->VDIOxti / model->VDIOn / Temp; + here->VDIOtSatCur = here->VDMOSm * model->VDIOjctSatCur * exp(arg1 + arg2); + here->VDIOtSatCur_dT = here->VDMOSm * model->VDIOjctSatCur * exp(arg1 + arg2) * (arg1_dT + arg2_dT); - phio = (model->VDMOSphi - pbfact1) / fact1; - here->VDMOStPhi = fact2 * phio + pbfact; /* needed for distortion analysis */ + /* the defintion of f1, just recompute after temperature adjusting + * all the variables used in it */ + here->VDIOtF1 = here->VDIOtJctPot* + (1 - exp((1 - here->VDIOtGradingCoeff)*xfc)) / + (1 - here->VDIOtGradingCoeff); + /* same for Depletion Capacitance */ + here->VDIOtDepCap = model->VDIOdepletionCapCoeff * + here->VDIOtJctPot; - /* body diode temperature model */ - double pbo, gmaold; - double gmanew, factor; - double tBreakdownVoltage, vte, cbv; - double xbv, xcbv, tol, iter; + /* and Vcrit */ + here->VDIOtVcrit = vte * log(vte / (CONSTroot2*here->VDIOtSatCur)); - /* Junction grading temperature adjust */ - factor = 1.0 + (model->VDIOgradCoeffTemp1 * dt) - + (model->VDIOgradCoeffTemp2 * dt * dt); - here->VDIOtGradingCoeff = model->VDIOgradCoeff * factor; - - pbo = (model->VDIOjunctionPot - pbfact1) / fact1; - gmaold = (model->VDIOjunctionPot - pbo) / pbo; - here->VDIOtJctCap = here->VDMOSm * model->VDIOjunctionCap / - (1 + here->VDIOtGradingCoeff* - (400e-6*(model->VDMOStnom - REFTEMP) - gmaold)); - here->VDIOtJctPot = pbfact + fact2*pbo; - gmanew = (here->VDIOtJctPot - pbo) / pbo; - here->VDIOtJctCap *= 1 + here->VDIOtGradingCoeff* - (400e-6*(here->VDMOStemp - REFTEMP) - gmanew); - - here->VDIOtSatCur = here->VDMOSm * model->VDIOjctSatCur * exp( - ((here->VDMOStemp / model->VDMOStnom) - 1) * - model->VDMOSeg / (model->VDMOSn*vt) + - model->VDMOSxti / model->VDMOSn * - log(here->VDMOStemp / model->VDMOStnom)); - - /* the defintion of f1, just recompute after temperature adjusting - * all the variables used in it */ - here->VDIOtF1 = here->VDIOtJctPot* - (1 - exp((1 - here->VDIOtGradingCoeff)*xfc)) / - (1 - here->VDIOtGradingCoeff); - /* same for Depletion Capacitance */ - here->VDIOtDepCap = model->VDIOdepletionCapCoeff * - here->VDIOtJctPot; - - /* and Vcrit */ - vte = model->VDMOSn*vt; - - here->VDIOtVcrit = vte * log(vte / (CONSTroot2*here->VDIOtSatCur)); - - /* limit junction potential to max of 1/FC */ - 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); - } - - /* and now to compute the breakdown voltage, again, using - * temperature adjusted basic parameters */ - if (model->VDMOSbvGiven) { - /* tlev == 0 */ - tBreakdownVoltage = fabs(model->VDMOSbv); - - 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->VDMOSname, cbv); - SPfrontEnd->IFerrorf(ERR_WARNING, - "incompatibility with specified saturation current"); -#endif - xbv = tBreakdownVoltage; - } - else { - tol = ckt->CKTreltol*cbv; - xbv = tBreakdownVoltage - model->VDIObrkdEmissionCoeff*vt*log(1 + cbv / - (here->VDIOtSatCur)); - iter = 0; - for (iter = 0; iter < 25; iter++) { - xbv = tBreakdownVoltage - model->VDIObrkdEmissionCoeff*vt*log(cbv / - (here->VDIOtSatCur) + 1 - xbv / vt); - xcbv = here->VDIOtSatCur * - (exp((tBreakdownVoltage - xbv) / (model->VDIObrkdEmissionCoeff*vt)) - 1 + xbv / vt); - 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->VDMOSname, xbv, xcbv); -#endif - } - matched: - here->VDIOtBrkdwnV = xbv; - } - - /* transit time temperature adjust */ - factor = 1.0 + (model->VDIOtranTimeTemp1 * dt) - + (model->VDIOtranTimeTemp2 * dt * dt); - here->VDIOtTransitTime = model->VDIOtransitTime * factor; - - /* Series resistance temperature adjust */ - here->VDIOtConductance = here->VDIOconductance / (1.0 + (model->VDMOStrb1 * dt) + (model->VDMOStrb2 * dt * dt)); - - here->VDIOtF2 = exp((1 + here->VDIOtGradingCoeff)*xfc); - here->VDIOtF3 = 1 - model->VDIOdepletionCapCoeff* - (1 + here->VDIOtGradingCoeff); - } + /* limit junction potential to max of 1/FC */ + if (here->VDIOtDepCap > 2.5) { + here->VDIOtJctPot = 2.5 / model->VDIOn; + here->VDIOtDepCap = model->VDIOn*here->VDIOtJctPot; + SPfrontEnd->IFerrorf(ERR_WARNING, + "%s: junction potential VJ too large, limited to %f", + model->VDMOSmodName, here->VDIOtJctPot); } + + /* and now to compute the breakdown voltage, again, using + * temperature adjusted basic parameters */ + if (model->VDIObvGiven) { + /* tlev == 0 */ + tBreakdownVoltage = fabs(model->VDIObv); + + cbv = model->VDIOibv; + + 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->VDMOSname, cbv); + SPfrontEnd->IFerrorf(ERR_WARNING, + "incompatibility with specified saturation current"); +#endif + xbv = tBreakdownVoltage; + } + else { + tol = ckt->CKTreltol*cbv; + xbv = tBreakdownVoltage - model->VDIObrkdEmissionCoeff*vt*log(1 + cbv / + (here->VDIOtSatCur)); + iter = 0; + for (iter = 0; iter < 25; iter++) { + xbv = tBreakdownVoltage - model->VDIObrkdEmissionCoeff*vt*log(cbv / + (here->VDIOtSatCur) + 1 - xbv / vt); + xcbv = here->VDIOtSatCur * + (exp((tBreakdownVoltage - xbv) / (model->VDIObrkdEmissionCoeff*vt)) - 1 + xbv / vt); + 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->VDMOSname, xbv, xcbv); +#endif + } + matched: + here->VDIOtBrkdwnV = xbv; + } + + /* transit time temperature adjust */ + factor = 1.0 + (model->VDIOtranTimeTemp1 * dt) + + (model->VDIOtranTimeTemp2 * dt * dt); + here->VDIOtTransitTime = model->VDIOtransitTime * factor; + + /* Series resistance temperature adjust */ + factor = 1.0 + (model->VDIOtrb1) * dt + + (model->VDIOtrb2 * dt * dt); + here->VDIOtConductance = here->VDIOconductance / factor; + here->VDIOtConductance_dT = -here->VDIOconductance * (model->VDIOtrb1 + model->VDIOtrb2 * dt) / (factor*factor); + + here->VDIOtF2 = exp((1 + here->VDIOtGradingCoeff)*xfc); + here->VDIOtF3 = 1 - model->VDIOdepletionCapCoeff* + (1 + here->VDIOtGradingCoeff); +} + +int +VDMOStemp(GENmodel *inModel, CKTcircuit *ckt) +{ + VDMOSmodel *model = (VDMOSmodel*)inModel; + VDMOSinstance *here; + + /* loop through all the vdmos models */ + for( ; model != NULL; model = VDMOSnextModel(model)) { + + /* loop through all the instances */ + for(here=VDMOSinstances(model);here;here=VDMOSnextInstance(here)) { + + if(!here->VDMOSdtempGiven) here->VDMOSdtemp = 0.0; + + if(!here->VDMOStempGiven) + here->VDMOStemp = ckt->CKTtemp + here->VDMOSdtemp; + + VDMOStempUpdate(model, here, here->VDMOStemp, ckt); + + } /* instance */ + + } /* model */ return(OK); } diff --git a/src/spicelib/devices/vdmos/vdmostrun.c b/src/spicelib/devices/vdmos/vdmostrun.c index d6886ba73..1b35dfffe 100644 --- a/src/spicelib/devices/vdmos/vdmostrun.c +++ b/src/spicelib/devices/vdmos/vdmostrun.c @@ -23,6 +23,7 @@ VDMOStrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep) CKTterr(here->VDMOSqgs,ckt,timeStep); CKTterr(here->VDMOSqgd,ckt,timeStep); + CKTterr(here->VDIOcapCharge,ckt,timeStep); } } return(OK);