Diode soft recovery model based on the idea of A. Buermen with iterated charge node for diffusion charge and model parameter Vp.
Small simplifications in AC model and capacitance reporting are made. No self-heating for this effect. Pole-Zero and distortion analysis is not implemented for this model extension.
This commit is contained in:
parent
7d808f991e
commit
f7ef88b637
|
|
@ -1,7 +1,7 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Thomas L. Quarles
|
||||
Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
||||
Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025
|
||||
**********/
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
|
|
@ -122,6 +122,7 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
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 */
|
||||
IOPX( "fv_max", DIO_MOD_FV_MAX, IF_REAL, "maximum voltage in forward direction"),
|
||||
|
|
|
|||
|
|
@ -91,6 +91,20 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
(*(here->DIOnegTempPtr) += -dIdioSw_dT);
|
||||
}
|
||||
}
|
||||
if ((here->DIOqpNode > 0) && (model->DIOsoftRevRecParam!=0) && (here->DIOtTransitTime!=0)) {
|
||||
/* QP subcircuit */
|
||||
double gdres= *(ckt->CKTstate0 + here->DIOresConduct);
|
||||
double fac = here->DIOtTransitTime / model->DIOsoftRevRecParam;
|
||||
double dcrrdvd = fac * gdres;
|
||||
*(here->DIOqpQpPtr) += 1/model->DIOsoftRevRecParam;
|
||||
*(here->DIOqpQpPtr + 1) += here->DIOtTransitTime * ckt->CKTomega;
|
||||
*(here->DIOqpPosPrimePtr) += -dcrrdvd;
|
||||
*(here->DIOqpNegPtr) += dcrrdvd;
|
||||
/* Gain of VCVS (1-vp)/tau * j*omega*tau = (1-vp) * j*omega */
|
||||
double xgain = (1 - model->DIOsoftRevRecParam) * ckt->CKTomega;
|
||||
*(here->DIOposPrimeQpPtr + 1) += xgain;
|
||||
*(here->DIOnegQpPtr + 1) += -xgain;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -75,9 +75,13 @@ DIOask (CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
|
|||
return(OK);
|
||||
case DIO_CURRENT:
|
||||
value->rValue = *(ckt->CKTstate0+here->DIOcurrent);
|
||||
if ((here->DIOqpNode > 0) && (here->DIOtTransitTime!=0))
|
||||
value->rValue += here->DIOqpGain * *(ckt->CKTstate0 + here->DIOcqcsr);
|
||||
return(OK);
|
||||
case DIO_CAP:
|
||||
value->rValue = here->DIOcap;
|
||||
if ((here->DIOqpNode > 0) && (here->DIOtTransitTime!=0))
|
||||
value->rValue += here->DIOtTransitTime * *(ckt->CKTstate0+here->DIOconduct);
|
||||
return(OK);
|
||||
case DIO_CHARGE:
|
||||
value->rValue = *(ckt->CKTstate0+here->DIOcapCharge);
|
||||
|
|
|
|||
|
|
@ -54,6 +54,14 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CREATE_KLU_BINDING_TABLE(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode);
|
||||
}
|
||||
}
|
||||
/* rev-rec */
|
||||
if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) {
|
||||
CREATE_KLU_BINDING_TABLE(DIOqpQpPtr , DIOqpQpBinding , DIOqpNode, DIOqpNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOqpPosPrimePtr, DIOqpPosPrimeBinding, DIOqpNode, DIOposPrimeNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOqpNegPtr , DIOqpNegBinding , DIOqpNode, DIOnegNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOposPrimeQpPtr, DIOposPrimeQpBinding, DIOposPrimeNode, DIOqpNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOnegQpPtr , DIOnegQpBinding , DIOnegNode, DIOqpNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -103,6 +111,14 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode);
|
||||
}
|
||||
}
|
||||
/* rev-rec */
|
||||
if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) {
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOqpQpPtr , DIOqpQpBinding , DIOqpNode, DIOqpNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOqpPosPrimePtr, DIOqpPosPrimeBinding, DIOqpNode, DIOposPrimeNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOqpNegPtr , DIOqpNegBinding , DIOqpNode, DIOnegNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimeQpPtr, DIOposPrimeQpBinding, DIOposPrimeNode, DIOqpNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegQpPtr , DIOnegQpBinding , DIOnegNode, DIOqpNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +168,14 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode);
|
||||
}
|
||||
}
|
||||
/* rev-rec */
|
||||
if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) {
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOqpQpPtr , DIOqpQpBinding , DIOqpNode, DIOqpNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOqpPosPrimePtr, DIOqpPosPrimeBinding, DIOqpNode, DIOposPrimeNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOqpNegPtr , DIOqpNegBinding , DIOqpNode, DIOnegNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimeQpPtr, DIOposPrimeQpBinding, DIOposPrimeNode, DIOqpNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegQpPtr , DIOnegQpBinding , DIOnegNode, DIOqpNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Thomas L. Quarles
|
||||
Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
||||
Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025
|
||||
**********/
|
||||
#ifndef DIO
|
||||
#define DIO
|
||||
|
|
@ -44,6 +44,7 @@ typedef struct sDIOinstance {
|
|||
const int DIOtempNode; /* number of the temperature node of the diode */
|
||||
int DIOposPrimeNode; /* number of positive prime node of diode */
|
||||
int DIOposSwPrimeNode; /* number of positive prime node of diode sidewall */
|
||||
int DIOqpNode; /* number of soft recovery charge node */
|
||||
|
||||
double *DIOposPosPrimePtr; /* pointer to sparse matrix at
|
||||
* (positive,positive prime) */
|
||||
|
|
@ -83,9 +84,19 @@ typedef struct sDIOinstance {
|
|||
double *DIOtempPosSwPrimePtr;
|
||||
double *DIOposSwPrimeTempPtr;
|
||||
|
||||
/* rev-rec */
|
||||
double *DIOqpQpPtr;
|
||||
double *DIOqpPosPrimePtr;
|
||||
double *DIOqpNegPtr;
|
||||
double *DIOposPrimeQpPtr;
|
||||
double *DIOnegQpPtr;
|
||||
|
||||
double DIOcap; /* stores the diode capacitance */
|
||||
double DIOcapSW; /* stores the diode Sw capacitance */
|
||||
|
||||
/* rev-rec */
|
||||
double DIOqpGain;/* converts iterated diffcharge current */
|
||||
|
||||
double *DIOsens; /* stores the perturbed values of geq and ceq in ac
|
||||
sensitivity analyis */
|
||||
|
||||
|
|
@ -229,13 +240,19 @@ typedef struct sDIOinstance {
|
|||
/* self heating */
|
||||
BindElement *DIOtempPosBinding;
|
||||
BindElement *DIOtempPosPrimeBinding;
|
||||
BindElement *DIOtempNegBinding;
|
||||
BindElement *DIOtempNegBinding;
|
||||
BindElement *DIOtempTempBinding;
|
||||
BindElement *DIOposTempBinding;
|
||||
BindElement *DIOposPrimeTempBinding;
|
||||
BindElement *DIOnegTempBinding;
|
||||
BindElement *DIOtempPosSwPrimeBinding;
|
||||
BindElement *DIOposSwPrimeTempBinding;
|
||||
/* rev-rec */
|
||||
BindElement *DIOqpQpBinding;
|
||||
BindElement *DIOqpPosPrimeBinding;
|
||||
BindElement *DIOqpNegBinding;
|
||||
BindElement *DIOposPrimeQpBinding;
|
||||
BindElement *DIOnegQpBinding;
|
||||
#endif
|
||||
|
||||
} DIOinstance ;
|
||||
|
|
@ -244,7 +261,6 @@ typedef struct sDIOinstance {
|
|||
#define DIOsenCeq DIOsens + 3 /* stores the perturbed values of ceq */
|
||||
#define DIOdphidp DIOsens + 6
|
||||
|
||||
|
||||
#define DIOvoltage DIOstate
|
||||
#define DIOcurrent DIOstate+1
|
||||
#define DIOconduct DIOstate+2
|
||||
|
|
@ -256,18 +272,25 @@ typedef struct sDIOinstance {
|
|||
#define DIOcapChargeSW DIOstate+8
|
||||
#define DIOcapCurrentSW DIOstate+9
|
||||
|
||||
#define DIOqth DIOstate+10 /* thermal capacitor charge */
|
||||
#define DIOcqth DIOstate+11 /* thermal capacitor current */
|
||||
|
||||
#define DIOdeltemp DIOstate+12 /* thermal voltage over rth0 */
|
||||
#define DIOqth DIOstate+10 /* thermal capacitor charge */
|
||||
#define DIOcqth DIOstate+11 /* thermal capacitor current */
|
||||
#define DIOdeltemp DIOstate+12 /* thermal voltage over rth0 */
|
||||
#define DIOdIdio_dT DIOstate+13
|
||||
#define DIOdIdioSW_dT DIOstate+14
|
||||
/* rev-rec */
|
||||
#define DIOsrcapCharge DIOstate+15
|
||||
#define DIOsrcapCurrent DIOstate+16
|
||||
#define DIOqp DIOstate+17
|
||||
#define DIOresCurrent DIOstate+18
|
||||
#define DIOresConduct DIOstate+19
|
||||
#define DIOcqcsr DIOstate+20
|
||||
#define DIOgqcsr DIOstate+21
|
||||
|
||||
#define DIOnumStates 15
|
||||
#define DIOnumStates 22
|
||||
|
||||
#define DIOsensxp DIOstate+15 /* charge sensitivities and their derivatives.
|
||||
* +16 for the derivatives - pointer to the
|
||||
* beginning of the array */
|
||||
#define DIOsensxp DIOstate+22 /* charge sensitivities and their derivatives.
|
||||
* +23 for the derivatives - pointer to the
|
||||
* beginning of the array */
|
||||
|
||||
#define DIOnumSenStates 2
|
||||
|
||||
|
|
@ -342,6 +365,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;
|
||||
|
|
@ -418,6 +442,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;
|
||||
|
|
@ -526,6 +551,7 @@ enum {
|
|||
DIO_MOD_PD_MAX,
|
||||
DIO_MOD_ISR,
|
||||
DIO_MOD_NR,
|
||||
DIO_MOD_VP,
|
||||
DIO_MOD_RTH0,
|
||||
DIO_MOD_CTH0,
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Thomas L. Quarles
|
||||
Modified: 2000 AlansFixes
|
||||
Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
||||
Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025
|
||||
**********/
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
|
|
@ -65,6 +65,10 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double dIdio_dT, dIth_dVdio=0.0, dIrs_dT=0.0, dIth_dVrs=0.0, dIth_dT=0.0;
|
||||
double dIdioSw_dT=0.0, dIth_dVdioSw=0.0, dIth_dVrssw=0.0, dIrssw_dT=0.0;
|
||||
double argsw_dT, csat_dT, csatsw_dT;
|
||||
/* rev-rec */
|
||||
double cdres, gdres;
|
||||
double vqp;
|
||||
double capsr, gqcsr, cqcsr;
|
||||
|
||||
/* loop through all the diode models */
|
||||
for( ; model != NULL; model = DIOnextModel(model)) {
|
||||
|
|
@ -74,6 +78,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
here=DIOnextInstance(here)) {
|
||||
|
||||
int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given));
|
||||
int revrec = ((here->DIOqpNode > 0) && (model->DIOsoftRevRecParam!=0) && (here->DIOtTransitTime!=0));
|
||||
|
||||
/*
|
||||
* this routine loads diodes for dc and transient analyses.
|
||||
|
|
@ -120,10 +125,12 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
vd = *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW);
|
||||
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
vqp = *(ckt->CKTstate1 + here->DIOqp);
|
||||
} else{
|
||||
vd = *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
vqp = *(ckt->CKTstate0 + here->DIOqp);
|
||||
}
|
||||
|
||||
#ifdef SENSDEBUG
|
||||
|
|
@ -137,24 +144,30 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
vqp= *(ckt->CKTstate0 + here->DIOqp);
|
||||
} else if (ckt->CKTmode & MODEINITTRAN) {
|
||||
vd= *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW);
|
||||
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
vqp= *(ckt->CKTstate1 + here->DIOqp);
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) &&
|
||||
(ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) {
|
||||
vd=here->DIOinitCond;
|
||||
if (model->DIOresistSWGiven) vdsw = here->DIOinitCond;
|
||||
vqp=0;
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) {
|
||||
vd=vdsw=0;
|
||||
delTemp = 0.0;
|
||||
vqp=0;
|
||||
} else if ( ckt->CKTmode & MODEINITJCT) {
|
||||
vd=here->DIOtVcrit;
|
||||
vdsw=here->DIOtVcritSW;
|
||||
delTemp = 0.0;
|
||||
vqp=0;
|
||||
} else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) {
|
||||
vd=vdsw=0;
|
||||
delTemp = 0.0;
|
||||
vqp=0;
|
||||
} else {
|
||||
#ifndef PREDICTOR
|
||||
if (ckt->CKTmode & MODEINITPRED) {
|
||||
|
|
@ -177,12 +190,22 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(ckt->CKTstate0 + here->DIOdIdioSW_dT) =
|
||||
*(ckt->CKTstate1 + here->DIOdIdioSW_dT);
|
||||
}
|
||||
vqp = DEVpred(ckt,here->DIOqp);
|
||||
*(ckt->CKTstate0 + here->DIOresCurrent) =
|
||||
*(ckt->CKTstate1 + here->DIOresCurrent);
|
||||
*(ckt->CKTstate0 + here->DIOresConduct) =
|
||||
*(ckt->CKTstate1 + here->DIOresConduct);
|
||||
*(ckt->CKTstate0 + here->DIOcqcsr) =
|
||||
*(ckt->CKTstate1 + here->DIOcqcsr);
|
||||
*(ckt->CKTstate0 + here->DIOgqcsr) =
|
||||
*(ckt->CKTstate1 + here->DIOgqcsr);
|
||||
} else {
|
||||
#endif /* PREDICTOR */
|
||||
vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->DIOnegNode);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTrhsOld+here->DIOposSwPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->DIOnegNode);
|
||||
|
||||
if (selfheat)
|
||||
delTemp = *(ckt->CKTrhsOld + here->DIOtempNode);
|
||||
else
|
||||
|
|
@ -192,6 +215,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(ckt->CKTstate1+here->DIOqth) =
|
||||
*(ckt->CKTstate0+here->DIOqth);
|
||||
}
|
||||
vqp = *(ckt->CKTrhsOld+here->DIOqpNode);
|
||||
#ifndef PREDICTOR
|
||||
}
|
||||
#endif /* PREDICTOR */
|
||||
|
|
@ -238,6 +262,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
gdsw= *(ckt->CKTstate0 + here->DIOconductSW);
|
||||
dIdioSw_dT= *(ckt->CKTstate0 + here->DIOdIdioSW_dT);
|
||||
}
|
||||
vqp= *(ckt->CKTstate0 + here->DIOqp);
|
||||
cdres= *(ckt->CKTstate0 + here->DIOresCurrent);
|
||||
gdres= *(ckt->CKTstate0 + here->DIOresConduct);
|
||||
cqcsr= *(ckt->CKTstate0 + here->DIOcqcsr);
|
||||
gqcsr= *(ckt->CKTstate0 + here->DIOgqcsr);
|
||||
goto load;
|
||||
}
|
||||
}
|
||||
|
|
@ -304,7 +333,7 @@ next1:
|
|||
|
||||
if (model->DIOsatSWCurGiven) { /* sidewall current */
|
||||
double vds;
|
||||
if (model->DIOresistSWGiven)
|
||||
if (model->DIOresistSWGiven)
|
||||
vds = vdsw; /* sidewall voltage used */
|
||||
else
|
||||
vds = vd; /* common voltage used */
|
||||
|
|
@ -470,7 +499,6 @@ next1:
|
|||
gdb = ((1+sqrt_ikx)*gdb + cdb*gdb/(2*sqrt_ikx*ikr_area_m))/(1+2*sqrt_ikx - cdb/ikr_area_m);
|
||||
cdb = cdb/(1+sqrt_ikx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( (model->DIOforwardSWKneeCurrentGiven) && (cdsw > 1.0e-18) ) {
|
||||
|
|
@ -493,6 +521,11 @@ next1:
|
|||
dIdioSw_dT = cdsw_dT;
|
||||
}
|
||||
|
||||
cdres = cd;
|
||||
gdres = gd;
|
||||
cqcsr = 0;
|
||||
gqcsr = 0;
|
||||
|
||||
if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) ||
|
||||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) {
|
||||
/*
|
||||
|
|
@ -528,22 +561,46 @@ next1:
|
|||
deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vdx/here->DIOtJctSWPot);
|
||||
}
|
||||
|
||||
diffcharge = here->DIOtTransitTime*cd;
|
||||
diffcap = here->DIOtTransitTime*gd;
|
||||
if (!model->DIOresistSWGiven) {
|
||||
if (revrec) {
|
||||
/*
|
||||
soft recovery with TT!=0
|
||||
add only depletion capacitance.
|
||||
*/
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge) =
|
||||
diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd;
|
||||
capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly;
|
||||
deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd;
|
||||
|
||||
capd = deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly;
|
||||
here->DIOcap = capd;
|
||||
/*
|
||||
DIOcap is now equal only to depletion capacitance + overlap capacitance.
|
||||
Diffusion capacitance is modelled via Qp so there is no clear way to define it.
|
||||
*/
|
||||
|
||||
/* Now prepare the charge for the capacitor connected to the QP node */
|
||||
*(ckt->CKTstate0 + here->DIOsrcapCharge) = here->DIOtTransitTime * vqp;
|
||||
capsr = here->DIOtTransitTime;
|
||||
} else {
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge) =
|
||||
diffcharge + deplcharge + (here->DIOcmetal + here->DIOcpoly)*vd;
|
||||
capd = diffcap + deplcap + here->DIOcmetal + here->DIOcpoly;
|
||||
here->DIOcap = capd;
|
||||
*(ckt->CKTstate0 + here->DIOcapChargeSW) =
|
||||
deplcapSW;
|
||||
capdsw = deplcapSW;
|
||||
here->DIOcapSW = capdsw;
|
||||
/* no soft recovery of soft recovery with TT=0 (i.e. no soft recovery due to TT=0) */
|
||||
diffcharge = here->DIOtTransitTime*cd;
|
||||
diffcap = here->DIOtTransitTime*gd;
|
||||
if (!model->DIOresistSWGiven) {
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge) =
|
||||
diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd;
|
||||
capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly;
|
||||
here->DIOcap = capd;
|
||||
} else {
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge) =
|
||||
diffcharge + deplcharge + (here->DIOcmetal + here->DIOcpoly)*vd;
|
||||
capd = diffcap + deplcap + here->DIOcmetal + here->DIOcpoly;
|
||||
here->DIOcap = capd;
|
||||
*(ckt->CKTstate0 + here->DIOcapChargeSW) =
|
||||
deplcapSW;
|
||||
capdsw = deplcapSW;
|
||||
here->DIOcapSW = capdsw;
|
||||
}
|
||||
|
||||
*(ckt->CKTstate0 + here->DIOsrcapCharge) = 0;
|
||||
capsr = 0;
|
||||
}
|
||||
/*
|
||||
* store small-signal parameters
|
||||
|
|
@ -564,6 +621,10 @@ next1:
|
|||
*(ckt->CKTstate0 + here->DIOconductSW) = gdsw;
|
||||
*(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT;
|
||||
}
|
||||
*(ckt->CKTstate0 + here->DIOresCurrent) = cdres;
|
||||
*(ckt->CKTstate0 + here->DIOresConduct) = gdres;
|
||||
*(ckt->CKTstate0 + here->DIOcqcsr) = cqcsr;
|
||||
*(ckt->CKTstate0 + here->DIOgqcsr) = gqcsr;
|
||||
#ifdef SENSDEBUG
|
||||
printf("storing small signal parameters\n");
|
||||
printf("cd = %.7e,vd = %.7e\n",cd,vd);
|
||||
|
|
@ -580,6 +641,7 @@ next1:
|
|||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
if (model->DIOresistSWGiven)
|
||||
*(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw;
|
||||
*(ckt->CKTstate0 + here->DIOresCurrent) = cdres;
|
||||
#ifdef SENSDEBUG
|
||||
printf("storing parameters for transient sensitivity\n"
|
||||
);
|
||||
|
|
@ -613,6 +675,21 @@ next1:
|
|||
*(ckt->CKTstate1 + here->DIOcapCurrentSW) =
|
||||
*(ckt->CKTstate0 + here->DIOcapCurrentSW);
|
||||
}
|
||||
if (revrec) {
|
||||
/* soft recovery subcircuit */
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOsrcapCharge) =
|
||||
*(ckt->CKTstate0 + here->DIOsrcapCharge);
|
||||
}
|
||||
error = NIintegrate(ckt,&geq,&ceq,capsr,here->DIOsrcapCharge);
|
||||
if(error) return(error);
|
||||
gqcsr = geq;
|
||||
cqcsr = *(ckt->CKTstate0 + here->DIOsrcapCurrent);
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOsrcapCurrent) =
|
||||
*(ckt->CKTstate0 + here->DIOsrcapCurrent);
|
||||
}
|
||||
}
|
||||
if (selfheat)
|
||||
{
|
||||
error = NIintegrate(ckt, &gcTt, &ceqqth, model->DIOcth0, here->DIOqth);
|
||||
|
|
@ -654,6 +731,11 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
|||
*(ckt->CKTstate0 + here->DIOconductSW) = gdsw;
|
||||
*(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT;
|
||||
}
|
||||
*(ckt->CKTstate0 + here->DIOqp) = vqp;
|
||||
*(ckt->CKTstate0 + here->DIOresCurrent) = cdres;
|
||||
*(ckt->CKTstate0 + here->DIOresConduct) = gdres;
|
||||
*(ckt->CKTstate0 + here->DIOcqcsr) = cqcsr;
|
||||
*(ckt->CKTstate0 + here->DIOgqcsr) = gqcsr;
|
||||
if(SenCond) continue;
|
||||
|
||||
#ifndef NOBYPASS
|
||||
|
|
@ -754,6 +836,29 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
|||
(*(here->DIOnegTempPtr) += -dIdioSw_dT);
|
||||
}
|
||||
}
|
||||
|
||||
if (revrec) {
|
||||
double fac, ceqrr, dcrrdvd, grr;
|
||||
double ceqrrd, geqrrd;
|
||||
/* QP subcircuit */
|
||||
fac = here->DIOtTransitTime / model->DIOsoftRevRecParam;
|
||||
dcrrdvd = fac*gdres;
|
||||
ceqrr = -fac*cdres + cqcsr + dcrrdvd*vd - gqcsr*vqp;
|
||||
grr = 1/model->DIOsoftRevRecParam;
|
||||
*(ckt->CKTrhs + here->DIOqpNode) -= ceqrr;
|
||||
*(here->DIOqpQpPtr) += grr + gqcsr;
|
||||
*(here->DIOqpPosPrimePtr) += -dcrrdvd;
|
||||
*(here->DIOqpNegPtr) += dcrrdvd;
|
||||
/* Contribution to diode current */
|
||||
here->DIOqpGain = (1 - model->DIOsoftRevRecParam) / here->DIOtTransitTime;
|
||||
/* Linear contribution -(1-vp)/tau*ddt(Qp) */
|
||||
geqrrd = here->DIOqpGain*gqcsr;
|
||||
ceqrrd = here->DIOqpGain*cqcsr - geqrrd*vqp;
|
||||
*(ckt->CKTrhs + here->DIOposPrimeNode) -= ceqrrd;
|
||||
*(ckt->CKTrhs + here->DIOnegNode) += ceqrrd;
|
||||
*(here->DIOposPrimeQpPtr) += geqrrd;
|
||||
*(here->DIOnegQpPtr) += -geqrrd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Thomas L. Quarles
|
||||
Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
||||
Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025
|
||||
**********/
|
||||
/*
|
||||
*/
|
||||
|
|
@ -199,6 +199,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);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Thomas L. Quarles
|
||||
Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
||||
Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025
|
||||
**********/
|
||||
/*
|
||||
*/
|
||||
|
|
@ -245,6 +245,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;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Thomas L. Quarles
|
||||
Modified: 2000 AlansFixes
|
||||
Modified by Paolo Nenzi 2003 and Dietmar Warning 2012
|
||||
Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025
|
||||
**********/
|
||||
|
||||
/* load the diode structure with those pointers needed later
|
||||
|
|
@ -222,6 +222,9 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
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)
|
||||
|
|
@ -412,6 +415,18 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
}
|
||||
}
|
||||
|
||||
/* rev-rec */
|
||||
if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) {
|
||||
if(here->DIOqpNode == 0) {
|
||||
error = CKTmkVolt(ckt, &tmp, here->DIOname, "qp");
|
||||
if(error) return(error);
|
||||
here->DIOqpNode = tmp->number;
|
||||
}
|
||||
} else {
|
||||
here->DIOqpNode = 0;
|
||||
}
|
||||
|
||||
|
||||
int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given));
|
||||
|
||||
/* macro to make elements with built in test for out of memory */
|
||||
|
|
@ -450,7 +465,15 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
|
|||
TSTALLOC(DIOposSwPrimeTempPtr, DIOposSwPrimeNode, DIOtempNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* rev-rec */
|
||||
if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) {
|
||||
TSTALLOC(DIOqpQpPtr , DIOqpNode, DIOqpNode);
|
||||
TSTALLOC(DIOqpPosPrimePtr, DIOqpNode, DIOposPrimeNode);
|
||||
TSTALLOC(DIOqpNegPtr , DIOqpNode, DIOnegNode);
|
||||
TSTALLOC(DIOposPrimeQpPtr, DIOposPrimeNode, DIOqpNode);
|
||||
TSTALLOC(DIOnegQpPtr, DIOnegNode, DIOqpNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
@ -474,7 +497,7 @@ DIOunsetup(
|
|||
if (here->DIOposPrimeNode > 0
|
||||
&& here->DIOposPrimeNode != here->DIOposNode)
|
||||
CKTdltNNum(ckt, here->DIOposPrimeNode);
|
||||
here->DIOposPrimeNode = 0;
|
||||
here->DIOposPrimeNode = 0;
|
||||
|
||||
if(model->DIOresistSWGiven) {
|
||||
/* separate sidewall */
|
||||
|
|
@ -484,6 +507,11 @@ DIOunsetup(
|
|||
here->DIOposSwPrimeNode = 0;
|
||||
}
|
||||
|
||||
/* rev-rec */
|
||||
if (here->DIOqpNode > 0)
|
||||
CKTdltNNum(ckt, here->DIOqpNode);
|
||||
here->DIOqpNode = 0;
|
||||
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ DIOtrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep)
|
|||
for(here=DIOinstances(model);here!=NULL;here = DIOnextInstance(here)){
|
||||
CKTterr(here->DIOcapCharge,ckt,timeStep);
|
||||
if (model->DIOresistSWGiven) CKTterr(here->DIOcapChargeSW,ckt,timeStep);
|
||||
if (model->DIOsoftRevRecParam!=0 && here->DIOtTransitTime!=0)
|
||||
CKTterr(here->DIOsrcapCharge,ckt,timeStep);
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
Loading…
Reference in New Issue