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

/**** 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);
}