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.
419 lines
12 KiB
419 lines
12 KiB
/**********
|
|
Copyright 1991 Regents of the University of California. All rights reserved.
|
|
Author: 1990 David A. Gates, U. C. Berkeley CAD Group
|
|
**********/
|
|
|
|
#include "ngspice/ngspice.h"
|
|
#include "ngspice/numglobs.h"
|
|
#include "ngspice/numconst.h"
|
|
#include "ngspice/numenum.h"
|
|
#include "ngspice/twomesh.h"
|
|
#include "ngspice/material.h"
|
|
#include "twoddefs.h"
|
|
#include "twodext.h"
|
|
|
|
/*
|
|
* These functions calculate the variable-dependence
|
|
* of the surface mobilities
|
|
*/
|
|
|
|
void
|
|
MOBsurfElec(TWOmaterial *info, TWOelem *pElem, double ex, double ey,
|
|
double es, double wx, double wy, double totalConc)
|
|
{
|
|
double thetaA = info->thetaA[ELEC];
|
|
double thetaB = info->thetaB[ELEC];
|
|
double eL, eN, eD, e0, mun;
|
|
double temp1, temp2, temp3, temp4, temp5;
|
|
double temp6, temp7, temp8, temp9;
|
|
double sgnN, sgnL;
|
|
double dMunDEs; /* Surface Field Derivative */
|
|
double dMunDEn; /* (Local) Normal Field Derivative */
|
|
double dMunDEl; /* Tangent Field Derivative */
|
|
double muHC, muSR, muLV;
|
|
double dMuSRDEn;
|
|
double d2MuSRDEn2;
|
|
double dMuHCDEl;
|
|
double dMuHCDMuSR;
|
|
double d2MuHCDMuSR2;
|
|
double d2MuHCDElDMuSR;
|
|
double dEnDEx; /* Normal Derivative x Component */
|
|
double dEnDEy; /* Normal Derivative y Component */
|
|
double dEnDWx; /* Normal Derivative x Component */
|
|
double dEnDWy; /* Normal Derivative y Component */
|
|
double dElDEx; /* Lateral Derivative x Component */
|
|
double dElDEy; /* Lateral Derivative y Component */
|
|
double dElDWx; /* Lateral Derivative x Component */
|
|
double dElDWy; /* Lateral Derivative y Component */
|
|
|
|
NG_IGNORE(wx);
|
|
NG_IGNORE(wy);
|
|
NG_IGNORE(totalConc);
|
|
|
|
if ( pElem->surface ) { /* replace one field component with surface field */
|
|
if ( pElem->direction == 0 ) {
|
|
ey = es;
|
|
} else {
|
|
ex = es;
|
|
}
|
|
}
|
|
|
|
e0 = 1.0 / ENorm;
|
|
if ( pElem->direction == 0 ) {
|
|
eN = ABS( SALPHA_N*ey + SBETA_N*es );
|
|
sgnN = SGN( SALPHA_N*ey + SBETA_N*es );
|
|
eD = SALPHA_N*( es - ey );
|
|
dEnDEx = 0.0;
|
|
dEnDEy = 1.0;
|
|
dEnDWx = 0.0;
|
|
dEnDWy = 0.0;
|
|
eL = ABS( ex );
|
|
sgnL = SGN( ex );
|
|
dElDEx = 1.0;
|
|
dElDEy = 0.0;
|
|
dElDWx = 0.0;
|
|
dElDWy = 0.0;
|
|
} else { /* pElem->direction == Y */
|
|
eN = ABS( SALPHA_N*ex + SBETA_N*es );
|
|
sgnN = SGN( SALPHA_N*ex + SBETA_N*es );
|
|
eD = SALPHA_N*( es - ex );
|
|
dEnDEx = 1.0;
|
|
dEnDEy = 0.0;
|
|
dEnDWx = 0.0;
|
|
dEnDWy = 0.0;
|
|
eL = ABS( ey );
|
|
sgnL = SGN( ey );
|
|
dElDEx = 0.0;
|
|
dElDEy = 1.0;
|
|
dElDWx = 0.0;
|
|
dElDWy = 0.0;
|
|
}
|
|
/*
|
|
fprintf(stderr,"En = %e, Ep = %e, Ey = %e, Es= %e\n",eN,eL,ey,es);
|
|
*/
|
|
|
|
muLV = pElem->mun0;
|
|
if ( TransDepMobility ) {
|
|
/* Compute various partial derivatives of muSR */
|
|
temp1 = 1.0 / ( 1.0 + thetaA*eN + thetaB*eN*eN );
|
|
temp2 = (thetaA + 2.0*thetaB*eN);
|
|
muSR = muLV * temp1;
|
|
dMuSRDEn = - muSR * temp1 * temp2;
|
|
d2MuSRDEn2 = - 2.0 * (dMuSRDEn * temp1 * temp2 + muSR * temp1 * thetaB);
|
|
if ( FieldDepMobility ) {
|
|
/* Compute various partial derivatives of muHC */
|
|
switch ( info->fieldModel ) {
|
|
case CT:
|
|
case AR:
|
|
case UF:
|
|
temp1 = 1.0 / info->vSat[ELEC];
|
|
temp2 = muSR * temp1;
|
|
temp3 = eL * temp1;
|
|
temp4 = eL * temp2;
|
|
temp5 = 1.0 / ( 1.0 + temp4 * temp4 );
|
|
temp6 = sqrt( temp5 );
|
|
muHC = muSR * temp6;
|
|
dMuHCDMuSR = temp5 * temp6;
|
|
temp7 = temp4 * dMuHCDMuSR;
|
|
temp8 = - 3.0 * temp7 * temp5;
|
|
dMuHCDEl = - muSR * temp7 * temp2;
|
|
d2MuHCDMuSR2 = temp8 * temp3;
|
|
d2MuHCDElDMuSR = temp8 * temp2;
|
|
break;
|
|
case SG:
|
|
default:
|
|
temp1 = 1.0 / info->vSat[ELEC];
|
|
temp2 = muSR * eL * temp1; /* Vdrift / Vsat */
|
|
temp3 = 1.0 / info->vWarm[ELEC];
|
|
temp4 = muSR * eL * temp3; /* Vdrift / Vwarm */
|
|
temp5 = temp4 / (temp4 + SG_FIT_N);
|
|
temp6 = 1.0 / (1.0 + temp5*temp4 + temp2*temp2);
|
|
temp7 = sqrt(temp6);
|
|
muHC = muSR * temp7;
|
|
temp7 *= temp6;
|
|
temp8 = (2.0 - temp5)*temp5*temp3 + 2.0*temp2*temp1;
|
|
dMuHCDEl = - 0.5*muSR*temp7*temp8 * muSR;
|
|
temp9 = temp5*temp5;
|
|
dMuHCDMuSR = (1.0 + 0.5*temp9*temp4) * temp7;
|
|
temp9 = (1.5 - temp5)*temp9*temp3 * temp7;
|
|
temp9 -= 1.5 * dMuHCDMuSR * temp6 * temp8;
|
|
d2MuHCDMuSR2 = temp9 * eL;
|
|
d2MuHCDElDMuSR = temp9 * muSR;
|
|
break;
|
|
}
|
|
|
|
/* Now compute total derivatives */
|
|
temp1 = dMuHCDMuSR * dMuSRDEn * sgnN;
|
|
temp2 = d2MuHCDMuSR2 * dMuSRDEn * dMuSRDEn + dMuHCDMuSR * d2MuSRDEn2;
|
|
temp3 = temp1 - temp2 * eD;
|
|
mun = muHC - temp1 * eD;
|
|
dMunDEn = (temp3 + temp1) * SALPHA_N;
|
|
dMunDEs = temp3 * SBETA_N - temp1 * SALPHA_N;
|
|
dMunDEl = (dMuHCDEl - d2MuHCDElDMuSR * dMuSRDEn * sgnN * eD) * sgnL;
|
|
} else {
|
|
/* Now compute total derivatives */
|
|
temp1 = dMuSRDEn * sgnN;
|
|
temp3 = temp1 - d2MuSRDEn2 * eD;
|
|
mun = muSR - temp1 * eD;
|
|
dMunDEn = (temp3 + temp1) * SALPHA_N;
|
|
dMunDEs = temp3 * SBETA_N - temp1 * SALPHA_N;
|
|
dMunDEl = 0.0;
|
|
}
|
|
} else {
|
|
if ( FieldDepMobility ) {
|
|
/* Compute various partial derivatives of muHC */
|
|
switch ( info->fieldModel ) {
|
|
case CT:
|
|
case AR:
|
|
case UF:
|
|
temp1 = muLV / info->vSat[ELEC];
|
|
temp2 = eL * temp1;
|
|
temp3 = 1.0 / ( 1.0 + temp2 * temp2 );
|
|
temp4 = sqrt( temp3 );
|
|
muHC = muLV * temp4;
|
|
dMuHCDEl = - muHC*temp2*temp3 * temp1;
|
|
break;
|
|
case SG:
|
|
default:
|
|
temp1 = 1.0 / info->vSat[ELEC];
|
|
temp2 = muLV * eL * temp1; /* Vdrift / Vsat */
|
|
temp3 = 1.0 / info->vWarm[ELEC];
|
|
temp4 = muLV * eL * temp3; /* Vdrift / Vwarm */
|
|
temp5 = temp4 / (temp4 + SG_FIT_N);
|
|
temp6 = 1.0 / (1.0 + temp5*temp4 + temp2*temp2);
|
|
temp7 = sqrt(temp6);
|
|
muHC = muLV * temp7;
|
|
temp8 = (2.0 - temp5)*temp5*temp3 + 2.0*temp2*temp1;
|
|
dMuHCDEl = - 0.5*muHC*temp6*temp8 * muLV;
|
|
break;
|
|
}
|
|
|
|
/* Now compute total derivatives */
|
|
mun = muHC;
|
|
dMunDEn = 0.0;
|
|
dMunDEs = 0.0;
|
|
dMunDEl = dMuHCDEl * sgnL;
|
|
} else {
|
|
mun = muLV;
|
|
dMunDEn = 0.0;
|
|
dMunDEs = 0.0;
|
|
dMunDEl = 0.0;
|
|
}
|
|
}
|
|
|
|
pElem->mun = mun;
|
|
pElem->dMunDEs = dMunDEs;
|
|
pElem->dMunDEx = dMunDEn * dEnDEx + dMunDEl * dElDEx;
|
|
pElem->dMunDEy = dMunDEn * dEnDEy + dMunDEl * dElDEy;
|
|
pElem->dMunDWx = dMunDEn * dEnDWx + dMunDEl * dElDWx;
|
|
pElem->dMunDWy = dMunDEn * dEnDWy + dMunDEl * dElDWy;
|
|
|
|
if ( pElem->surface ) { /* replace one field component with surface field */
|
|
if ( pElem->direction == 0 ) {
|
|
pElem->dMunDEs += pElem->dMunDEy;
|
|
pElem->dMunDEy = 0.0;
|
|
} else {
|
|
pElem->dMunDEs += pElem->dMunDEx;
|
|
pElem->dMunDEx = 0.0;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
MOBsurfHole(TWOmaterial *info, TWOelem *pElem, double ex, double ey,
|
|
double es, double wx, double wy, double totalConc)
|
|
{
|
|
double thetaA = info->thetaA[HOLE];
|
|
double thetaB = info->thetaB[HOLE];
|
|
double eL, eN, eD, mup;
|
|
double temp1, temp2, temp3, temp4, temp5;
|
|
double temp6, temp7, temp8, temp9;
|
|
double sgnN, sgnL;
|
|
double dMupDEs; /* Surface Field Derivative */
|
|
double dMupDEn; /* (Local) Normal Field Derivative */
|
|
double dMupDEl; /* Tangent Field Derivative */
|
|
double muHC, muSR, muLV;
|
|
double dMuSRDEn;
|
|
double d2MuSRDEn2;
|
|
double dMuHCDEl;
|
|
double dMuHCDMuSR;
|
|
double d2MuHCDMuSR2;
|
|
double d2MuHCDElDMuSR;
|
|
double dEnDEx; /* Normal Derivative x Component */
|
|
double dEnDEy; /* Normal Derivative y Component */
|
|
double dEnDWx; /* Normal Derivative x Component */
|
|
double dEnDWy; /* Normal Derivative y Component */
|
|
double dElDEx; /* Lateral Derivative x Component */
|
|
double dElDEy; /* Lateral Derivative y Component */
|
|
double dElDWx; /* Lateral Derivative x Component */
|
|
double dElDWy; /* Lateral Derivative y Component */
|
|
|
|
NG_IGNORE(wx);
|
|
NG_IGNORE(wy);
|
|
NG_IGNORE(totalConc);
|
|
|
|
if ( pElem->surface ) { /* replace one field component with surface field */
|
|
if ( pElem->direction == 0 ) {
|
|
ey = es;
|
|
} else {
|
|
ex = es;
|
|
}
|
|
}
|
|
|
|
if ( pElem->direction == 0 ) {
|
|
eN = ABS( SALPHA_P*ey + SBETA_P*es );
|
|
sgnN = SGN( SALPHA_P*ey + SBETA_P*es );
|
|
eD = SALPHA_P*( es - ey );
|
|
dEnDEx = 0.0;
|
|
dEnDEy = 1.0;
|
|
dEnDWx = 0.0;
|
|
dEnDWy = 0.0;
|
|
eL = ABS( ex );
|
|
sgnL = SGN( ex );
|
|
dElDEx = 1.0;
|
|
dElDEy = 0.0;
|
|
dElDWx = 0.0;
|
|
dElDWy = 0.0;
|
|
} else { /* pElem->direction == Y */
|
|
eN = ABS( SALPHA_P*ex + SBETA_P*es );
|
|
sgnN = SGN( SALPHA_P*ex + SBETA_P*es );
|
|
eD = SALPHA_P*( es - ex );
|
|
dEnDEx = 1.0;
|
|
dEnDEy = 0.0;
|
|
dEnDWx = 0.0;
|
|
dEnDWy = 0.0;
|
|
eL = ABS( ey );
|
|
sgnL = SGN( ey );
|
|
dElDEx = 0.0;
|
|
dElDEy = 1.0;
|
|
dElDWx = 0.0;
|
|
dElDWy = 0.0;
|
|
}
|
|
|
|
muLV = pElem->mup0;
|
|
if ( TransDepMobility ) {
|
|
/* Compute various partial derivatives of muSR */
|
|
temp1 = 1.0 / ( 1.0 + thetaA*eN + thetaB*eN*eN );
|
|
temp2 = thetaA + 2.0*thetaB*eN;
|
|
muSR = muLV * temp1;
|
|
dMuSRDEn = - muSR * temp1 * temp2;
|
|
d2MuSRDEn2 = - 2.0 * (dMuSRDEn * temp1 * temp2 + muSR * temp1 * thetaB);
|
|
if ( FieldDepMobility ) {
|
|
/* Compute various partial derivatives of muHC */
|
|
switch ( info->fieldModel ) {
|
|
case CT:
|
|
case AR:
|
|
case UF:
|
|
temp1 = 1.0 / info->vSat[HOLE];
|
|
temp2 = muSR * temp1;
|
|
temp3 = eL * temp1;
|
|
temp4 = eL * temp2;
|
|
temp5 = 1.0 / ( 1.0 + temp4 );
|
|
muHC = muSR * temp5;
|
|
dMuHCDMuSR = temp5 * temp5;
|
|
dMuHCDEl = - muSR * dMuHCDMuSR * temp2;
|
|
temp6 = - 2.0 * dMuHCDMuSR * temp5;
|
|
d2MuHCDMuSR2 = temp6 * temp3;
|
|
d2MuHCDElDMuSR = temp6 * temp2;
|
|
break;
|
|
case SG:
|
|
default:
|
|
temp1 = 1.0 / info->vSat[HOLE];
|
|
temp2 = muSR * eL * temp1; /* Vdrift / Vsat */
|
|
temp3 = 1.0 / info->vWarm[HOLE];
|
|
temp4 = muSR * eL * temp3; /* Vdrift / Vwarm */
|
|
temp5 = temp4 / (temp4 + SG_FIT_P);
|
|
temp6 = 1.0 / (1.0 + temp5*temp4 + temp2*temp2);
|
|
temp7 = sqrt(temp6);
|
|
muHC = muSR * temp7;
|
|
temp7 *= temp6;
|
|
temp8 = (2.0 - temp5)*temp5*temp3 + 2.0*temp2*temp1;
|
|
dMuHCDEl = - 0.5*muSR*temp7*temp8 * muSR;
|
|
temp9 = temp5*temp5;
|
|
dMuHCDMuSR = (1.0 + 0.5*temp9*temp4) * temp7;
|
|
temp9 = (1.5 - temp5)*temp9*temp3 * temp7;
|
|
temp9 -= 1.5 * dMuHCDMuSR * temp6 * temp8;
|
|
d2MuHCDMuSR2 = temp9 * eL;
|
|
d2MuHCDElDMuSR = temp9 * muSR;
|
|
break;
|
|
}
|
|
|
|
/* Now compute total derivatives */
|
|
temp1 = dMuHCDMuSR * dMuSRDEn * sgnN;
|
|
temp2 = d2MuHCDMuSR2 * dMuSRDEn * dMuSRDEn + dMuHCDMuSR * d2MuSRDEn2;
|
|
temp3 = temp1 - temp2 * eD;
|
|
mup = muHC - temp1 * eD;
|
|
dMupDEn = (temp3 + temp1) * SALPHA_P;
|
|
dMupDEs = temp3 * SBETA_P - temp1 * SALPHA_P;
|
|
dMupDEl = (dMuHCDEl - d2MuHCDElDMuSR * dMuSRDEn * sgnN * eD ) * sgnL;
|
|
} else {
|
|
/* Now compute total derivatives */
|
|
temp1 = dMuSRDEn * sgnN;
|
|
temp3 = temp1 - d2MuSRDEn2 * eD;
|
|
mup = muSR - temp1 * eD;
|
|
dMupDEn = (temp3 + temp1) * SALPHA_P;
|
|
dMupDEs = temp3 * SBETA_P - temp1 * SALPHA_P;
|
|
dMupDEl = 0.0;
|
|
}
|
|
} else {
|
|
if ( FieldDepMobility ) {
|
|
/* Compute various partial derivatives of muHC */
|
|
switch ( info->fieldModel ) {
|
|
case CT:
|
|
case AR:
|
|
case UF:
|
|
temp1 = muLV / info->vSat[HOLE];
|
|
temp2 = eL * temp1;
|
|
temp3 = 1.0 / ( 1.0 + temp2 );
|
|
muHC = muLV * temp3;
|
|
dMuHCDEl = - muHC * temp3 * temp1;
|
|
break;
|
|
case SG:
|
|
default:
|
|
temp1 = 1.0 / info->vSat[HOLE];
|
|
temp2 = muLV * eL * temp1; /* Vdrift / Vsat */
|
|
temp3 = 1.0 / info->vWarm[HOLE];
|
|
temp4 = muLV * eL * temp3; /* Vdrift / Vwarm */
|
|
temp5 = temp4 / (temp4 + SG_FIT_P);
|
|
temp6 = 1.0 / (1.0 + temp5*temp4 + temp2*temp2);
|
|
temp7 = sqrt(temp6);
|
|
muHC = muLV * temp7;
|
|
temp8 = (2.0 - temp5)*temp5*temp3 + 2.0*temp2*temp1;
|
|
dMuHCDEl = - 0.5*muHC*temp6*temp8 * muLV;
|
|
break;
|
|
}
|
|
|
|
/* Now compute total derivatives */
|
|
mup = muHC;
|
|
dMupDEn = 0.0;
|
|
dMupDEs = 0.0;
|
|
dMupDEl = dMuHCDEl * sgnL;
|
|
} else {
|
|
mup = muLV;
|
|
dMupDEn = 0.0;
|
|
dMupDEs = 0.0;
|
|
dMupDEl = 0.0;
|
|
}
|
|
}
|
|
|
|
pElem->mup = mup;
|
|
pElem->dMupDEs = dMupDEs;
|
|
pElem->dMupDEx = dMupDEn * dEnDEx + dMupDEl * dElDEx;
|
|
pElem->dMupDEy = dMupDEn * dEnDEy + dMupDEl * dElDEy;
|
|
pElem->dMupDWx = dMupDEn * dEnDWx + dMupDEl * dElDWx;
|
|
pElem->dMupDWy = dMupDEn * dEnDWy + dMupDEl * dElDWy;
|
|
|
|
if ( pElem->surface ) { /* replace one field component with surface field */
|
|
if ( pElem->direction == 0 ) {
|
|
pElem->dMupDEs += pElem->dMupDEy;
|
|
pElem->dMupDEy = 0.0;
|
|
} else {
|
|
pElem->dMupDEs += pElem->dMupDEx;
|
|
pElem->dMupDEx = 0.0;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|