From 280bea9d5096a91509e16ca6113f69c94ab2b9e8 Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 23 Jun 2020 17:27:26 +0200 Subject: [PATCH] restructering thermal update by unified function introduce diode series resistor thermal contribution separate naming of mos and diode model parameter --- src/spicelib/devices/vdmos/vdmos.c | 30 +-- src/spicelib/devices/vdmos/vdmosdefs.h | 75 +++--- src/spicelib/devices/vdmos/vdmosload.c | 75 +++--- src/spicelib/devices/vdmos/vdmosmask.c | 44 ++-- src/spicelib/devices/vdmos/vdmosmpar.c | 58 ++--- src/spicelib/devices/vdmos/vdmosset.c | 109 +++++--- src/spicelib/devices/vdmos/vdmostemp.c | 336 ++++++++++++------------- 7 files changed, 376 insertions(+), 351 deletions(-) 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 a388b242a..56b6ae769 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 @@ -233,6 +234,8 @@ typedef struct sVDMOSinstance { double *VDMOSTempdPtr; double *VDIOPosPrimetempPtr; 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 2f324129e..927aee292 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -14,6 +14,8 @@ VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning #include "ngspice/sperror.h" #include "ngspice/suffix.h" +void VDMOStempUpdate(VDMOSmodel *inModel, VDMOSinstance *here, double Temp, CKTcircuit *ckt); + int VDMOSload(GENmodel *inModel, CKTcircuit *ckt) /* actually load the current value into the @@ -279,7 +281,12 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) } - 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 */ @@ -665,14 +672,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 @@ -684,7 +692,7 @@ bypass: gspr = here->VDIOtConductance; vt = CONSTKoverQ * Temp; - vte = model->VDMOSn * vt; + vte = model->VDIOn * vt; vtebrk = model->VDIObrkdEmissionCoeff * vt; vbrknp = here->VDIOtBrkdwnV; @@ -751,7 +759,7 @@ bypass: /* * limit new junction voltage */ - if ((model->VDMOSbvGiven) && + if ((model->VDIObvGiven) && (vd < MIN(0, -vbrknp + 10 * vtebrk))) { double vdtemp; vdtemp = -(vd + vbrknp); @@ -766,19 +774,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 */ @@ -786,27 +781,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; } @@ -888,9 +883,18 @@ bypass: load: #endif 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 @@ -904,9 +908,10 @@ load: *(ckt->CKTrhs + here->VDIOposPrimeNode) += cdeq; } if (selfheat) { - *(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp; + *(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrs_dT*delTemp; *(ckt->CKTrhs + here->VDMOSdNode) += -dIdio_dT*delTemp; - *(ckt->CKTrhs + here->VDMOStempNode) += Ith - model->VDMOStype*dIth_dVdio*vd - dIth_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 @@ -919,10 +924,12 @@ load: *(here->VDIORPsPtr) -= gspr; *(here->VDIORPdPtr) -= gd; if (selfheat) { - (*(here->VDIOTempposPrimePtr) += -dIth_dVdio); + (*(here->VDMOStempSPtr) += -dIth_dVrs); + (*(here->VDIOTempposPrimePtr) += -dIth_dVdio + dIth_dVrs); (*(here->VDMOSTempdPtr) += dIth_dVdio); (*(here->VDMOSTemptempPtr) += -dIth_dT); - (*(here->VDIOPosPrimetempPtr) += dIdio_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 ee5bc94cd..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,30 +400,6 @@ 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(VDMOSTempdPtr, VDMOStempNode, VDMOSdNode); - TSTALLOC(VDIOPosPrimetempPtr, VDIOposPrimeNode, VDMOStempNode); - TSTALLOC(VDMOSDtempPtr, 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); @@ -409,7 +417,7 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(VDMOSSPsPtr, VDMOSsNodePrime, VDMOSsNode); TSTALLOC(VDMOSSPdpPtr, VDMOSsNodePrime, VDMOSdNodePrime); - TSTALLOC(VDMOSGgpPtr, VDMOSgNode, VDMOSgNodePrime); + TSTALLOC(VDMOSGgpPtr, VDMOSgNode, VDMOSgNodePrime); TSTALLOC(VDMOSGPgPtr, VDMOSgNodePrime, VDMOSgNode); TSTALLOC(VDMOSDsPtr, VDMOSdNode, VDMOSsNode); @@ -420,6 +428,33 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ 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); }