📄 oneadmit.c
字号:
/**********Copyright 1992 Regents of the University of California. All rights reserved.Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group**********//* Functions to compute small-signal parameters of 1D devices */#include <math.h>#include "numglobs.h"#include "numenum.h"#include "nummacs.h"#include "numconst.h"#include "onedev.h"#include "onemesh.h"#include "numcmplx.h"#include "spmatrix.h"#include "ifsim.h"extern IFfrontEnd *SPfrontEnd;int ONEacDebug = FALSE;/* External Declarations */extern void ONE_jacLoad();extern BOOLEAN hasSORConverged();/* Forward Declarations */complex *computeAdmittance();BOOLEAN ONEsorSolve();intNUMDadmittance(pDevice, omega, yd) ONEdevice *pDevice; double omega; complex *yd;{ ONEnode *pNode; ONEelem *pElem; ONEedge *pEdge; int index, i; double yReal, yImag; double *solutionReal, *solutionImag; complex yAc, cOmega; complex *y; BOOLEAN SORFailed; double startTime; /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; /* * Change context names of solution vectors for ac analysis. * dcDeltaSolution stores the real part and copiedSolution stores the * imaginary part of the ac solution vector. */ solutionReal = pDevice->dcDeltaSolution; solutionImag = pDevice->copiedSolution; pDevice->solverType = SLV_SMSIG; /* use a normalized radian frequency */ omega *= TNorm; CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega); yReal = 0.0; yImag = 0.0; if (AcAnalysisMethod IS SOR OR AcAnalysisMethod IS SOR_ONLY) { /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* zero the rhs before loading in the new rhs */ for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhs[index] = 0.0; pDevice->rhsImag[index] = 0.0; } /* store the new rhs vector */ pElem = pDevice->elemArray[pDevice->numNodes - 1]; pNode = pElem->pLeftNode; pDevice->rhs[pNode->psiEqn] = pElem->epsRel * pElem->rDx; if (pElem->elemType IS SEMICON) { pEdge = pElem->pEdge; pDevice->rhs[pNode->nEqn] -= pEdge->dJnDpsiP1; pDevice->rhs[pNode->pEqn] -= pEdge->dJpDpsiP1; } pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); SORFailed = ONEsorSolve(pDevice, solutionReal, solutionImag, omega); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; if (SORFailed AND AcAnalysisMethod IS SOR) { AcAnalysisMethod = DIRECT; printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n", omega / (TWO_PI * TNorm) ); } else if (SORFailed) { /* Told to only do SOR, so give up. */ printf("SOR failed at %g Hz, returning null admittance.\n", omega / (TWO_PI * TNorm) ); CMPLX_ASSIGN_VALUE(*yd, 0.0, 0.0); return (AcAnalysisMethod); } } if (AcAnalysisMethod IS DIRECT) { /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* solve the system of equations directly */ for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhs[index] = 0.0; pDevice->rhsImag[index] = 0.0; } pElem = pDevice->elemArray[pDevice->numNodes - 1]; pNode = pElem->pLeftNode; pDevice->rhs[pNode->psiEqn] = pElem->epsRel * pElem->rDx; if (pElem->elemType IS SEMICON) { pEdge = pElem->pEdge; pDevice->rhs[pNode->nEqn] -= pEdge->dJnDpsiP1; pDevice->rhs[pNode->pEqn] -= pEdge->dJpDpsiP1; } ONE_jacLoad(pDevice); spSetComplex(pDevice->matrix); for (index = 1; index < pDevice->numNodes; index++) { pElem = pDevice->elemArray[index]; if (pElem->elemType IS SEMICON) { for (i = 0; i <= 1; i++) { pNode = pElem->pNodes[i]; if (pNode->nodeType ISNOT CONTACT) { spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -0.5 * pElem->dx * omega); spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, 0.5 * pElem->dx * omega); } } } } pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* FACTOR */ startTime = SPfrontEnd->IFseconds(); spFactor(pDevice->matrix); pDevice->pStats->factorTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); spSolve(pDevice->matrix, pDevice->rhs, solutionReal, pDevice->rhsImag, solutionImag); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; } /* MISC */ startTime = SPfrontEnd->IFseconds(); pNode = pDevice->elemArray[1]->pLeftNode; y = computeAdmittance(pNode, FALSE, solutionReal, solutionImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc, -y->real, -y->imag); CMPLX_ASSIGN(*yd, yAc); CMPLX_MULT_SELF_SCALAR(*yd, GNorm * pDevice->area); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; return (AcAnalysisMethod);}intNBJTadmittance(pDevice, omega, yIeVce, yIcVce, yIeVbe, yIcVbe) ONEdevice *pDevice; double omega; complex *yIeVce, *yIcVce, *yIeVbe, *yIcVbe;{ ONEelem *pCollElem = pDevice->elemArray[pDevice->numNodes - 1]; ONEelem *pBaseElem = pDevice->elemArray[pDevice->baseIndex - 1]; ONEelem *pElem; ONEedge *pEdge; ONEnode *pNode; int index, i; double area = pDevice->area; double *solutionReal, *solutionImag; BOOLEAN SORFailed; complex *y; complex cOmega, pIeVce, pIcVce, pIeVbe, pIcVbe; double startTime; /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; /* * change context names of solution vectors for ac analysis dcDeltaSolution * stores the real part and copiedSolution stores the imaginary part of the * ac solution vector */ solutionReal = pDevice->dcDeltaSolution; solutionImag = pDevice->copiedSolution; pDevice->solverType = SLV_SMSIG; /* use a normalized radian frequency */ omega *= TNorm; CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega); if (AcAnalysisMethod IS SOR OR AcAnalysisMethod IS SOR_ONLY) { /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* zero the rhs before loading in the new rhs */ for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhs[index] = 0.0; pDevice->rhsImag[index] = 0.0; } /* store the new rhs vector */ pNode = pCollElem->pLeftNode; pDevice->rhs[pNode->psiEqn] = pCollElem->epsRel * pCollElem->rDx; if (pCollElem->elemType IS SEMICON) { pEdge = pCollElem->pEdge; pDevice->rhs[pNode->nEqn] -= pEdge->dJnDpsiP1; pDevice->rhs[pNode->pEqn] -= pEdge->dJpDpsiP1; } pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); SORFailed = ONEsorSolve(pDevice, solutionReal, solutionImag, omega); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; if (SORFailed AND AcAnalysisMethod IS SOR) { AcAnalysisMethod = DIRECT; printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n", omega / (TWO_PI * TNorm) ); } else if (SORFailed) { /* Told to only do SOR, so give up. */ printf("SOR failed at %g Hz, returning null admittance.\n", omega / (TWO_PI * TNorm) ); CMPLX_ASSIGN_VALUE(*yIeVce, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIcVce, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIeVbe, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIcVbe, 0.0, 0.0); return (AcAnalysisMethod); } else { /* MISC */ startTime = SPfrontEnd->IFseconds(); pElem = pDevice->elemArray[1]; pNode = pElem->pLeftNode; y = computeAdmittance(pNode, FALSE, solutionReal, solutionImag, &cOmega); CMPLX_ASSIGN_VALUE(pIeVce, -y->real, -y->imag); pNode = pCollElem->pRightNode; y = computeAdmittance(pNode, TRUE, solutionReal, solutionImag, &cOmega); CMPLX_ASSIGN_VALUE(pIcVce, -y->real, -y->imag); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* load in the base contribution to the rhs */ for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhs[index] = 0.0; } pNode = pBaseElem->pRightNode; if (pNode->baseType IS N_TYPE) { pDevice->rhs[pNode->nEqn] = pNode->nConc * pNode->eg; } else if (pNode->baseType IS P_TYPE) { pDevice->rhs[pNode->pEqn] = pNode->pConc * pNode->eg; } else { printf("projectBJTsolution: unknown base type\n"); } pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); SORFailed = ONEsorSolve(pDevice, solutionReal, solutionImag, omega); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; if (SORFailed AND AcAnalysisMethod IS SOR) { AcAnalysisMethod = DIRECT; printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n", omega / (TWO_PI * TNorm) ); } else if (SORFailed) { /* Told to only do SOR, so give up. */ printf("SOR failed at %g Hz, returning null admittance.\n", omega / (TWO_PI * TNorm) ); CMPLX_ASSIGN_VALUE(*yIeVce, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIcVce, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIeVbe, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIcVbe, 0.0, 0.0); return (AcAnalysisMethod); } } } if (AcAnalysisMethod IS DIRECT) { /* LOAD */ startTime = SPfrontEnd->IFseconds(); for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhs[index] = 0.0; pDevice->rhsImag[index] = 0.0; } /* solve the system of equations directly */ ONE_jacLoad(pDevice); pNode = pCollElem->pLeftNode; pDevice->rhs[pNode->psiEqn] = pCollElem->epsRel * pCollElem->rDx; if (pCollElem->elemType IS SEMICON) { pEdge = pCollElem->pEdge; pDevice->rhs[pNode->nEqn] -= pEdge->dJnDpsiP1; pDevice->rhs[pNode->pEqn] -= pEdge->dJpDpsiP1; } spSetComplex(pDevice->matrix); for (index = 1; index < pDevice->numNodes; index++) { pElem = pDevice->elemArray[index]; if (pElem->elemType IS SEMICON) { for (i = 0; i <= 1; i++) { pNode = pElem->pNodes[i]; if (pNode->nodeType ISNOT CONTACT) { spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -0.5 * pElem->dx * omega); spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, 0.5 * pElem->dx * omega); } } } } pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* FACTOR */ startTime = SPfrontEnd->IFseconds(); spFactor(pDevice->matrix); pDevice->pStats->factorTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); spSolve(pDevice->matrix, pDevice->rhs, solutionReal, pDevice->rhsImag, solutionImag); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* MISC */ startTime = SPfrontEnd->IFseconds(); pElem = pDevice->elemArray[1]; pNode = pElem->pLeftNode; y = computeAdmittance(pNode, FALSE, solutionReal, solutionImag, &cOmega); CMPLX_ASSIGN_VALUE(pIeVce, -y->real, -y->imag); pNode = pCollElem->pRightNode; y = computeAdmittance(pNode, TRUE, solutionReal, solutionImag, &cOmega); CMPLX_ASSIGN_VALUE(pIcVce, -y->real, -y->imag); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* load in the base contribution in the rhs */ for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhs[index] = 0.0; } pNode = pBaseElem->pRightNode; if (pNode->baseType IS N_TYPE) { pDevice->rhs[pNode->nEqn] = pNode->nConc * pNode->eg; } else if (pNode->baseType IS P_TYPE) { pDevice->rhs[pNode->pEqn] = pNode->pConc * pNode->eg; } else { printf("\n BJTadmittance: unknown base type"); } pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* FACTOR: already done, no need to repeat. */ /* SOLVE */ startTime = SPfrontEnd->IFseconds(); spSolve(pDevice->matrix, pDevice->rhs, solutionReal, pDevice->rhsImag, solutionImag); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; } /* MISC */ startTime = SPfrontEnd->IFseconds(); pElem = pDevice->elemArray[1]; pNode = pElem->pLeftNode; y = computeAdmittance(pNode, FALSE, solutionReal, solutionImag, &cOmega); CMPLX_ASSIGN_VALUE(pIeVbe, -y->real, -y->imag); pNode = pCollElem->pRightNode; y = computeAdmittance(pNode, FALSE, solutionReal, solutionImag, &cOmega); CMPLX_ASSIGN_VALUE(pIcVbe, -y->real, -y->imag); CMPLX_ASSIGN(*yIeVce, pIeVce); CMPLX_ASSIGN(*yIcVce, pIcVce); CMPLX_ASSIGN(*yIeVbe, pIeVbe); CMPLX_ASSIGN(*yIcVbe, pIcVbe); CMPLX_MULT_SELF_SCALAR(*yIeVce, GNorm * area); CMPLX_MULT_SELF_SCALAR(*yIeVbe, GNorm * area); CMPLX_MULT_SELF_SCALAR(*yIcVce, GNorm * area); CMPLX_MULT_SELF_SCALAR(*yIcVbe, GNorm * area); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; return (AcAnalysisMethod);}BOOLEAN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -