rebase old dio_rev_rec branch
This commit is contained in:
parent
2a942a2161
commit
64a433ebaa
|
|
@ -16,7 +16,6 @@ IFparm DIOpTable[] = { /* parameters */
|
|||
IOPAU("ic", DIO_IC, IF_REAL, "Initial device voltage"),
|
||||
IOPU("area", DIO_AREA, IF_REAL, "Area factor"),
|
||||
IOPU("pj", DIO_PJ, IF_REAL, "Perimeter factor"),
|
||||
IOPUR("perim", DIO_PJ, IF_REAL, "Perimeter factor"),
|
||||
IOPU("w", DIO_W, IF_REAL, "Diode width"),
|
||||
IOPU("l", DIO_L, IF_REAL, "Diode length"),
|
||||
IOPU("m", DIO_M, IF_REAL, "Multiplier"),
|
||||
|
|
@ -50,7 +49,6 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
IOP( "is", DIO_MOD_IS, IF_REAL, "Saturation current"),
|
||||
IOPR( "js", DIO_MOD_IS, IF_REAL, "Saturation current"),
|
||||
IOP( "jsw", DIO_MOD_JSW, IF_REAL, "Sidewall Saturation current"),
|
||||
IOPR( "isw", DIO_MOD_JSW, IF_REAL, "Sidewall Saturation current"),
|
||||
|
||||
IOPU( "tnom",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"),
|
||||
IOPUR("tref",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"),
|
||||
|
|
@ -75,21 +73,17 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
IOP( "cjp", DIO_MOD_CJSW, IF_REAL, "Sidewall junction capacitance"),
|
||||
IOPR( "cjsw", DIO_MOD_CJSW, IF_REAL, "Sidewall junction capacitance"),
|
||||
IOP( "php", DIO_MOD_VJSW, IF_REAL, "Sidewall junction potential"),
|
||||
IOPR( "vjsw", DIO_MOD_VJSW, IF_REAL, "Sidewall junction potential"),
|
||||
IOP( "mjsw", DIO_MOD_MJSW, IF_REAL, "Sidewall Grading coefficient"),
|
||||
IOP( "ikf", DIO_MOD_IKF, IF_REAL, "Forward Knee current"),
|
||||
IOPR( "ik", DIO_MOD_IKF, IF_REAL, "Forward Knee current"),
|
||||
IOP( "ikr", DIO_MOD_IKR, IF_REAL, "Reverse Knee current"),
|
||||
IOP( "nbv", DIO_MOD_NBV, IF_REAL, "Breakdown Emission Coefficient"),
|
||||
IOPR( "nz", DIO_MOD_NBV, IF_REAL, "Breakdown Emission Coefficient"),
|
||||
IOP("area", DIO_MOD_AREA, IF_REAL, "Area factor"),
|
||||
IOP( "pj", DIO_MOD_PJ, IF_REAL, "Perimeter factor"),
|
||||
|
||||
IOP( "tlev", DIO_MOD_TLEV, IF_INTEGER, "Diode temperature equation selector"),
|
||||
IOP( "tlevc", DIO_MOD_TLEVC, IF_INTEGER, "Diode temperature equation selector"),
|
||||
IOP( "eg", DIO_MOD_EG, IF_REAL, "Activation energy"),
|
||||
IOP( "gap1", DIO_MOD_GAP1, IF_REAL, "First bandgap correction factor"),
|
||||
IOP( "gap2", DIO_MOD_GAP2, IF_REAL, "Second bandgap correction factor"),
|
||||
IOP( "xti", DIO_MOD_XTI, IF_REAL, "Saturation current temperature exp."),
|
||||
IOP( "cta", DIO_MOD_CTA, IF_REAL, "Area junction temperature coefficient"),
|
||||
IOPR( "ctc", DIO_MOD_CTA, IF_REAL, "Area junction capacitance temperature coefficient"),
|
||||
|
|
@ -110,16 +104,13 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
IOP( "fc", DIO_MOD_FC, IF_REAL, "Forward bias junction fit parameter"),
|
||||
IOP( "fcs", DIO_MOD_FCS, IF_REAL, "Forward bias sidewall junction fit parameter"),
|
||||
IOP( "bv", DIO_MOD_BV, IF_REAL, "Reverse breakdown voltage"),
|
||||
IOPR( "vb", DIO_MOD_BV, IF_REAL, "Reverse breakdown voltage (level=3)"),
|
||||
IOPR( "vrb", DIO_MOD_BV, IF_REAL, "Reverse breakdown voltage (level=3)"),
|
||||
IOPR( "var", DIO_MOD_BV, IF_REAL, "Reverse breakdown voltage (level=3)"),
|
||||
IOP( "ibv", DIO_MOD_IBV, IF_REAL, "Current at reverse breakdown voltage"),
|
||||
IOPR( "ib", DIO_MOD_IBV, IF_REAL, "Current at reverse breakdown voltage"),
|
||||
IOP( "tcv", DIO_MOD_TCV, IF_REAL, "Reverse breakdown voltage temperature coefficient"),
|
||||
IOPR("tbv1", DIO_MOD_TCV, IF_REAL, "Reverse breakdown voltage temperature coefficient"),
|
||||
OPU( "cond", DIO_MOD_COND,IF_REAL, "Ohmic conductance"),
|
||||
IOP( "isr", DIO_MOD_ISR, IF_REAL, "Recombination saturation current"),
|
||||
IOP( "nr", DIO_MOD_NR, IF_REAL, "Recombination current emission coefficient"),
|
||||
IOP( "vp", DIO_MOD_VP, IF_REAL, "Soft reverse recovery parameter"),
|
||||
|
||||
/* SOA parameters */
|
||||
IOP( "fv_max", DIO_MOD_FV_MAX, IF_REAL, "maximum voltage in forward direction"),
|
||||
|
|
@ -140,7 +131,6 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
IOP( "xoi", DIO_MOD_XOI, IF_REAL, "Thickness of the polysilicon to bulk oxide (level=3)"),
|
||||
IOP( "xm", DIO_MOD_XM, IF_REAL, "Masking and etching effects in metal (level=3)"),
|
||||
IOP( "xp", DIO_MOD_XP, IF_REAL, "Masking and etching effects in polysilicon (level=3)"),
|
||||
IOP( "xw", DIO_MOD_XW, IF_REAL, "Masking and etching effects (level=3)"),
|
||||
|
||||
IP( "d", DIO_MOD_D, IF_FLAG, "Diode model")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,19 +41,19 @@ typedef struct sDIOinstance {
|
|||
const int DIOtempNode; /* number of the temperature node of the diode */
|
||||
int DIOposPrimeNode; /* number of positive prime node of diode */
|
||||
|
||||
double *DIOposPosPrimePtr; /* pointer to sparse matrix at
|
||||
double *DIOposPosPrimePtr; /* pointer to sparse matrix at
|
||||
* (positive,positive prime) */
|
||||
double *DIOnegPosPrimePtr; /* pointer to sparse matrix at
|
||||
double *DIOnegPosPrimePtr; /* pointer to sparse matrix at
|
||||
* (negative,positive prime) */
|
||||
double *DIOposPrimePosPtr; /* pointer to sparse matrix at
|
||||
double *DIOposPrimePosPtr; /* pointer to sparse matrix at
|
||||
* (positive prime,positive) */
|
||||
double *DIOposPrimeNegPtr; /* pointer to sparse matrix at
|
||||
double *DIOposPrimeNegPtr; /* pointer to sparse matrix at
|
||||
* (positive prime,negative) */
|
||||
double *DIOposPosPtr; /* pointer to sparse matrix at
|
||||
double *DIOposPosPtr; /* pointer to sparse matrix at
|
||||
* (positive,positive) */
|
||||
double *DIOnegNegPtr; /* pointer to sparse matrix at
|
||||
double *DIOnegNegPtr; /* pointer to sparse matrix at
|
||||
* (negative,negative) */
|
||||
double *DIOposPrimePosPrimePtr; /* pointer to sparse matrix at
|
||||
double *DIOposPrimePosPrimePtr; /* pointer to sparse matrix at
|
||||
* (positive prime,positive prime) */
|
||||
|
||||
/* self heating */
|
||||
|
|
@ -131,7 +131,7 @@ typedef struct sDIOinstance {
|
|||
double DIOtVcrit; /* temperature adjusted V crit */
|
||||
double DIOtF1; /* temperature adjusted f1 */
|
||||
double DIOtBrkdwnV; /* temperature adjusted breakdown voltage */
|
||||
|
||||
|
||||
double DIOtF2; /* coeff. for capacitance equation precomputation */
|
||||
double DIOtF3; /* coeff. for capacitance equation precomputation */
|
||||
double DIOtF2SW; /* coeff. for capacitance equation precomputation */
|
||||
|
|
@ -210,7 +210,7 @@ typedef struct sDIOinstance {
|
|||
|
||||
#define DIOsenGeq DIOsens /* stores the perturbed values of geq */
|
||||
#define DIOsenCeq DIOsens + 3 /* stores the perturbed values of ceq */
|
||||
#define DIOdphidp DIOsens + 6
|
||||
#define DIOdphidp DIOsens + 6
|
||||
|
||||
|
||||
#define DIOvoltage DIOstate
|
||||
|
|
@ -218,16 +218,21 @@ typedef struct sDIOinstance {
|
|||
#define DIOconduct DIOstate+2
|
||||
#define DIOcapCharge DIOstate+3
|
||||
#define DIOcapCurrent DIOstate+4
|
||||
#define DIOdiffCharge DIOstate+5
|
||||
#define DIOdiffCurrent DIOstate+6
|
||||
#define DIOdiffCap DIOstate+7
|
||||
#define DIOoldCurr DIOstate+8
|
||||
#define DIOoldCond DIOstate+9
|
||||
|
||||
#define DIOqth DIOstate+5 /* thermal capacitor charge */
|
||||
#define DIOcqth DIOstate+6 /* thermal capacitor current */
|
||||
#define DIOqth DIOstate+10 /* thermal capacitor charge */
|
||||
#define DIOcqth DIOstate+11 /* thermal capacitor current */
|
||||
|
||||
#define DIOdeltemp DIOstate+7 /* thermal voltage over rth0 */
|
||||
#define DIOdIdio_dT DIOstate+8
|
||||
#define DIOdeltemp DIOstate+12 /* thermal voltage over rth0 */
|
||||
#define DIOdIdio_dT DIOstate+13
|
||||
|
||||
#define DIOnumStates 9
|
||||
#define DIOnumStates 14
|
||||
|
||||
#define DIOsensxp DIOstate+9 /* charge sensitivities and their derivatives.
|
||||
#define DIOsensxp DIOstate+14 /* charge sensitivities and their derivatives.
|
||||
* +10 for the derivatives - pointer to the
|
||||
* beginning of the array */
|
||||
|
||||
|
|
@ -272,8 +277,6 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
unsigned DIOtlevGiven : 1;
|
||||
unsigned DIOtlevcGiven : 1;
|
||||
unsigned DIOactivationEnergyGiven : 1;
|
||||
unsigned DIOfirstBGcorrFactorGiven : 1;
|
||||
unsigned DIOsecndBGcorrFactorGiven : 1;
|
||||
unsigned DIOsaturationCurrentExpGiven : 1;
|
||||
unsigned DIOctaGiven : 1;
|
||||
unsigned DIOctpGiven : 1;
|
||||
|
|
@ -302,6 +305,7 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
unsigned DIOte_maxGiven : 1;
|
||||
unsigned DIOrecSatCurGiven : 1;
|
||||
unsigned DIOrecEmissionCoeffGiven : 1;
|
||||
unsigned DIOsoftRevRecParamGiven : 1;
|
||||
|
||||
unsigned DIOrth0Given :1;
|
||||
unsigned DIOcth0Given :1;
|
||||
|
|
@ -314,13 +318,12 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
unsigned DIOpolyOxideThickGiven : 1; /* Thickness of the polysilicon to bulk oxide (level=3) */
|
||||
unsigned DIOmetalMaskOffsetGiven : 1; /* Masking and etching effects in metal (level=3)") */
|
||||
unsigned DIOpolyMaskOffsetGiven : 1; /* Masking and etching effects in polysilicon (level=3) */
|
||||
unsigned DIOmaskOffsetGiven : 1; /* Masking and etching effects (level=3) */
|
||||
|
||||
int DIOlevel; /* level selector */
|
||||
double DIOsatCur; /* saturation current */
|
||||
double DIOsatSWCur; /* Sidewall saturation current */
|
||||
|
||||
double DIOresist; /* ohmic series resistance */
|
||||
double DIOresist; /* ohmic series resistance */
|
||||
double DIOresistTemp1; /* series resistance 1st order temp. coeff. */
|
||||
double DIOresistTemp2; /* series resistance 2nd order temp. coeff. */
|
||||
double DIOconductance; /* conductance corresponding to ohmic R */
|
||||
|
|
@ -344,8 +347,6 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
int DIOtlev; /* Diode temperature equation selector */
|
||||
int DIOtlevc; /* Diode temperature equation selector */
|
||||
double DIOactivationEnergy; /* activation energy (EG) */
|
||||
double DIOfirstBGcorrFactor; /* First bandgap correction factor */
|
||||
double DIOsecndBGcorrFactor; /* Second bandgap correction factor */
|
||||
double DIOsaturationCurrentExp; /* Saturation current exponential (XTI) */
|
||||
double DIOcta; /* Area junction temperature coefficient */
|
||||
double DIOctp; /* Perimeter junction temperature coefficient */
|
||||
|
|
@ -375,6 +376,7 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
double DIOte_max; /* maximum temperature */
|
||||
double DIOrecSatCur; /* Recombination saturation current */
|
||||
double DIOrecEmissionCoeff; /* Recombination emission coefficient */
|
||||
double DIOsoftRevRecParam; /* Soft reverse recovery parameter */
|
||||
|
||||
double DIOrth0;
|
||||
double DIOcth0;
|
||||
|
|
@ -387,7 +389,6 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
double DIOpolyOxideThick; /* Thickness of the polysilicon to bulk oxide (level=3) */
|
||||
double DIOmetalMaskOffset; /* Masking and etching effects in metal (level=3)") */
|
||||
double DIOpolyMaskOffset; /* Masking and etching effects in polysilicon (level=3) */
|
||||
double DIOmaskOffset; /* Masking and etching effects (level=3) */
|
||||
|
||||
} DIOmodel;
|
||||
|
||||
|
|
@ -434,8 +435,6 @@ enum {
|
|||
DIO_MOD_VJ,
|
||||
DIO_MOD_M,
|
||||
DIO_MOD_EG,
|
||||
DIO_MOD_GAP1,
|
||||
DIO_MOD_GAP2,
|
||||
DIO_MOD_XTI,
|
||||
DIO_MOD_FC,
|
||||
DIO_MOD_BV,
|
||||
|
|
@ -481,6 +480,7 @@ enum {
|
|||
DIO_MOD_PD_MAX,
|
||||
DIO_MOD_ISR,
|
||||
DIO_MOD_NR,
|
||||
DIO_MOD_VP,
|
||||
DIO_MOD_RTH0,
|
||||
DIO_MOD_CTH0,
|
||||
|
||||
|
|
@ -492,7 +492,6 @@ enum {
|
|||
DIO_MOD_XOI,
|
||||
DIO_MOD_XM,
|
||||
DIO_MOD_XP,
|
||||
DIO_MOD_XW,
|
||||
};
|
||||
|
||||
void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit *ckt);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ DIOdSetup(DIOmodel *model, CKTcircuit *ckt)
|
|||
* This is an old analysis anyway....
|
||||
*/
|
||||
|
||||
csat=here->DIOtSatCur+here->DIOtSatSWCur; // area and multiplier are already counted in tSatCur and tSatSWCur
|
||||
csat=(here->DIOtSatCur*here->DIOarea+here->DIOtSatSWCur*here->DIOpj)*here->DIOm;
|
||||
vt = CONSTKoverQ * here->DIOtemp;
|
||||
vte=model->DIOemissionCoeff * vt;
|
||||
vd = *(ckt->CKTrhsOld + (here->DIOposPrimeNode)) -
|
||||
|
|
@ -113,7 +113,7 @@ DIOdSetup(DIOmodel *model, CKTcircuit *ckt)
|
|||
/*
|
||||
* junction charge storage elements
|
||||
*/
|
||||
czero=here->DIOtJctCap; // area and multiplier are already counted in DIOtJctCap
|
||||
czero=here->DIOtJctCap*here->DIOarea*here->DIOm;
|
||||
if (czero != 0.0) {
|
||||
if (vd < here->DIOtDepCap){
|
||||
arg=1-vd/model->DIOjunctionPot;
|
||||
|
|
@ -143,7 +143,7 @@ DIOdSetup(DIOmodel *model, CKTcircuit *ckt)
|
|||
{
|
||||
cjunc1 = cjunc2 = cjunc3 = 0.0;
|
||||
}
|
||||
czeroSW=+here->DIOtJctSWCap; // pj and multiplier are already counted in DIOtJctSWCap
|
||||
czeroSW=+here->DIOtJctSWCap*here->DIOpj*here->DIOm;
|
||||
if (czeroSW != 0.0) {
|
||||
if (vd < here->DIOtDepCap){
|
||||
arg=1-vd/model->DIOjunctionSWPot;
|
||||
|
|
|
|||
|
|
@ -27,8 +27,3 @@ extern int DIOnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*);
|
|||
extern int DIOdSetup(DIOmodel*,CKTcircuit*);
|
||||
extern int DIOsoaCheck(CKTcircuit *, GENmodel *);
|
||||
|
||||
#ifdef KLU
|
||||
extern int DIObindCSC (GENmodel*, CKTcircuit*) ;
|
||||
extern int DIObindCSCComplex (GENmodel*, CKTcircuit*) ;
|
||||
extern int DIObindCSCComplexToReal (GENmodel*, CKTcircuit*) ;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -67,12 +67,6 @@ SPICEdev DIOinfo = {
|
|||
.DEVdump = NULL,
|
||||
.DEVacct = NULL,
|
||||
#endif
|
||||
|
||||
#ifdef KLU
|
||||
.DEVbindCSC = DIObindCSC,
|
||||
.DEVbindCSCComplex = DIObindCSCComplex,
|
||||
.DEVbindCSCComplexToReal = DIObindCSCComplexToReal,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,30 +23,19 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
DIOmodel *model = (DIOmodel*)inModel;
|
||||
DIOinstance *here;
|
||||
double arg;
|
||||
double argsw;
|
||||
double capd;
|
||||
double cd, cdb, cdsw, cdb_dT, cdsw_dT;
|
||||
double cd;
|
||||
double cdeq;
|
||||
double cdhat;
|
||||
double ceq;
|
||||
double csat; /* area-scaled saturation current */
|
||||
double csatsw; /* perimeter-scaled saturation current */
|
||||
double czero;
|
||||
double czof2;
|
||||
double argSW;
|
||||
double czeroSW;
|
||||
double czof2SW;
|
||||
double sargSW;
|
||||
double sqrt_ikr;
|
||||
double sqrt_ikf;
|
||||
double ikf_area_m;
|
||||
double ikr_area_m;
|
||||
|
||||
double delvd; /* change in diode voltage temporary */
|
||||
double evd;
|
||||
double evrev;
|
||||
double gd, gdb, gdsw, gen_fac, gen_fac_vd;
|
||||
double t1, evd_rec, cdb_rec, gdb_rec, cdb_rec_dT;
|
||||
double gd;
|
||||
double geq;
|
||||
double gspr; /* area-scaled conductance */
|
||||
double sarg;
|
||||
|
|
@ -56,16 +45,13 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double vd; /* current diode voltage */
|
||||
double vdtemp;
|
||||
double vt; /* K t / Q */
|
||||
double vte, vtesw, vtetun, vtebrk;
|
||||
int Check_dio=0, Check_th;
|
||||
double vte, vtebrk;
|
||||
int Check=0;
|
||||
int error;
|
||||
int SenCond=0; /* sensitivity condition */
|
||||
double diffcharge, deplcharge, deplchargeSW, diffcap, deplcap, deplcapSW;
|
||||
|
||||
double deldelTemp, delTemp, Temp;
|
||||
double ceqqth=0.0, Ith=0.0, gcTt=0.0, vrs=0.0;
|
||||
double dIdio_dT, dIth_dVdio=0.0, dIrs_dT=0.0, dIth_dVrs=0.0, dIth_dT=0.0;
|
||||
double argsw_dT, csat_dT, csatsw_dT;
|
||||
double diffcharge, deplcharge, diffcap, deplcap;
|
||||
double tt;
|
||||
double vp;
|
||||
|
||||
/* loop through all the diode models */
|
||||
for( ; model != NULL; model = DIOnextModel(model)) {
|
||||
|
|
@ -74,17 +60,10 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
for (here = DIOinstances(model); here != NULL ;
|
||||
here=DIOnextInstance(here)) {
|
||||
|
||||
int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given));
|
||||
|
||||
/*
|
||||
* this routine loads diodes for dc and transient analyses.
|
||||
*/
|
||||
|
||||
if (selfheat)
|
||||
Check_th = 1;
|
||||
else
|
||||
Check_th = 0;
|
||||
|
||||
if(ckt->CKTsenInfo){
|
||||
if((ckt->CKTsenInfo->SENstatus == PERTURBATION)
|
||||
&& (here->DIOsenPertFlag == OFF))continue;
|
||||
|
|
@ -95,14 +74,13 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
#endif /* SENSDEBUG */
|
||||
|
||||
}
|
||||
cdsw = 0.0;
|
||||
cdsw_dT = 0.0;
|
||||
gdsw = 0.0;
|
||||
delTemp = 0.0;
|
||||
csat = here->DIOtSatCur;
|
||||
gspr = here->DIOtConductance;
|
||||
vt = CONSTKoverQ * here->DIOtemp;
|
||||
vte = model->DIOemissionCoeff * vt;
|
||||
vtebrk = model->DIObrkdEmissionCoeff * vt;
|
||||
gspr = here->DIOtConductance;
|
||||
tt = here->DIOtTransitTime;
|
||||
vp = model->DIOsoftRevRecParam;
|
||||
/*
|
||||
* initialization
|
||||
*/
|
||||
|
|
@ -116,10 +94,8 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
if((ckt->CKTsenInfo->SENmode == TRANSEN)&&
|
||||
(ckt->CKTmode & MODEINITTRAN)) {
|
||||
vd = *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
} else{
|
||||
vd = *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
}
|
||||
|
||||
#ifdef SENSDEBUG
|
||||
|
|
@ -128,25 +104,20 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
goto next1;
|
||||
}
|
||||
|
||||
Check_dio=1;
|
||||
Check=1;
|
||||
if(ckt->CKTmode & MODEINITSMSIG) {
|
||||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
} else if (ckt->CKTmode & MODEINITTRAN) {
|
||||
vd= *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) &&
|
||||
(ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) {
|
||||
vd=here->DIOinitCond;
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) {
|
||||
vd=0;
|
||||
delTemp = 0.0;
|
||||
} else if ( ckt->CKTmode & MODEINITJCT) {
|
||||
vd=here->DIOtVcrit;
|
||||
delTemp = 0.0;
|
||||
} else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) {
|
||||
vd=0;
|
||||
delTemp = 0.0;
|
||||
} else {
|
||||
#ifndef PREDICTOR
|
||||
if (ckt->CKTmode & MODEINITPRED) {
|
||||
|
|
@ -157,34 +128,16 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(ckt->CKTstate1 + here->DIOcurrent);
|
||||
*(ckt->CKTstate0 + here->DIOconduct) =
|
||||
*(ckt->CKTstate1 + here->DIOconduct);
|
||||
*(ckt->CKTstate0 + here->DIOdeltemp) =
|
||||
*(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
delTemp = DEVpred(ckt,here->DIOdeltemp);
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) =
|
||||
*(ckt->CKTstate1 + here->DIOdIdio_dT);
|
||||
*(ckt->CKTstate0+here->DIOqth) =
|
||||
*(ckt->CKTstate1+here->DIOqth);
|
||||
} else {
|
||||
#endif /* PREDICTOR */
|
||||
vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->DIOnegNode);
|
||||
if (selfheat)
|
||||
delTemp = *(ckt->CKTrhsOld + here->DIOtempNode);
|
||||
else
|
||||
delTemp = 0.0;
|
||||
*(ckt->CKTstate0+here->DIOqth) = model->DIOcth0 * delTemp;
|
||||
if((ckt->CKTmode & MODEINITTRAN)) {
|
||||
*(ckt->CKTstate1+here->DIOqth) =
|
||||
*(ckt->CKTstate0+here->DIOqth);
|
||||
}
|
||||
#ifndef PREDICTOR
|
||||
}
|
||||
#endif /* PREDICTOR */
|
||||
delvd=vd- *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
deldelTemp = delTemp - *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
cdhat= *(ckt->CKTstate0 + here->DIOcurrent) +
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd +
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd;
|
||||
/*
|
||||
* bypass if solution has not changed
|
||||
*/
|
||||
|
|
@ -198,17 +151,10 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
ckt->CKTabstol;
|
||||
if (fabs(cdhat- *(ckt->CKTstate0 + here->DIOcurrent))
|
||||
< tol) {
|
||||
if ((here->DIOtempNode == 0) ||
|
||||
(fabs(deldelTemp) < (ckt->CKTreltol * MAX(fabs(delTemp),
|
||||
fabs(*(ckt->CKTstate0+here->DIOdeltemp)))+
|
||||
ckt->CKTvoltTol*1e4))) {
|
||||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
cd= *(ckt->CKTstate0 + here->DIOcurrent);
|
||||
gd= *(ckt->CKTstate0 + here->DIOconduct);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
dIdio_dT= *(ckt->CKTstate0 + here->DIOdIdio_dT);
|
||||
goto load;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -222,192 +168,62 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
vdtemp = DEVpnjlim(vdtemp,
|
||||
-(*(ckt->CKTstate0 + here->DIOvoltage) +
|
||||
here->DIOtBrkdwnV),vtebrk,
|
||||
here->DIOtVcrit,&Check_dio);
|
||||
here->DIOtVcrit,&Check);
|
||||
vd = -(vdtemp+here->DIOtBrkdwnV);
|
||||
} else {
|
||||
vd = DEVpnjlim(vd,*(ckt->CKTstate0 + here->DIOvoltage),
|
||||
vte,here->DIOtVcrit,&Check_dio);
|
||||
vte,here->DIOtVcrit,&Check);
|
||||
}
|
||||
if (selfheat)
|
||||
delTemp = DEVlimitlog(delTemp,
|
||||
*(ckt->CKTstate0 + here->DIOdeltemp), 100, &Check_th);
|
||||
else
|
||||
delTemp = 0.0;
|
||||
}
|
||||
/*
|
||||
* compute dc current and derivitives
|
||||
*/
|
||||
next1:
|
||||
if (selfheat) {
|
||||
Temp = here->DIOtemp + delTemp;
|
||||
DIOtempUpdate(model, here, Temp, ckt);
|
||||
vt = CONSTKoverQ * Temp;
|
||||
vte = model->DIOemissionCoeff * vt;
|
||||
vtebrk = model->DIObrkdEmissionCoeff * vt;
|
||||
next1:
|
||||
|
||||
if (vd >= -3*vte) {
|
||||
|
||||
evd = exp(vd/vte);
|
||||
cd = csat*(evd-1);
|
||||
gd = csat*evd/vte;
|
||||
|
||||
} else if((!(model->DIObreakdownVoltageGiven)) ||
|
||||
vd >= -here->DIOtBrkdwnV) {
|
||||
|
||||
arg = 3*vte/(vd*CONSTe);
|
||||
arg = arg * arg * arg;
|
||||
cd = -csat*(1+arg);
|
||||
gd = csat*3*arg/vd;
|
||||
|
||||
} else {
|
||||
Temp = here->DIOtemp;
|
||||
}
|
||||
|
||||
csat = here->DIOtSatCur;
|
||||
csat_dT = here->DIOtSatCur_dT;
|
||||
csatsw = here->DIOtSatSWCur;
|
||||
csatsw_dT = here->DIOtSatSWCur_dT;
|
||||
gspr = here->DIOtConductance;
|
||||
|
||||
if (model->DIOsatSWCurGiven) { /* sidewall current */
|
||||
|
||||
if (model->DIOswEmissionCoeffGiven) { /* current with own characteristic */
|
||||
|
||||
vtesw = model->DIOswEmissionCoeff * vt;
|
||||
|
||||
if (vd >= -3*vtesw) { /* forward */
|
||||
|
||||
evd = exp(vd/vtesw);
|
||||
cdsw = csatsw*(evd-1);
|
||||
gdsw = csatsw*evd/vtesw;
|
||||
cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vd * evd / (vtesw * Temp);
|
||||
|
||||
} else if((!(model->DIObreakdownVoltageGiven)) ||
|
||||
vd >= -here->DIOtBrkdwnV) { /* reverse */
|
||||
|
||||
argsw = 3*vtesw/(vd*CONSTe);
|
||||
argsw = argsw * argsw * argsw;
|
||||
argsw_dT = 3 * argsw / Temp;
|
||||
cdsw = -csatsw*(1+argsw);
|
||||
gdsw = csatsw*3*argsw/vd;
|
||||
cdsw_dT = -csatsw_dT - (csatsw_dT*argsw + csatsw*argsw_dT);
|
||||
|
||||
} else { /* breakdown */
|
||||
double evrev_dT;
|
||||
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk);
|
||||
evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp);
|
||||
cdsw = -csatsw*evrev;
|
||||
gdsw = csatsw*evrev/vtebrk;
|
||||
cdsw_dT = -(csatsw_dT*evrev + csatsw*evrev_dT);
|
||||
|
||||
}
|
||||
|
||||
} else { /* merge saturation currents and use same characteristic as bottom diode */
|
||||
|
||||
csat = csat + csatsw;
|
||||
csat_dT = csat_dT + csatsw_dT;
|
||||
cdsw_dT = 0.0;
|
||||
|
||||
}
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk);
|
||||
cd = -csat*evrev;
|
||||
gd = csat*evrev/vtebrk;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* temperature dependent diode saturation current and derivative
|
||||
*/
|
||||
|
||||
if (vd >= -3*vte) { /* bottom current forward */
|
||||
|
||||
evd = exp(vd/vte);
|
||||
cdb = csat*(evd-1);
|
||||
gdb = csat*evd/vte;
|
||||
cdb_dT = csat_dT * (evd - 1) - csat * vd * evd / (vte * Temp);
|
||||
if (model->DIOrecSatCurGiven) { /* recombination current */
|
||||
double vterec = model->DIOrecEmissionCoeff*vt;
|
||||
evd_rec = exp(vd/(vterec));
|
||||
cdb_rec = here->DIOtRecSatCur*(evd_rec-1);
|
||||
gdb_rec = here->DIOtRecSatCur*evd_rec/vterec;
|
||||
cdb_rec_dT = here->DIOtRecSatCur_dT * (evd_rec - 1)
|
||||
-here->DIOtRecSatCur * vd * evd_rec / (vterec*Temp);
|
||||
t1 = pow((1-vd/here->DIOtJctPot), 2) + 0.005;
|
||||
gen_fac = pow(t1, here->DIOtGradingCoeff/2);
|
||||
gen_fac_vd = -here->DIOtGradingCoeff * (1-vd/here->DIOtJctPot)
|
||||
* pow(t1, (here->DIOtGradingCoeff/2-1));
|
||||
cdb_rec = cdb_rec * gen_fac;
|
||||
gdb_rec = gdb_rec * gen_fac + cdb_rec * gen_fac_vd;
|
||||
cdb = cdb + cdb_rec;
|
||||
gdb = gdb + gdb_rec;
|
||||
cdb_dT = cdb_dT + cdb_rec_dT*gen_fac;
|
||||
}
|
||||
|
||||
} else if((!(model->DIObreakdownVoltageGiven)) ||
|
||||
vd >= -here->DIOtBrkdwnV) { /* reverse */
|
||||
|
||||
double darg_dT;
|
||||
|
||||
arg = 3*vte/(vd*CONSTe);
|
||||
arg = arg * arg * arg;
|
||||
darg_dT = 3 * arg / Temp;
|
||||
cdb = -csat*(1+arg);
|
||||
gdb = csat*3*arg/vd;
|
||||
cdb_dT = -csat_dT - (csat_dT*arg + csat*darg_dT);
|
||||
|
||||
} else { /* breakdown */
|
||||
double evrev_dT;
|
||||
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk);
|
||||
evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp);
|
||||
cdb = -csat*evrev;
|
||||
gdb = csat*evrev/vtebrk;
|
||||
cdb_dT = -(csat_dT*evrev + csat*evrev_dT);
|
||||
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOoldCurr) = cd;
|
||||
*(ckt->CKTstate1 + here->DIOoldCond) = gd;
|
||||
*(ckt->CKTstate2 + here->DIOoldCurr) = cd;
|
||||
*(ckt->CKTstate2 + here->DIOoldCond) = gd;
|
||||
}
|
||||
|
||||
if (model->DIOtunSatSWCurGiven) { /* tunnel sidewall current */
|
||||
|
||||
vtetun = model->DIOtunEmissionCoeff * vt;
|
||||
evd = exp(-vd/vtetun);
|
||||
|
||||
cdsw = cdsw - here->DIOtTunSatSWCur * (evd - 1);
|
||||
gdsw = gdsw + here->DIOtTunSatSWCur * evd / vtetun;
|
||||
cdsw_dT = cdsw_dT - here->DIOtTunSatSWCur_dT * (evd - 1)
|
||||
- here->DIOtTunSatSWCur * vd * evd / (vtetun * Temp);
|
||||
|
||||
}
|
||||
|
||||
if (model->DIOtunSatCurGiven) { /* tunnel bottom current */
|
||||
|
||||
vtetun = model->DIOtunEmissionCoeff * vt;
|
||||
evd = exp(-vd/vtetun);
|
||||
|
||||
cdb = cdb - here->DIOtTunSatCur * (evd - 1);
|
||||
gdb = gdb + here->DIOtTunSatCur * evd / vtetun;
|
||||
cdb_dT = cdb_dT - here->DIOtTunSatCur_dT * (evd - 1)
|
||||
- here->DIOtTunSatCur * vd * evd / (vtetun * Temp);
|
||||
|
||||
}
|
||||
|
||||
cd = cdb + cdsw;
|
||||
gd = gdb + gdsw;
|
||||
dIdio_dT = cdb_dT + cdsw_dT;
|
||||
|
||||
if (vd >= -3*vte) { /* limit forward */
|
||||
|
||||
if( (model->DIOforwardKneeCurrentGiven) && (cd > 1.0e-18) ) {
|
||||
ikf_area_m = here->DIOforwardKneeCurrent;
|
||||
sqrt_ikf = sqrt(cd/ikf_area_m);
|
||||
gd = ((1+sqrt_ikf)*gd - cd*gd/(2*sqrt_ikf*ikf_area_m))/(1+2*sqrt_ikf + cd/ikf_area_m) + ckt->CKTgmin;
|
||||
cd = cd/(1+sqrt_ikf) + ckt->CKTgmin*vd;
|
||||
} else {
|
||||
gd = gd + ckt->CKTgmin;
|
||||
cd = cd + ckt->CKTgmin*vd;
|
||||
}
|
||||
|
||||
} else { /* limit reverse */
|
||||
|
||||
if( (model->DIOreverseKneeCurrentGiven) && (cd < -1.0e-18) ) {
|
||||
ikr_area_m = here->DIOreverseKneeCurrent;
|
||||
sqrt_ikr = sqrt(cd/(-ikr_area_m));
|
||||
gd = ((1+sqrt_ikr)*gd + cd*gd/(2*sqrt_ikr*ikr_area_m))/(1+2*sqrt_ikr - cd/ikr_area_m) + ckt->CKTgmin;
|
||||
cd = cd/(1+sqrt_ikr) + ckt->CKTgmin*vd;
|
||||
} else {
|
||||
gd = gd + ckt->CKTgmin;
|
||||
cd = cd + ckt->CKTgmin*vd;
|
||||
}
|
||||
|
||||
else {
|
||||
//cd = (*(ckt->CKTstate1 + here->DIOoldCurr) - (ckt->CKTdelta)*cd) / (1 + (ckt->CKTdelta)*vp);
|
||||
//gd = (*(ckt->CKTstate1 + here->DIOoldCond) - (ckt->CKTdelta)*gd) / (1 + (ckt->CKTdelta)*vp);
|
||||
//cd = (1 - vp)*cd + vp*(*(ckt->CKTstate1 + here->DIOoldCurr))*(ckt->CKTdelta);
|
||||
//gd = (1 - vp)*gd + vp*(*(ckt->CKTstate1 + here->DIOoldCond))*(ckt->CKTdelta);
|
||||
}
|
||||
*/
|
||||
|
||||
if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) ||
|
||||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) {
|
||||
/*
|
||||
* charge storage elements
|
||||
*/
|
||||
|
||||
/* junction(depletion) charge */
|
||||
czero=here->DIOtJctCap;
|
||||
if (vd < here->DIOtDepCap){
|
||||
arg=1-vd/here->DIOtJctPot;
|
||||
|
|
@ -420,26 +236,106 @@ next1:
|
|||
(here->DIOtGradingCoeff/(here->DIOtJctPot+here->DIOtJctPot))*(vd*vd-here->DIOtDepCap*here->DIOtDepCap));
|
||||
deplcap = czof2*(here->DIOtF3+here->DIOtGradingCoeff*vd/here->DIOtJctPot);
|
||||
}
|
||||
czeroSW=here->DIOtJctSWCap;
|
||||
if (vd < here->DIOtDepSWCap){
|
||||
argSW=1-vd/here->DIOtJctSWPot;
|
||||
sargSW=exp(-model->DIOgradingSWCoeff*log(argSW));
|
||||
deplchargeSW = here->DIOtJctSWPot*czeroSW*(1-argSW*sargSW)/(1-model->DIOgradingSWCoeff);
|
||||
deplcapSW = czeroSW*sargSW;
|
||||
} else {
|
||||
czof2SW=czeroSW/here->DIOtF2SW;
|
||||
deplchargeSW = czeroSW*here->DIOtF1+czof2SW*(here->DIOtF3SW*(vd-here->DIOtDepSWCap)+
|
||||
(model->DIOgradingSWCoeff/(here->DIOtJctSWPot+here->DIOtJctSWPot))*(vd*vd-here->DIOtDepSWCap*here->DIOtDepSWCap));
|
||||
deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vd/here->DIOtJctSWPot);
|
||||
|
||||
/* diffusion charge */
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
diffcharge = tt * cd;
|
||||
diffcap = tt * gd;
|
||||
*(ckt->CKTstate2 + here->DIOdiffCharge) = diffcharge;
|
||||
*(ckt->CKTstate2 + here->DIOdiffCap) = diffcap;
|
||||
*(ckt->CKTstate1 + here->DIOdiffCharge) = diffcharge;
|
||||
*(ckt->CKTstate1 + here->DIOdiffCap) = diffcap;
|
||||
*(ckt->CKTstate1 + here->DIOoldCurr) = cd;
|
||||
*(ckt->CKTstate1 + here->DIOoldCond) = gd;
|
||||
}
|
||||
else {
|
||||
double dt = ckt->CKTdelta;
|
||||
/*
|
||||
//Fixed-point iteration
|
||||
double diffcharge_old, diffcap_old;
|
||||
|
||||
//Forward Euler predictor
|
||||
diffcharge = (*(ckt->CKTstate1 + here->DIOdiffCharge))*(1 - dt / (tt*vp)) + (dt*(*(ckt->CKTstate1 + here->DIOoldCurr)) / vp);
|
||||
diffcap = (*(ckt->CKTstate1 + here->DIOdiffCap))*(1 - dt / (tt*vp)) + (dt*(*(ckt->CKTstate1 + here->DIOoldCond)) / vp);
|
||||
do {
|
||||
diffcharge_old = diffcharge;
|
||||
diffcharge = (*(ckt->CKTstate1 + here->DIOdiffCharge)) + ((dt / vp)*(cd - (diffcharge_old / tt)));
|
||||
} while (fabs(diffcharge - diffcharge_old) > 1e-12);
|
||||
do {
|
||||
diffcap_old = diffcap;
|
||||
diffcap = (*(ckt->CKTstate1 + here->DIOdiffCap)) + ((dt / vp)*(gd - (diffcap_old / tt)));
|
||||
} while (fabs(diffcap - diffcap_old) > 1e-12);
|
||||
*/
|
||||
|
||||
/*
|
||||
//Newton's method
|
||||
double diffcharge_old, diffcap_old;
|
||||
|
||||
//Forward Euler predictor
|
||||
diffcharge = (*(ckt->CKTstate1 + here->DIOdiffCharge))*(1 - dt / (tt*vp)) + (dt*(*(ckt->CKTstate1 + here->DIOoldCurr)) / vp);
|
||||
diffcap = (*(ckt->CKTstate1 + here->DIOdiffCap))*(1 - dt / (tt*vp)) + (dt*(*(ckt->CKTstate1 + here->DIOoldCond)) / vp);
|
||||
do {
|
||||
diffcharge_old = diffcharge;
|
||||
diffcharge = diffcharge_old + ((tt*vp*(*(ckt->CKTstate1 + here->DIOdiffCharge)) + tt*dt*cd - diffcharge_old*(dt + tt*vp)) / (dt + tt*vp));
|
||||
} while (fabs(diffcharge - diffcharge_old) > 1e-12);
|
||||
|
||||
do {
|
||||
diffcap_old = diffcap;
|
||||
diffcap = diffcap_old + ((tt*vp*(*(ckt->CKTstate1 + here->DIOdiffCap)) + tt * dt*gd - diffcap_old * (dt + tt*vp)) / (dt + tt*vp));
|
||||
} while (fabs(diffcap - diffcap_old) > 1e-12);
|
||||
*/
|
||||
|
||||
//Backward Difference Operator
|
||||
//diffcharge = tt * (cd - vp * (((*(ckt->CKTstate1 + here->DIOdiffCharge)) - (*(ckt->CKTstate2 + here->DIOdiffCharge))) / (ckt->CKTdeltaOld[1])));
|
||||
//diffcap = tt * (gd - vp * (((*(ckt->CKTstate1 + here->DIOdiffCap)) - (*(ckt->CKTstate2 + here->DIOdiffCap))) / (ckt->CKTdeltaOld[1])));
|
||||
|
||||
//Standard Diffy-Q w/ trap integral
|
||||
//diffcharge = (dt / (2.0*vt))*(exp(-dt / (tt*vt))*(*(ckt->CKTstate1 + here->DIOoldCurr)) + cd) + exp(-dt / (tt*vt))*(*(ckt->CKTstate1 + here->DIOdiffCharge));
|
||||
//diffcap = (dt / (2.0*vt))*(exp(-dt / (tt*vt))*(*(ckt->CKTstate1 + here->DIOoldCond)) + gd) + exp(-dt / (tt*vt))*(*(ckt->CKTstate1 + here->DIOdiffCap));
|
||||
|
||||
//Forward Euler
|
||||
//diffcharge = ((*(ckt->CKTstate1 + here->DIOdiffCharge))*(tt*vp - dt) + dt*tt*cd) / (tt*vp);
|
||||
//diffcap = ((*(ckt->CKTstate1 + here->DIOdiffCap))*(tt*vp - dt) + dt*tt*gd) / (tt*vp);
|
||||
|
||||
//Backward Euler
|
||||
//diffcharge = tt*((vp*(*(ckt->CKTstate1 + here->DIOdiffCharge)) + dt*cd) / (tt*vp + dt));
|
||||
//diffcap = tt*((vp*(*(ckt->CKTstate1 + here->DIOdiffCap)) + dt*gd) / (tt*vp + dt));
|
||||
|
||||
//Trap
|
||||
diffcharge = ((*(ckt->CKTstate1 + here->DIOdiffCharge))*(2.0*tt*vp - dt) + dt*tt*((*(ckt->CKTstate1 + here->DIOoldCurr)) + cd)) / (2.0*tt*vp + dt);
|
||||
diffcap = ((*(ckt->CKTstate1 + here->DIOdiffCap))*(2.0*tt*vp - dt) + dt*tt*((*(ckt->CKTstate1 + here->DIOoldCond)) + gd)) / (2.0*tt*vp + dt);
|
||||
|
||||
//Gear
|
||||
//diffcharge = tt*((vp*(4.0*(*(ckt->CKTstate1 + here->DIOdiffCharge)) - (*(ckt->CKTstate2 + here->DIOdiffCharge))) + 2.0*dt*cd) / (3.0*tt*vp + 2.0*dt));
|
||||
//diffcap = tt*((vp*(4.0*(*(ckt->CKTstate1 + here->DIOdiffCap)) - (*(ckt->CKTstate2 + here->DIOdiffCap))) + 2.0*dt*gd) / (3.0*tt*vp + 2.0*dt));
|
||||
|
||||
//Nothing
|
||||
//diffcharge = tt * cd;
|
||||
//diffcap = tt * gd;
|
||||
}
|
||||
|
||||
diffcharge = here->DIOtTransitTime*cd;
|
||||
*(ckt->CKTstate0 + here->DIOdiffCharge) = diffcharge;
|
||||
*(ckt->CKTstate0 + here->DIOdiffCap) = diffcap;
|
||||
*(ckt->CKTstate0 + here->DIOoldCurr) = cd;
|
||||
*(ckt->CKTstate0 + here->DIOoldCond) = gd;
|
||||
|
||||
//printf("Time: %e\n", ckt->CKTtime);
|
||||
//printf("Charge: %e\n", diffcharge);
|
||||
//printf("Cap: %e\n", diffcap);
|
||||
//printf("Curr: %e\n", cd);
|
||||
//printf("Cond: %e\n", gd);
|
||||
//printf("DelCharge: %e\n", diffcharge-(*(ckt->CKTstate1 + here->DIOdiffCharge)));
|
||||
//printf("DelCap: %e\n", diffcap-(*(ckt->CKTstate1 + here->DIOdiffCap)));
|
||||
//printf("DelCurr: %e\n", cd-(*(ckt->CKTstate1 + here->DIOoldCurr)));
|
||||
//printf("DelCond: %e\n\n", gd-(*(ckt->CKTstate1 + here->DIOoldCond)));
|
||||
|
||||
//diffcharge = here->DIOtTransitTime*cd;
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge) =
|
||||
diffcharge + deplcharge + deplchargeSW;
|
||||
diffcharge + deplcharge;
|
||||
|
||||
diffcap = here->DIOtTransitTime*gd;
|
||||
//diffcap = here->DIOtTransitTime*gd;
|
||||
|
||||
capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly;
|
||||
capd = diffcap + deplcap + here->DIOcmetal + here->DIOcpoly;
|
||||
|
||||
here->DIOcap = capd;
|
||||
|
||||
|
|
@ -454,7 +350,6 @@ next1:
|
|||
if(SenCond){
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) = gd;
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT;
|
||||
#ifdef SENSDEBUG
|
||||
printf("storing small signal parameters\n");
|
||||
printf("cd = %.7e,vd = %.7e\n",cd,vd);
|
||||
|
|
@ -490,15 +385,6 @@ next1:
|
|||
*(ckt->CKTstate1 + here->DIOcapCurrent) =
|
||||
*(ckt->CKTstate0 + here->DIOcapCurrent);
|
||||
}
|
||||
if (selfheat)
|
||||
{
|
||||
error = NIintegrate(ckt, &gcTt, &ceqqth, model->DIOcth0, here->DIOqth);
|
||||
if (error) return(error);
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOcqth) =
|
||||
*(ckt->CKTstate0 + here->DIOcqth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -508,7 +394,7 @@ next1:
|
|||
* check convergence
|
||||
*/
|
||||
if ( (!(ckt->CKTmode & MODEINITFIX)) || (!(here->DIOoff)) ) {
|
||||
if ((Check_th == 1) || (Check_dio == 1)) {
|
||||
if (Check == 1) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
}
|
||||
|
|
@ -516,44 +402,18 @@ next1:
|
|||
next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) = gd;
|
||||
*(ckt->CKTstate0 + here->DIOdeltemp) = delTemp;
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT;
|
||||
|
||||
if(SenCond) continue;
|
||||
|
||||
#ifndef NOBYPASS
|
||||
load:
|
||||
#endif
|
||||
if (selfheat) {
|
||||
double dIrs_dVrs, dIrs_dgspr, dIth_dIrs;
|
||||
vrs = *(ckt->CKTrhsOld + here->DIOposNode) - *(ckt->CKTrhsOld + here->DIOposPrimeNode);
|
||||
Ith = vd*cd + vrs*vrs*gspr; /* Diode dissipated power */
|
||||
dIrs_dVrs = gspr;
|
||||
dIrs_dgspr = vrs;
|
||||
dIrs_dT = dIrs_dgspr * here->DIOtConductance_dT;
|
||||
dIth_dVrs = vrs*gspr;
|
||||
dIth_dIrs = vrs;
|
||||
dIth_dVrs = dIth_dVrs + dIth_dIrs*dIrs_dVrs;
|
||||
dIth_dT = dIth_dIrs*dIrs_dT + dIdio_dT*vd;
|
||||
dIth_dVdio = cd + vd*gd;
|
||||
here->DIOdIth_dVrs = dIth_dVrs;
|
||||
here->DIOdIth_dVdio = dIth_dVdio;
|
||||
here->DIOdIth_dT = dIth_dT;
|
||||
here->DIOgcTt = gcTt;
|
||||
here->DIOdIrs_dT = dIrs_dT;
|
||||
}
|
||||
/*
|
||||
* load current vector
|
||||
*/
|
||||
cdeq=cd-gd*vd;
|
||||
*(ckt->CKTrhs + here->DIOnegNode) += cdeq;
|
||||
*(ckt->CKTrhs + here->DIOposPrimeNode) -= cdeq;
|
||||
if (selfheat) {
|
||||
*(ckt->CKTrhs + here->DIOposNode) += dIrs_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOposPrimeNode) += dIdio_dT*delTemp - dIrs_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOnegNode) += -dIdio_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOtempNode) += Ith - dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp - ceqqth;
|
||||
}
|
||||
/*
|
||||
* load matrix
|
||||
*/
|
||||
|
|
@ -564,15 +424,6 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
|||
*(here->DIOnegPosPrimePtr) -= gd;
|
||||
*(here->DIOposPrimePosPtr) -= gspr;
|
||||
*(here->DIOposPrimeNegPtr) -= gd;
|
||||
if (selfheat) {
|
||||
(*(here->DIOtempPosPtr) += -dIth_dVrs);
|
||||
(*(here->DIOtempPosPrimePtr) += -dIth_dVdio + dIth_dVrs);
|
||||
(*(here->DIOtempNegPtr) += dIth_dVdio);
|
||||
(*(here->DIOtempTempPtr) += -dIth_dT + 1/model->DIOrth0 + gcTt);
|
||||
(*(here->DIOposTempPtr) += dIrs_dT);
|
||||
(*(here->DIOposPrimeTempPtr) += dIdio_dT - dIrs_dT);
|
||||
(*(here->DIOnegTempPtr) += -dIdio_dT);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,372 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Thomas L. Quarles
|
||||
Modified: 2000 AlansFixes
|
||||
Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Ste Kulov 2021
|
||||
**********/
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/devdefs.h"
|
||||
#include "ngspice/cktdefs.h"
|
||||
#include "diodefs.h"
|
||||
#include "ngspice/const.h"
|
||||
#include "ngspice/trandefs.h"
|
||||
#include "ngspice/sperror.h"
|
||||
#include "ngspice/suffix.h"
|
||||
|
||||
int
|
||||
DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
||||
/* actually load the current resistance value into the
|
||||
* sparse matrix previously provided
|
||||
*/
|
||||
{
|
||||
DIOmodel *model = (DIOmodel*)inModel;
|
||||
DIOinstance *here;
|
||||
double arg;
|
||||
double cd;
|
||||
double cdeq;
|
||||
double cdhat;
|
||||
double ceq;
|
||||
double csat; /* area-scaled saturation current */
|
||||
double czero;
|
||||
double czof2;
|
||||
double delvd; /* change in diode voltage temporary */
|
||||
double evd;
|
||||
double evrev;
|
||||
double gd;
|
||||
double geq;
|
||||
double gspr; /* area-scaled conductance */
|
||||
double sarg;
|
||||
#ifndef NOBYPASS
|
||||
double tol; /* temporary for tolerence calculations */
|
||||
#endif
|
||||
double vd; /* current diode voltage */
|
||||
double vdtemp;
|
||||
double vt; /* K t / Q */
|
||||
double vte, vtebrk;
|
||||
int Check=0;
|
||||
int error;
|
||||
int SenCond=0; /* sensitivity condition */
|
||||
double diffcharge, deplcharge, diffcap, deplcap;
|
||||
|
||||
double tt;
|
||||
double vp;
|
||||
|
||||
/* loop through all the diode models */
|
||||
for( ; model != NULL; model = DIOnextModel(model)) {
|
||||
|
||||
vp = model->DIOsoftRevRecParam;
|
||||
|
||||
/* loop through all the instances of the model */
|
||||
for (here = DIOinstances(model); here != NULL ;
|
||||
here=DIOnextInstance(here)) {
|
||||
|
||||
/*
|
||||
* this routine loads diodes for dc and transient analyses.
|
||||
*/
|
||||
|
||||
if(ckt->CKTsenInfo){
|
||||
if((ckt->CKTsenInfo->SENstatus == PERTURBATION)
|
||||
&& (here->DIOsenPertFlag == OFF))continue;
|
||||
SenCond = here->DIOsenPertFlag;
|
||||
|
||||
#ifdef SENSDEBUG
|
||||
printf("DIOload \n");
|
||||
#endif /* SENSDEBUG */
|
||||
|
||||
}
|
||||
csat = here->DIOtSatCur;
|
||||
gspr = here->DIOtConductance;
|
||||
vt = CONSTKoverQ * here->DIOtemp;
|
||||
vte = model->DIOemissionCoeff * vt;
|
||||
vtebrk = model->DIObrkdEmissionCoeff * vt;
|
||||
tt = here->DIOtTransitTime;
|
||||
/*
|
||||
* initialization
|
||||
*/
|
||||
|
||||
if(SenCond){
|
||||
|
||||
#ifdef SENSDEBUG
|
||||
printf("DIOsenPertFlag = ON \n");
|
||||
#endif /* SENSDEBUG */
|
||||
|
||||
if((ckt->CKTsenInfo->SENmode == TRANSEN)&&
|
||||
(ckt->CKTmode & MODEINITTRAN)) {
|
||||
vd = *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
} else{
|
||||
vd = *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
}
|
||||
|
||||
#ifdef SENSDEBUG
|
||||
printf("vd = %.7e \n",vd);
|
||||
#endif /* SENSDEBUG */
|
||||
goto next1;
|
||||
}
|
||||
|
||||
Check=1;
|
||||
if(ckt->CKTmode & MODEINITSMSIG) {
|
||||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
} else if (ckt->CKTmode & MODEINITTRAN) {
|
||||
vd= *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) &&
|
||||
(ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) {
|
||||
vd=here->DIOinitCond;
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) {
|
||||
vd=0;
|
||||
} else if ( ckt->CKTmode & MODEINITJCT) {
|
||||
vd=here->DIOtVcrit;
|
||||
} else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) {
|
||||
vd=0;
|
||||
} else {
|
||||
#ifndef PREDICTOR
|
||||
if (ckt->CKTmode & MODEINITPRED) {
|
||||
*(ckt->CKTstate0 + here->DIOvoltage) =
|
||||
*(ckt->CKTstate1 + here->DIOvoltage);
|
||||
vd = DEVpred(ckt,here->DIOvoltage);
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) =
|
||||
*(ckt->CKTstate1 + here->DIOcurrent);
|
||||
*(ckt->CKTstate0 + here->DIOconduct) =
|
||||
*(ckt->CKTstate1 + here->DIOconduct);
|
||||
} else {
|
||||
#endif /* PREDICTOR */
|
||||
vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->DIOnegNode);
|
||||
#ifndef PREDICTOR
|
||||
}
|
||||
#endif /* PREDICTOR */
|
||||
delvd=vd- *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
cdhat= *(ckt->CKTstate0 + here->DIOcurrent) +
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd;
|
||||
/*
|
||||
* bypass if solution has not changed
|
||||
*/
|
||||
#ifndef NOBYPASS
|
||||
if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) {
|
||||
tol=ckt->CKTvoltTol + ckt->CKTreltol*
|
||||
MAX(fabs(vd),fabs(*(ckt->CKTstate0 +here->DIOvoltage)));
|
||||
if (fabs(delvd) < tol){
|
||||
tol=ckt->CKTreltol* MAX(fabs(cdhat),
|
||||
fabs(*(ckt->CKTstate0 + here->DIOcurrent)))+
|
||||
ckt->CKTabstol;
|
||||
if (fabs(cdhat- *(ckt->CKTstate0 + here->DIOcurrent))
|
||||
< tol) {
|
||||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
cd= *(ckt->CKTstate0 + here->DIOcurrent);
|
||||
gd= *(ckt->CKTstate0 + here->DIOconduct);
|
||||
goto load;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* NOBYPASS */
|
||||
/*
|
||||
* limit new junction voltage
|
||||
*/
|
||||
if ( (model->DIObreakdownVoltageGiven) &&
|
||||
(vd < MIN(0,-here->DIOtBrkdwnV+10*vtebrk))) {
|
||||
vdtemp = -(vd+here->DIOtBrkdwnV);
|
||||
vdtemp = DEVpnjlim(vdtemp,
|
||||
-(*(ckt->CKTstate0 + here->DIOvoltage) +
|
||||
here->DIOtBrkdwnV),vtebrk,
|
||||
here->DIOtVcrit,&Check);
|
||||
vd = -(vdtemp+here->DIOtBrkdwnV);
|
||||
} else {
|
||||
vd = DEVpnjlim(vd,*(ckt->CKTstate0 + here->DIOvoltage),
|
||||
vte,here->DIOtVcrit,&Check);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* compute dc current and derivitives
|
||||
*/
|
||||
next1:
|
||||
if (vd >= -3*vte) { /* forward */
|
||||
|
||||
evd = exp(vd/vte);
|
||||
cd = csat*(evd-1);
|
||||
gd = csat*evd/vte;
|
||||
|
||||
} else if((!(model->DIObreakdownVoltageGiven)) ||
|
||||
vd >= -here->DIOtBrkdwnV) { /* reverse */
|
||||
|
||||
arg = 3*vte/(vd*CONSTe);
|
||||
arg = arg * arg * arg;
|
||||
cd = -csat*(1+arg);
|
||||
gd = csat*3*arg/vd;
|
||||
|
||||
} else { /* breakdown */
|
||||
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk);
|
||||
cd = -csat*evrev;
|
||||
gd = csat*evrev/vtebrk;
|
||||
|
||||
}
|
||||
|
||||
gd = gd + ckt->CKTgmin;
|
||||
cd = cd + ckt->CKTgmin*vd;
|
||||
|
||||
if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) ||
|
||||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) {
|
||||
/*
|
||||
* charge storage elements
|
||||
*/
|
||||
czero=here->DIOtJctCap;
|
||||
if (vd < here->DIOtDepCap){
|
||||
arg=1-vd/here->DIOtJctPot;
|
||||
sarg=exp(-here->DIOtGradingCoeff*log(arg));
|
||||
deplcharge = here->DIOtJctPot*czero*(1-arg*sarg)/(1-here->DIOtGradingCoeff);
|
||||
deplcap = czero*sarg;
|
||||
} else {
|
||||
czof2=czero/here->DIOtF2;
|
||||
deplcharge = czero*here->DIOtF1+czof2*(here->DIOtF3*(vd-here->DIOtDepCap)+
|
||||
(here->DIOtGradingCoeff/(here->DIOtJctPot+here->DIOtJctPot))*(vd*vd-here->DIOtDepCap*here->DIOtDepCap));
|
||||
deplcap = czof2*(here->DIOtF3+here->DIOtGradingCoeff*vd/here->DIOtJctPot);
|
||||
}
|
||||
|
||||
if (model->DIOsoftRevRecParamGiven) {
|
||||
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
diffcharge = tt * cd;
|
||||
diffcap = tt * gd;
|
||||
*(ckt->CKTstate2 + here->DIOdiffCharge) = diffcharge;
|
||||
*(ckt->CKTstate2 + here->DIOdiffCap) = diffcap;
|
||||
*(ckt->CKTstate1 + here->DIOdiffCharge) = diffcharge;
|
||||
*(ckt->CKTstate1 + here->DIOdiffCap) = diffcap;
|
||||
*(ckt->CKTstate1 + here->DIOoldCurr) = cd;
|
||||
*(ckt->CKTstate1 + here->DIOoldCond) = gd;
|
||||
}
|
||||
else {
|
||||
double dt = 1*ckt->CKTdelta;
|
||||
|
||||
//Backward Euler
|
||||
// Qk+1 = tt (VP Qk + h Ik+1) / (tt VP + h)
|
||||
diffcharge = tt*((vp*(*(ckt->CKTstate1 + here->DIOdiffCharge)) + dt*cd) / (tt*vp + dt));
|
||||
diffcap = tt*((vp*(*(ckt->CKTstate1 + here->DIOdiffCap)) + dt*gd) / (tt*vp + dt));
|
||||
|
||||
//Trap
|
||||
// Qk+1 = (Qk (2 tt VP - h) + h tt (Ik + Ik+1)) / (2 tt VP + h)
|
||||
//diffcharge = ((*(ckt->CKTstate1 + here->DIOdiffCharge))*(2.0*tt*vp - dt) + dt*tt*((*(ckt->CKTstate1 + here->DIOoldCurr)) + cd)) / (2.0*tt*vp + dt);
|
||||
//diffcap = ((*(ckt->CKTstate1 + here->DIOdiffCap))*(2.0*tt*vp - dt) + dt*tt*((*(ckt->CKTstate1 + here->DIOoldCond)) + gd)) / (2.0*tt*vp + dt);
|
||||
|
||||
//Gear
|
||||
// Qk+1 = tt ((VP (4 Qk - Qk-1) + 2 h Ik+1) / (3 tt VP + 2 h))
|
||||
//diffcharge = tt*((vp*(4.0*(*(ckt->CKTstate1 + here->DIOdiffCharge)) - (*(ckt->CKTstate2 + here->DIOdiffCharge))) + 2.0*dt*cd) / (3.0*tt*vp + 2.0*dt));
|
||||
//diffcap = tt*((vp*(4.0*(*(ckt->CKTstate1 + here->DIOdiffCap)) - (*(ckt->CKTstate2 + here->DIOdiffCap))) + 2.0*dt*gd) / (3.0*tt*vp + 2.0*dt));
|
||||
|
||||
}
|
||||
|
||||
*(ckt->CKTstate0 + here->DIOdiffCap) = diffcap;
|
||||
*(ckt->CKTstate0 + here->DIOoldCurr) = cd;
|
||||
*(ckt->CKTstate0 + here->DIOoldCond) = gd;
|
||||
|
||||
//printf("time: %e vd: %e\n", ckt->CKTtime, vd);
|
||||
//printf("%e %e %e %e %e %e\n", ckt->CKTtime, ckt->CKTdelta, diffcharge, diffcap, cd, gd);
|
||||
|
||||
} else {
|
||||
|
||||
diffcharge = tt*cd;
|
||||
diffcap = tt*gd;
|
||||
|
||||
}
|
||||
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge) = deplcharge;
|
||||
*(ckt->CKTstate0 + here->DIOdiffCharge) = diffcharge;
|
||||
|
||||
here->DIOcap = deplcap + diffcap;
|
||||
|
||||
/*
|
||||
* store small-signal parameters
|
||||
*/
|
||||
if( (!(ckt->CKTmode & MODETRANOP)) ||
|
||||
(!(ckt->CKTmode & MODEUIC)) ) {
|
||||
if (ckt->CKTmode & MODEINITSMSIG){
|
||||
*(ckt->CKTstate0 + here->DIOcapCurrent) = deplcap + diffcap;
|
||||
|
||||
if(SenCond){
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) = gd;
|
||||
#ifdef SENSDEBUG
|
||||
printf("storing small signal parameters\n");
|
||||
printf("cd = %.7e,vd = %.7e\n",cd,vd);
|
||||
printf("capd = %.7e ,gd = %.7e \n",deplcap+diffcap,gd);
|
||||
#endif /* SENSDEBUG */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* transient analysis
|
||||
*/
|
||||
if(SenCond && (ckt->CKTsenInfo->SENmode == TRANSEN)){
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
#ifdef SENSDEBUG
|
||||
printf("storing parameters for transient sensitivity\n"
|
||||
);
|
||||
printf("qd = %.7e, capd = %.7e,cd = %.7e\n",
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge),deplcap+diffcap,cd);
|
||||
#endif /* SENSDEBUG */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOcapCharge) =
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge);
|
||||
*(ckt->CKTstate1 + here->DIOdiffCharge) =
|
||||
*(ckt->CKTstate0 + here->DIOdiffCharge);
|
||||
}
|
||||
error = NIintegrate(ckt,&geq,&ceq,deplcap,here->DIOcapCharge);
|
||||
if(error) return(error);
|
||||
gd=gd+geq;
|
||||
cd=cd+*(ckt->CKTstate0 + here->DIOcapCurrent);
|
||||
error = NIintegrate(ckt,&geq,&ceq,diffcap,here->DIOdiffCharge);
|
||||
if(error) return(error);
|
||||
gd=gd+geq;
|
||||
cd=cd+*(ckt->CKTstate0 + here->DIOdiffCurrent);
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOcapCurrent) =
|
||||
*(ckt->CKTstate0 + here->DIOcapCurrent);
|
||||
*(ckt->CKTstate1 + here->DIOdiffCurrent) =
|
||||
*(ckt->CKTstate0 + here->DIOdiffCurrent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(SenCond) goto next2;
|
||||
|
||||
/*
|
||||
* check convergence
|
||||
*/
|
||||
if ( (!(ckt->CKTmode & MODEINITFIX)) || (!(here->DIOoff)) ) {
|
||||
if (Check == 1) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
}
|
||||
}
|
||||
next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) = gd;
|
||||
|
||||
if(SenCond) continue;
|
||||
|
||||
#ifndef NOBYPASS
|
||||
load:
|
||||
#endif
|
||||
/*
|
||||
* load current vector
|
||||
*/
|
||||
cdeq=cd-gd*vd;
|
||||
*(ckt->CKTrhs + here->DIOnegNode) += cdeq;
|
||||
*(ckt->CKTrhs + here->DIOposPrimeNode) -= cdeq;
|
||||
/*
|
||||
* load matrix
|
||||
*/
|
||||
*(here->DIOposPosPtr) += gspr;
|
||||
*(here->DIOnegNegPtr) += gd;
|
||||
*(here->DIOposPrimePosPrimePtr) += (gd + gspr);
|
||||
*(here->DIOposPosPrimePtr) -= gspr;
|
||||
*(here->DIOnegPosPrimePtr) -= gd;
|
||||
*(here->DIOposPrimePosPtr) -= gspr;
|
||||
*(here->DIOposPrimeNegPtr) -= gd;
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
|
@ -106,12 +106,6 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value)
|
|||
case DIO_MOD_EG:
|
||||
value->rValue = model->DIOactivationEnergy;
|
||||
return (OK);
|
||||
case DIO_MOD_GAP1:
|
||||
value->rValue = model->DIOfirstBGcorrFactor;
|
||||
return (OK);
|
||||
case DIO_MOD_GAP2:
|
||||
value->rValue = model->DIOsecndBGcorrFactor;
|
||||
return (OK);
|
||||
case DIO_MOD_XTI:
|
||||
value->rValue = model->DIOsaturationCurrentExp;
|
||||
return(OK);
|
||||
|
|
@ -193,6 +187,9 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value)
|
|||
case DIO_MOD_NR:
|
||||
value->rValue = model->DIOrecEmissionCoeff;
|
||||
return(OK);
|
||||
case DIO_MOD_VP:
|
||||
value->rValue = model->DIOsoftRevRecParam;
|
||||
return(OK);
|
||||
case DIO_MOD_RTH0:
|
||||
value->rValue = model->DIOrth0;
|
||||
return(OK);
|
||||
|
|
@ -224,9 +221,6 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value)
|
|||
case DIO_MOD_XP:
|
||||
value->rValue = model->DIOpolyMaskOffset;
|
||||
return(OK);
|
||||
case DIO_MOD_XW:
|
||||
value->rValue = model->DIOmaskOffset;
|
||||
return(OK);
|
||||
|
||||
default:
|
||||
return(E_BADPARM);
|
||||
|
|
|
|||
|
|
@ -133,14 +133,6 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel)
|
|||
model->DIOactivationEnergy = value->rValue;
|
||||
model->DIOactivationEnergyGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_GAP1:
|
||||
model->DIOfirstBGcorrFactor = value->rValue;
|
||||
model->DIOfirstBGcorrFactorGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_GAP2:
|
||||
model->DIOsecndBGcorrFactor = value->rValue;
|
||||
model->DIOsecndBGcorrFactorGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_XTI:
|
||||
model->DIOsaturationCurrentExp = value->rValue;
|
||||
model->DIOsaturationCurrentExpGiven = TRUE;
|
||||
|
|
@ -237,6 +229,10 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel)
|
|||
model->DIOrecEmissionCoeff = value->rValue;
|
||||
model->DIOrecEmissionCoeffGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_VP:
|
||||
model->DIOsoftRevRecParam = value->rValue;
|
||||
model->DIOsoftRevRecParamGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_RTH0:
|
||||
model->DIOrth0 = value->rValue;
|
||||
model->DIOrth0Given = TRUE;
|
||||
|
|
@ -278,10 +274,6 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel)
|
|||
model->DIOpolyMaskOffset = value->rValue;
|
||||
model->DIOpolyMaskOffsetGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_XW:
|
||||
model->DIOmaskOffset = value->rValue;
|
||||
model->DIOmaskOffsetGiven = TRUE;
|
||||
break;
|
||||
|
||||
case DIO_MOD_D:
|
||||
/* no action - we already know we are a diode, but this */
|
||||
|
|
|
|||
|
|
@ -12,22 +12,23 @@ Modified by Dietmar Warning 2003
|
|||
#include "ngspice/suffix.h"
|
||||
|
||||
/*
|
||||
*DIOnoise (mode, operation, firstModel, ckt, data, OnDens)
|
||||
* This routine names and evaluates all of the noise sources
|
||||
* associated with diodes. It starts with the model *firstModel and
|
||||
* traverses all of its instancess. It then proceeds to any other
|
||||
* models on the linked list. The total output noise density
|
||||
* generated by all of the diodes is summed with the variable
|
||||
* "OnDens".
|
||||
* DIOnoise (mode, operation, firstModel, ckt, data, OnDens)
|
||||
* This routine names and evaluates all of the noise sources
|
||||
* associated with diodes. It starts with the model *firstModel and
|
||||
* traverses all of its instancess. It then proceeds to any other
|
||||
* models on the linked list. The total output noise density
|
||||
* generated by all of the diodes is summed with the variable
|
||||
* "OnDens".
|
||||
*/
|
||||
|
||||
int
|
||||
DIOnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
|
||||
Ndata *data, double *OnDens)
|
||||
{
|
||||
NOISEAN *job = (NOISEAN*) ckt->CKTcurJob;
|
||||
|
||||
DIOmodel *firstModel = (DIOmodel*) genmodel;
|
||||
int
|
||||
DIOnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
|
||||
Ndata *data, double *OnDens)
|
||||
{
|
||||
NOISEAN *job = (NOISEAN *) ckt->CKTcurJob;
|
||||
|
||||
DIOmodel *firstModel = (DIOmodel *) genmodel;
|
||||
DIOmodel *model;
|
||||
DIOinstance *inst;
|
||||
double tempOnoise;
|
||||
|
|
@ -35,152 +36,141 @@ DIOnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
|
|||
double noizDens[DIONSRCS];
|
||||
double lnNdens[DIONSRCS];
|
||||
int i;
|
||||
double dtemp;
|
||||
|
||||
/* define the names of the noise sources */
|
||||
|
||||
static char *DIOnNames[DIONSRCS] = {
|
||||
/* Note that we have to keep the order
|
||||
consistent with thestrchr definitions in DIOdefs.h */
|
||||
"_rs", /* noise due to rs */
|
||||
"_id", /* noise due to id */
|
||||
"_1overf", /* flicker (1/f) noise */
|
||||
"" /* total diode noise */
|
||||
static char *DIOnNames[DIONSRCS] = { /* Note that we have to keep the order */
|
||||
"_rs", /* noise due to rs */ /* consistent with thestrchr definitions */
|
||||
"_id", /* noise due to id */ /* in DIOdefs.h */
|
||||
"_1overf", /* flicker (1/f) noise */
|
||||
"" /* total diode noise */
|
||||
};
|
||||
|
||||
for (model = firstModel; model != NULL; model = DIOnextModel(model)) {
|
||||
for (inst = DIOinstances(model); inst != NULL; inst = DIOnextInstance(inst)) {
|
||||
for (model=firstModel; model != NULL; model=DIOnextModel(model)) {
|
||||
for (inst=DIOinstances(model); inst != NULL; inst=DIOnextInstance(inst)) {
|
||||
|
||||
switch (operation) {
|
||||
switch (operation) {
|
||||
|
||||
case N_OPEN:
|
||||
case N_OPEN:
|
||||
|
||||
/* see if we have to to produce a summary report */
|
||||
/* if so, name all the noise generators */
|
||||
/* see if we have to to produce a summary report */
|
||||
/* if so, name all the noise generators */
|
||||
|
||||
if (job->NStpsSm != 0) {
|
||||
switch (mode) {
|
||||
if (job->NStpsSm != 0) {
|
||||
switch (mode) {
|
||||
|
||||
case N_DENS:
|
||||
for (i = 0; i < DIONSRCS; i++) {
|
||||
NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->DIOname, DIOnNames[i]);
|
||||
}
|
||||
break;
|
||||
case N_DENS:
|
||||
for (i=0; i < DIONSRCS; i++) {
|
||||
NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->DIOname, DIOnNames[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case INT_NOIZ:
|
||||
for (i = 0; i < DIONSRCS; i++) {
|
||||
NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->DIOname, DIOnNames[i]);
|
||||
NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->DIOname, DIOnNames[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case INT_NOIZ:
|
||||
for (i=0; i < DIONSRCS; i++) {
|
||||
NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->DIOname, DIOnNames[i]);
|
||||
NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->DIOname, DIOnNames[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case N_CALC:
|
||||
switch (mode) {
|
||||
case N_CALC:
|
||||
switch (mode) {
|
||||
|
||||
case N_DENS:
|
||||
case N_DENS:
|
||||
NevalSrc(&noizDens[DIORSNOIZ],&lnNdens[DIORSNOIZ],
|
||||
ckt,THERMNOISE,inst->DIOposPrimeNode,inst->DIOposNode,
|
||||
inst->DIOtConductance * inst->DIOarea * inst->DIOm);
|
||||
NevalSrc(&noizDens[DIOIDNOIZ],&lnNdens[DIOIDNOIZ],
|
||||
ckt,SHOTNOISE,inst->DIOposPrimeNode, inst->DIOnegNode,
|
||||
*(ckt->CKTstate0 + inst->DIOcurrent));
|
||||
|
||||
if (inst->DIOtempGiven)
|
||||
dtemp = inst->DIOtemp - ckt->CKTtemp + (model->DIOnomTemp-CONSTCtoK);
|
||||
else
|
||||
dtemp = inst->DIOdtemp;
|
||||
NevalSrc(&noizDens[DIOFLNOIZ], NULL, ckt,
|
||||
N_GAIN,inst->DIOposPrimeNode, inst->DIOnegNode,
|
||||
(double)0.0);
|
||||
noizDens[DIOFLNOIZ] *= model->DIOfNcoef *
|
||||
exp(model->DIOfNexp *
|
||||
log(MAX(fabs(*(ckt->CKTstate0 + inst->DIOcurrent)/inst->DIOm),N_MINLOG))) /
|
||||
data->freq * inst->DIOm;
|
||||
lnNdens[DIOFLNOIZ] =
|
||||
log(MAX(noizDens[DIOFLNOIZ],N_MINLOG));
|
||||
|
||||
NevalSrcInstanceTemp(&noizDens[DIORSNOIZ],&lnNdens[DIORSNOIZ],
|
||||
ckt, THERMNOISE, inst->DIOposPrimeNode, inst->DIOposNode,
|
||||
inst->DIOtConductance, dtemp);
|
||||
noizDens[DIOTOTNOIZ] = noizDens[DIORSNOIZ] +
|
||||
noizDens[DIOIDNOIZ] +
|
||||
noizDens[DIOFLNOIZ];
|
||||
lnNdens[DIOTOTNOIZ] =
|
||||
log(MAX(noizDens[DIOTOTNOIZ], N_MINLOG));
|
||||
|
||||
NevalSrc(&noizDens[DIOIDNOIZ],&lnNdens[DIOIDNOIZ],
|
||||
ckt, SHOTNOISE, inst->DIOposPrimeNode, inst->DIOnegNode,
|
||||
*(ckt->CKTstate0 + inst->DIOcurrent));
|
||||
*OnDens += noizDens[DIOTOTNOIZ];
|
||||
|
||||
NevalSrc(&noizDens[DIOFLNOIZ], NULL, ckt,
|
||||
N_GAIN, inst->DIOposPrimeNode, inst->DIOnegNode,
|
||||
(double) 0.0);
|
||||
noizDens[DIOFLNOIZ] *= model->DIOfNcoef *
|
||||
exp(model->DIOfNexp *
|
||||
log(MAX(fabs(*(ckt->CKTstate0 + inst->DIOcurrent) / inst->DIOm), N_MINLOG))) /
|
||||
data->freq * inst->DIOm;
|
||||
lnNdens[DIOFLNOIZ] =
|
||||
log(MAX(noizDens[DIOFLNOIZ], N_MINLOG));
|
||||
if (data->delFreq == 0.0) {
|
||||
|
||||
noizDens[DIOTOTNOIZ] = noizDens[DIORSNOIZ] +
|
||||
noizDens[DIOIDNOIZ] +
|
||||
noizDens[DIOFLNOIZ];
|
||||
lnNdens[DIOTOTNOIZ] =
|
||||
log(MAX(noizDens[DIOTOTNOIZ], N_MINLOG));
|
||||
/* if we haven't done any previous integration, we need to */
|
||||
/* initialize our "history" variables */
|
||||
|
||||
*OnDens += noizDens[DIOTOTNOIZ];
|
||||
for (i=0; i < DIONSRCS; i++) {
|
||||
inst->DIOnVar[LNLSTDENS][i] = lnNdens[i];
|
||||
}
|
||||
|
||||
if (data->delFreq == 0.0) {
|
||||
/* clear out our integration variables if it's the first pass */
|
||||
|
||||
/* if we haven't done any previous integration, we need to */
|
||||
/* initialize our "history" variables */
|
||||
if (data->freq == job->NstartFreq) {
|
||||
for (i=0; i < DIONSRCS; i++) {
|
||||
inst->DIOnVar[OUTNOIZ][i] = 0.0;
|
||||
inst->DIOnVar[INNOIZ][i] = 0.0;
|
||||
}
|
||||
}
|
||||
} else { /* data->delFreq != 0.0 (we have to integrate) */
|
||||
|
||||
for (i = 0; i < DIONSRCS; i++) {
|
||||
inst->DIOnVar[LNLSTDENS][i] = lnNdens[i];
|
||||
}
|
||||
/* To insure accurracy, we have to integrate each component separately */
|
||||
|
||||
/* clear out our integration variables if it's the first pass */
|
||||
|
||||
if (data->freq == job->NstartFreq) {
|
||||
for (i = 0; i < DIONSRCS; i++) {
|
||||
inst->DIOnVar[OUTNOIZ][i] = 0.0;
|
||||
inst->DIOnVar[INNOIZ][i] = 0.0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* data->delFreq != 0.0 (we have to integrate) */
|
||||
|
||||
/* To insure accurracy, we have to integrate each component separately */
|
||||
|
||||
for (i = 0; i < DIONSRCS; i++) {
|
||||
if (i != DIOTOTNOIZ) {
|
||||
tempOnoise = Nintegrate(noizDens[i], lnNdens[i],
|
||||
inst->DIOnVar[LNLSTDENS][i], data);
|
||||
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv,
|
||||
lnNdens[i] + data->lnGainInv,
|
||||
inst->DIOnVar[LNLSTDENS][i] + data->lnGainInv,
|
||||
data);
|
||||
inst->DIOnVar[LNLSTDENS][i] = lnNdens[i];
|
||||
data->outNoiz += tempOnoise;
|
||||
data->inNoise += tempInoise;
|
||||
if (job->NStpsSm != 0) {
|
||||
inst->DIOnVar[OUTNOIZ][i] += tempOnoise;
|
||||
inst->DIOnVar[OUTNOIZ][DIOTOTNOIZ] += tempOnoise;
|
||||
inst->DIOnVar[INNOIZ][i] += tempInoise;
|
||||
inst->DIOnVar[INNOIZ][DIOTOTNOIZ] += tempInoise;
|
||||
for (i=0; i < DIONSRCS; i++) {
|
||||
if (i != DIOTOTNOIZ) {
|
||||
tempOnoise = Nintegrate(noizDens[i], lnNdens[i],
|
||||
inst->DIOnVar[LNLSTDENS][i], data);
|
||||
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv ,
|
||||
lnNdens[i] + data->lnGainInv,
|
||||
inst->DIOnVar[LNLSTDENS][i] + data->lnGainInv,
|
||||
data);
|
||||
inst->DIOnVar[LNLSTDENS][i] = lnNdens[i];
|
||||
data->outNoiz += tempOnoise;
|
||||
data->inNoise += tempInoise;
|
||||
if (job->NStpsSm != 0) {
|
||||
inst->DIOnVar[OUTNOIZ][i] += tempOnoise;
|
||||
inst->DIOnVar[OUTNOIZ][DIOTOTNOIZ] += tempOnoise;
|
||||
inst->DIOnVar[INNOIZ][i] += tempInoise;
|
||||
inst->DIOnVar[INNOIZ][DIOTOTNOIZ] += tempInoise;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data->prtSummary) {
|
||||
for (i = 0; i < DIONSRCS; i++) {
|
||||
/* print a summary report */
|
||||
data->outpVector[data->outNumber++] = noizDens[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data->prtSummary) {
|
||||
for (i=0; i < DIONSRCS; i++) { /* print a summary report */
|
||||
data->outpVector[data->outNumber++] = noizDens[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case INT_NOIZ:
|
||||
/* already calculated, just output */
|
||||
if (job->NStpsSm != 0) {
|
||||
for (i = 0; i < DIONSRCS; i++) {
|
||||
data->outpVector[data->outNumber++] = inst->DIOnVar[OUTNOIZ][i];
|
||||
data->outpVector[data->outNumber++] = inst->DIOnVar[INNOIZ][i];
|
||||
}
|
||||
} /* if */
|
||||
break;
|
||||
} /* switch (mode) */
|
||||
break;
|
||||
case INT_NOIZ: /* already calculated, just output */
|
||||
if (job->NStpsSm != 0) {
|
||||
for (i=0; i < DIONSRCS; i++) {
|
||||
data->outpVector[data->outNumber++] = inst->DIOnVar[OUTNOIZ][i];
|
||||
data->outpVector[data->outNumber++] = inst->DIOnVar[INNOIZ][i];
|
||||
}
|
||||
} /* if */
|
||||
break;
|
||||
} /* switch (mode) */
|
||||
break;
|
||||
|
||||
case N_CLOSE:
|
||||
return (OK); /* do nothing, the main calling routine will close */
|
||||
break; /* the plots */
|
||||
} /* switch (operation) */
|
||||
} /* for inst */
|
||||
} /* for model */
|
||||
case N_CLOSE:
|
||||
return (OK); /* do nothing, the main calling routine will close */
|
||||
break; /* the plots */
|
||||
} /* switch (operation) */
|
||||
} /* for inst */
|
||||
} /* for model */
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
|
@ -172,7 +172,7 @@ pertvd: /* Perturbation of Diode Voltage */
|
|||
*(here->DIOsenCeq + 2)= *(ckt->CKTstate0 + here->DIOcapCurrent);
|
||||
*(ckt->CKTstate0 + here->DIOvoltage) = A0;
|
||||
}
|
||||
gspr=here->DIOtConductance;
|
||||
gspr=here->DIOtConductance*here->DIOarea;
|
||||
geq = *(here->DIOsenGeq + 2);
|
||||
xceq = *(here->DIOsenCeq + 2) * ckt->CKTomega;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
|||
#include "ngspice/sperror.h"
|
||||
#include "ngspice/suffix.h"
|
||||
#include "ngspice/fteext.h"
|
||||
#include "ngspice/compatmode.h"
|
||||
|
||||
int
|
||||
DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
||||
|
|
@ -79,20 +78,7 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
model->DIOtranTimeTemp2 = 0.0;
|
||||
}
|
||||
if(!model->DIOjunctionCapGiven) {
|
||||
if (newcompat.ps || newcompat.lt) {
|
||||
double cdiode = 0.;
|
||||
/* to improve convergence (sometimes) */
|
||||
if (cp_getvar("diode_cj0", CP_REAL, &cdiode, 0) && cdiode > 0) {
|
||||
model->DIOjunctionCap = cdiode;
|
||||
if (ft_ngdebug)
|
||||
fprintf(stderr, "Diode junction capacitance in model %s set to %e F\n", model->gen.GENmodName, cdiode);
|
||||
}
|
||||
else
|
||||
model->DIOjunctionCap = 0.0;
|
||||
}
|
||||
else {
|
||||
model->DIOjunctionCap = 0.0;
|
||||
}
|
||||
model->DIOjunctionCap = 0;
|
||||
}
|
||||
if(!model->DIOjunctionSWCapGiven) {
|
||||
model->DIOjunctionSWCap = 0;
|
||||
|
|
@ -103,19 +89,11 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
if(!model->DIOgradingSWCoeffGiven) {
|
||||
model->DIOgradingSWCoeff = .33;
|
||||
}
|
||||
if(model->DIOforwardKneeCurrentGiven) {
|
||||
if (model->DIOforwardKneeCurrent < ckt->CKTepsmin) {
|
||||
model->DIOforwardKneeCurrentGiven = FALSE;
|
||||
fprintf(stderr, "Warning: %s: IKF too small - model effect disabled!\n",
|
||||
model->DIOmodName);
|
||||
}
|
||||
if(!model->DIOforwardKneeCurrentGiven) {
|
||||
model->DIOforwardKneeCurrent = 0.0;
|
||||
}
|
||||
if(model->DIOreverseKneeCurrentGiven) {
|
||||
if (model->DIOreverseKneeCurrent < ckt->CKTepsmin) {
|
||||
model->DIOreverseKneeCurrentGiven = FALSE;
|
||||
fprintf(stderr, "Warning: %s: IKR too small - model effect disabled!\n",
|
||||
model->DIOmodName);
|
||||
}
|
||||
if(!model->DIOreverseKneeCurrentGiven) {
|
||||
model->DIOreverseKneeCurrent = 0.0;
|
||||
}
|
||||
if(!model->DIObrkdEmissionCoeffGiven) {
|
||||
model->DIObrkdEmissionCoeff = model->DIOemissionCoeff;
|
||||
|
|
@ -127,17 +105,7 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
model->DIOtlevc = 0;
|
||||
}
|
||||
if(!model->DIOactivationEnergyGiven) {
|
||||
if(model->DIOtlev == 2) {
|
||||
model->DIOactivationEnergy = 1.16;
|
||||
} else {
|
||||
model->DIOactivationEnergy = 1.11;
|
||||
}
|
||||
}
|
||||
if(!model->DIOfirstBGcorrFactorGiven) {
|
||||
model->DIOfirstBGcorrFactor = 7.02e-4;
|
||||
}
|
||||
if(!model->DIOsecndBGcorrFactorGiven) {
|
||||
model->DIOsecndBGcorrFactor = 1108.0;
|
||||
model->DIOactivationEnergy = 1.11;
|
||||
}
|
||||
if(!model->DIOsaturationCurrentExpGiven) {
|
||||
model->DIOsaturationCurrentExp = 3;
|
||||
|
|
@ -206,11 +174,14 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
model->DIOte_max = 1e99;
|
||||
}
|
||||
if(!model->DIOrecEmissionCoeffGiven) {
|
||||
model->DIOrecEmissionCoeff = 2;
|
||||
model->DIOrecEmissionCoeff = 1;
|
||||
}
|
||||
if(!model->DIOrecSatCurGiven) {
|
||||
model->DIOrecSatCur = 1e-14;
|
||||
}
|
||||
if (!model->DIOsoftRevRecParamGiven) {
|
||||
model->DIOsoftRevRecParam = 0.0;
|
||||
}
|
||||
|
||||
/* set lower limit of saturation current */
|
||||
if (model->DIOsatCur < ckt->CKTepsmin)
|
||||
|
|
@ -221,20 +192,7 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
}
|
||||
|
||||
if((!model->DIOresistGiven) || (model->DIOresist==0)) {
|
||||
if (newcompat.ps || newcompat.lt) {
|
||||
double rsdiode = 0.;
|
||||
/* to improve convergence (sometimes) */
|
||||
if (cp_getvar("diode_rser", CP_REAL, &rsdiode, 0) && rsdiode > 0) {
|
||||
model->DIOconductance = 1./rsdiode;
|
||||
model->DIOresist = rsdiode;
|
||||
if (ft_ngdebug)
|
||||
fprintf(stderr, "Diode series resistance in model %s set to %e Ohm\n", model->gen.GENmodName, rsdiode);
|
||||
}
|
||||
else
|
||||
model->DIOconductance = 0.0;
|
||||
}
|
||||
else
|
||||
model->DIOconductance = 0.0;
|
||||
model->DIOconductance = 0.0;
|
||||
} else {
|
||||
model->DIOconductance = 1/model->DIOresist;
|
||||
}
|
||||
|
|
@ -270,9 +228,6 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
if(!model->DIOpolyMaskOffsetGiven) {
|
||||
model->DIOpolyMaskOffset = 0.0;
|
||||
}
|
||||
if(!model->DIOmaskOffsetGiven) {
|
||||
model->DIOmaskOffset = 0.0;
|
||||
}
|
||||
|
||||
/* loop through all the instances of the model */
|
||||
for (here = DIOinstances(model); here != NULL ;
|
||||
|
|
@ -296,41 +251,45 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
here->DIOm = 1;
|
||||
}
|
||||
|
||||
here->DIOcmetal = 0.0;
|
||||
here->DIOcpoly = 0.0;
|
||||
here->DIOarea = here->DIOarea * here->DIOm;
|
||||
here->DIOpj = here->DIOpj * here->DIOm;
|
||||
here->DIOcmetal = 0.0;
|
||||
here->DIOcpoly = 0.0;
|
||||
if (model->DIOlevel == 3) {
|
||||
double wm, lm, wp, lp;
|
||||
if((here->DIOwGiven) && (here->DIOlGiven)) {
|
||||
here->DIOarea = (here->DIOw+model->DIOmaskOffset) * (here->DIOl+model->DIOmaskOffset) * here->DIOm * scale * scale;
|
||||
here->DIOpj = (2 * (here->DIOw+model->DIOmaskOffset) + 2 * (here->DIOl+model->DIOmaskOffset)) * here->DIOm * scale;
|
||||
here->DIOarea = here->DIOw * here->DIOl * here->DIOm;
|
||||
here->DIOpj = (2 * here->DIOw + 2 * here->DIOl) * here->DIOm;
|
||||
}
|
||||
if (here->DIOwidthMetalGiven)
|
||||
here->DIOarea = here->DIOarea * scale * scale;
|
||||
here->DIOpj = here->DIOpj * scale;
|
||||
if (here->DIOwidthMetalGiven)
|
||||
wm = here->DIOwidthMetal;
|
||||
else
|
||||
wm = model->DIOwidthMetal;
|
||||
if (here->DIOlengthMetalGiven)
|
||||
if (here->DIOlengthMetalGiven)
|
||||
lm = here->DIOlengthMetal;
|
||||
else
|
||||
lm = model->DIOlengthMetal;
|
||||
if (here->DIOwidthPolyGiven)
|
||||
if (here->DIOwidthPolyGiven)
|
||||
wp = here->DIOwidthPoly;
|
||||
else
|
||||
wp = model->DIOwidthPoly;
|
||||
if (here->DIOlengthPolyGiven)
|
||||
if (here->DIOlengthPolyGiven)
|
||||
lp = here->DIOlengthPoly;
|
||||
else
|
||||
lp = model->DIOlengthPoly;
|
||||
here->DIOcmetal = CONSTepsSiO2 / model->DIOmetalOxideThick * here->DIOm
|
||||
* (wm * scale + model->DIOmetalMaskOffset)
|
||||
* (wm * scale + model->DIOmetalMaskOffset)
|
||||
* (lm * scale + model->DIOmetalMaskOffset);
|
||||
here->DIOcpoly = CONSTepsSiO2 / model->DIOpolyOxideThick * here->DIOm
|
||||
* (wp * scale + model->DIOpolyMaskOffset)
|
||||
* (wp * scale + model->DIOpolyMaskOffset)
|
||||
* (lp * scale + model->DIOpolyMaskOffset);
|
||||
}
|
||||
here->DIOforwardKneeCurrent = model->DIOforwardKneeCurrent * here->DIOarea * here->DIOm;
|
||||
here->DIOreverseKneeCurrent = model->DIOreverseKneeCurrent * here->DIOarea * here->DIOm;
|
||||
here->DIOjunctionCap = model->DIOjunctionCap * here->DIOarea * here->DIOm;
|
||||
here->DIOjunctionSWCap = model->DIOjunctionSWCap * here->DIOpj * here->DIOm;
|
||||
here->DIOforwardKneeCurrent = model->DIOforwardKneeCurrent * here->DIOarea;
|
||||
here->DIOreverseKneeCurrent = model->DIOreverseKneeCurrent * here->DIOarea;
|
||||
here->DIOjunctionCap = model->DIOjunctionCap * here->DIOarea;
|
||||
here->DIOjunctionSWCap = model->DIOjunctionSWCap * here->DIOpj;
|
||||
|
||||
here->DIOstate = *states;
|
||||
*states += DIOnumStates;
|
||||
|
|
|
|||
|
|
@ -33,46 +33,44 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit
|
|||
double egfet1,arg1,fact1,pbfact1,pbo,gmaold,pboSW,gmaSWold;
|
||||
double fact2,pbfact,arg,egfet,gmanew,gmaSWnew;
|
||||
double arg1_dT, arg2, arg2_dT;
|
||||
double lnTRatio, egfet_dT = 0.0, arg0, vte_dT, vts_dT, vtt_dT, vtr_dT;
|
||||
double gclimit;
|
||||
|
||||
if (!cp_getvar("DIOgradingCoeffMax", CP_REAL, &gclimit, 0))
|
||||
gclimit = 0.9;
|
||||
|
||||
vt = CONSTKoverQ * Temp;
|
||||
vte = model->DIOemissionCoeff * vt;
|
||||
vte_dT = CONSTKoverQ * model->DIOemissionCoeff;
|
||||
vts = model->DIOswEmissionCoeff * vt;
|
||||
vts_dT = CONSTKoverQ * model->DIOswEmissionCoeff;
|
||||
vtt = model->DIOtunEmissionCoeff * vt;
|
||||
vtt_dT = CONSTKoverQ * model->DIOtunEmissionCoeff;
|
||||
vtr = model->DIOrecEmissionCoeff * vt;
|
||||
vtr_dT = CONSTKoverQ * model->DIOrecEmissionCoeff;
|
||||
vtnom = CONSTKoverQ * model->DIOnomTemp;
|
||||
dt = Temp - model->DIOnomTemp;
|
||||
lnTRatio = log(Temp / model->DIOnomTemp);
|
||||
|
||||
/* Junction grading temperature adjust */
|
||||
factor = 1.0 + (model->DIOgradCoeffTemp1 * dt)
|
||||
+ (model->DIOgradCoeffTemp2 * dt * dt);
|
||||
here->DIOtGradingCoeff = model->DIOgradingCoeff * factor;
|
||||
|
||||
/* limit temperature adjusted grading coeff
|
||||
* to max of .9, or set new limit with variable DIOgradingCoeffMax
|
||||
*/
|
||||
if(here->DIOtGradingCoeff>gclimit) {
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING,
|
||||
"%s: temperature adjusted grading coefficient too large, limited to %g",
|
||||
here->DIOname, gclimit);
|
||||
here->DIOtGradingCoeff=gclimit;
|
||||
}
|
||||
|
||||
/* this part gets really ugly - I won't even try to
|
||||
* explain these equations */
|
||||
if ((model->DIOtlev == 0) || (model->DIOtlev == 1)) {
|
||||
egfet = 1.16-(7.02e-4*Temp*Temp)/
|
||||
(Temp+1108);
|
||||
egfet1 = 1.16 - (7.02e-4*model->DIOnomTemp*model->DIOnomTemp)/
|
||||
(model->DIOnomTemp+1108);
|
||||
} else {
|
||||
egfet = model->DIOactivationEnergy-(model->DIOfirstBGcorrFactor*Temp*Temp)/
|
||||
(Temp+model->DIOsecndBGcorrFactor);
|
||||
egfet_dT = (model->DIOfirstBGcorrFactor*Temp*Temp)/
|
||||
((Temp+model->DIOsecndBGcorrFactor)*(Temp+model->DIOsecndBGcorrFactor))
|
||||
- 2*model->DIOfirstBGcorrFactor*Temp/(Temp+model->DIOsecndBGcorrFactor);
|
||||
egfet1 = model->DIOactivationEnergy - (model->DIOfirstBGcorrFactor*model->DIOnomTemp*model->DIOnomTemp)/
|
||||
(model->DIOnomTemp+model->DIOsecndBGcorrFactor);
|
||||
}
|
||||
fact2 = Temp/REFTEMP;
|
||||
egfet = 1.16-(7.02e-4*Temp*Temp)/
|
||||
(Temp+1108);
|
||||
arg = -egfet/(2*CONSTboltz*Temp) +
|
||||
1.1150877/(CONSTboltz*(REFTEMP+REFTEMP));
|
||||
pbfact = -2*vt*(1.5*log(fact2)+CHARGE*arg);
|
||||
egfet1 = 1.16 - (7.02e-4*model->DIOnomTemp*model->DIOnomTemp)/
|
||||
(model->DIOnomTemp+1108);
|
||||
arg1 = -egfet1/(CONSTboltz*2*model->DIOnomTemp) +
|
||||
1.1150877/(2*CONSTboltz*REFTEMP);
|
||||
fact1 = model->DIOnomTemp/REFTEMP;
|
||||
|
|
@ -110,77 +108,45 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit
|
|||
(1+model->DIOctp*(Temp-REFTEMP));
|
||||
}
|
||||
|
||||
if ((model->DIOtlev == 0) || (model->DIOtlev == 1)) {
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOactivationEnergy / vte;
|
||||
arg1_dT = model->DIOactivationEnergy / (vte*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vte*Temp);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOemissionCoeff * lnTRatio;
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOemissionCoeff / Temp;
|
||||
here->DIOtSatCur = model->DIOsatCur * here->DIOarea * here->DIOm * exp(arg1 + arg2);
|
||||
here->DIOtSatCur_dT = here->DIOtSatCur * (arg1_dT + arg2_dT);
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOactivationEnergy / vte;
|
||||
arg1_dT = model->DIOactivationEnergy / (vte*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vte*Temp);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOemissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOemissionCoeff / Temp;
|
||||
here->DIOtSatCur = here->DIOm * model->DIOsatCur * here->DIOarea * exp(arg1 + arg2);
|
||||
here->DIOtSatCur_dT = here->DIOm * model->DIOsatCur * here->DIOarea * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOactivationEnergy / vts;
|
||||
arg1_dT = model->DIOactivationEnergy / (vts*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vts*Temp);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOswEmissionCoeff * lnTRatio;
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOswEmissionCoeff / Temp;
|
||||
here->DIOtSatSWCur = model->DIOsatSWCur * here->DIOpj * here->DIOm * exp(arg1 + arg2);
|
||||
here->DIOtSatSWCur_dT = here->DIOtSatSWCur * (arg1_dT + arg2_dT);
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOactivationEnergy / vts;
|
||||
arg1_dT = model->DIOactivationEnergy / (vts*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vts*Temp);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOswEmissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOswEmissionCoeff / Temp;
|
||||
here->DIOtSatSWCur = here->DIOm * model->DIOsatSWCur * here->DIOpj * exp(arg1 + arg2);
|
||||
here->DIOtSatSWCur_dT = here->DIOm * model->DIOsatSWCur * here->DIOpj * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
arg1 = ((Temp/model->DIOnomTemp)-1) * model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / vtt;
|
||||
arg1_dT = model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / (vtt*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vtt*Temp);
|
||||
arg2 = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff * lnTRatio;
|
||||
arg2_dT = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff / Temp;
|
||||
here->DIOtTunSatCur = model->DIOtunSatCur * here->DIOarea * here->DIOm * exp(arg1 + arg2);
|
||||
here->DIOtTunSatCur_dT = here->DIOtTunSatCur * (arg1_dT + arg2_dT);
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / vtt;
|
||||
arg1_dT = model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / (vtt*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vtt*Temp);
|
||||
arg2 = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff / Temp;
|
||||
here->DIOtTunSatCur = here->DIOm * model->DIOtunSatCur * here->DIOarea * exp(arg1 + arg2);
|
||||
here->DIOtTunSatCur_dT = here->DIOm * model->DIOtunSatCur * here->DIOarea * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
here->DIOtTunSatSWCur = model->DIOtunSatSWCur * here->DIOpj * here->DIOm * exp(arg1 + arg2);
|
||||
here->DIOtTunSatSWCur_dT = here->DIOtTunSatSWCur * (arg1_dT + arg2_dT);
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / vtt;
|
||||
arg1_dT = model->DIOtunEGcorrectionFactor*model->DIOactivationEnergy / (vtt*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vtt*Temp);
|
||||
arg2 = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff / Temp;
|
||||
here->DIOtTunSatSWCur = here->DIOm * model->DIOtunSatSWCur * here->DIOpj * exp(arg1 + arg2);
|
||||
here->DIOtTunSatSWCur_dT = here->DIOm * model->DIOtunSatSWCur * here->DIOpj * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOactivationEnergy / vtr;
|
||||
arg1_dT = model->DIOactivationEnergy / (vtr*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vtr*Temp);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOrecEmissionCoeff * lnTRatio;
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOrecEmissionCoeff / Temp;
|
||||
here->DIOtRecSatCur = model->DIOrecSatCur * here->DIOarea * here->DIOm * exp(arg1 + arg2);
|
||||
here->DIOtRecSatCur_dT = here->DIOtRecSatCur * (arg1_dT + arg2_dT);
|
||||
} else {
|
||||
arg0 = egfet1 / (model->DIOemissionCoeff * vtnom);
|
||||
arg1 = egfet / vte;
|
||||
arg1_dT = (egfet_dT * vte - egfet * vte_dT) / (egfet*egfet);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOemissionCoeff * lnTRatio;
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOemissionCoeff / Temp;
|
||||
here->DIOtSatCur = model->DIOsatCur * here->DIOarea * here->DIOm * exp(arg0 - arg1 + arg2);
|
||||
here->DIOtSatCur_dT = here->DIOtSatCur * (-arg1_dT + arg2_dT);
|
||||
|
||||
arg0 = egfet1 / (model->DIOswEmissionCoeff * vtnom);
|
||||
arg1 = egfet / vts;
|
||||
arg1_dT = (egfet_dT * vts - egfet * vts_dT) / (egfet*egfet);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOswEmissionCoeff * lnTRatio;
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOswEmissionCoeff / Temp;
|
||||
here->DIOtSatSWCur = model->DIOsatSWCur * here->DIOpj * here->DIOm * exp(arg0 - arg1 + arg2);
|
||||
here->DIOtSatSWCur_dT = here->DIOtSatSWCur * (-arg1_dT + arg2_dT);
|
||||
|
||||
arg0 = model->DIOtunEGcorrectionFactor * egfet1 / (model->DIOtunEmissionCoeff * vtnom);
|
||||
arg1 = model->DIOtunEGcorrectionFactor * egfet / vtt;
|
||||
arg1_dT = model->DIOtunEGcorrectionFactor * (egfet_dT * vtt - egfet * vtt_dT) / (egfet*egfet);
|
||||
arg2 = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff * lnTRatio;
|
||||
arg2_dT = model->DIOtunSaturationCurrentExp / model->DIOtunEmissionCoeff / Temp;
|
||||
here->DIOtTunSatCur = model->DIOtunSatCur * here->DIOarea * here->DIOm * exp(arg0 - arg1 + arg2);
|
||||
here->DIOtTunSatCur_dT = here->DIOtTunSatCur * (-arg1_dT + arg2_dT);
|
||||
|
||||
here->DIOtTunSatSWCur = model->DIOtunSatSWCur * here->DIOpj * here->DIOm * exp(arg0 - arg1 + arg2);
|
||||
here->DIOtTunSatSWCur_dT = here->DIOtTunSatSWCur * (-arg1_dT + arg2_dT);
|
||||
|
||||
arg0 = egfet1 / (model->DIOrecEmissionCoeff * vtnom);
|
||||
arg1 = egfet / vtr;
|
||||
arg1_dT = (egfet_dT * vtr - egfet * vtr_dT) / (egfet*egfet);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOrecEmissionCoeff * lnTRatio;
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOrecEmissionCoeff / Temp;
|
||||
here->DIOtRecSatCur = model->DIOrecSatCur * here->DIOarea * here->DIOm * exp(arg0 - arg1 + arg2);
|
||||
here->DIOtRecSatCur_dT = here->DIOtRecSatCur * (-arg1_dT + arg2_dT);
|
||||
}
|
||||
arg1 = ((Temp / model->DIOnomTemp) - 1) * model->DIOactivationEnergy / vtr;
|
||||
arg1_dT = model->DIOactivationEnergy / (vtr*model->DIOnomTemp)
|
||||
- model->DIOactivationEnergy*(Temp/model->DIOnomTemp -1)/(vtr*Temp);
|
||||
arg2 = model->DIOsaturationCurrentExp / model->DIOrecEmissionCoeff * log(Temp / model->DIOnomTemp);
|
||||
arg2_dT = model->DIOsaturationCurrentExp / model->DIOrecEmissionCoeff / Temp;
|
||||
here->DIOtRecSatCur = here->DIOm * model->DIOrecSatCur * here->DIOarea * exp(arg1 + arg2);
|
||||
here->DIOtRecSatCur_dT = here->DIOm * model->DIOrecSatCur * here->DIOarea * exp(arg1 + arg2) * (arg1_dT + arg2_dT);
|
||||
|
||||
xfc=log(1-model->DIOdepletionCapCoeff);
|
||||
xfcs=log(1-model->DIOdepletionSWcapCoeff);
|
||||
|
|
@ -196,8 +162,26 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit
|
|||
here->DIOtDepSWCap=model->DIOdepletionSWcapCoeff*
|
||||
here->DIOtJctSWPot;
|
||||
/* and Vcrit */
|
||||
double totalSatCur = here->DIOtSatCur + here->DIOtSatSWCur;
|
||||
here->DIOtVcrit = vte * log(vte/(CONSTroot2*totalSatCur));
|
||||
vte=model->DIOemissionCoeff*vt;
|
||||
|
||||
here->DIOtVcrit = vte * log(vte/(CONSTroot2*here->DIOtSatCur));
|
||||
|
||||
/* limit junction potential to max of 1/FC */
|
||||
if(here->DIOtDepCap > 1.0) {
|
||||
here->DIOtJctPot=1.0/model->DIOdepletionCapCoeff;
|
||||
here->DIOtDepCap=model->DIOdepletionCapCoeff*here->DIOtJctPot;
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING,
|
||||
"%s: junction potential VJ too large, limited to %f",
|
||||
model->DIOmodName, here->DIOtJctPot);
|
||||
}
|
||||
/* limit sidewall junction potential to max of 1/FCS */
|
||||
if(here->DIOtDepSWCap > 1.0) {
|
||||
here->DIOtJctSWPot=1.0/model->DIOdepletionSWcapCoeff;
|
||||
here->DIOtDepSWCap=model->DIOdepletionSWcapCoeff*here->DIOtJctSWPot;
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING,
|
||||
"%s: junction potential VJS too large, limited to %f",
|
||||
model->DIOmodName, here->DIOtJctSWPot);
|
||||
}
|
||||
|
||||
/* and now to compute the breakdown voltage, again, using
|
||||
* temperature adjusted basic parameters */
|
||||
|
|
@ -210,11 +194,11 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit
|
|||
if (model->DIOlevel == 1) {
|
||||
cbv = here->DIOm * model->DIObreakdownCurrent;
|
||||
} else { /* level=3 */
|
||||
cbv = model->DIObreakdownCurrent * here->DIOarea * here->DIOm;
|
||||
cbv = here->DIOm * model->DIObreakdownCurrent * here->DIOarea;
|
||||
}
|
||||
if (cbv < totalSatCur * tBreakdownVoltage/vt) {
|
||||
if (cbv < here->DIOtSatCur * tBreakdownVoltage/vt) {
|
||||
#ifdef TRACE
|
||||
cbv=totalSatCur * tBreakdownVoltage/vt;
|
||||
cbv=here->DIOtSatCur * tBreakdownVoltage/vt;
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING, "%s: breakdown current increased to %g to resolve", here->DIOname, cbv);
|
||||
SPfrontEnd->IFerrorf (ERR_WARNING,
|
||||
"incompatibility with specified saturation current");
|
||||
|
|
@ -223,11 +207,11 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit
|
|||
} else {
|
||||
tol=ckt->CKTreltol*cbv;
|
||||
xbv=tBreakdownVoltage-model->DIObrkdEmissionCoeff*vt*log(1+cbv/
|
||||
totalSatCur);
|
||||
(here->DIOtSatCur));
|
||||
for(iter=0 ; iter < 25 ; iter++) {
|
||||
xbv=tBreakdownVoltage-model->DIObrkdEmissionCoeff*vt*log(cbv/
|
||||
totalSatCur+1-xbv/vt);
|
||||
xcbv=totalSatCur *
|
||||
(here->DIOtSatCur)+1-xbv/vt);
|
||||
xcbv=here->DIOtSatCur *
|
||||
(exp((tBreakdownVoltage-xbv)/(model->DIObrkdEmissionCoeff*vt))-1+xbv/vt);
|
||||
if (fabs(xcbv-cbv) <= tol) goto matched;
|
||||
}
|
||||
|
|
@ -245,12 +229,12 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit
|
|||
here->DIOtTransitTime = model->DIOtransitTime * factor;
|
||||
|
||||
/* Series resistance temperature adjust */
|
||||
here->DIOtConductance = model->DIOconductance * here->DIOarea * here->DIOm;
|
||||
here->DIOtConductance = here->DIOm * model->DIOconductance * here->DIOarea;
|
||||
if(model->DIOresistGiven && model->DIOresist!=0.0) {
|
||||
factor = 1.0 + (model->DIOresistTemp1) * dt
|
||||
+ (model->DIOresistTemp2 * dt * dt);
|
||||
here->DIOtConductance = model->DIOconductance * here->DIOarea * here->DIOm / factor;
|
||||
here->DIOtConductance_dT = -model->DIOconductance * here->DIOarea * here->DIOm *
|
||||
here->DIOtConductance = here->DIOm * model->DIOconductance * here->DIOarea / factor;
|
||||
here->DIOtConductance_dT = here->DIOm * -model->DIOconductance * here->DIOarea *
|
||||
(model->DIOresistTemp1 + model->DIOresistTemp2 * dt) / (factor*factor);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ DIOtrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep)
|
|||
for( ; model != NULL; model = DIOnextModel(model)) {
|
||||
for(here=DIOinstances(model);here!=NULL;here = DIOnextInstance(here)){
|
||||
CKTterr(here->DIOcapCharge,ckt,timeStep);
|
||||
CKTterr(here->DIOdiffCharge,ckt,timeStep);
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
Loading…
Reference in New Issue