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.
 
 
 
 
 
 

233 lines
6.3 KiB

/**********
Copyright 1991 Regents of the University of California. All rights reserved.
Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
Author: 1991 David A. Gates, U. C. Berkeley CAD Group
**********/
/**********
One-Dimensional Numerical Device Setup Routines
**********/
#include "ngspice.h"
#include "numglobs.h"
#include "numconst.h"
#include "numenum.h"
#include "onemesh.h"
#include "onedev.h"
#include "carddefs.h" /* XXX Not really modular if we need this. */
/* #include "material.h" */
#include "onedext.h"
#include "oneddefs.h"
#include "cidersupt.h"
/* compute node parameters */
void
ONEsetup(ONEdevice *pDevice)
{
double temp1, deltaEg, avgConc, totalConc, absNetConc;
double ncv0, dBand, dNie, psiBand[2];
int index, eIndex;
int numContactNodes;
ONEnode *pNode;
ONEelem *pElem;
ONEedge *pEdge;
ONEmaterial *info;
for (eIndex = 1; eIndex < pDevice->numNodes; eIndex++) {
pElem = pDevice->elemArray[eIndex];
info = pElem->matlInfo;
pElem->dx = pElem->pRightNode->x - pElem->pLeftNode->x;
pElem->epsRel = info->eps;
if (pElem->elemType == INSULATOR) {
for (index = 0; index <= 1; index++) {
if (pElem->evalNodes[index]) {
pNode = pElem->pNodes[index];
if (pNode->nodeType == CONTACT) {
pNode->eaff = PHI_METAL;
pNode->eg = 0.0;
} else {
pNode->eaff = info->affin;
pNode->eg = info->eg0;
}
}
}
} else if (pElem->elemType == SEMICON) {
ncv0 = sqrt(info->nc0) * sqrt(info->nv0);
for (index = 0; index <= 1; index++) {
if (pElem->evalNodes[index]) {
pNode = pElem->pNodes[index];
/* Fixed Interface Charge */
pNode->qf = 0.0;
/* Narrowing of Energy Band-Gap */
if (BandGapNarrowing) {
absNetConc = ABS(pNode->netConc);
if (pNode->netConc > 0.0) {
temp1 = log(absNetConc / info->nrefBGN[ELEC]);
deltaEg = -info->dEgDn[ELEC] * (temp1 + sqrt(temp1 * temp1 + 0.5));
pNode->eg = info->eg0 + deltaEg;
} else if (pNode->netConc < 0.0) {
temp1 = log(absNetConc / info->nrefBGN[HOLE]);
deltaEg = -info->dEgDn[HOLE] * (temp1 + sqrt(temp1 * temp1 + 0.5));
pNode->eg = info->eg0 + deltaEg;
} else {
pNode->eg = info->eg0;
}
} else {
pNode->eg = info->eg0;
}
pNode->nie = ncv0 * exp(-0.5 * pNode->eg / Vt);
pNode->eaff = info->affin;
/* Save band structure parameter. */
psiBand[index] = -info->refPsi;
/* Ionized-Impurity-Scattering Reduction of Carrier Lifetime */
if (ConcDepLifetime) {
totalConc = pNode->totalConc;
temp1 = 1.0 / (1.0 + totalConc / info->nrefSRH[ELEC]);
pNode->tn = info->tau0[ELEC] * temp1;
temp1 = 1.0 / (1.0 + totalConc / info->nrefSRH[HOLE]);
pNode->tp = info->tau0[HOLE] * temp1;
} else {
pNode->tn = info->tau0[ELEC];
pNode->tp = info->tau0[HOLE];
}
}
}
pEdge = pElem->pEdge;
/* Variable Band Built-In Potential */
dBand = psiBand[1] - psiBand[0];
dNie = log(pElem->pNodes[1]->nie / pElem->pNodes[0]->nie);
pEdge->dCBand = dBand + dNie;
pEdge->dVBand = -dBand + dNie;
/* Evaluate conc.-dep. mobility. */
avgConc = 0.5 * (pElem->pRightNode->totalConc + pElem->pLeftNode->totalConc);
MOBconcDep(info, avgConc, &pEdge->mun, &pEdge->mup);
}
}
}
/* Transfer BC info from bdry to nodes and edges. */
static void
ONEcopyBCinfo(ONEdevice *pDevice, ONEelem *pElem, BDRYcard *bdry, int index)
{
ONEnode *pNode;
ONEelem *pNElem;
int eIndex, nIndex;
double length;
/* First add fixed charge. */
pNode = pElem->pNodes[index];
pNode->qf += bdry->BDRYqf;
/* Now add surface recombination. */
/* Compute semiconductor length around this node. */
length = 0.0;
for (eIndex = 0; eIndex <= 3; eIndex++) {
pNElem = pNode->pElems[eIndex];
if ((pNElem != NIL(ONEelem)) && (pElem->elemType == SEMICON)) {
length += 0.5 * pElem->dx;
}
}
if (bdry->BDRYsnGiven) {
pNode->tn = pNode->tn /
(1.0 + ((bdry->BDRYsn * TNorm) * pNode->tn) / length);
}
if (bdry->BDRYspGiven) {
pNode->tp = pNode->tp /
(1.0 + ((bdry->BDRYsp * TNorm) * pNode->tp) / length);
}
/* Finally, surface layer is irrelevant for 1d devices. */
}
/* Compute boundary condition parameters. */
void
ONEsetBCparams(ONEdevice *pDevice, BDRYcard *bdryList, CONTcard *contList)
{
int index, xIndex;
ONEnode *pNode;
ONEelem *pElem, *pNElem;
BDRYcard *bdry;
CONTcard *cont;
for (bdry = bdryList; bdry != NIL(BDRYcard); bdry = bdry->BDRYnextCard) {
for (xIndex = bdry->BDRYixLow; xIndex < bdry->BDRYixHigh; xIndex++) {
pElem = pDevice->elemArray[xIndex];
if (pElem != NIL(ONEelem)) {
if (pElem->domain == bdry->BDRYdomain) {
for (index = 0; index <= 1; index++) {
if (pElem->evalNodes[index]) {
pNElem = pElem->pElems[index];
if (bdry->BDRYneighborGiven) {
if (pNElem && (pNElem->domain == bdry->BDRYneighbor)) {
/* Found an interface node. */
ONEcopyBCinfo(pDevice, pElem, bdry, index);
}
} else {
if ((!pNElem) || (pNElem->domain != pElem->domain)) {
/* Found a boundary node. */
ONEcopyBCinfo(pDevice, pElem, bdry, index);
}
}
}
}
}
}
}
}
for (cont = contList; cont != NIL(CONTcard); cont = cont->CONTnextCard) {
if (!cont->CONTworkfunGiven) {
cont->CONTworkfun = PHI_METAL;
}
/*
* XXX This won't work right if someone tries to change the 1d BJT base
* contact workfunction and doesn't want to change the emitter. But no
* one will probably try to do that.
*/
if (cont->CONTnumber == 1) {
pDevice->elemArray[1]->pNodes[0]->eaff = cont->CONTworkfun;
} else if ((cont->CONTnumber == 2) || (cont->CONTnumber == 3)) {
pDevice->elemArray[pDevice->numNodes - 1]->pNodes[1]->eaff =
cont->CONTworkfun;
}
}
}
void
ONEnormalize(ONEdevice *pDevice)
{
int index, eIndex;
ONEelem *pElem;
ONEnode *pNode;
for (eIndex = 1; eIndex < pDevice->numNodes; eIndex++) {
pElem = pDevice->elemArray[eIndex];
pElem->dx /= LNorm;
pElem->rDx = 1.0 / pElem->dx;
pElem->epsRel /= EpsNorm;
for (index = 0; index <= 1; index++) {
if (pElem->evalNodes[index]) {
pNode = pElem->pNodes[index];
pNode->netConc /= NNorm;
pNode->nd /= NNorm;
pNode->na /= NNorm;
pNode->qf /= (NNorm * LNorm);
pNode->nie /= NNorm;
pNode->eg /= VNorm;
pNode->eaff /= VNorm;
}
}
}
}