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.
550 lines
22 KiB
550 lines
22 KiB
/**** BSIM4.6.2 Released by Wenwei Yang 07/31/2008 ****/
|
|
/**** BSIM4.6.4 Update ngspice 08/22/2009 ****/
|
|
/**********
|
|
* Copyright 2006 Regents of the University of California. All rights reserved.
|
|
* File: b4noi.c of BSIM4.6.2.
|
|
* Author: 2000 Weidong Liu
|
|
* Authors: 2001- Xuemei Xi, Mohan Dunga, Ali Niknejad, Chenming Hu.
|
|
* Authors: 2006- Mohan Dunga, Ali Niknejad, Chenming Hu
|
|
* Authors: 2007- Mohan Dunga, Wenwei Yang, Ali Niknejad, Chenming Hu
|
|
* Authors: 2008- Wenwei Yang, Ali Niknejad, Chenming Hu
|
|
* Project Director: Prof. Chenming Hu.
|
|
* Modified by Xuemei Xi, 04/06/2001.
|
|
* Modified by Xuemei Xi, 10/05/2001.
|
|
* Modified by Xuemei Xi, 05/09/2003.
|
|
* Modified by Xuemei Xi, 03/04/2004.
|
|
* Modified by Xuemei Xi, 07/29/2005.
|
|
* Modified by Mohan Dunga, 12/13/2006
|
|
* Modified by Wenwei Yang, 07/31/2008.
|
|
**********/
|
|
|
|
#include "ngspice.h"
|
|
#include "bsim4def.h"
|
|
#include "cktdefs.h"
|
|
#include "iferrmsg.h"
|
|
#include "noisedef.h"
|
|
#include "suffix.h"
|
|
#include "const.h"
|
|
|
|
|
|
extern void NevalSrc();
|
|
extern double Nintegrate();
|
|
|
|
/*
|
|
* WDL: 1/f noise model has been smoothed out and enhanced with
|
|
* bulk charge effect as well as physical N* equ. and necessary
|
|
* conversion into the SI unit system.
|
|
*/
|
|
|
|
double
|
|
Eval1ovFNoise(double Vds, BSIM4model *model, BSIM4instance *here, double freq, double temp)
|
|
{
|
|
struct bsim4SizeDependParam *pParam;
|
|
double cd, esat, DelClm, EffFreq, N0, Nl, Leff, Leffsq;
|
|
double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Ssi;
|
|
|
|
pParam = here->pParam;
|
|
cd = fabs(here->BSIM4cd);
|
|
Leff = pParam->BSIM4leff - 2.0 * model->BSIM4lintnoi;
|
|
Leffsq = Leff * Leff;
|
|
esat = 2.0 * here->BSIM4vsattemp / here->BSIM4ueff;
|
|
if(model->BSIM4em<=0.0) DelClm = 0.0; /* flicker noise modified -JX */
|
|
else {
|
|
T0 = ((((Vds - here->BSIM4Vdseff) / pParam->BSIM4litl)
|
|
+ model->BSIM4em) / esat);
|
|
DelClm = pParam->BSIM4litl * log (MAX(T0, N_MINLOG));
|
|
if (DelClm < 0.0) DelClm = 0.0; /* bugfix */
|
|
}
|
|
EffFreq = pow(freq, model->BSIM4ef);
|
|
T1 = CHARGE * CHARGE * CONSTboltz * cd * temp * here->BSIM4ueff;
|
|
T2 = 1.0e10 * EffFreq * here->BSIM4Abulk * model->BSIM4coxe * Leffsq;
|
|
N0 = model->BSIM4coxe * here->BSIM4Vgsteff / CHARGE;
|
|
Nl = model->BSIM4coxe * here->BSIM4Vgsteff
|
|
* (1.0 - here->BSIM4AbovVgst2Vtm * here->BSIM4Vdseff) / CHARGE;
|
|
|
|
T3 = model->BSIM4oxideTrapDensityA
|
|
* log(MAX(((N0 + here->BSIM4nstar) / (Nl + here->BSIM4nstar)), N_MINLOG));
|
|
T4 = model->BSIM4oxideTrapDensityB * (N0 - Nl);
|
|
T5 = model->BSIM4oxideTrapDensityC * 0.5 * (N0 * N0 - Nl * Nl);
|
|
|
|
T6 = CONSTboltz * temp * cd * cd;
|
|
T7 = 1.0e10 * EffFreq * Leffsq * pParam->BSIM4weff * here->BSIM4nf;
|
|
T8 = model->BSIM4oxideTrapDensityA + model->BSIM4oxideTrapDensityB * Nl
|
|
+ model->BSIM4oxideTrapDensityC * Nl * Nl;
|
|
T9 = (Nl + here->BSIM4nstar) * (Nl + here->BSIM4nstar);
|
|
Ssi = T1 / T2 * (T3 + T4 + T5) + T6 / T7 * DelClm * T8 / T9;
|
|
return Ssi;
|
|
}
|
|
|
|
|
|
int
|
|
BSIM4noise(int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, Ndata *data, double *OnDens)
|
|
{
|
|
BSIM4model *model = (BSIM4model *)inModel;
|
|
BSIM4instance *here;
|
|
struct bsim4SizeDependParam *pParam;
|
|
char name[N_MXVLNTH];
|
|
double tempOnoise;
|
|
double tempInoise;
|
|
double noizDens[BSIM4NSRCS];
|
|
double lnNdens[BSIM4NSRCS];
|
|
|
|
double T0, T1, T2, T5, T10, T11;
|
|
double Vds, Ssi, Swi;
|
|
double tmp=0.0, gdpr, gspr, npart_theta=0.0, npart_beta=0.0, igsquare, bodymode;
|
|
|
|
double m;
|
|
|
|
int i;
|
|
|
|
/* define the names of the noise sources */
|
|
static char *BSIM4nNames[BSIM4NSRCS] =
|
|
{ /* Note that we have to keep the order */
|
|
".rd", /* noise due to rd */
|
|
".rs", /* noise due to rs */
|
|
".rg", /* noise due to rgeltd */
|
|
".rbps", /* noise due to rbps */
|
|
".rbpd", /* noise due to rbpd */
|
|
".rbpb", /* noise due to rbpb */
|
|
".rbsb", /* noise due to rbsb */
|
|
".rbdb", /* noise due to rbdb */
|
|
".id", /* noise due to id */
|
|
".1overf", /* flicker (1/f) noise */
|
|
".igs", /* shot noise due to IGS */
|
|
".igd", /* shot noise due to IGD */
|
|
".igb", /* shot noise due to IGB */
|
|
"" /* total transistor noise */
|
|
};
|
|
|
|
for (; model != NULL; model = model->BSIM4nextModel)
|
|
{ for (here = model->BSIM4instances; here != NULL;
|
|
here = here->BSIM4nextInstance)
|
|
{ pParam = here->pParam;
|
|
switch (operation)
|
|
{ case N_OPEN:
|
|
/* see if we have to to produce a summary report */
|
|
/* if so, name all the noise generators */
|
|
|
|
if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0)
|
|
{ switch (mode)
|
|
{ case N_DENS:
|
|
for (i = 0; i < BSIM4NSRCS; i++)
|
|
{ (void) sprintf(name, "onoise.%s%s",
|
|
here->BSIM4name,
|
|
BSIM4nNames[i]);
|
|
data->namelist = (IFuid *) trealloc(
|
|
(char *) data->namelist,
|
|
(data->numPlots + 1)
|
|
* sizeof(IFuid));
|
|
if (!data->namelist)
|
|
return(E_NOMEM);
|
|
(*(SPfrontEnd->IFnewUid)) (ckt,
|
|
&(data->namelist[data->numPlots++]),
|
|
(IFuid) NULL, name, UID_OTHER,
|
|
(void **) NULL);
|
|
/* we've added one more plot */
|
|
}
|
|
break;
|
|
case INT_NOIZ:
|
|
for (i = 0; i < BSIM4NSRCS; i++)
|
|
{ (void) sprintf(name, "onoise_total.%s%s",
|
|
here->BSIM4name,
|
|
BSIM4nNames[i]);
|
|
data->namelist = (IFuid *) trealloc(
|
|
(char *) data->namelist,
|
|
(data->numPlots + 1)
|
|
* sizeof(IFuid));
|
|
if (!data->namelist)
|
|
return(E_NOMEM);
|
|
(*(SPfrontEnd->IFnewUid)) (ckt,
|
|
&(data->namelist[data->numPlots++]),
|
|
(IFuid) NULL, name, UID_OTHER,
|
|
(void **) NULL);
|
|
/* we've added one more plot */
|
|
|
|
(void) sprintf(name, "inoise_total.%s%s",
|
|
here->BSIM4name,
|
|
BSIM4nNames[i]);
|
|
data->namelist = (IFuid *) trealloc(
|
|
(char *) data->namelist,
|
|
(data->numPlots + 1)
|
|
* sizeof(IFuid));
|
|
if (!data->namelist)
|
|
return(E_NOMEM);
|
|
(*(SPfrontEnd->IFnewUid)) (ckt,
|
|
&(data->namelist[data->numPlots++]),
|
|
(IFuid) NULL, name, UID_OTHER,
|
|
(void **)NULL);
|
|
/* we've added one more plot */
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case N_CALC:
|
|
m = here->BSIM4m;
|
|
switch (mode)
|
|
{ case N_DENS:
|
|
if (model->BSIM4tnoiMod == 0)
|
|
{ if (model->BSIM4rdsMod == 0)
|
|
{ gspr = here->BSIM4sourceConductance;
|
|
gdpr = here->BSIM4drainConductance;
|
|
if (here->BSIM4grdsw > 0.0)
|
|
tmp = 1.0 / here->BSIM4grdsw; /* tmp used below */
|
|
else
|
|
tmp = 0.0;
|
|
}
|
|
else
|
|
{ gspr = here->BSIM4gstot;
|
|
gdpr = here->BSIM4gdtot;
|
|
tmp = 0.0;
|
|
}
|
|
}
|
|
else
|
|
{ T5 = here->BSIM4Vgsteff / here->BSIM4EsatL;
|
|
T5 *= T5;
|
|
npart_beta = model->BSIM4rnoia * (1.0 + T5
|
|
* model->BSIM4tnoia * pParam->BSIM4leff);
|
|
npart_theta = model->BSIM4rnoib * (1.0 + T5
|
|
* model->BSIM4tnoib * pParam->BSIM4leff);
|
|
if(npart_theta > 0.9)
|
|
npart_theta = 0.9;
|
|
if(npart_theta > 0.9 * npart_beta)
|
|
npart_theta = 0.9 * npart_beta; //4.6.2
|
|
|
|
if (model->BSIM4rdsMod == 0)
|
|
{ gspr = here->BSIM4sourceConductance;
|
|
gdpr = here->BSIM4drainConductance;
|
|
}
|
|
else
|
|
{ gspr = here->BSIM4gstot;
|
|
gdpr = here->BSIM4gdtot;
|
|
}
|
|
|
|
if ((*(ckt->CKTstates[0] + here->BSIM4vds)) >= 0.0)
|
|
gspr = gspr * (1.0 + npart_theta * npart_theta * gspr
|
|
/ here->BSIM4IdovVds); /* bugfix */
|
|
else
|
|
gdpr = gdpr * (1.0 + npart_theta * npart_theta * gdpr
|
|
/ here->BSIM4IdovVds);
|
|
}
|
|
|
|
NevalSrc(&noizDens[BSIM4RDNOIZ],
|
|
&lnNdens[BSIM4RDNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4dNodePrime, here->BSIM4dNode,
|
|
gdpr * m);
|
|
|
|
NevalSrc(&noizDens[BSIM4RSNOIZ],
|
|
&lnNdens[BSIM4RSNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4sNodePrime, here->BSIM4sNode,
|
|
gspr * m);
|
|
|
|
|
|
if (here->BSIM4rgateMod == 1)
|
|
{ NevalSrc(&noizDens[BSIM4RGNOIZ],
|
|
&lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4gNodePrime, here->BSIM4gNodeExt,
|
|
here->BSIM4grgeltd * m);
|
|
}
|
|
else if (here->BSIM4rgateMod == 2)
|
|
{
|
|
T0 = 1.0 + here->BSIM4grgeltd/here->BSIM4gcrg;
|
|
T1 = T0 * T0;
|
|
NevalSrc(&noizDens[BSIM4RGNOIZ],
|
|
&lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4gNodePrime, here->BSIM4gNodeExt,
|
|
here->BSIM4grgeltd * m / T1);
|
|
}
|
|
else if (here->BSIM4rgateMod == 3)
|
|
{ NevalSrc(&noizDens[BSIM4RGNOIZ],
|
|
&lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4gNodeMid, here->BSIM4gNodeExt,
|
|
here->BSIM4grgeltd * m);
|
|
}
|
|
else
|
|
{ noizDens[BSIM4RGNOIZ] = 0.0;
|
|
lnNdens[BSIM4RGNOIZ] =
|
|
log(MAX(noizDens[BSIM4RGNOIZ], N_MINLOG));
|
|
}
|
|
|
|
bodymode = 5;
|
|
if (here->BSIM4rbodyMod == 2)
|
|
{ if( ( !model->BSIM4rbps0Given) ||
|
|
( !model->BSIM4rbpd0Given) )
|
|
bodymode = 1;
|
|
else
|
|
if( (!model->BSIM4rbsbx0Given && !model->BSIM4rbsby0Given) ||
|
|
(!model->BSIM4rbdbx0Given && !model->BSIM4rbdby0Given) )
|
|
bodymode = 3;
|
|
}
|
|
|
|
if (here->BSIM4rbodyMod)
|
|
{
|
|
if(bodymode == 5)
|
|
{
|
|
NevalSrc(&noizDens[BSIM4RBPSNOIZ],
|
|
&lnNdens[BSIM4RBPSNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4bNodePrime, here->BSIM4sbNode,
|
|
here->BSIM4grbps * m);
|
|
NevalSrc(&noizDens[BSIM4RBPDNOIZ],
|
|
&lnNdens[BSIM4RBPDNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4bNodePrime, here->BSIM4dbNode,
|
|
here->BSIM4grbpd * m);
|
|
NevalSrc(&noizDens[BSIM4RBPBNOIZ],
|
|
&lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4bNodePrime, here->BSIM4bNode,
|
|
here->BSIM4grbpb * m);
|
|
NevalSrc(&noizDens[BSIM4RBSBNOIZ],
|
|
&lnNdens[BSIM4RBSBNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4bNode, here->BSIM4sbNode,
|
|
here->BSIM4grbsb * m);
|
|
NevalSrc(&noizDens[BSIM4RBDBNOIZ],
|
|
&lnNdens[BSIM4RBDBNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4bNode, here->BSIM4dbNode,
|
|
here->BSIM4grbdb * m);
|
|
}
|
|
if(bodymode == 3)
|
|
{
|
|
NevalSrc(&noizDens[BSIM4RBPSNOIZ],
|
|
&lnNdens[BSIM4RBPSNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4bNodePrime, here->BSIM4sbNode,
|
|
here->BSIM4grbps * m);
|
|
NevalSrc(&noizDens[BSIM4RBPDNOIZ],
|
|
&lnNdens[BSIM4RBPDNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4bNodePrime, here->BSIM4dbNode,
|
|
here->BSIM4grbpd * m);
|
|
NevalSrc(&noizDens[BSIM4RBPBNOIZ],
|
|
&lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4bNodePrime, here->BSIM4bNode,
|
|
here->BSIM4grbpb * m);
|
|
noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0;
|
|
lnNdens[BSIM4RBSBNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBSBNOIZ], N_MINLOG));
|
|
lnNdens[BSIM4RBDBNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBDBNOIZ], N_MINLOG));
|
|
}
|
|
if(bodymode == 1)
|
|
{
|
|
NevalSrc(&noizDens[BSIM4RBPBNOIZ],
|
|
&lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE,
|
|
here->BSIM4bNodePrime, here->BSIM4bNode,
|
|
here->BSIM4grbpb * m);
|
|
noizDens[BSIM4RBPSNOIZ] = noizDens[BSIM4RBPDNOIZ] = 0.0;
|
|
noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0;
|
|
lnNdens[BSIM4RBPSNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBPSNOIZ], N_MINLOG));
|
|
lnNdens[BSIM4RBPDNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBPDNOIZ], N_MINLOG));
|
|
lnNdens[BSIM4RBSBNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBSBNOIZ], N_MINLOG));
|
|
lnNdens[BSIM4RBDBNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBDBNOIZ], N_MINLOG));
|
|
}
|
|
}
|
|
else
|
|
{ noizDens[BSIM4RBPSNOIZ] = noizDens[BSIM4RBPDNOIZ] = 0.0;
|
|
noizDens[BSIM4RBPBNOIZ] = 0.0;
|
|
noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0;
|
|
lnNdens[BSIM4RBPSNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBPSNOIZ], N_MINLOG));
|
|
lnNdens[BSIM4RBPDNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBPDNOIZ], N_MINLOG));
|
|
lnNdens[BSIM4RBPBNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBPBNOIZ], N_MINLOG));
|
|
lnNdens[BSIM4RBSBNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBSBNOIZ], N_MINLOG));
|
|
lnNdens[BSIM4RBDBNOIZ] =
|
|
log(MAX(noizDens[BSIM4RBDBNOIZ], N_MINLOG));
|
|
}
|
|
|
|
|
|
switch(model->BSIM4tnoiMod)
|
|
{ case 0:
|
|
T0 = m * here->BSIM4ueff * fabs(here->BSIM4qinv);
|
|
T1 = T0 * tmp + pParam->BSIM4leff
|
|
* pParam->BSIM4leff;
|
|
NevalSrc(&noizDens[BSIM4IDNOIZ],
|
|
&lnNdens[BSIM4IDNOIZ], ckt,
|
|
THERMNOISE, here->BSIM4dNodePrime,
|
|
here->BSIM4sNodePrime,
|
|
(T0 / T1) * model->BSIM4ntnoi);
|
|
break;
|
|
case 1:
|
|
T0 = m * here->BSIM4gm + here->BSIM4gmbs + here->BSIM4gds;
|
|
T0 *= T0;
|
|
igsquare = npart_theta * npart_theta * T0 / here->BSIM4IdovVds;
|
|
T1 = npart_beta * (here->BSIM4gm
|
|
+ here->BSIM4gmbs) + here->BSIM4gds;
|
|
T2 = T1 * T1 / here->BSIM4IdovVds;
|
|
NevalSrc(&noizDens[BSIM4IDNOIZ],
|
|
&lnNdens[BSIM4IDNOIZ], ckt,
|
|
THERMNOISE, here->BSIM4dNodePrime,
|
|
here->BSIM4sNodePrime, (T2 - igsquare));
|
|
break;
|
|
}
|
|
|
|
NevalSrc(&noizDens[BSIM4FLNOIZ], (double*) NULL,
|
|
ckt, N_GAIN, here->BSIM4dNodePrime,
|
|
here->BSIM4sNodePrime, (double) 0.0);
|
|
|
|
switch(model->BSIM4fnoiMod)
|
|
{ case 0:
|
|
noizDens[BSIM4FLNOIZ] *= m * model->BSIM4kf
|
|
* exp(model->BSIM4af
|
|
* log(MAX(fabs(here->BSIM4cd),
|
|
N_MINLOG)))
|
|
/ (pow(data->freq, model->BSIM4ef)
|
|
* pParam->BSIM4leff
|
|
* pParam->BSIM4leff
|
|
* model->BSIM4coxe);
|
|
break;
|
|
case 1:
|
|
Vds = *(ckt->CKTstates[0] + here->BSIM4vds);
|
|
if (Vds < 0.0)
|
|
Vds = -Vds;
|
|
|
|
Ssi = Eval1ovFNoise(Vds, model, here,
|
|
data->freq, ckt->CKTtemp);
|
|
T10 = model->BSIM4oxideTrapDensityA
|
|
* CONSTboltz * ckt->CKTtemp;
|
|
T11 = pParam->BSIM4weff * here->BSIM4nf * pParam->BSIM4leff
|
|
* pow(data->freq, model->BSIM4ef) * 1.0e10
|
|
* here->BSIM4nstar * here->BSIM4nstar;
|
|
Swi = T10 / T11 * here->BSIM4cd
|
|
* here->BSIM4cd;
|
|
T1 = Swi + Ssi;
|
|
if (T1 > 0.0)
|
|
noizDens[BSIM4FLNOIZ] *= m * (Ssi * Swi) / T1;
|
|
else
|
|
noizDens[BSIM4FLNOIZ] *= 0.0;
|
|
break;
|
|
}
|
|
|
|
lnNdens[BSIM4FLNOIZ] =
|
|
log(MAX(noizDens[BSIM4FLNOIZ], N_MINLOG));
|
|
|
|
|
|
if(here->BSIM4mode >= 0) { /* bugfix */
|
|
NevalSrc(&noizDens[BSIM4IGSNOIZ],
|
|
&lnNdens[BSIM4IGSNOIZ], ckt, SHOTNOISE,
|
|
here->BSIM4gNodePrime, here->BSIM4sNodePrime,
|
|
m * (here->BSIM4Igs + here->BSIM4Igcs));
|
|
NevalSrc(&noizDens[BSIM4IGDNOIZ],
|
|
&lnNdens[BSIM4IGDNOIZ], ckt, SHOTNOISE,
|
|
here->BSIM4gNodePrime, here->BSIM4dNodePrime,
|
|
m * (here->BSIM4Igd + here->BSIM4Igcd));
|
|
} else {
|
|
NevalSrc(&noizDens[BSIM4IGSNOIZ],
|
|
&lnNdens[BSIM4IGSNOIZ], ckt, SHOTNOISE,
|
|
here->BSIM4gNodePrime, here->BSIM4sNodePrime,
|
|
m * (here->BSIM4Igs + here->BSIM4Igcd));
|
|
NevalSrc(&noizDens[BSIM4IGDNOIZ],
|
|
&lnNdens[BSIM4IGDNOIZ], ckt, SHOTNOISE,
|
|
here->BSIM4gNodePrime, here->BSIM4dNodePrime,
|
|
m * (here->BSIM4Igd + here->BSIM4Igcs));
|
|
}
|
|
NevalSrc(&noizDens[BSIM4IGBNOIZ],
|
|
&lnNdens[BSIM4IGBNOIZ], ckt, SHOTNOISE,
|
|
here->BSIM4gNodePrime, here->BSIM4bNodePrime,
|
|
m * here->BSIM4Igb);
|
|
|
|
|
|
noizDens[BSIM4TOTNOIZ] = noizDens[BSIM4RDNOIZ]
|
|
+ noizDens[BSIM4RSNOIZ] + noizDens[BSIM4RGNOIZ]
|
|
+ noizDens[BSIM4RBPSNOIZ] + noizDens[BSIM4RBPDNOIZ]
|
|
+ noizDens[BSIM4RBPBNOIZ]
|
|
+ noizDens[BSIM4RBSBNOIZ] + noizDens[BSIM4RBDBNOIZ]
|
|
+ noizDens[BSIM4IDNOIZ] + noizDens[BSIM4FLNOIZ]
|
|
+ noizDens[BSIM4IGSNOIZ] + noizDens[BSIM4IGDNOIZ]
|
|
+ noizDens[BSIM4IGBNOIZ];
|
|
lnNdens[BSIM4TOTNOIZ] =
|
|
log(MAX(noizDens[BSIM4TOTNOIZ], N_MINLOG));
|
|
|
|
*OnDens += noizDens[BSIM4TOTNOIZ];
|
|
|
|
if (data->delFreq == 0.0)
|
|
{ /* if we haven't done any previous
|
|
integration, we need to initialize our
|
|
"history" variables.
|
|
*/
|
|
|
|
for (i = 0; i < BSIM4NSRCS; i++)
|
|
{ here->BSIM4nVar[LNLSTDENS][i] =
|
|
lnNdens[i];
|
|
}
|
|
|
|
/* clear out our integration variables
|
|
if it's the first pass
|
|
*/
|
|
if (data->freq ==
|
|
((NOISEAN*) ckt->CKTcurJob)->NstartFreq)
|
|
{ for (i = 0; i < BSIM4NSRCS; i++)
|
|
{ here->BSIM4nVar[OUTNOIZ][i] = 0.0;
|
|
here->BSIM4nVar[INNOIZ][i] = 0.0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ /* data->delFreq != 0.0,
|
|
we have to integrate.
|
|
*/
|
|
for (i = 0; i < BSIM4NSRCS; i++)
|
|
{ if (i != BSIM4TOTNOIZ)
|
|
{ tempOnoise = Nintegrate(noizDens[i],
|
|
lnNdens[i],
|
|
here->BSIM4nVar[LNLSTDENS][i],
|
|
data);
|
|
tempInoise = Nintegrate(noizDens[i]
|
|
* data->GainSqInv, lnNdens[i]
|
|
+ data->lnGainInv,
|
|
here->BSIM4nVar[LNLSTDENS][i]
|
|
+ data->lnGainInv, data);
|
|
here->BSIM4nVar[LNLSTDENS][i] =
|
|
lnNdens[i];
|
|
data->outNoiz += tempOnoise;
|
|
data->inNoise += tempInoise;
|
|
if (((NOISEAN*)
|
|
ckt->CKTcurJob)->NStpsSm != 0)
|
|
{ here->BSIM4nVar[OUTNOIZ][i]
|
|
+= tempOnoise;
|
|
here->BSIM4nVar[OUTNOIZ][BSIM4TOTNOIZ]
|
|
+= tempOnoise;
|
|
here->BSIM4nVar[INNOIZ][i]
|
|
+= tempInoise;
|
|
here->BSIM4nVar[INNOIZ][BSIM4TOTNOIZ]
|
|
+= tempInoise;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (data->prtSummary)
|
|
{ for (i = 0; i < BSIM4NSRCS; i++)
|
|
{ /* print a summary report */
|
|
data->outpVector[data->outNumber++]
|
|
= noizDens[i];
|
|
}
|
|
}
|
|
break;
|
|
case INT_NOIZ:
|
|
/* already calculated, just output */
|
|
if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0)
|
|
{ for (i = 0; i < BSIM4NSRCS; i++)
|
|
{ data->outpVector[data->outNumber++]
|
|
= here->BSIM4nVar[OUTNOIZ][i];
|
|
data->outpVector[data->outNumber++]
|
|
= here->BSIM4nVar[INNOIZ][i];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case N_CLOSE:
|
|
/* do nothing, the main calling routine will close */
|
|
return (OK);
|
|
break; /* the plots */
|
|
} /* switch (operation) */
|
|
} /* for here */
|
|
} /* for model */
|
|
|
|
return(OK);
|
|
}
|