613 lines
18 KiB
C
613 lines
18 KiB
C
/**********
|
|
Copyright 1991 Regents of the University of California. All rights reserved.
|
|
Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
|
|
**********/
|
|
|
|
/* Functions to compute terminal conductances & currents. */
|
|
|
|
#include "ngspice.h"
|
|
#include "numglobs.h"
|
|
#include "numenum.h"
|
|
#include "twomesh.h"
|
|
#include "twodev.h"
|
|
#include "bool.h"
|
|
#include "spMatrix.h"
|
|
#include "twoddefs.h"
|
|
#include "twodext.h"
|
|
|
|
|
|
void
|
|
NUMD2conductance(TWOdevice *pDevice, BOOLEAN tranAnalysis,
|
|
double *intCoeff, double *gd)
|
|
{
|
|
TWOcontact *pContact = pDevice->pFirstContact;
|
|
int index;
|
|
double *incVpn;
|
|
BOOLEAN deltaVContact = FALSE;
|
|
|
|
/*
|
|
* store the new rhs for computing the incremental quantities
|
|
* with the second to last node. solve the system of equations
|
|
*/
|
|
incVpn = pDevice->dcDeltaSolution;
|
|
storeNewRhs( pDevice, pDevice->pLastContact );
|
|
spSolve( pDevice->matrix, pDevice->rhs, incVpn, NIL(spREAL), NIL(spREAL));
|
|
|
|
incVpn = pDevice->dcDeltaSolution;
|
|
*gd = contactConductance( pDevice, pContact, deltaVContact, incVpn,
|
|
tranAnalysis, intCoeff );
|
|
*gd *= - GNorm * pDevice->width * LNorm;
|
|
}
|
|
|
|
void
|
|
NBJT2conductance(TWOdevice *pDevice, BOOLEAN tranAnalysis,
|
|
double *intCoeff, double *dIeDVce, double *dIcDVce,
|
|
double *dIeDVbe, double *dIcDVbe)
|
|
{
|
|
TWOcontact *pEmitContact = pDevice->pLastContact;
|
|
TWOcontact *pColContact = pDevice->pFirstContact;
|
|
TWOcontact *pBaseContact = pDevice->pFirstContact->next;
|
|
int index;
|
|
double width = pDevice->width;
|
|
double *incVce, *incVbe;
|
|
|
|
/*
|
|
* store the new rhs for computing the incremental quantities
|
|
* incVce (dcDeltaSolution) and incVbe (copiedSolution) are used to
|
|
* store the incremental quantities associated with Vce and Vbe
|
|
*/
|
|
|
|
incVce = pDevice->dcDeltaSolution;
|
|
incVbe = pDevice->copiedSolution;
|
|
storeNewRhs( pDevice, pColContact );
|
|
spSolve( pDevice->matrix, pDevice->rhs, incVce, NIL(spREAL), NIL(spREAL));
|
|
storeNewRhs( pDevice, pBaseContact );
|
|
spSolve( pDevice->matrix, pDevice->rhs, incVbe, NIL(spREAL), NIL(spREAL));
|
|
|
|
*dIeDVce = contactConductance( pDevice, pEmitContact, FALSE, incVce,
|
|
tranAnalysis, intCoeff );
|
|
*dIeDVbe = contactConductance( pDevice, pEmitContact, FALSE, incVbe,
|
|
tranAnalysis, intCoeff );
|
|
|
|
*dIcDVce = contactConductance( pDevice, pColContact, TRUE, incVce,
|
|
tranAnalysis, intCoeff );
|
|
*dIcDVbe = contactConductance( pDevice, pColContact, FALSE, incVbe,
|
|
tranAnalysis, intCoeff );
|
|
*dIeDVce *= GNorm * width * LNorm;
|
|
*dIcDVce *= GNorm * width * LNorm;
|
|
*dIeDVbe *= GNorm * width * LNorm;
|
|
*dIcDVbe *= GNorm * width * LNorm;
|
|
}
|
|
|
|
void
|
|
NUMOSconductance(TWOdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff,
|
|
struct mosConductances *dIdV)
|
|
{
|
|
TWOcontact *pDContact = pDevice->pFirstContact;
|
|
TWOcontact *pGContact = pDevice->pFirstContact->next;
|
|
TWOcontact *pSContact = pDevice->pFirstContact->next->next;
|
|
TWOcontact *pBContact = pDevice->pLastContact;
|
|
int index;
|
|
double width = pDevice->width;
|
|
double *incVdb, *incVsb, *incVgb;
|
|
|
|
/*
|
|
* store the new rhs for computing the incremental quantities
|
|
* incVdb (dcDeltaSolution)
|
|
*/
|
|
|
|
incVdb = pDevice->dcDeltaSolution;
|
|
incVsb = pDevice->copiedSolution;
|
|
incVgb = pDevice->rhsImag;
|
|
storeNewRhs( pDevice, pDContact );
|
|
spSolve( pDevice->matrix, pDevice->rhs, incVdb, NIL(spREAL), NIL(spREAL));
|
|
storeNewRhs( pDevice, pSContact );
|
|
spSolve( pDevice->matrix, pDevice->rhs, incVsb, NIL(spREAL), NIL(spREAL));
|
|
storeNewRhs( pDevice, pGContact );
|
|
spSolve( pDevice->matrix, pDevice->rhs, incVgb, NIL(spREAL), NIL(spREAL));
|
|
|
|
dIdV->dIdDVdb = contactConductance( pDevice, pDContact, TRUE,
|
|
incVdb, tranAnalysis, intCoeff );
|
|
dIdV->dIsDVdb = contactConductance( pDevice, pSContact, FALSE,
|
|
incVdb, tranAnalysis, intCoeff );
|
|
dIdV->dIgDVdb = GateTypeConductance( pDevice, pGContact, FALSE,
|
|
incVdb, tranAnalysis, intCoeff );
|
|
dIdV->dIdDVsb = contactConductance( pDevice, pDContact, FALSE,
|
|
incVsb, tranAnalysis, intCoeff );
|
|
dIdV->dIsDVsb = contactConductance( pDevice, pSContact, TRUE,
|
|
incVsb, tranAnalysis, intCoeff );
|
|
dIdV->dIgDVsb = GateTypeConductance( pDevice, pGContact, FALSE,
|
|
incVsb, tranAnalysis, intCoeff );
|
|
dIdV->dIdDVgb = contactConductance( pDevice, pDContact, FALSE,
|
|
incVgb, tranAnalysis, intCoeff );
|
|
dIdV->dIsDVgb = contactConductance( pDevice, pSContact, FALSE,
|
|
incVgb, tranAnalysis, intCoeff );
|
|
dIdV->dIgDVgb = GateTypeConductance( pDevice, pGContact, TRUE,
|
|
incVgb, tranAnalysis, intCoeff );
|
|
|
|
dIdV->dIdDVdb *= GNorm * width * LNorm;
|
|
dIdV->dIdDVsb *= GNorm * width * LNorm;
|
|
dIdV->dIdDVgb *= GNorm * width * LNorm;
|
|
dIdV->dIsDVdb *= GNorm * width * LNorm;
|
|
dIdV->dIsDVsb *= GNorm * width * LNorm;
|
|
dIdV->dIsDVgb *= GNorm * width * LNorm;
|
|
dIdV->dIgDVdb *= GNorm * width * LNorm;
|
|
dIdV->dIgDVsb *= GNorm * width * LNorm;
|
|
dIdV->dIgDVgb *= GNorm * width * LNorm;
|
|
|
|
}
|
|
|
|
double
|
|
contactCurrent(TWOdevice *pDevice, TWOcontact *pContact)
|
|
{
|
|
/* computes the current through the contact given in pContact */
|
|
int index, i, numContactNodes;
|
|
TWOnode *pNode;
|
|
TWOelem *pElem;
|
|
TWOedge *pHEdge, *pVEdge;
|
|
double dx, dy;
|
|
double jTotal = 0.0;
|
|
|
|
numContactNodes = pContact->numNodes;
|
|
for ( index = 0; index < numContactNodes; index++ ) {
|
|
pNode = pContact->pNodes[ index ];
|
|
for ( i = 0; i <= 3; i++ ) {
|
|
pElem = pNode->pElems[ i ];
|
|
if ( pElem != NIL(TWOelem) ) {
|
|
dx = 0.5 * pElem->dx;
|
|
dy = 0.5 * pElem->dy;
|
|
switch ( i ) {
|
|
case 0:
|
|
/* Bottom Right node */
|
|
pHEdge = pElem->pBotEdge;
|
|
pVEdge = pElem->pRightEdge;
|
|
jTotal += pElem->epsRel * ( -dy * pHEdge->jd - dx * pVEdge->jd );
|
|
if ( pElem->elemType == SEMICON ) {
|
|
jTotal += -dy * (pHEdge->jn + pHEdge->jp)
|
|
-dx * (pVEdge->jn + pVEdge->jp);
|
|
}
|
|
break;
|
|
case 1:
|
|
/* Bottom Left node */
|
|
pHEdge = pElem->pBotEdge;
|
|
pVEdge = pElem->pLeftEdge;
|
|
jTotal += pElem->epsRel * ( dy * pHEdge->jd - dx * pVEdge->jd );
|
|
if ( pElem->elemType == SEMICON ) {
|
|
jTotal += dy * (pHEdge->jn + pHEdge->jp)
|
|
-dx * (pVEdge->jn + pVEdge->jp);
|
|
}
|
|
break;
|
|
case 2:
|
|
/* Top Left node */
|
|
pHEdge = pElem->pTopEdge;
|
|
pVEdge = pElem->pLeftEdge;
|
|
jTotal += pElem->epsRel * ( dy * pHEdge->jd + dx * pVEdge->jd );
|
|
if ( pElem->elemType == SEMICON ) {
|
|
jTotal += dy * (pHEdge->jn + pHEdge->jp)
|
|
+ dx * (pVEdge->jn + pVEdge->jp);
|
|
}
|
|
break;
|
|
case 3:
|
|
/* Top Right Node */
|
|
pHEdge = pElem->pTopEdge;
|
|
pVEdge = pElem->pRightEdge;
|
|
jTotal += pElem->epsRel * ( -dy * pHEdge->jd + dx * pVEdge->jd );
|
|
if ( pElem->elemType == SEMICON ) {
|
|
jTotal += -dy * (pHEdge->jn + pHEdge->jp)
|
|
+ dx * (pVEdge->jn + pVEdge->jp);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( jTotal * pDevice->width * LNorm * JNorm );
|
|
}
|
|
|
|
double
|
|
oxideCurrent(TWOdevice *pDevice, TWOcontact *pContact,
|
|
BOOLEAN tranAnalysis)
|
|
{
|
|
/* computes the current through the contact given in pContact */
|
|
int index, i, numContactNodes;
|
|
TWOnode *pNode;
|
|
TWOelem *pElem;
|
|
TWOedge *pHEdge, *pVEdge;
|
|
double dx, dy;
|
|
double jTotal = 0.0;
|
|
|
|
if ( !tranAnalysis ) {
|
|
return( jTotal );
|
|
}
|
|
|
|
numContactNodes = pContact->numNodes;
|
|
for ( index = 0; index < numContactNodes; index++ ) {
|
|
pNode = pContact->pNodes[ index ];
|
|
for ( i = 0; i <= 3; i++ ) {
|
|
pElem = pNode->pElems[ i ];
|
|
if ( pElem != NIL(TWOelem) ) {
|
|
dx = 0.5 * pElem->dx;
|
|
dy = 0.5 * pElem->dy;
|
|
switch ( i ) {
|
|
case 0:
|
|
/* Bottom Right node */
|
|
pHEdge = pElem->pBotEdge;
|
|
pVEdge = pElem->pRightEdge;
|
|
jTotal += pElem->epsRel * ( -dy * pHEdge->jd - dx * pVEdge->jd );
|
|
break;
|
|
case 1:
|
|
/* Bottom Left node */
|
|
pHEdge = pElem->pBotEdge;
|
|
pVEdge = pElem->pLeftEdge;
|
|
jTotal += pElem->epsRel * ( dy * pHEdge->jd - dx * pVEdge->jd );
|
|
break;
|
|
case 2:
|
|
/* Top Left node */
|
|
pHEdge = pElem->pTopEdge;
|
|
pVEdge = pElem->pLeftEdge;
|
|
jTotal += pElem->epsRel * ( dy * pHEdge->jd + dx * pVEdge->jd );
|
|
break;
|
|
case 3:
|
|
/* Top Right Node */
|
|
pHEdge = pElem->pTopEdge;
|
|
pVEdge = pElem->pRightEdge;
|
|
jTotal += pElem->epsRel * ( -dy * pHEdge->jd + dx * pVEdge->jd );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( jTotal * pDevice->width * LNorm * JNorm );
|
|
}
|
|
|
|
|
|
double
|
|
contactConductance(TWOdevice *pDevice, TWOcontact *pContact,
|
|
BOOLEAN delVContact, double *dxDv,
|
|
BOOLEAN tranAnalysis, double *intCoeff)
|
|
{
|
|
/* computes the conductance of the contact given in pContact */
|
|
int index, i, numContactNodes;
|
|
TWOnode *pNode, *pHNode = NULL, *pVNode = NULL;
|
|
TWOelem *pElem;
|
|
TWOedge *pHEdge = NULL, *pVEdge = NULL;
|
|
double dPsiDv, dnDv, dpDv;
|
|
double gTotal = 0.0;
|
|
int nInc, pInc;
|
|
|
|
/* for one carrier the rest of this code relies on appropriate
|
|
current derivative term to be zero */
|
|
if ( !OneCarrier ) {
|
|
nInc = 1;
|
|
pInc = 2;
|
|
} else {
|
|
nInc = 1;
|
|
pInc = 1;
|
|
}
|
|
|
|
numContactNodes = pContact->numNodes;
|
|
for ( index = 0; index < numContactNodes; index++ ) {
|
|
pNode = pContact->pNodes[ index ];
|
|
for ( i = 0; i <= 3; i++ ) {
|
|
pElem = pNode->pElems[ i ];
|
|
if ( pElem != NIL(TWOelem) ) {
|
|
switch ( i ) {
|
|
case 0:
|
|
/* the TL element */
|
|
pHNode = pElem->pBLNode;
|
|
pVNode = pElem->pTRNode;
|
|
pHEdge = pElem->pBotEdge;
|
|
pVEdge = pElem->pRightEdge;
|
|
if ( pElem->elemType == SEMICON ) {
|
|
/* compute the derivatives with n,p */
|
|
if ( pHNode->nodeType != CONTACT ) {
|
|
dnDv = dxDv[ pHNode->nEqn ];
|
|
dpDv = dxDv[ pHNode->pEqn ];
|
|
gTotal -= 0.5 * pElem->dy * (pHEdge->dJnDn * dnDv
|
|
+ pHEdge->dJpDp * dpDv);
|
|
}
|
|
if ( pVNode->nodeType != CONTACT ) {
|
|
dnDv = dxDv[ pVNode->nEqn ];
|
|
dpDv = dxDv[ pVNode->pEqn ];
|
|
gTotal -= 0.5 * pElem->dx * (pVEdge->dJnDn * dnDv
|
|
+ pVEdge->dJpDp * dpDv);
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
/* the TR element */
|
|
pHNode = pElem->pBRNode;
|
|
pVNode = pElem->pTLNode;
|
|
pHEdge = pElem->pBotEdge;
|
|
pVEdge = pElem->pLeftEdge;
|
|
if ( pElem->elemType == SEMICON ) {
|
|
/* compute the derivatives with n,p */
|
|
if ( pHNode->nodeType != CONTACT ) {
|
|
dnDv = dxDv[ pHNode->nEqn ];
|
|
dpDv = dxDv[ pHNode->pEqn ];
|
|
gTotal += 0.5 * pElem->dy * (pHEdge->dJnDnP1 * dnDv
|
|
+ pHEdge->dJpDpP1 * dpDv);
|
|
}
|
|
if ( pVNode->nodeType != CONTACT ) {
|
|
dnDv = dxDv[ pVNode->nEqn ];
|
|
dpDv = dxDv[ pVNode->pEqn ];
|
|
gTotal -= 0.5 * pElem->dx * (pVEdge->dJnDn * dnDv
|
|
+ pVEdge->dJpDp * dpDv);
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
/* the BR element*/
|
|
pHNode = pElem->pTRNode;
|
|
pVNode = pElem->pBLNode;
|
|
pHEdge = pElem->pTopEdge;
|
|
pVEdge = pElem->pLeftEdge;
|
|
if ( pElem->elemType == SEMICON ) {
|
|
/* compute the derivatives with n,p */
|
|
if ( pHNode->nodeType != CONTACT ) {
|
|
dnDv = dxDv[ pHNode->nEqn ];
|
|
dpDv = dxDv[ pHNode->pEqn ];
|
|
gTotal += 0.5 * pElem->dy * (pHEdge->dJnDnP1 * dnDv
|
|
+ pHEdge->dJpDpP1 * dpDv);
|
|
}
|
|
if ( pVNode->nodeType != CONTACT ) {
|
|
dnDv = dxDv[ pVNode->nEqn ];
|
|
dpDv = dxDv[ pVNode->pEqn ];
|
|
gTotal += 0.5 * pElem->dx * (pVEdge->dJnDnP1 * dnDv
|
|
+ pVEdge->dJpDpP1 * dpDv);
|
|
}
|
|
}
|
|
break;
|
|
case 3:
|
|
/* the BL element */
|
|
pHNode = pElem->pTLNode;
|
|
pVNode = pElem->pBRNode;
|
|
pHEdge = pElem->pTopEdge;
|
|
pVEdge = pElem->pRightEdge;
|
|
if ( pElem->elemType == SEMICON ) {
|
|
/* compute the derivatives with n,p */
|
|
if ( pHNode->nodeType != CONTACT ) {
|
|
dnDv = dxDv[ pHNode->nEqn ];
|
|
dpDv = dxDv[ pHNode->pEqn ];
|
|
gTotal -= 0.5 * pElem->dy * (pHEdge->dJnDn * dnDv
|
|
+ pHEdge->dJpDp * dpDv);
|
|
}
|
|
if ( pVNode->nodeType != CONTACT ) {
|
|
dnDv = dxDv[ pVNode->nEqn ];
|
|
dpDv = dxDv[ pVNode->pEqn ];
|
|
gTotal += 0.5 * pElem->dx * (pVEdge->dJnDnP1 * dnDv
|
|
+ pVEdge->dJpDpP1 * dpDv);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if ( pElem->elemType == SEMICON ) {
|
|
if ( pHNode->nodeType != CONTACT ) {
|
|
dPsiDv = dxDv[ pHNode->psiEqn ];
|
|
gTotal += 0.5 * pElem->dy * dPsiDv * (pHEdge->dJnDpsiP1 + pHEdge->dJpDpsiP1 );
|
|
if ( delVContact ) {
|
|
gTotal -= 0.5 * pElem->dy * (pHEdge->dJnDpsiP1 + pHEdge->dJpDpsiP1 );
|
|
}
|
|
}
|
|
if ( pVNode->nodeType != CONTACT ) {
|
|
dPsiDv = dxDv[ pVNode->psiEqn ];
|
|
gTotal += 0.5 * pElem->dx * dPsiDv * (pVEdge->dJnDpsiP1 + pVEdge->dJpDpsiP1 );
|
|
if ( delVContact ) {
|
|
gTotal -= 0.5 * pElem->dx * (pVEdge->dJnDpsiP1 + pVEdge->dJpDpsiP1 );
|
|
}
|
|
}
|
|
}
|
|
if ( tranAnalysis ) {
|
|
/* add the displacement current terms */
|
|
if ( pHNode->nodeType != CONTACT ) {
|
|
dPsiDv = dxDv[ pHNode->psiEqn ];
|
|
gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx * dPsiDv;
|
|
if ( delVContact ) {
|
|
gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx;
|
|
}
|
|
}
|
|
if ( pVNode->nodeType != CONTACT ) {
|
|
dPsiDv = dxDv[ pVNode->psiEqn ];
|
|
gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy * dPsiDv;
|
|
if ( delVContact ) {
|
|
gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( gTotal );
|
|
}
|
|
|
|
|
|
double
|
|
oxideConductance(TWOdevice *pDevice, TWOcontact *pContact,
|
|
BOOLEAN delVContact, double *dxDv,
|
|
BOOLEAN tranAnalysis, double *intCoeff)
|
|
{
|
|
/* computes the conductance of the contact given in pContact */
|
|
int index, i, numContactNodes;
|
|
TWOnode *pNode, *pHNode = NULL, *pVNode = NULL;
|
|
TWOelem *pElem;
|
|
double dPsiDv, dnDv, dpDv;
|
|
double gTotal = 0.0;
|
|
|
|
if ( !tranAnalysis ) {
|
|
return( gTotal );
|
|
}
|
|
|
|
numContactNodes = pContact->numNodes;
|
|
for ( index = 0; index < numContactNodes; index++ ) {
|
|
pNode = pContact->pNodes[ index ];
|
|
for ( i = 0; i <= 3; i++ ) {
|
|
pElem = pNode->pElems[ i ];
|
|
if ( pElem != NIL(TWOelem) ) {
|
|
switch ( i ) {
|
|
case 0:
|
|
/* the TL element */
|
|
pHNode = pElem->pBLNode;
|
|
pVNode = pElem->pTRNode;
|
|
break;
|
|
case 1:
|
|
/* the TR element */
|
|
pHNode = pElem->pBRNode;
|
|
pVNode = pElem->pTLNode;
|
|
break;
|
|
case 2:
|
|
/* the BR element*/
|
|
pHNode = pElem->pTRNode;
|
|
pVNode = pElem->pBLNode;
|
|
break;
|
|
case 3:
|
|
/* the BL element */
|
|
pHNode = pElem->pTLNode;
|
|
pVNode = pElem->pBRNode;
|
|
break;
|
|
}
|
|
/* add the displacement current terms */
|
|
if ( pHNode->nodeType != CONTACT ) {
|
|
dPsiDv = dxDv[ pHNode->psiEqn ];
|
|
gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx * dPsiDv;
|
|
if ( delVContact ) {
|
|
gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx;
|
|
}
|
|
}
|
|
if ( pVNode->nodeType != CONTACT ) {
|
|
dPsiDv = dxDv[ pVNode->psiEqn ];
|
|
gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy * dPsiDv;
|
|
if ( delVContact ) {
|
|
gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( gTotal );
|
|
}
|
|
|
|
/* these functions are used for solving the complete system of
|
|
* equations directly using LU decomposition 1/22/88
|
|
*/
|
|
|
|
void
|
|
NUMD2current(TWOdevice *pDevice, BOOLEAN tranAnalysis,
|
|
double *intCoeff, double *id)
|
|
{
|
|
TWOcontact *pPContact = pDevice->pFirstContact;
|
|
TWOcontact *pNContact = pDevice->pLastContact;
|
|
int index;
|
|
double ip, ipPrime, *solution;
|
|
double in;
|
|
BOOLEAN deltaVContact = FALSE;
|
|
|
|
solution = pDevice->dcDeltaSolution;
|
|
ip = contactCurrent( pDevice, pPContact );
|
|
/*
|
|
in = contactCurrent( pDevice, pNContact );
|
|
fprintf(stdout, "DIO current: ( %11.4e error )\n", ip+in );
|
|
fprintf(stdout, " Ip = %11.4e In = %11.4e\n", ip, in );
|
|
*/
|
|
|
|
/*
|
|
* for the additional contribution to id will make use of
|
|
* contactConductance. This function will be called
|
|
* with the dcDeltaSolution vector instead of the incremental quantities
|
|
*/
|
|
ipPrime = contactConductance( pDevice, pPContact, deltaVContact,
|
|
solution, tranAnalysis, intCoeff );
|
|
|
|
ipPrime *= JNorm * pDevice->width * LNorm;
|
|
ip += ipPrime;
|
|
*id = ip;
|
|
}
|
|
|
|
void
|
|
NBJT2current(TWOdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff,
|
|
double *ie, double *ic)
|
|
{
|
|
TWOcontact *pEmitContact = pDevice->pLastContact;
|
|
TWOcontact *pColContact = pDevice->pFirstContact;
|
|
TWOcontact *pBaseContact = pDevice->pFirstContact->next;
|
|
double *solution, iePrime, icPrime;
|
|
double ib;
|
|
|
|
solution = pDevice->dcDeltaSolution;
|
|
|
|
*ie = contactCurrent( pDevice, pEmitContact );
|
|
*ic = contactCurrent( pDevice, pColContact );
|
|
/*
|
|
ib = contactCurrent( pDevice, pBaseContact );
|
|
fprintf(stdout, "BJT current: ( %11.4e error )\n", *ic+ib+*ie );
|
|
fprintf(stdout, " Ic = %11.4e Ib = %11.4e\n", *ic, ib );
|
|
fprintf(stdout, " Ie = %11.4e\n", *ie );
|
|
*/
|
|
|
|
iePrime = contactConductance( pDevice, pEmitContact, FALSE, solution,
|
|
tranAnalysis, intCoeff );
|
|
|
|
icPrime = contactConductance( pDevice, pColContact, FALSE, solution,
|
|
tranAnalysis, intCoeff );
|
|
|
|
iePrime *= JNorm * pDevice->width * LNorm;
|
|
icPrime *= JNorm * pDevice->width * LNorm;
|
|
|
|
*ie += iePrime;
|
|
*ic += icPrime;
|
|
}
|
|
|
|
void
|
|
NUMOScurrent(TWOdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff,
|
|
double *id, double *is, double *ig)
|
|
{
|
|
TWOcontact *pDContact = pDevice->pFirstContact;
|
|
TWOcontact *pGContact = pDevice->pFirstContact->next;
|
|
TWOcontact *pSContact = pDevice->pFirstContact->next->next;
|
|
TWOcontact *pBContact = pDevice->pLastContact;
|
|
double *solution, idPrime, isPrime, igPrime;
|
|
double ib;
|
|
|
|
solution = pDevice->dcDeltaSolution;
|
|
|
|
*id = contactCurrent( pDevice, pDContact );
|
|
|
|
/*
|
|
* This is a terrible hack
|
|
*/
|
|
|
|
#ifdef NORMAL_GATE
|
|
*ig = GateTypeCurrent( pDevice, pGContact, tranAnalysis );
|
|
#else
|
|
*ig = GateTypeCurrent( pDevice, pGContact);
|
|
#endif
|
|
|
|
*is = contactCurrent( pDevice, pSContact );
|
|
/*
|
|
ib = contactCurrent( pDevice, pBContact );
|
|
fprintf(stdout, "MOS current: ( %11.4e error )\n", *id+*ig+*is+ib );
|
|
fprintf(stdout, " Id = %11.4e Is = %11.4e\n", *id, *is );
|
|
fprintf(stdout, " Ig = %11.4e Ib = %11.4e\n", *ig, ib );
|
|
*/
|
|
|
|
idPrime = contactConductance( pDevice, pDContact, FALSE,
|
|
solution, tranAnalysis, intCoeff );
|
|
|
|
isPrime = contactConductance( pDevice, pSContact, FALSE,
|
|
solution, tranAnalysis, intCoeff );
|
|
|
|
igPrime = GateTypeConductance( pDevice, pGContact, FALSE,
|
|
solution, tranAnalysis, intCoeff );
|
|
|
|
idPrime *= JNorm * pDevice->width * LNorm;
|
|
isPrime *= JNorm * pDevice->width * LNorm;
|
|
igPrime *= JNorm * pDevice->width * LNorm;
|
|
|
|
*id += idPrime;
|
|
*is += isPrime;
|
|
*ig += igPrime;
|
|
}
|