ngspice/src/spicelib/devices/bjt/bjtload.c

985 lines
41 KiB
C

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
**********/
/*
* This is the function called each iteration to evaluate the
* BJTs in the circuit and load them into the matrix as appropriate
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "bjtdefs.h"
#include "ngspice/const.h"
#include "ngspice/trandefs.h"
#include "ngspice/sperror.h"
#include "ngspice/devdefs.h"
#include "ngspice/suffix.h"
int
BJTload(GENmodel *inModel, CKTcircuit *ckt)
/* actually load the current resistance value into the
* sparse matrix previously provided
*/
{
BJTmodel *model = (BJTmodel*)inModel;
BJTinstance *here;
double arg1;
double arg2;
double arg3;
double arg;
double argtf;
double c2;
double c4;
double capbc;
double capbe;
double capbx=0;
double capsub=0;
double cb;
double cbc;
double cbcn;
double cbe;
double cben;
double cbhat;
double cc;
double cchat;
double cdis;
double ceq;
double ceqbc;
double ceqbe;
double ceqbx;
double geqsub;
double ceqsub;
double cex;
double csat;
double csubsat;
double ctot;
double czbc;
double czbcf2;
double czbe;
double czbef2;
double czbx;
double czbxf2;
double czsub;
double delvbc;
double delvbcx;
double delvbe;
double denom;
double dqbdvc;
double dqbdve;
double evbc;
double evbcn;
double evbe;
double evben;
double f1;
double f2;
double f3;
double fcpc;
double fcpe;
double gbc;
double gbcn;
double gbe;
double gben;
double gcsub;
double gcpr;
double gepr;
double geq;
double geqbx;
double geqcb;
double gex;
double gm;
double gmu;
double go;
double gpi;
double gx;
double oik;
double oikr;
double ovtf;
double pc;
double pe;
double ps;
double q1;
double q2;
double qb;
double rbpi;
double rbpr;
double sarg;
double sqarg;
double td;
double temp;
double tf;
double tr;
double vbc;
double vbcx;
double vbe;
double vbx=0.0;
double vce;
double vsub=0.0;
double vt;
double vtc;
double vte;
double vtn;
double vts;
#ifndef PREDICTOR
double xfact;
#endif
double xjrb;
double xjtf;
double xmc;
double xme;
double xms;
double xtf;
double evsub;
double gdsub;
double cdsub;
int icheck=1;
int ichk1;
int error;
int SenCond=0;
double m;
double vrci=0.0, delvrci;
double Irci=0.0, Irci_Vrci=0.0, Irci_Vbci=0.0, Irci_Vbcx=0.0;
double Qbci=0.0, Qbci_Vbci=0.0, Qbcx, Qbcx_Vbcx=0.0, gbcx, cbcx;
/* loop through all the models */
for( ; model != NULL; model = BJTnextModel(model)) {
/* loop through all the instances of the model */
for (here = BJTinstances(model); here != NULL ;
here=BJTnextInstance(here)) {
vt = here->BJTtemp * CONSTKoverQ;
m = here->BJTm;
if(ckt->CKTsenInfo){
#ifdef SENSDEBUG
printf("BJTload \n");
#endif /* SENSDEBUG */
if((ckt->CKTsenInfo->SENstatus == PERTURBATION)&&
(here->BJTsenPertFlag == OFF)) continue;
SenCond = here->BJTsenPertFlag;
}
gcsub=0;
geqbx=0;
geqcb=0;
gbcx=0;
cbcx=0;
/*
* dc model paramters
*/
csat=here->BJTtSatCur*here->BJTarea;
csubsat=here->BJTtSubSatCur*here->BJTarea;
rbpr=here->BJTtminBaseResist/here->BJTarea;
rbpi=here->BJTtbaseResist/here->BJTarea-rbpr;
gcpr=here->BJTtcollectorConduct*here->BJTarea;
gepr=here->BJTtemitterConduct*here->BJTarea;
oik=here->BJTtinvRollOffF/here->BJTarea;
c2=here->BJTtBEleakCur*here->BJTarea;
vte=here->BJTtleakBEemissionCoeff*vt;
oikr=here->BJTtinvRollOffR/here->BJTarea;
if (model->BJTsubs == VERTICAL)
c4=here->BJTtBCleakCur * here->BJTareab;
else
c4=here->BJTtBCleakCur * here->BJTareac;
vtc=here->BJTtleakBCemissionCoeff*vt;
td=model->BJTexcessPhaseFactor;
xjrb=here->BJTtbaseCurrentHalfResist*here->BJTarea;
if(SenCond){
#ifdef SENSDEBUG
printf("BJTsenPertFlag = ON \n");
#endif /* SENSDEBUG */
if((ckt->CKTsenInfo->SENmode == TRANSEN)&&
(ckt->CKTmode & MODEINITTRAN)) {
vbe = *(ckt->CKTstate1 + here->BJTvbe);
vbc = *(ckt->CKTstate1 + here->BJTvbc);
vbcx = *(ckt->CKTstate1 + here->BJTvbcx);
vrci = *(ckt->CKTstate1 + here->BJTvrci);
vbx=model->BJTtype*(
*(ckt->CKTrhsOp+here->BJTbaseNode)-
*(ckt->CKTrhsOp+here->BJTcolPrimeNode));
vsub=model->BJTtype*model->BJTsubs*(
*(ckt->CKTrhsOp+here->BJTsubstNode)-
*(ckt->CKTrhsOp+here->BJTsubstConNode));
}
else{
vbe = *(ckt->CKTstate0 + here->BJTvbe);
vbc = *(ckt->CKTstate0 + here->BJTvbc);
vbcx = *(ckt->CKTstate0 + here->BJTvbcx);
vrci = *(ckt->CKTstate0 + here->BJTvrci);
if((ckt->CKTsenInfo->SENmode == DCSEN)||
(ckt->CKTsenInfo->SENmode == TRANSEN)){
vbx=model->BJTtype*(
*(ckt->CKTrhsOld+here->BJTbaseNode)-
*(ckt->CKTrhsOld+here->BJTcolPrimeNode));
vsub=model->BJTtype*model->BJTsubs*(
*(ckt->CKTrhsOld+here->BJTsubstNode)-
*(ckt->CKTrhsOld+here->BJTsubstConNode));
}
if(ckt->CKTsenInfo->SENmode == ACSEN){
vbx=model->BJTtype*(
*(ckt->CKTrhsOp+here->BJTbaseNode)-
*(ckt->CKTrhsOp+here->BJTcolPrimeNode));
vsub=model->BJTtype*model->BJTsubs*(
*(ckt->CKTrhsOp+here->BJTsubstNode)-
*(ckt->CKTrhsOp+here->BJTsubstConNode));
}
}
goto next1;
}
/*
* initialization
*/
icheck=1;
if(ckt->CKTmode & MODEINITSMSIG) {
vbe= *(ckt->CKTstate0 + here->BJTvbe);
vbc= *(ckt->CKTstate0 + here->BJTvbc);
vbcx= *(ckt->CKTstate0 + here->BJTvbcx);
vrci = *(ckt->CKTstate0 + here->BJTvrci);
vbx=model->BJTtype*(
*(ckt->CKTrhsOld+here->BJTbaseNode)-
*(ckt->CKTrhsOld+here->BJTcolPrimeNode));
vsub=model->BJTtype*model->BJTsubs*(
*(ckt->CKTrhsOld+here->BJTsubstNode)-
*(ckt->CKTrhsOld+here->BJTsubstConNode));
} else if(ckt->CKTmode & MODEINITTRAN) {
vbe = *(ckt->CKTstate1 + here->BJTvbe);
vbc = *(ckt->CKTstate1 + here->BJTvbc);
vbcx = *(ckt->CKTstate1 + here->BJTvbcx);
vrci = *(ckt->CKTstate1 + here->BJTvrci);
vbx=model->BJTtype*(
*(ckt->CKTrhsOld+here->BJTbaseNode)-
*(ckt->CKTrhsOld+here->BJTcolPrimeNode));
vsub=model->BJTtype*model->BJTsubs*(
*(ckt->CKTrhsOld+here->BJTsubstNode)-
*(ckt->CKTrhsOld+here->BJTsubstConNode));
if( (ckt->CKTmode & MODETRAN) && (ckt->CKTmode & MODEUIC) ) {
vbx=model->BJTtype*(here->BJTicVBE-here->BJTicVCE);
vsub=0;
}
} else if((ckt->CKTmode & MODEINITJCT) &&
(ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)){
vbe=model->BJTtype*here->BJTicVBE;
vce=model->BJTtype*here->BJTicVCE;
vbc=vbcx=vbe-vce;
vbx=vbc;
vsub=0;
vrci=0.0;
} else if((ckt->CKTmode & MODEINITJCT) && (here->BJToff==0)) {
vbe=here->BJTtVcrit;
vbc=vbcx=0;
/* ERROR: need to initialize VSUB, VBX here */
vsub=vbx=0;
vrci=0.0;
} else if((ckt->CKTmode & MODEINITJCT) ||
( (ckt->CKTmode & MODEINITFIX) && (here->BJToff!=0))) {
vbe=0;
vbc=vbcx=0;
/* ERROR: need to initialize VSUB, VBX here */
vsub=vbx=0;
vrci=0.0;
} else {
#ifndef PREDICTOR
if(ckt->CKTmode & MODEINITPRED) {
xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1];
*(ckt->CKTstate0 + here->BJTvbe) =
*(ckt->CKTstate1 + here->BJTvbe);
vbe = (1+xfact)**(ckt->CKTstate1 + here->BJTvbe)-
xfact* *(ckt->CKTstate2 + here->BJTvbe);
*(ckt->CKTstate0 + here->BJTvbc) =
*(ckt->CKTstate1 + here->BJTvbc);
vbc = (1+xfact)**(ckt->CKTstate1 + here->BJTvbc)-
xfact* *(ckt->CKTstate2 + here->BJTvbc);
*(ckt->CKTstate0 + here->BJTvbcx) =
*(ckt->CKTstate1 + here->BJTvbcx);
vbcx = (1+xfact)**(ckt->CKTstate1 + here->BJTvbcx)-
xfact* *(ckt->CKTstate2 + here->BJTvbcx);
*(ckt->CKTstate0 + here->BJTvrci) =
*(ckt->CKTstate1 + here->BJTvrci);
vrci = (1+xfact) * *(ckt->CKTstate1 + here->BJTvrci)-
xfact * *(ckt->CKTstate2 + here->BJTvrci);
*(ckt->CKTstate0 + here->BJTcc) =
*(ckt->CKTstate1 + here->BJTcc);
*(ckt->CKTstate0 + here->BJTcb) =
*(ckt->CKTstate1 + here->BJTcb);
*(ckt->CKTstate0 + here->BJTgpi) =
*(ckt->CKTstate1 + here->BJTgpi);
*(ckt->CKTstate0 + here->BJTgmu) =
*(ckt->CKTstate1 + here->BJTgmu);
*(ckt->CKTstate0 + here->BJTgm) =
*(ckt->CKTstate1 + here->BJTgm);
*(ckt->CKTstate0 + here->BJTgo) =
*(ckt->CKTstate1 + here->BJTgo);
*(ckt->CKTstate0 + here->BJTgx) =
*(ckt->CKTstate1 + here->BJTgx);
*(ckt->CKTstate0 + here->BJTvsub) =
*(ckt->CKTstate1 + here->BJTvsub);
*(ckt->CKTstate0 + here->BJTirci) =
*(ckt->CKTstate1 + here->BJTirci);
*(ckt->CKTstate0 + here->BJTirci_Vrci) =
*(ckt->CKTstate1 + here->BJTirci_Vrci);
*(ckt->CKTstate0 + here->BJTirci_Vbci) =
*(ckt->CKTstate1 + here->BJTirci_Vbci);
*(ckt->CKTstate0 + here->BJTirci_Vbcx) =
*(ckt->CKTstate1 + here->BJTirci_Vbcx);
} else {
#endif /* PREDICTOR */
/*
* compute new nonlinear branch voltages
*/
vbe=model->BJTtype*(
*(ckt->CKTrhsOld+here->BJTbasePrimeNode)-
*(ckt->CKTrhsOld+here->BJTemitPrimeNode));
vbc=model->BJTtype*(
*(ckt->CKTrhsOld+here->BJTbasePrimeNode)-
*(ckt->CKTrhsOld+here->BJTcolPrimeNode));
vbcx=model->BJTtype*(
*(ckt->CKTrhsOld+here->BJTbasePrimeNode)-
*(ckt->CKTrhsOld+here->BJTcollCXNode));
vrci=model->BJTtype*(
*(ckt->CKTrhsOld+here->BJTcollCXNode)-
*(ckt->CKTrhsOld+here->BJTcolPrimeNode));
#ifndef PREDICTOR
}
#endif /* PREDICTOR */
delvbe=vbe- *(ckt->CKTstate0 + here->BJTvbe);
delvbc=vbc- *(ckt->CKTstate0 + here->BJTvbc);
delvbcx=vbcx- *(ckt->CKTstate0 + here->BJTvbcx);
delvrci = vrci - *(ckt->CKTstate0 + here->BJTvrci);
vbx=model->BJTtype*(
*(ckt->CKTrhsOld+here->BJTbaseNode)-
*(ckt->CKTrhsOld+here->BJTcolPrimeNode));
vsub=model->BJTtype*model->BJTsubs*(
*(ckt->CKTrhsOld+here->BJTsubstNode)-
*(ckt->CKTrhsOld+here->BJTsubstConNode));
cchat= *(ckt->CKTstate0 + here->BJTcc)+(*(ckt->CKTstate0 +
here->BJTgm)+ *(ckt->CKTstate0 + here->BJTgo))*delvbe-
(*(ckt->CKTstate0 + here->BJTgo)+*(ckt->CKTstate0 +
here->BJTgmu))*delvbc;
cbhat= *(ckt->CKTstate0 + here->BJTcb)+ *(ckt->CKTstate0 +
here->BJTgpi)*delvbe+ *(ckt->CKTstate0 + here->BJTgmu)*
delvbc;
#ifndef NOBYPASS
/*
* bypass if solution has not changed
*/
/* the following collections of if's would be just one
* if the average compiler could handle it, but many
* find the expression too complicated, thus the split.
*/
if( (ckt->CKTbypass) &&
(!(ckt->CKTmode & MODEINITPRED)) &&
(fabs(delvbe) < (ckt->CKTreltol*MAX(fabs(vbe),
fabs(*(ckt->CKTstate0 + here->BJTvbe)))+
ckt->CKTvoltTol)) )
if( (fabs(delvbc) < ckt->CKTreltol*MAX(fabs(vbc),
fabs(*(ckt->CKTstate0 + here->BJTvbc)))+
ckt->CKTvoltTol) )
if( (fabs(delvbcx) < ckt->CKTreltol*MAX(fabs(vbcx),
fabs(*(ckt->CKTstate0 + here->BJTvbcx)))+
ckt->CKTvoltTol) )
if( (fabs(delvrci) < ckt->CKTreltol*MAX(fabs(vrci),
fabs(*(ckt->CKTstate0 + here->BJTvrci)))+
ckt->CKTvoltTol) )
if( (fabs(cchat-*(ckt->CKTstate0 + here->BJTcc)) <
ckt->CKTreltol* MAX(fabs(cchat),
fabs(*(ckt->CKTstate0 + here->BJTcc)))+
ckt->CKTabstol) )
if( (fabs(cbhat-*(ckt->CKTstate0 + here->BJTcb)) <
ckt->CKTreltol* MAX(fabs(cbhat),
fabs(*(ckt->CKTstate0 + here->BJTcb)))+
ckt->CKTabstol) ) {
/*
* bypassing....
*/
vbe = *(ckt->CKTstate0 + here->BJTvbe);
vbc = *(ckt->CKTstate0 + here->BJTvbc);
vbcx = *(ckt->CKTstate0 + here->BJTvbcx);
vrci = *(ckt->CKTstate0 + here->BJTvrci);
cc = *(ckt->CKTstate0 + here->BJTcc);
cb = *(ckt->CKTstate0 + here->BJTcb);
gpi = *(ckt->CKTstate0 + here->BJTgpi);
gmu = *(ckt->CKTstate0 + here->BJTgmu);
gm = *(ckt->CKTstate0 + here->BJTgm);
go = *(ckt->CKTstate0 + here->BJTgo);
gx = *(ckt->CKTstate0 + here->BJTgx);
geqcb = *(ckt->CKTstate0 + here->BJTgeqcb);
gcsub = *(ckt->CKTstate0 + here->BJTgcsub);
geqbx = *(ckt->CKTstate0 + here->BJTgeqbx);
vsub = *(ckt->CKTstate0 + here->BJTvsub);
gdsub = *(ckt->CKTstate0 + here->BJTgdsub);
cdsub = *(ckt->CKTstate0 + here->BJTcdsub);
Irci = *(ckt->CKTstate0 + here->BJTirci);
Irci_Vrci = *(ckt->CKTstate0 + here->BJTirci_Vrci);
Irci_Vbci = *(ckt->CKTstate0 + here->BJTirci_Vbci);
Irci_Vbcx = *(ckt->CKTstate0 + here->BJTirci_Vbcx);
gbcx = *(ckt->CKTstate0 + here->BJTgbcx);
cbcx = *(ckt->CKTstate0 + here->BJTcqbcx);
goto load;
}
#endif /*NOBYPASS*/
/*
* limit nonlinear branch voltages
*/
ichk1=1;
vbe = DEVpnjlim(vbe,*(ckt->CKTstate0 + here->BJTvbe),vt,
here->BJTtVcrit,&icheck);
vbc = DEVpnjlim(vbc,*(ckt->CKTstate0 + here->BJTvbc),vt,
here->BJTtVcrit,&ichk1);
if (ichk1 == 1) icheck=1;
vsub = DEVpnjlim(vsub,*(ckt->CKTstate0 + here->BJTvsub),vt,
here->BJTtSubVcrit,&ichk1);
if (ichk1 == 1) icheck=1;
vrci = vbc - vbcx; /* in case vbc was limited */
}
/*
* determine dc current and derivitives
*/
next1: vtn=vt*here->BJTtemissionCoeffF;
if(vbe >= -3*vtn){
evbe=exp(vbe/vtn);
cbe=csat*(evbe-1);
gbe=csat*evbe/vtn;
} else {
arg=3*vtn/(vbe*CONSTe);
arg = arg * arg * arg;
cbe = -csat*(1+arg);
gbe = csat*3*arg/vbe;
}
if (c2 == 0) {
cben=0;
gben=0;
} else {
if(vbe >= -3*vte){
evben=exp(vbe/vte);
cben=c2*(evben-1);
gben=c2*evben/vte;
} else {
arg=3*vte/(vbe*CONSTe);
arg = arg * arg * arg;
cben = -c2*(1+arg);
gben = c2*3*arg/vbe;
}
}
gben+=ckt->CKTgmin;
cben+=ckt->CKTgmin*vbe;
vtn=vt*here->BJTtemissionCoeffR;
if(vbc >= -3*vtn) {
evbc=exp(vbc/vtn);
cbc=csat*(evbc-1);
gbc=csat*evbc/vtn;
} else {
arg=3*vtn/(vbc*CONSTe);
arg = arg * arg * arg;
cbc = -csat*(1+arg);
gbc = csat*3*arg/vbc;
}
if (c4 == 0) {
cbcn=0;
gbcn=0;
} else {
if(vbc >= -3*vtc) {
evbcn=exp(vbc/vtc);
cbcn=c4*(evbcn-1);
gbcn=c4*evbcn/vtc;
} else {
arg=3*vtc/(vbc*CONSTe);
arg = arg * arg * arg;
cbcn = -c4*(1+arg);
gbcn = c4*3*arg/vbc;
}
}
gbcn+=ckt->CKTgmin;
cbcn+=ckt->CKTgmin*vbc;
vts=vt*here->BJTtemissionCoeffS;
if(vsub <= -3*vts) {
arg=3*vts/(vsub*CONSTe);
arg = arg * arg * arg;
gdsub = csubsat*3*arg/vsub+ckt->CKTgmin;
cdsub = -csubsat*(1+arg)+ckt->CKTgmin*vsub;
} else {
evsub = exp(MIN(MAX_EXP_ARG,vsub/vts));
gdsub = csubsat*evsub/vts + ckt->CKTgmin;
cdsub = csubsat*(evsub-1) + ckt->CKTgmin*vsub;
}
/*
* Kull's Quasi-Saturation model
*/
if (model->BJTintCollResistGiven) {
if (vrci > 0.) {
double Kbci,Kbci_Vbci,Kbcx,Kbcx_Vbcx;
double rKp1,rKp1_Vbci,rKp1_Vbcx,xvar1,xvar1_Vbci,xvar1_Vbcx;
double Vcorr,Vcorr_Vbci,Vcorr_Vbcx,Iohm,Iohm_Vrci,Iohm_Vbci,Iohm_Vbcx;
double quot,quot_Vrci;
Kbci = sqrt(1+here->BJTtepiDoping*exp(vbc/vt));
Kbci_Vbci = here->BJTtepiDoping*exp(vbc/vt)/(2*vt*Kbci);
Kbcx = sqrt(1+here->BJTtepiDoping*exp(vbcx/vt));
Kbcx_Vbcx = here->BJTtepiDoping*exp(vbcx/vt)/(2*vt*Kbcx);
rKp1 = (1+Kbci)/(1+Kbcx);
rKp1_Vbci = Kbci_Vbci/(1+Kbci);
rKp1_Vbcx = -(1+Kbci)*Kbcx_Vbcx/((Kbcx+1)*(Kbcx+1));
xvar1 = log(rKp1);
xvar1_Vbci = rKp1_Vbci/rKp1;
xvar1_Vbcx = rKp1_Vbcx/rKp1;
Vcorr = vt*(Kbci - Kbcx - xvar1);
Vcorr_Vbci = vt*(Kbci_Vbci - xvar1_Vbci);
Vcorr_Vbcx = vt*(-Kbcx_Vbcx - xvar1_Vbcx);
Iohm = (vrci+Vcorr)/here->BJTtintCollResist;
Iohm_Vrci = 1/here->BJTtintCollResist;
Iohm_Vbci = Vcorr_Vbci/here->BJTtintCollResist;
Iohm_Vbcx = Vcorr_Vbcx/here->BJTtintCollResist;
quot = 1+fabs(vrci)/here->BJTtepiSatVoltage;
quot_Vrci = vrci/(here->BJTtepiSatVoltage*fabs(vrci));
Irci = Iohm/quot + ckt->CKTgmin*vrci;
Irci_Vrci = Iohm_Vrci/quot-Iohm*quot_Vrci/(quot*quot) + ckt->CKTgmin;
Irci_Vbci = Iohm_Vbci/quot;
Irci_Vbcx = Iohm_Vbcx/quot;
Qbci = model->BJTepiCharge*Kbci;
Qbci_Vbci = model->BJTepiCharge*Kbci_Vbci;
Qbcx = model->BJTepiCharge*Kbcx;
Qbcx_Vbcx = model->BJTepiCharge*Kbcx_Vbcx;
*(ckt->CKTstate0 + here->BJTqbcx) = Qbcx;
here->BJTcapbcx = Qbcx_Vbcx;
} else {
Irci = vrci/here->BJTtintCollResist + ckt->CKTgmin*vrci;
Irci_Vrci = 1/here->BJTtintCollResist + ckt->CKTgmin;
Irci_Vbci = 0.0;
Irci_Vbcx = 0.0;
Qbci = 0.0;
Qbci_Vbci = 0.0;
Qbcx = 0.0;
Qbcx_Vbcx = 0.0;
*(ckt->CKTstate0 + here->BJTqbcx) = Qbcx;
here->BJTcapbcx = Qbcx_Vbcx;
}
}
/*
* determine base charge terms
*/
q1=1/(1-here->BJTtinvEarlyVoltF*vbc-here->BJTtinvEarlyVoltR*vbe);
if(oik == 0 && oikr == 0) {
qb=q1;
dqbdve=q1*qb*here->BJTtinvEarlyVoltR;
dqbdvc=q1*qb*here->BJTtinvEarlyVoltF;
} else {
q2=oik*cbe+oikr*cbc;
arg=MAX(0,1+4*q2);
sqarg=1;
if(!model->BJTnkfGiven) {
if(arg != 0) sqarg=sqrt(arg);
} else {
if(arg != 0) sqarg=pow(arg,model->BJTnkf);
}
qb=q1*(1+sqarg)/2;
if(!model->BJTnkfGiven) {
dqbdve=q1*(qb*here->BJTtinvEarlyVoltR+oik*gbe/sqarg);
dqbdvc=q1*(qb*here->BJTtinvEarlyVoltF+oikr*gbc/sqarg);
} else {
dqbdve=q1*(qb*here->BJTtinvEarlyVoltR+oik*gbe*2*sqarg*model->BJTnkf/arg);
dqbdvc=q1*(qb*here->BJTtinvEarlyVoltF+oikr*gbc*2*sqarg*model->BJTnkf/arg);
}
}
/*
* weil's approx. for excess phase applied with backward-
* euler integration
*/
cc=0;
cex=cbe;
gex=gbe;
if(ckt->CKTmode & (MODETRAN | MODEAC) && td != 0) {
arg1=ckt->CKTdelta/td;
arg2=3*arg1;
arg1=arg2*arg1;
denom=1+arg1+arg2;
arg3=arg1/denom;
if(ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->BJTcexbc)=cbe/qb;
*(ckt->CKTstate2 + here->BJTcexbc)=
*(ckt->CKTstate1 + here->BJTcexbc);
}
cc=(*(ckt->CKTstate1 + here->BJTcexbc)*(1+ckt->CKTdelta/
ckt->CKTdeltaOld[1]+arg2)-
*(ckt->CKTstate2 + here->BJTcexbc)*ckt->CKTdelta/
ckt->CKTdeltaOld[1])/denom;
cex=cbe*arg3;
gex=gbe*arg3;
*(ckt->CKTstate0 + here->BJTcexbc)=cc+cex/qb;
}
/*
* determine dc incremental conductances
*/
cc=cc+(cex-cbc)/qb-cbc/here->BJTtBetaR-cbcn;
cb=cbe/here->BJTtBetaF+cben+cbc/here->BJTtBetaR+cbcn;
gx=rbpr+rbpi/qb;
if(xjrb != 0) {
arg1=MAX(cb/xjrb,1e-9);
arg2=(-1+sqrt(1+14.59025*arg1))/2.4317/sqrt(arg1);
arg1=tan(arg2);
gx=rbpr+3*rbpi*(arg1-arg2)/arg2/arg1/arg1;
}
if(gx != 0) gx=1/gx;
gpi=gbe/here->BJTtBetaF+gben;
gmu=gbc/here->BJTtBetaR+gbcn;
go=(gbc+(cex-cbc)*dqbdvc/qb)/qb;
gm=(gex-(cex-cbc)*dqbdve/qb)/qb-go;
if( (ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC)) ||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ||
(ckt->CKTmode & MODEINITSMSIG)) {
/*
* charge storage elements
*/
tf=here->BJTttransitTimeF;
tr=here->BJTttransitTimeR;
czbe=here->BJTtBEcap*here->BJTarea;
pe=here->BJTtBEpot;
xme=here->BJTtjunctionExpBE;
cdis=model->BJTbaseFractionBCcap;
if (model->BJTsubs == VERTICAL)
ctot=here->BJTtBCcap*here->BJTareab;
else
ctot=here->BJTtBCcap*here->BJTareac;
czbc=ctot*cdis;
czbx=ctot-czbc;
pc=here->BJTtBCpot;
xmc=here->BJTtjunctionExpBC;
fcpe=here->BJTtDepCap;
if (model->BJTsubs == VERTICAL)
czsub=here->BJTtSubcap*here->BJTareac;
else
czsub=here->BJTtSubcap*here->BJTareab;
ps=here->BJTtSubpot;
xms=here->BJTtjunctionExpSub;
xtf=model->BJTtransitTimeBiasCoeffF;
ovtf=model->BJTtransitTimeVBCFactor;
xjtf=here->BJTttransitTimeHighCurrentF*here->BJTarea;
if(tf != 0 && vbe >0) {
argtf=0;
arg2=0;
arg3=0;
if(xtf != 0){
argtf=xtf;
if(ovtf != 0) {
argtf=argtf*exp(vbc*ovtf);
}
arg2=argtf;
if(xjtf != 0) {
temp=cbe/(cbe+xjtf);
argtf=argtf*temp*temp;
arg2=argtf*(3-temp-temp);
}
arg3=cbe*argtf*ovtf;
}
cbe=cbe*(1+argtf)/qb;
gbe=(gbe*(1+arg2)-cbe*dqbdve)/qb;
geqcb=tf*(arg3-cbe*dqbdvc)/qb;
}
if (vbe < fcpe) {
arg=1-vbe/pe;
sarg=exp(-xme*log(arg));
*(ckt->CKTstate0 + here->BJTqbe)=tf*cbe+pe*czbe*
(1-arg*sarg)/(1-xme);
capbe=tf*gbe+czbe*sarg;
} else {
f1=here->BJTtf1;
f2=here->BJTtf2;
f3=here->BJTtf3;
czbef2=czbe/f2;
*(ckt->CKTstate0 + here->BJTqbe) = tf*cbe+czbe*f1+czbef2*
(f3*(vbe-fcpe) +(xme/(pe+pe))*(vbe*vbe-fcpe*fcpe));
capbe=tf*gbe+czbef2*(f3+xme*vbe/pe);
}
fcpc=here->BJTtf4;
f1=here->BJTtf5;
f2=here->BJTtf6;
f3=here->BJTtf7;
if (vbc < fcpc) {
arg=1-vbc/pc;
sarg=exp(-xmc*log(arg));
*(ckt->CKTstate0 + here->BJTqbc) = tr*cbc+pc*czbc*(
1-arg*sarg)/(1-xmc);
capbc=tr*gbc+czbc*sarg;
} else {
czbcf2=czbc/f2;
*(ckt->CKTstate0 + here->BJTqbc) = tr*cbc+czbc*f1+czbcf2*
(f3*(vbc-fcpc) +(xmc/(pc+pc))*(vbc*vbc-fcpc*fcpc));
capbc=tr*gbc+czbcf2*(f3+xmc*vbc/pc);
}
if(vbx < fcpc) {
arg=1-vbx/pc;
sarg=exp(-xmc*log(arg));
*(ckt->CKTstate0 + here->BJTqbx)=
pc*czbx* (1-arg*sarg)/(1-xmc);
capbx=czbx*sarg;
} else {
czbxf2=czbx/f2;
*(ckt->CKTstate0 + here->BJTqbx)=czbx*f1+czbxf2*
(f3*(vbx-fcpc)+(xmc/(pc+pc))*(vbx*vbx-fcpc*fcpc));
capbx=czbxf2*(f3+xmc*vbx/pc);
}
if(vsub < 0){
arg=1-vsub/ps;
sarg=exp(-xms*log(arg));
*(ckt->CKTstate0 + here->BJTqsub) = ps*czsub*(1-arg*sarg)/
(1-xms);
capsub=czsub*sarg;
} else {
*(ckt->CKTstate0 + here->BJTqsub) = vsub*czsub*(1+xms*vsub/
(2*ps));
capsub=czsub*(1+xms*vsub/ps);
}
here->BJTcapbe = capbe;
here->BJTcapbc = capbc;
if (model->BJTintCollResistGiven) {
*(ckt->CKTstate0 + here->BJTqbc) += Qbci;
here->BJTcapbc += Qbci_Vbci;
capbc += Qbci_Vbci;
}
here->BJTcapsub = capsub;
here->BJTcapbx = capbx;
/*
* store small-signal parameters
*/
if ( (!(ckt->CKTmode & MODETRANOP))||
(!(ckt->CKTmode & MODEUIC)) ) {
if(ckt->CKTmode & MODEINITSMSIG) {
*(ckt->CKTstate0 + here->BJTcqbe) = capbe;
*(ckt->CKTstate0 + here->BJTcqbc) = capbc;
*(ckt->CKTstate0 + here->BJTcqsub) = capsub;
*(ckt->CKTstate0 + here->BJTcqbx) = capbx;
*(ckt->CKTstate0 + here->BJTcexbc) = geqcb;
*(ckt->CKTstate0 + here->BJTcqbcx) = Qbcx_Vbcx;
if(SenCond){
*(ckt->CKTstate0 + here->BJTcc) = cc;
*(ckt->CKTstate0 + here->BJTcb) = cb;
*(ckt->CKTstate0 + here->BJTgpi) = gpi;
*(ckt->CKTstate0 + here->BJTgmu) = gmu;
*(ckt->CKTstate0 + here->BJTgm) = gm;
*(ckt->CKTstate0 + here->BJTgo) = go;
*(ckt->CKTstate0 + here->BJTgx) = gx;
*(ckt->CKTstate0 + here->BJTirci_Vrci) = Irci_Vrci;
*(ckt->CKTstate0 + here->BJTirci_Vbci) = Irci_Vbci;
*(ckt->CKTstate0 + here->BJTirci_Vbcx) = Irci_Vbcx;
*(ckt->CKTstate0 + here->BJTgcsub) = gcsub;
*(ckt->CKTstate0 + here->BJTgeqbx) = geqbx;
}
#ifdef SENSDEBUG
printf("storing small signal parameters for op\n");
printf("capbe = %.7e ,capbc = %.7e\n",capbe,capbc);
printf("capsub = %.7e ,capbx = %.7e\n",capsub,capbx);
printf("geqcb = %.7e ,gpi = %.7e\n",geqcb,gpi);
printf("gmu = %.7e ,gm = %.7e\n",gmu,gm);
printf("go = %.7e ,gx = %.7e\n",go,gx);
printf("gcsub = %.7e ,geqbx = %.7e\n",gcsub,geqbx);
printf("cc = %.7e ,cb = %.7e\n",cc,cb);
#endif /* SENSDEBUG */
continue; /* go to 1000 */
}
/*
* transient analysis
*/
if(SenCond && ckt->CKTsenInfo->SENmode == TRANSEN){
*(ckt->CKTstate0 + here->BJTcc) = cc;
*(ckt->CKTstate0 + here->BJTcb) = cb;
*(ckt->CKTstate0 + here->BJTgx) = gx;
continue;
}
if(ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->BJTqbe) =
*(ckt->CKTstate0 + here->BJTqbe) ;
*(ckt->CKTstate1 + here->BJTqbc) =
*(ckt->CKTstate0 + here->BJTqbc) ;
*(ckt->CKTstate1 + here->BJTqbx) =
*(ckt->CKTstate0 + here->BJTqbx) ;
*(ckt->CKTstate1 + here->BJTqsub) =
*(ckt->CKTstate0 + here->BJTqsub) ;
*(ckt->CKTstate1 + here->BJTqbcx) =
*(ckt->CKTstate0 + here->BJTqbcx) ;
}
error = NIintegrate(ckt,&geq,&ceq,capbe,here->BJTqbe);
if(error) return(error);
geqcb=geqcb*ckt->CKTag[0];
gpi=gpi+geq;
cb=cb+*(ckt->CKTstate0 + here->BJTcqbe);
error = NIintegrate(ckt,&geq,&ceq,capbc,here->BJTqbc);
if(error) return(error);
gmu=gmu+geq;
cb=cb+*(ckt->CKTstate0 + here->BJTcqbc);
cc=cc-*(ckt->CKTstate0 + here->BJTcqbc);
if (model->BJTintCollResistGiven) {
error = NIintegrate(ckt,&geq,&ceq,Qbcx_Vbcx,here->BJTqbcx);
if(error) return(error);
gbcx = geq;
cbcx = *(ckt->CKTstate0 + here->BJTcqbcx);
}
if(ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->BJTcqbe) =
*(ckt->CKTstate0 + here->BJTcqbe);
*(ckt->CKTstate1 + here->BJTcqbc) =
*(ckt->CKTstate0 + here->BJTcqbc);
*(ckt->CKTstate1 + here->BJTcqbcx) =
*(ckt->CKTstate0 + here->BJTcqbcx);
}
}
}
if(SenCond) goto next2;
/*
* check convergence
*/
if ( (!(ckt->CKTmode & MODEINITFIX))||(!(here->BJToff))) {
if (icheck == 1) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
}
}
/*
* charge storage for c-s and b-x junctions
*/
if(ckt->CKTmode & (MODETRAN | MODEAC)) {
error = NIintegrate(ckt,&gcsub,&ceq,capsub,here->BJTqsub);
if(error) return(error);
error = NIintegrate(ckt,&geqbx,&ceq,capbx,here->BJTqbx);
if(error) return(error);
if(ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->BJTcqbx) =
*(ckt->CKTstate0 + here->BJTcqbx);
*(ckt->CKTstate1 + here->BJTcqsub) =
*(ckt->CKTstate0 + here->BJTcqsub);
}
}
next2:
*(ckt->CKTstate0 + here->BJTvbe) = vbe;
*(ckt->CKTstate0 + here->BJTvbc) = vbc;
*(ckt->CKTstate0 + here->BJTvbcx) = vbcx;
*(ckt->CKTstate0 + here->BJTvrci) = vrci;
*(ckt->CKTstate0 + here->BJTcc) = cc;
*(ckt->CKTstate0 + here->BJTcb) = cb;
*(ckt->CKTstate0 + here->BJTgpi) = gpi;
*(ckt->CKTstate0 + here->BJTgmu) = gmu;
*(ckt->CKTstate0 + here->BJTgm) = gm;
*(ckt->CKTstate0 + here->BJTgo) = go;
*(ckt->CKTstate0 + here->BJTgx) = gx;
*(ckt->CKTstate0 + here->BJTgeqcb) = geqcb;
*(ckt->CKTstate0 + here->BJTgcsub) = gcsub;
*(ckt->CKTstate0 + here->BJTgeqbx) = geqbx;
*(ckt->CKTstate0 + here->BJTvsub) = vsub;
*(ckt->CKTstate0 + here->BJTgdsub) = gdsub;
*(ckt->CKTstate0 + here->BJTcdsub) = cdsub;
*(ckt->CKTstate0 + here->BJTirci) = Irci;
*(ckt->CKTstate0 + here->BJTirci_Vrci) = Irci_Vrci;
*(ckt->CKTstate0 + here->BJTirci_Vbci) = Irci_Vbci;
*(ckt->CKTstate0 + here->BJTirci_Vbcx) = Irci_Vbcx;
/* Do not load the Jacobian and the rhs if
perturbation is being carried out */
if(SenCond)continue;
#ifndef NOBYPASS
load:
#endif
/*
* load current excitation vector
*/
geqsub = gcsub + gdsub;
ceqsub=model->BJTtype * model->BJTsubs *
(*(ckt->CKTstate0 + here->BJTcqsub) + cdsub - vsub*geqsub);
ceqbx=model->BJTtype * (*(ckt->CKTstate0 + here->BJTcqbx) -
vbx * geqbx);
ceqbe=model->BJTtype * (cc + cb - vbe * (gm + go + gpi) + vbc *
(go - geqcb));
ceqbc=model->BJTtype * (-cc + vbe * (gm + go) - vbc * (gmu + go));
*(ckt->CKTrhs + here->BJTbaseNode) += m * (-ceqbx);
*(ckt->CKTrhs + here->BJTcolPrimeNode) +=
m * (ceqbx+ceqbc);
*(ckt->CKTrhs + here->BJTsubstConNode) += m * ceqsub;
*(ckt->CKTrhs + here->BJTbasePrimeNode) +=
m * (-ceqbe-ceqbc);
*(ckt->CKTrhs + here->BJTemitPrimeNode) += m * (ceqbe);
*(ckt->CKTrhs + here->BJTsubstNode) += m * (-ceqsub);
/*
* load y matrix
*/
*(here->BJTcolColPtr) += m * (gcpr);
*(here->BJTbaseBasePtr) += m * (gx+geqbx);
*(here->BJTemitEmitPtr) += m * (gepr);
*(here->BJTcolPrimeColPrimePtr) += m * (gmu+go+geqbx);
*(here->BJTcollCXcollCXPtr) += m * (gcpr);
*(here->BJTsubstConSubstConPtr) += m * (geqsub);
*(here->BJTbasePrimeBasePrimePtr) += m * (gx +gpi+gmu+geqcb);
*(here->BJTemitPrimeEmitPrimePtr) += m * (gpi+gepr+gm+go);
*(here->BJTcollCollCXPtr) += m * (-gcpr);
*(here->BJTbaseBasePrimePtr) += m * (-gx);
*(here->BJTemitEmitPrimePtr) += m * (-gepr);
*(here->BJTcollCXCollPtr) += m * (-gcpr);
*(here->BJTcolPrimeBasePrimePtr) += m * (-gmu+gm);
*(here->BJTcolPrimeEmitPrimePtr) += m * (-gm-go);
*(here->BJTbasePrimeBasePtr) += m * (-gx);
*(here->BJTbasePrimeColPrimePtr) += m * (-gmu-geqcb);
*(here->BJTbasePrimeEmitPrimePtr) += m * (-gpi);
*(here->BJTemitPrimeEmitPtr) += m * (-gepr);
*(here->BJTemitPrimeColPrimePtr) += m * (-go+geqcb);
*(here->BJTemitPrimeBasePrimePtr) += m * (-gpi-gm-geqcb);
*(here->BJTsubstSubstPtr) += m * (geqsub);
*(here->BJTsubstConSubstPtr) += m * (-geqsub);
*(here->BJTsubstSubstConPtr) += m * (-geqsub);
*(here->BJTbaseColPrimePtr) += m * (-geqbx);
*(here->BJTcolPrimeBasePtr) += m * (-geqbx);
/*
c Stamp element: Irci
*/
if (model->BJTintCollResistGiven) {
double rhs_current = model->BJTtype * m * (Irci - Irci_Vrci*vrci - Irci_Vbci*vbc - Irci_Vbcx*vbcx);
*(ckt->CKTrhs + here->BJTcollCXNode) += -rhs_current;
*(here->BJTcollCXcollCXPtr) += m * Irci_Vrci;
*(here->BJTcollCXColPrimePtr) += m * -Irci_Vrci;
*(here->BJTcollCXBasePrimePtr) += m * Irci_Vbci;
*(here->BJTcollCXColPrimePtr) += m * -Irci_Vbci;
*(here->BJTcollCXBasePrimePtr) += m * Irci_Vbcx;
*(here->BJTcollCXcollCXPtr) += m * -Irci_Vbcx;
*(ckt->CKTrhs + here->BJTcolPrimeNode) += rhs_current;
*(here->BJTcolPrimeCollCXPtr) += m * -Irci_Vrci;
*(here->BJTcolPrimeColPrimePtr) += m * Irci_Vrci;
*(here->BJTcolPrimeBasePrimePtr) += m * -Irci_Vbci;
*(here->BJTcolPrimeColPrimePtr) += m * Irci_Vbci;
*(here->BJTcolPrimeBasePrimePtr) += m * -Irci_Vbcx;
*(here->BJTcolPrimeCollCXPtr) += m * Irci_Vbcx;
*(ckt->CKTrhs + here->BJTbasePrimeNode) += m * -cbcx;
*(ckt->CKTrhs + here->BJTcollCXNode) += m * cbcx;
*(here->BJTbasePrimeBasePrimePtr) += m * gbcx;
*(here->BJTcollCXcollCXPtr) += m * gbcx;
*(here->BJTbasePrimeCollCXPtr) += m * -gbcx;
*(here->BJTcollCXBasePrimePtr) += m * -gbcx;
}
}
}
return(OK);
}