You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

348 lines
14 KiB

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
Modified by Dietmar Warning 2003
**********/
#include "ngspice.h"
#include "devdefs.h"
#include "cktdefs.h"
#include "diodefs.h"
#include "const.h"
#include "trandefs.h"
#include "sperror.h"
#include "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 capd;
double cd;
double cdeq;
double cdhat;
double ceq;
double csat; /* area-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;
double geq;
double gspr; /* area-scaled conductance */
double sarg;
double tol; /* temporary for tolerence calculations */
double vd; /* current diode voltage */
double vdtemp;
double vt; /* K t / Q */
double vte;
int Check;
int error;
int SenCond=0; /* sensitivity condition */
/* loop through all the diode models */
for( ; model != NULL; model = model->DIOnextModel ) {
/* loop through all the instances of the model */
for (here = model->DIOinstances; here != NULL ;
here=here->DIOnextInstance) {
if (here->DIOowner != ARCHme) continue;
/*
* 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*here->DIOarea+here->DIOtSatSWCur*here->DIOpj)*here->DIOm;
gspr=here->DIOtConductance*here->DIOarea*here->DIOm;
vt = CONSTKoverQ * here->DIOtemp;
vte=model->DIOemissionCoeff * vt;
/*
* 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
*/
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;
}
}
}
/*
* limit new junction voltage
*/
if ( (model->DIObreakdownVoltageGiven) &&
(vd < MIN(0,-here->DIOtBrkdwnV+10*vte))) {
vdtemp = -(vd+here->DIOtBrkdwnV);
vdtemp = DEVpnjlim(vdtemp,
-(*(ckt->CKTstate0 + here->DIOvoltage) +
here->DIOtBrkdwnV),vte,
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) + ckt->CKTgmin*vd;
gd = csat*evd/vte + ckt->CKTgmin;
if( (model->DIOforwardKneeCurrentGiven) && (model->DIOforwardKneeCurrent > 0.0) && (cd > 1.0e-18) ) {
gd = gd-ckt->CKTgmin;
cd = cd-ckt->CKTgmin*vd;
ikf_area_m = model->DIOforwardKneeCurrent*here->DIOarea*here->DIOm;
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 if((!(model->DIObreakdownVoltageGiven)) || /* reverse*/
vd >= -here->DIOtBrkdwnV) {
arg=3*vte/(vd*CONSTe);
arg = arg * arg * arg;
cd = -csat*(1+arg) + ckt->CKTgmin*vd ;
gd = csat*3*arg/vd + ckt->CKTgmin;
if( (model->DIOreverseKneeCurrentGiven) && (model->DIOreverseKneeCurrent > 0.0) && (cd < -1.0e-18) ) {
gd = gd-ckt->CKTgmin;
cd = cd-ckt->CKTgmin*vd;
ikr_area_m = model->DIOreverseKneeCurrent*here->DIOarea*here->DIOm;
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 { /* breakdown */
evrev=exp(-(here->DIOtBrkdwnV+vd)/vte);
cd = -csat*evrev + ckt->CKTgmin*vd;
gd = csat*evrev/vte + ckt->CKTgmin;
if( (model->DIOreverseKneeCurrentGiven) && (model->DIOreverseKneeCurrent > 0.0) && (cd < -1.0e-18) ) {
gd = gd-ckt->CKTgmin;
cd = cd-ckt->CKTgmin*vd;
ikr_area_m = model->DIOreverseKneeCurrent*here->DIOarea*here->DIOm;
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);
cd = cd/(1+sqrt_ikr);
}
}
if ((ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG)) ||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) {
/*
* charge storage elements
*/
czero=here->DIOtJctCap*here->DIOarea*here->DIOm;
czeroSW=here->DIOtJctSWCap*here->DIOpj*here->DIOm;
if (vd < here->DIOtDepCap){
arg=1-vd/here->DIOtJctPot;
argSW=1-vd/here->DIOtJctSWPot;
sarg=exp(-here->DIOtGradingCoeff*log(arg));
sargSW=exp(-model->DIOgradingSWCoeff*log(argSW));
*(ckt->CKTstate0 + here->DIOcapCharge) =
here->DIOtTransitTime*cd+
here->DIOtJctPot*czero*(1-arg*sarg)/(1-here->DIOtGradingCoeff)+
here->DIOtJctSWPot*czeroSW*(1-argSW*sargSW)/(1-model->DIOgradingSWCoeff);
capd=here->DIOtTransitTime*gd+czero*sarg+czeroSW*sargSW;
} else {
czof2=czero/here->DIOtF2;
czof2SW=czeroSW/here->DIOtF2SW;
*(ckt->CKTstate0 + here->DIOcapCharge) =
here->DIOtTransitTime*cd+czero*here->DIOtF1+
czof2*(here->DIOtF3*(vd-here->DIOtDepCap)+(here->DIOtGradingCoeff/(here->DIOtJctPot+here->DIOtJctPot))*(vd*vd-here->DIOtDepCap*here->DIOtDepCap))+
czof2SW*(here->DIOtF3SW*(vd-here->DIOtDepCap)+(model->DIOgradingSWCoeff/(here->DIOtJctSWPot+here->DIOtJctSWPot))*(vd*vd-here->DIOtDepCap*here->DIOtDepCap));
capd=here->DIOtTransitTime*gd+
czof2*(here->DIOtF3+here->DIOtGradingCoeff*vd/here->DIOtJctPot)+
czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vd/here->DIOtJctSWPot);
}
here->DIOcap = capd;
/*
* store small-signal parameters
*/
if( (!(ckt->CKTmode & MODETRANOP)) ||
(!(ckt->CKTmode & MODEUIC)) ) {
if (ckt->CKTmode & MODEINITSMSIG){
*(ckt->CKTstate0 + here->DIOcapCurrent) = capd;
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",capd,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),capd,cd);
#endif /* SENSDEBUG */
continue;
}
if (ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->DIOcapCharge) =
*(ckt->CKTstate0 + here->DIOcapCharge);
}
error = NIintegrate(ckt,&geq,&ceq,capd,here->DIOcapCharge);
if(error) return(error);
gd=gd+geq;
cd=cd+*(ckt->CKTstate0 + here->DIOcapCurrent);
if (ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->DIOcapCurrent) =
*(ckt->CKTstate0 + here->DIOcapCurrent);
}
}
}
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;
load:
/*
* 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);
}