Merge commit 'fef64ab241973fb5b937777c904649a31b52d6c3' into pre-master-46

Basic load routine with soft recovery model from A. Buermen
This commit is contained in:
dwarning 2025-09-20 16:14:40 +02:00
commit 2f7f5996ac
6 changed files with 185 additions and 17 deletions

View File

@ -120,6 +120,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 */
IOP( "fv_max", DIO_MOD_FV_MAX, IF_REAL, "maximum voltage in forward direction"),

View File

@ -40,6 +40,7 @@ typedef struct sDIOinstance {
const int DIOnegNode; /* number of negative node of diode */
const int DIOtempNode; /* number of the temperature node of the diode */
int DIOposPrimeNode; /* number of positive prime node of diode */
int DIOqpNode; /* number of soft recovery charge node */
double *DIOposPosPrimePtr; /* pointer to sparse matrix at
* (positive,positive prime) */
@ -65,6 +66,13 @@ typedef struct sDIOinstance {
double *DIOposPrimeTempPtr;
double *DIOnegTempPtr;
/* rev-rec */
double *DIOqpQpPtr;
double *DIOqpPosPrimePtr;
double *DIOqpNegPtr;
double *DIOposPrimeQpPtr;
double *DIOnegQpPtr;
double DIOcap; /* stores the diode capacitance */
double *DIOsens; /* stores the perturbed values of geq and ceq in ac
@ -218,16 +226,24 @@ typedef struct sDIOinstance {
#define DIOconduct DIOstate+2
#define DIOcapCharge DIOstate+3
#define DIOcapCurrent DIOstate+4
#define DIOsrcapCharge DIOstate+5
#define DIOsrcapCurrent DIOstate+6
#define DIOqp DIOstate+7
#define DIOresCurrent DIOstate+8
#define DIOresConduct DIOstate+9
#define DIOcqcsr DIOstate+10
#define DIOgqcsr DIOstate+11
#define DIOqth DIOstate+5 /* thermal capacitor charge */
#define DIOcqth DIOstate+6 /* thermal capacitor current */
#define DIOdeltemp DIOstate+7 /* thermal voltage over rth0 */
#define DIOdIdio_dT DIOstate+8
#define DIOqth DIOstate+10 /* thermal capacitor charge */
#define DIOcqth DIOstate+11 /* thermal capacitor current */
#define DIOnumStates 9
#define DIOdeltemp DIOstate+12 /* thermal voltage over rth0 */
#define DIOdIdio_dT DIOstate+13
#define DIOsensxp DIOstate+9 /* charge sensitivities and their derivatives.
#define DIOnumStates 14
#define DIOsensxp DIOstate+14 /* charge sensitivities and their derivatives.
* +10 for the derivatives - pointer to the
* beginning of the array */
@ -302,6 +318,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;
@ -375,6 +392,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;
@ -481,6 +499,7 @@ enum {
DIO_MOD_PD_MAX,
DIO_MOD_ISR,
DIO_MOD_NR,
DIO_MOD_VP,
DIO_MOD_RTH0,
DIO_MOD_CTH0,

View File

@ -25,7 +25,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
double arg;
double argsw;
double capd;
double cd, cdb, cdsw, cdb_dT, cdsw_dT;
double cd, cdres, gdres, cdb, cdsw, cdb_dT, cdsw_dT;
double cdeq;
double cdhat;
double ceq;
@ -46,6 +46,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
double evd;
double evrev;
double gd, gdb, gdsw, gen_fac, gen_fac_vd;
double capsr, gqcsr, cqcsr;
double t1, evd_rec, cdb_rec, gdb_rec, cdb_rec_dT;
double geq;
double gspr; /* area-scaled conductance */
@ -54,6 +55,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
double tol; /* temporary for tolerence calculations */
#endif
double vd; /* current diode voltage */
double vqp;
double vdtemp;
double vt; /* K t / Q */
double vte, vtesw, vtetun, vtebrk;
@ -116,9 +118,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
if((ckt->CKTsenInfo->SENmode == TRANSEN)&&
(ckt->CKTmode & MODEINITTRAN)) {
vd = *(ckt->CKTstate1 + here->DIOvoltage);
vqp = *(ckt->CKTstate1 + here->DIOqp);
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
} else{
vd = *(ckt->CKTstate0 + here->DIOvoltage);
vqp = *(ckt->CKTstate0 + here->DIOqp);
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
}
@ -131,21 +135,27 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
Check_dio=1;
if(ckt->CKTmode & MODEINITSMSIG) {
vd= *(ckt->CKTstate0 + here->DIOvoltage);
vqp= *(ckt->CKTstate0 + here->DIOqp);
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
} else if (ckt->CKTmode & MODEINITTRAN) {
vd= *(ckt->CKTstate1 + here->DIOvoltage);
vqp= *(ckt->CKTstate1 + here->DIOqp);
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
} else if ( (ckt->CKTmode & MODEINITJCT) &&
(ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) {
vd=here->DIOinitCond;
vqp=0;
} else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) {
vd=0;
vqp=0;
delTemp = 0.0;
} else if ( ckt->CKTmode & MODEINITJCT) {
vd=here->DIOtVcrit;
vqp=0;
delTemp = 0.0;
} else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) {
vd=0;
vqp=0;
delTemp = 0.0;
} else {
#ifndef PREDICTOR
@ -153,10 +163,19 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
*(ckt->CKTstate0 + here->DIOvoltage) =
*(ckt->CKTstate1 + here->DIOvoltage);
vd = DEVpred(ckt,here->DIOvoltage);
vqp = DEVpred(ckt,here->DIOqp);
*(ckt->CKTstate0 + here->DIOcurrent) =
*(ckt->CKTstate1 + here->DIOcurrent);
*(ckt->CKTstate0 + here->DIOconduct) =
*(ckt->CKTstate1 + here->DIOconduct);
*(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);
*(ckt->CKTstate0 + here->DIOdeltemp) =
*(ckt->CKTstate1 + here->DIOdeltemp);
delTemp = DEVpred(ckt,here->DIOdeltemp);
@ -168,6 +187,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
#endif /* PREDICTOR */
vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)-
*(ckt->CKTrhsOld + here->DIOnegNode);
vqp = *(ckt->CKTrhsOld+here->DIOqpNode);
if (selfheat)
delTemp = *(ckt->CKTrhsOld + here->DIOtempNode);
else
@ -203,8 +223,13 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
fabs(*(ckt->CKTstate0+here->DIOdeltemp)))+
ckt->CKTvoltTol*1e4))) {
vd= *(ckt->CKTstate0 + here->DIOvoltage);
vqp= *(ckt->CKTstate0 + here->DIOqp);
cd= *(ckt->CKTstate0 + here->DIOcurrent);
gd= *(ckt->CKTstate0 + here->DIOconduct);
cdres= *(ckt->CKTstate0 + here->DIOresCurrent);
gdres= *(ckt->CKTstate0 + here->DIOresConduct);
cqcsr= *(ckt->CKTstate0 + here->DIOcqcsr);
gqcsr= *(ckt->CKTstate0 + here->DIOgqcsr);
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
dIdio_dT= *(ckt->CKTstate0 + here->DIOdIdio_dT);
goto load;
@ -400,9 +425,12 @@ next1:
gd = gd + ckt->CKTgmin;
cd = cd + ckt->CKTgmin*vd;
}
}
gdres = gd;
cdres = cd;
gqcsr = 0;
cqcsr = 0;
if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) ||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) {
/*
@ -433,15 +461,44 @@ next1:
deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vd/here->DIOtJctSWPot);
}
diffcharge = here->DIOtTransitTime*cd;
*(ckt->CKTstate0 + here->DIOcapCharge) =
diffcharge + deplcharge + deplchargeSW;
/*
Dietmar: should not we also add a term (DIOcmetal+DIOcpoly)*vd to DIOcapCharge?
*/
if (model->DIOsoftRevRecParam!=0 && here->DIOtTransitTime!=0) {
/*
soft recovery with TT!=0
add only depletion capacitance.
*/
*(ckt->CKTstate0 + here->DIOcapCharge) =
deplcharge + deplchargeSW;
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.
Situation is similar to the one when we have an NQS model for the charge.
*/
diffcap = here->DIOtTransitTime*gd;
capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly;
here->DIOcap = capd;
/* Now prepare the charge for the capacitor connected to the QP node */
*(ckt->CKTstate0 + here->DIOsrcapCharge) = here->DIOtTransitTime * vqp;
capsr = here->DIOtTransitTime;
} else {
/* no soft recovery of soft recovery with TT=0 (i.e. no soft recovery due to TT=0) */
diffcharge = here->DIOtTransitTime*cd;
*(ckt->CKTstate0 + here->DIOcapCharge) =
diffcharge + deplcharge + deplchargeSW;
diffcap = here->DIOtTransitTime*gd;
capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly;
here->DIOcap = capd;
*(ckt->CKTstate0 + here->DIOsrcapCharge) = 0;
capsr = 0;
}
/*
* store small-signal parameters
@ -454,6 +511,10 @@ next1:
if(SenCond){
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
*(ckt->CKTstate0 + here->DIOconduct) = gd;
*(ckt->CKTstate0 + here->DIOresCurrent) = cdres;
*(ckt->CKTstate0 + here->DIOresConduct) = gdres;
*(ckt->CKTstate0 + here->DIOcqcsr) = cqcsr;
*(ckt->CKTstate0 + here->DIOgqcsr) = gqcsr;
*(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT;
#ifdef SENSDEBUG
printf("storing small signal parameters\n");
@ -469,6 +530,7 @@ next1:
*/
if(SenCond && (ckt->CKTsenInfo->SENmode == TRANSEN)){
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
*(ckt->CKTstate0 + here->DIOresCurrent) = cdres;
#ifdef SENSDEBUG
printf("storing parameters for transient sensitivity\n"
);
@ -490,6 +552,22 @@ next1:
*(ckt->CKTstate1 + here->DIOcapCurrent) =
*(ckt->CKTstate0 + here->DIOcapCurrent);
}
if (model->DIOsoftRevRecParam!=0 && here->DIOtTransitTime!=0) {
/* 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);
@ -514,8 +592,13 @@ next1:
}
}
next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
*(ckt->CKTstate0 + here->DIOqp) = vqp;
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
*(ckt->CKTstate0 + here->DIOconduct) = gd;
*(ckt->CKTstate0 + here->DIOresCurrent) = cdres;
*(ckt->CKTstate0 + here->DIOresConduct) = gdres;
*(ckt->CKTstate0 + here->DIOcqcsr) = cqcsr;
*(ckt->CKTstate0 + here->DIOgqcsr) = gqcsr;
*(ckt->CKTstate0 + here->DIOdeltemp) = delTemp;
*(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT;
@ -573,6 +656,35 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
(*(here->DIOposPrimeTempPtr) += dIdio_dT - dIrs_dT);
(*(here->DIOnegTempPtr) += -dIdio_dT);
}
if (model->DIOsoftRevRecParam!=0 && here->DIOtTransitTime!=0) {
// Compute
} else {
}
if (model->DIOsoftRevRecParam!=0 && here->DIOtTransitTime!=0) {
double fac, ceqrr, dcrrdvd, grr;
double gain, 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 */
gain = (1 - model->DIOsoftRevRecParam) / here->DIOtTransitTime;
/* Linear contribution -(1-vp)/tau*ddt(Qp) */
geqrrd = gain*gqcsr;
ceqrrd = gain*cqcsr - geqrrd*vqp;
*(ckt->CKTrhs + here->DIOposPrimeNode) -= ceqrrd;
*(ckt->CKTrhs + here->DIOnegNode) += ceqrrd;
*(here->DIOposPrimeQpPtr) += geqrrd;
*(here->DIOnegQpPtr) += -geqrrd;
}
}
}
return(OK);

View File

@ -193,6 +193,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);

View File

@ -237,6 +237,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;

View File

@ -211,6 +211,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)
@ -360,6 +363,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 */
@ -385,7 +400,15 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
TSTALLOC(DIOposPrimeTempPtr, DIOposPrimeNode, DIOtempNode);
TSTALLOC(DIOnegTempPtr, DIOnegNode, 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);
@ -410,6 +433,12 @@ DIOunsetup(
&& here->DIOposPrimeNode != here->DIOposNode)
CKTdltNNum(ckt, here->DIOposPrimeNode);
here->DIOposPrimeNode = 0;
/* rev-rec */
if (here->DIOqpNode > 0)
CKTdltNNum(ckt, here->DIOqpNode);
here->DIOqpNode = 0;
}
}
return OK;