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