int BSIM4v7noise ( int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; BSIM4v7model *model = (BSIM4v7model *)inModel; BSIM4v7instance *here; struct bsim4SizeDependParam *pParam; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[BSIM4v7NSRCS]; double lnNdens[BSIM4v7NSRCS]; double T0, T1, T2, T3, T4, T5, T6, T7, T8, T10, T11; double Vds, Ssi, Swi; double tmp=0.0, gdpr, gspr, npart_theta=0.0, npart_beta=0.0, igsquare, bodymode; /* tnoiMod=2 (v4.7) */ double eta, Leff, Lvsat, gamma, delta, epsilon, GammaGd0=0.0; double npart_c, sigrat=0.0, C0, omega, ctnoi=0.0; int i; double m; /* define the names of the noise sources */ static char *BSIM4v7nNames[BSIM4v7NSRCS] = { /* 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 (for tnoiMod2: uncorrelated portion only) */ ".1overf", /* flicker (1/f) noise */ ".igs", /* shot noise due to IGS */ ".igd", /* shot noise due to IGD */ ".igb", /* shot noise due to IGB */ ".corl", /* contribution of correlated drain and induced gate noise */ "" /* total transistor noise */ }; for (; model != NULL; model = model->BSIM4v7nextModel) { if(model->BSIM4v7tnoiMod != 2) { noizDens[BSIM4v7CORLNOIZ] = 0.0; lnNdens[BSIM4v7CORLNOIZ] = N_MINLOG; } for (here = model->BSIM4v7instances; here != NULL; here = here->BSIM4v7nextInstance) { 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 (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i = 0; i < BSIM4v7NSRCS; i++) { (void) sprintf(name, "onoise.%s%s", here->BSIM4v7name, BSIM4v7nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; case INT_NOIZ: for (i = 0; i < BSIM4v7NSRCS; i++) { (void) sprintf(name, "onoise_total.%s%s", here->BSIM4v7name, BSIM4v7nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ (void) sprintf(name, "inoise_total.%s%s", here->BSIM4v7name, BSIM4v7nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; } } break; case N_CALC: m = here->BSIM4v7m; switch (mode) { case N_DENS: if (model->BSIM4v7tnoiMod == 0) { if (model->BSIM4v7rdsMod == 0) { gspr = here->BSIM4v7sourceConductance; gdpr = here->BSIM4v7drainConductance; if (here->BSIM4v7grdsw > 0.0) tmp = 1.0 / here->BSIM4v7grdsw; /* tmp used below */ else tmp = 0.0; } else { gspr = here->BSIM4v7gstot; gdpr = here->BSIM4v7gdtot; tmp = 0.0; } } else if(model->BSIM4v7tnoiMod == 1) { T5 = here->BSIM4v7Vgsteff / here->BSIM4v7EsatL; T5 *= T5; npart_beta = model->BSIM4v7rnoia * (1.0 + T5 * model->BSIM4v7tnoia * pParam->BSIM4v7leff); npart_theta = model->BSIM4v7rnoib * (1.0 + T5 * model->BSIM4v7tnoib * pParam->BSIM4v7leff); 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->BSIM4v7rdsMod == 0) { gspr = here->BSIM4v7sourceConductance; gdpr = here->BSIM4v7drainConductance; } else { gspr = here->BSIM4v7gstot; gdpr = here->BSIM4v7gdtot; } if ((*(ckt->CKTstates[0] + here->BSIM4v7vds)) >= 0.0) gspr = gspr * (1.0 + npart_theta * npart_theta * gspr / here->BSIM4v7IdovVds); else gdpr = gdpr * (1.0 + npart_theta * npart_theta * gdpr / here->BSIM4v7IdovVds); } else { /* tnoiMod=2 (v4.7) */ if (model->BSIM4v7rdsMod == 0) { gspr = here->BSIM4v7sourceConductance; gdpr = here->BSIM4v7drainConductance; } else { gspr = here->BSIM4v7gstot; gdpr = here->BSIM4v7gdtot; } } NevalSrc(&noizDens[BSIM4v7RDNOIZ], &lnNdens[BSIM4v7RDNOIZ], ckt, THERMNOISE, here->BSIM4v7dNodePrime, here->BSIM4v7dNode, gdpr * m); NevalSrc(&noizDens[BSIM4v7RSNOIZ], &lnNdens[BSIM4v7RSNOIZ], ckt, THERMNOISE, here->BSIM4v7sNodePrime, here->BSIM4v7sNode, gspr * m); if (here->BSIM4v7rgateMod == 1) { NevalSrc(&noizDens[BSIM4v7RGNOIZ], &lnNdens[BSIM4v7RGNOIZ], ckt, THERMNOISE, here->BSIM4v7gNodePrime, here->BSIM4v7gNodeExt, here->BSIM4v7grgeltd * m); } else if (here->BSIM4v7rgateMod == 2) { T0 = 1.0 + here->BSIM4v7grgeltd/here->BSIM4v7gcrg; T1 = T0 * T0; NevalSrc(&noizDens[BSIM4v7RGNOIZ], &lnNdens[BSIM4v7RGNOIZ], ckt, THERMNOISE, here->BSIM4v7gNodePrime, here->BSIM4v7gNodeExt, here->BSIM4v7grgeltd * m / T1); } else if (here->BSIM4v7rgateMod == 3) { NevalSrc(&noizDens[BSIM4v7RGNOIZ], &lnNdens[BSIM4v7RGNOIZ], ckt, THERMNOISE, here->BSIM4v7gNodeMid, here->BSIM4v7gNodeExt, here->BSIM4v7grgeltd * m); } else { noizDens[BSIM4v7RGNOIZ] = 0.0; lnNdens[BSIM4v7RGNOIZ] = log(MAX(noizDens[BSIM4v7RGNOIZ], N_MINLOG)); } bodymode = 5; if (here->BSIM4v7rbodyMod == 2) { if( ( !model->BSIM4v7rbps0Given) || ( !model->BSIM4v7rbpd0Given) ) bodymode = 1; else if( (!model->BSIM4v7rbsbx0Given && !model->BSIM4v7rbsby0Given) || (!model->BSIM4v7rbdbx0Given && !model->BSIM4v7rbdby0Given) ) bodymode = 3; } if (here->BSIM4v7rbodyMod) { if(bodymode == 5) { NevalSrc(&noizDens[BSIM4v7RBPSNOIZ], &lnNdens[BSIM4v7RBPSNOIZ], ckt, THERMNOISE, here->BSIM4v7bNodePrime, here->BSIM4v7sbNode, here->BSIM4v7grbps * m); NevalSrc(&noizDens[BSIM4v7RBPDNOIZ], &lnNdens[BSIM4v7RBPDNOIZ], ckt, THERMNOISE, here->BSIM4v7bNodePrime, here->BSIM4v7dbNode, here->BSIM4v7grbpd * m); NevalSrc(&noizDens[BSIM4v7RBPBNOIZ], &lnNdens[BSIM4v7RBPBNOIZ], ckt, THERMNOISE, here->BSIM4v7bNodePrime, here->BSIM4v7bNode, here->BSIM4v7grbpb * m); NevalSrc(&noizDens[BSIM4v7RBSBNOIZ], &lnNdens[BSIM4v7RBSBNOIZ], ckt, THERMNOISE, here->BSIM4v7bNode, here->BSIM4v7sbNode, here->BSIM4v7grbsb * m); NevalSrc(&noizDens[BSIM4v7RBDBNOIZ], &lnNdens[BSIM4v7RBDBNOIZ], ckt, THERMNOISE, here->BSIM4v7bNode, here->BSIM4v7dbNode, here->BSIM4v7grbdb * m); } if(bodymode == 3) { NevalSrc(&noizDens[BSIM4v7RBPSNOIZ], &lnNdens[BSIM4v7RBPSNOIZ], ckt, THERMNOISE, here->BSIM4v7bNodePrime, here->BSIM4v7sbNode, here->BSIM4v7grbps * m); NevalSrc(&noizDens[BSIM4v7RBPDNOIZ], &lnNdens[BSIM4v7RBPDNOIZ], ckt, THERMNOISE, here->BSIM4v7bNodePrime, here->BSIM4v7dbNode, here->BSIM4v7grbpd * m); NevalSrc(&noizDens[BSIM4v7RBPBNOIZ], &lnNdens[BSIM4v7RBPBNOIZ], ckt, THERMNOISE, here->BSIM4v7bNodePrime, here->BSIM4v7bNode, here->BSIM4v7grbpb * m); noizDens[BSIM4v7RBSBNOIZ] = noizDens[BSIM4v7RBDBNOIZ] = 0.0; lnNdens[BSIM4v7RBSBNOIZ] = log(MAX(noizDens[BSIM4v7RBSBNOIZ], N_MINLOG)); lnNdens[BSIM4v7RBDBNOIZ] = log(MAX(noizDens[BSIM4v7RBDBNOIZ], N_MINLOG)); } if(bodymode == 1) { NevalSrc(&noizDens[BSIM4v7RBPBNOIZ], &lnNdens[BSIM4v7RBPBNOIZ], ckt, THERMNOISE, here->BSIM4v7bNodePrime, here->BSIM4v7bNode, here->BSIM4v7grbpb * m); noizDens[BSIM4v7RBPSNOIZ] = noizDens[BSIM4v7RBPDNOIZ] = 0.0; noizDens[BSIM4v7RBSBNOIZ] = noizDens[BSIM4v7RBDBNOIZ] = 0.0; lnNdens[BSIM4v7RBPSNOIZ] = log(MAX(noizDens[BSIM4v7RBPSNOIZ], N_MINLOG)); lnNdens[BSIM4v7RBPDNOIZ] = log(MAX(noizDens[BSIM4v7RBPDNOIZ], N_MINLOG)); lnNdens[BSIM4v7RBSBNOIZ] = log(MAX(noizDens[BSIM4v7RBSBNOIZ], N_MINLOG)); lnNdens[BSIM4v7RBDBNOIZ] = log(MAX(noizDens[BSIM4v7RBDBNOIZ], N_MINLOG)); } } else { noizDens[BSIM4v7RBPSNOIZ] = noizDens[BSIM4v7RBPDNOIZ] = 0.0; noizDens[BSIM4v7RBPBNOIZ] = 0.0; noizDens[BSIM4v7RBSBNOIZ] = noizDens[BSIM4v7RBDBNOIZ] = 0.0; lnNdens[BSIM4v7RBPSNOIZ] = log(MAX(noizDens[BSIM4v7RBPSNOIZ], N_MINLOG)); lnNdens[BSIM4v7RBPDNOIZ] = log(MAX(noizDens[BSIM4v7RBPDNOIZ], N_MINLOG)); lnNdens[BSIM4v7RBPBNOIZ] = log(MAX(noizDens[BSIM4v7RBPBNOIZ], N_MINLOG)); lnNdens[BSIM4v7RBSBNOIZ] = log(MAX(noizDens[BSIM4v7RBSBNOIZ], N_MINLOG)); lnNdens[BSIM4v7RBDBNOIZ] = log(MAX(noizDens[BSIM4v7RBDBNOIZ], N_MINLOG)); } if(model->BSIM4v7tnoiMod == 2) { eta = 1.0 - here->BSIM4v7Vdseff * here->BSIM4v7AbovVgst2Vtm; T0 = 1.0 - eta; T1 = 1.0 + eta; T2 = T1 + 2.0 * here->BSIM4v7Abulk * model->BSIM4v7vtm / here->BSIM4v7Vgsteff; Leff = pParam->BSIM4v7leff; Lvsat = Leff * (1.0 + here->BSIM4v7Vdseff / here->BSIM4v7EsatL); T6 = Leff / Lvsat; T5 = here->BSIM4v7Vgsteff / here->BSIM4v7EsatL; T5 = T5 * T5; gamma = T6 * (0.5 * T1 + T0 * T0 / (6.0 * T2)); T3 = T2 * T2; T4 = T0 * T0; T5 = T3 * T3; delta = (T1 / T3 - (5.0 * T1 + T2) * T4 / (15.0 * T5) + T4 * T4 / (9.0 * T5 * T2)) / (6.0 * T6 * T6 * T6); T7 = T0 / T2; epsilon = (T7 - T7 * T7 * T7 / 3.0) / (6.0 * T6); T8 = here->BSIM4v7Vgsteff / here->BSIM4v7EsatL; T8 *= T8; npart_c = model->BSIM4v7rnoic * (1.0 + T8 * model->BSIM4v7tnoic * Leff); ctnoi = epsilon / sqrt(gamma * delta) * (2.5316 * npart_c); npart_beta = model->BSIM4v7rnoia * (1.0 + T8 * model->BSIM4v7tnoia * Leff); npart_theta = model->BSIM4v7rnoib * (1.0 + T8 * model->BSIM4v7tnoib * Leff); gamma = gamma * (3.0 * npart_beta * npart_beta); delta = delta * (3.75 * npart_theta * npart_theta); GammaGd0 = gamma * here->BSIM4v7noiGd0; C0 = here->BSIM4v7Coxeff * pParam->BSIM4v7weffCV * here->BSIM4v7nf * pParam->BSIM4v7leffCV; T0 = C0 / here->BSIM4v7noiGd0; sigrat = T0 * sqrt(delta / gamma); } switch(model->BSIM4v7tnoiMod) { case 0: T0 = here->BSIM4v7ueff * fabs(here->BSIM4v7qinv); T1 = T0 * tmp + pParam->BSIM4v7leff * pParam->BSIM4v7leff; NevalSrc(&noizDens[BSIM4v7IDNOIZ], &lnNdens[BSIM4v7IDNOIZ], ckt, THERMNOISE, here->BSIM4v7dNodePrime, here->BSIM4v7sNodePrime, (T0 / T1) * model->BSIM4v7ntnoi * m); break; case 1: T0 = here->BSIM4v7gm + here->BSIM4v7gmbs + here->BSIM4v7gds; T0 *= T0; igsquare = npart_theta * npart_theta * T0 / here->BSIM4v7IdovVds; T1 = npart_beta * (here->BSIM4v7gm + here->BSIM4v7gmbs) + here->BSIM4v7gds; T2 = T1 * T1 / here->BSIM4v7IdovVds; NevalSrc(&noizDens[BSIM4v7IDNOIZ], &lnNdens[BSIM4v7IDNOIZ], ckt, THERMNOISE, here->BSIM4v7dNodePrime, here->BSIM4v7sNodePrime, (T2 - igsquare) * m); break; case 2: T2 = GammaGd0; T3 = ctnoi * ctnoi; T4 = 1.0 - T3; NevalSrc(&noizDens[BSIM4v7IDNOIZ], &lnNdens[BSIM4v7IDNOIZ], ckt, THERMNOISE, here->BSIM4v7dNodePrime, here->BSIM4v7sNodePrime, T2 * T4 * m); /* Evaluate output noise due to two correlated noise sources */ omega = 2.0 * M_PI * data->freq; T5 = omega * sigrat; T6 = T5 * T5; T7 = T6 / (1.0 + T6); if (here->BSIM4v7mode >= 0) { NevalSrc2(&noizDens[BSIM4v7CORLNOIZ], &lnNdens[BSIM4v7CORLNOIZ], ckt, THERMNOISE, here->BSIM4v7dNodePrime, here->BSIM4v7sNodePrime, T2 * T3 * m, here->BSIM4v7gNodePrime, here->BSIM4v7sNodePrime, T2 * T7 * m, 0.5 * M_PI); } else { NevalSrc2(&noizDens[BSIM4v7CORLNOIZ], &lnNdens[BSIM4v7CORLNOIZ], ckt, THERMNOISE, here->BSIM4v7sNodePrime, here->BSIM4v7dNodePrime, T2 * T3 * m, here->BSIM4v7gNodePrime, here->BSIM4v7dNodePrime, T2 * T7 * m, 0.5 * M_PI); } break; } NevalSrc(&noizDens[BSIM4v7FLNOIZ], (double*) NULL, ckt, N_GAIN, here->BSIM4v7dNodePrime, here->BSIM4v7sNodePrime, (double) 0.0); switch(model->BSIM4v7fnoiMod) { case 0: noizDens[BSIM4v7FLNOIZ] *= m * model->BSIM4v7kf * exp(model->BSIM4v7af * log(MAX(fabs(here->BSIM4v7cd), N_MINLOG))) / (pow(data->freq, model->BSIM4v7ef) * pParam->BSIM4v7leff * pParam->BSIM4v7leff * model->BSIM4v7coxe); break; case 1: Vds = *(ckt->CKTstates[0] + here->BSIM4v7vds); if (Vds < 0.0) Vds = -Vds; Ssi = Eval1ovFNoise(Vds, model, here, data->freq, ckt->CKTtemp); T10 = model->BSIM4v7oxideTrapDensityA * CONSTboltz * ckt->CKTtemp; T11 = pParam->BSIM4v7weff * here->BSIM4v7nf * pParam->BSIM4v7leff * pow(data->freq, model->BSIM4v7ef) * 1.0e10 * here->BSIM4v7nstar * here->BSIM4v7nstar; Swi = T10 / T11 * here->BSIM4v7cd * here->BSIM4v7cd; T1 = Swi + Ssi; if (T1 > 0.0) noizDens[BSIM4v7FLNOIZ] *= m * (Ssi * Swi) / T1; else noizDens[BSIM4v7FLNOIZ] *= 0.0; break; } lnNdens[BSIM4v7FLNOIZ] = log(MAX(noizDens[BSIM4v7FLNOIZ], N_MINLOG)); if(here->BSIM4v7mode >= 0) { /* bugfix */ NevalSrc(&noizDens[BSIM4v7IGSNOIZ], &lnNdens[BSIM4v7IGSNOIZ], ckt, SHOTNOISE, here->BSIM4v7gNodePrime, here->BSIM4v7sNodePrime, m * (here->BSIM4v7Igs + here->BSIM4v7Igcs)); NevalSrc(&noizDens[BSIM4v7IGDNOIZ], &lnNdens[BSIM4v7IGDNOIZ], ckt, SHOTNOISE, here->BSIM4v7gNodePrime, here->BSIM4v7dNodePrime, m * (here->BSIM4v7Igd + here->BSIM4v7Igcd)); } else { NevalSrc(&noizDens[BSIM4v7IGSNOIZ], &lnNdens[BSIM4v7IGSNOIZ], ckt, SHOTNOISE, here->BSIM4v7gNodePrime, here->BSIM4v7sNodePrime, m * (here->BSIM4v7Igs + here->BSIM4v7Igcd)); NevalSrc(&noizDens[BSIM4v7IGDNOIZ], &lnNdens[BSIM4v7IGDNOIZ], ckt, SHOTNOISE, here->BSIM4v7gNodePrime, here->BSIM4v7dNodePrime, m * (here->BSIM4v7Igd + here->BSIM4v7Igcs)); } NevalSrc(&noizDens[BSIM4v7IGBNOIZ], &lnNdens[BSIM4v7IGBNOIZ], ckt, SHOTNOISE, here->BSIM4v7gNodePrime, here->BSIM4v7bNodePrime, m * here->BSIM4v7Igb); noizDens[BSIM4v7TOTNOIZ] = noizDens[BSIM4v7RDNOIZ] + noizDens[BSIM4v7RSNOIZ] + noizDens[BSIM4v7RGNOIZ] + noizDens[BSIM4v7RBPSNOIZ] + noizDens[BSIM4v7RBPDNOIZ] + noizDens[BSIM4v7RBPBNOIZ] + noizDens[BSIM4v7RBSBNOIZ] + noizDens[BSIM4v7RBDBNOIZ] + noizDens[BSIM4v7IDNOIZ] + noizDens[BSIM4v7FLNOIZ] + noizDens[BSIM4v7IGSNOIZ] + noizDens[BSIM4v7IGDNOIZ] + noizDens[BSIM4v7IGBNOIZ] + noizDens[BSIM4v7CORLNOIZ]; lnNdens[BSIM4v7TOTNOIZ] = log(MAX(noizDens[BSIM4v7TOTNOIZ], N_MINLOG)); *OnDens += noizDens[BSIM4v7TOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to initialize our "history" variables. */ for (i = 0; i < BSIM4v7NSRCS; i++) { here->BSIM4v7nVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i = 0; i < BSIM4v7NSRCS; i++) { here->BSIM4v7nVar[OUTNOIZ][i] = 0.0; here->BSIM4v7nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0, we have to integrate. */ for (i = 0; i < BSIM4v7NSRCS; i++) { if (i != BSIM4v7TOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], here->BSIM4v7nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv, lnNdens[i] + data->lnGainInv, here->BSIM4v7nVar[LNLSTDENS][i] + data->lnGainInv, data); here->BSIM4v7nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { here->BSIM4v7nVar[OUTNOIZ][i] += tempOnoise; here->BSIM4v7nVar[OUTNOIZ][BSIM4v7TOTNOIZ] += tempOnoise; here->BSIM4v7nVar[INNOIZ][i] += tempInoise; here->BSIM4v7nVar[INNOIZ][BSIM4v7TOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i = 0; i < BSIM4v7NSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i = 0; i < BSIM4v7NSRCS; i++) { data->outpVector[data->outNumber++] = here->BSIM4v7nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = here->BSIM4v7nVar[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); }
int BJTnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; BJTmodel *firstModel = (BJTmodel *) genmodel; BJTmodel *model; BJTinstance *inst; double tempOnoise; double tempInoise; double noizDens[BJTNSRCS]; double lnNdens[BJTNSRCS]; int i; /* define the names of the noise sources */ static char *BJTnNames[BJTNSRCS] = { /* Note that we have to keep the order consistent with the strchr definitions in BJTdefs.h */ "_rc", /* noise due to rc */ "_rb", /* noise due to rb */ "_re", /* noise due to re */ "_ic", /* noise due to ic */ "_ib", /* noise due to ib */ "_1overf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for (model=firstModel; model != NULL; model=BJTnextModel(model)) { for (inst=BJTinstances(model); inst != NULL; inst=BJTnextInstance(inst)) { switch (operation) { case N_OPEN: /* see if we have to to produce a summary report */ /* if so, name all the noise generators */ if (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i=0; i < BJTNSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->BJTname, BJTnNames[i]); } break; case INT_NOIZ: for (i=0; i < BJTNSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->BJTname, BJTnNames[i]); NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->BJTname, BJTnNames[i]); } break; } } break; case N_CALC: switch (mode) { case N_DENS: NevalSrc(&noizDens[BJTRCNOIZ],&lnNdens[BJTRCNOIZ], ckt,THERMNOISE,inst->BJTcolPrimeNode,inst->BJTcolNode, inst->BJTtcollectorConduct * inst->BJTarea * inst->BJTm); NevalSrc(&noizDens[BJTRBNOIZ],&lnNdens[BJTRBNOIZ], ckt,THERMNOISE,inst->BJTbasePrimeNode,inst->BJTbaseNode, *(ckt->CKTstate0 + inst->BJTgx) * inst->BJTm); NevalSrc(&noizDens[BJT_RE_NOISE],&lnNdens[BJT_RE_NOISE], ckt,THERMNOISE,inst->BJTemitPrimeNode,inst->BJTemitNode, inst->BJTtemitterConduct * inst->BJTarea * inst-> BJTm); NevalSrc(&noizDens[BJTICNOIZ],&lnNdens[BJTICNOIZ], ckt,SHOTNOISE,inst->BJTcolPrimeNode, inst->BJTemitPrimeNode, *(ckt->CKTstate0 + inst->BJTcc) * inst->BJTm); NevalSrc(&noizDens[BJTIBNOIZ],&lnNdens[BJTIBNOIZ], ckt,SHOTNOISE,inst->BJTbasePrimeNode, inst->BJTemitPrimeNode, *(ckt->CKTstate0 + inst->BJTcb) * inst->BJTm); NevalSrc(&noizDens[BJTFLNOIZ], NULL, ckt, N_GAIN,inst->BJTbasePrimeNode, inst->BJTemitPrimeNode, (double)0.0); noizDens[BJTFLNOIZ] *= inst->BJTm * model->BJTfNcoef * exp(model->BJTfNexp * log(MAX(fabs(*(ckt->CKTstate0 + inst->BJTcb)),N_MINLOG))) / data->freq; lnNdens[BJTFLNOIZ] = log(MAX(noizDens[BJTFLNOIZ],N_MINLOG)); noizDens[BJTTOTNOIZ] = noizDens[BJTRCNOIZ] + noizDens[BJTRBNOIZ] + noizDens[BJT_RE_NOISE] + noizDens[BJTICNOIZ] + noizDens[BJTIBNOIZ] + noizDens[BJTFLNOIZ]; lnNdens[BJTTOTNOIZ] = log(noizDens[BJTTOTNOIZ]); *OnDens += noizDens[BJTTOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ for (i=0; i < BJTNSRCS; i++) { inst->BJTnVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i=0; i < BJTNSRCS; i++) { inst->BJTnVar[OUTNOIZ][i] = 0.0; inst->BJTnVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0 (we have to integrate) */ /* In order to get the best curve fit, we have to integrate each component separately */ for (i=0; i < BJTNSRCS; i++) { if (i != BJTTOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], inst->BJTnVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , lnNdens[i] + data->lnGainInv, inst->BJTnVar[LNLSTDENS][i] + data->lnGainInv, data); inst->BJTnVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { inst->BJTnVar[OUTNOIZ][i] += tempOnoise; inst->BJTnVar[OUTNOIZ][BJTTOTNOIZ] += tempOnoise; inst->BJTnVar[INNOIZ][i] += tempInoise; inst->BJTnVar[INNOIZ][BJTTOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i=0; i < BJTNSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i=0; i < BJTNSRCS; i++) { data->outpVector[data->outNumber++] = inst->BJTnVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = inst->BJTnVar[INNOIZ][i]; } } /* if */ break; } /* switch (mode) */ break; case N_CLOSE: return (OK); /* do nothing, the main calling routine will close */ break; /* the plots */ } /* switch (operation) */ } /* for inst */ } /* for model */ return(OK); }
int HSMHV2noise ( int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, Ndata *data, double *OnDens) { HSMHV2model *model = (HSMHV2model *)inModel; HSMHV2instance *here; char name[N_MXVLNTH]; double tempOnoise=0.0 ; double tempInoise=0.0 ; double noizDens[HSMHV2NSRCS] ; double lnNdens[HSMHV2NSRCS] ; int i; double G =0.0 ; double TTEMP = 0.0 ; /* define the names of the noise sources */ static char * HSMHV2nNames[HSMHV2NSRCS] = { /* Note that we have to keep the order consistent with the index definitions in hsmhvdefs.h */ ".rd", /* noise due to rd */ ".rs", /* noise due to rs */ ".id", /* noise due to id */ ".1ovf", /* flicker (1/f) noise */ ".ign", /* induced gate noise component at the drain node */ "" /* total transistor noise */ }; for ( ;model != NULL; model = model->HSMHV2nextModel ) { for ( here = model->HSMHV2instances; here != NULL; here = here->HSMHV2nextInstance ) { 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 < HSMHV2NSRCS; i++ ) { (void) sprintf(name, "onoise.%s%s", (char *)here->HSMHV2name, HSMHV2nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); } break; case INT_NOIZ: for ( i = 0; i < HSMHV2NSRCS; i++ ) { (void) sprintf(name, "onoise_total.%s%s", (char *)here->HSMHV2name, HSMHV2nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); (void) sprintf(name, "inoise_total.%s%s", (char *)here->HSMHV2name, HSMHV2nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); } break; } } break; case N_CALC: switch (mode) { case N_DENS: /* temperature */ TTEMP = ckt->CKTtemp; if ( here->HSMHV2_dtemp_Given ) { TTEMP = TTEMP + here->HSMHV2_dtemp ; } TTEMP = TTEMP + *(ckt->CKTstate0 + here->HSMHV2deltemp) ; /* rs/rd thermal noise */ if ( model->HSMHV2_corsrd == 1 || model->HSMHV2_corsrd == 3 || model->HSMHV2_cordrift == 1 ) { NevalSrc(&noizDens[HSMHV2RDNOIZ], NULL, ckt, N_GAIN, here->HSMHV2dNodePrime, here->HSMHV2dNode, 0.0); noizDens[HSMHV2RDNOIZ] *= 4 * C_KB * TTEMP * here->HSMHV2drainConductance ; lnNdens[HSMHV2RDNOIZ] = log( MAX(noizDens[HSMHV2RDNOIZ],N_MINLOG) ); NevalSrc(&noizDens[HSMHV2RSNOIZ], NULL, ckt, N_GAIN, here->HSMHV2sNodePrime, here->HSMHV2sNode, 0.0); noizDens[HSMHV2RSNOIZ] *= 4 * C_KB * TTEMP * here->HSMHV2sourceConductance ; lnNdens[HSMHV2RSNOIZ] = log( MAX(noizDens[HSMHV2RSNOIZ],N_MINLOG) ); } else { noizDens[HSMHV2RDNOIZ] = 0e0 ; lnNdens[HSMHV2RDNOIZ] = N_MINLOG ; noizDens[HSMHV2RSNOIZ] = 0e0 ; lnNdens[HSMHV2RSNOIZ] = N_MINLOG ; } /* channel thermal noise */ NevalSrc(&noizDens[HSMHV2IDNOIZ], NULL, ckt, N_GAIN, here->HSMHV2dNodePrime, here->HSMHV2sNodePrime, 0.0); switch( model->HSMHV2_noise ) { case 1: /* HiSIMHV model */ G = here->HSMHV2_noithrml ; noizDens[HSMHV2IDNOIZ] *= 4 * C_KB * TTEMP * G ; lnNdens[HSMHV2IDNOIZ] = log( MAX(noizDens[HSMHV2IDNOIZ],N_MINLOG) ); break; } /* flicker noise */ NevalSrc(&noizDens[HSMHV2FLNOIZ], NULL, ckt, N_GAIN, here->HSMHV2dNodePrime, here->HSMHV2sNodePrime, 0.0); switch ( model->HSMHV2_noise ) { case 1: /* HiSIM model */ noizDens[HSMHV2FLNOIZ] *= here->HSMHV2_noiflick / pow(data->freq, model->HSMHV2_falph) ; lnNdens[HSMHV2FLNOIZ] = log(MAX(noizDens[HSMHV2FLNOIZ], N_MINLOG)); break; } /* induced gate noise */ NevalSrc(&noizDens[HSMHV2IGNOIZ], NULL, ckt, N_GAIN, here->HSMHV2dNodePrime, here->HSMHV2sNodePrime, 0.0); switch ( model->HSMHV2_noise ) { case 1: /* HiSIM model */ noizDens[HSMHV2IGNOIZ] *= here->HSMHV2_noiigate * here->HSMHV2_noicross * here->HSMHV2_noicross * data->freq * data->freq; lnNdens[HSMHV2IGNOIZ] = log(MAX(noizDens[HSMHV2IGNOIZ], N_MINLOG)); break; } /* total */ noizDens[HSMHV2TOTNOIZ] = noizDens[HSMHV2RDNOIZ] + noizDens[HSMHV2RSNOIZ] + noizDens[HSMHV2IDNOIZ] + noizDens[HSMHV2FLNOIZ] + noizDens[HSMHV2IGNOIZ]; lnNdens[HSMHV2TOTNOIZ] = log(MAX(noizDens[HSMHV2TOTNOIZ], N_MINLOG)); *OnDens += noizDens[HSMHV2TOTNOIZ]; if ( data->delFreq == 0.0 ) { /* if we haven't done any previous integration, we need to initialize our "history" variables. */ for ( i = 0; i < HSMHV2NSRCS; i++ ) here->HSMHV2nVar[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 < HSMHV2NSRCS; i++) { here->HSMHV2nVar[OUTNOIZ][i] = 0.0; here->HSMHV2nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0, we have to integrate. */ for ( i = 0; i < HSMHV2NSRCS; i++ ) { if ( i != HSMHV2TOTNOIZ ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], here->HSMHV2nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv, lnNdens[i] + data->lnGainInv, here->HSMHV2nVar[LNLSTDENS][i] + data->lnGainInv, data); here->HSMHV2nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if ( ((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0 ) { here->HSMHV2nVar[OUTNOIZ][i] += tempOnoise; here->HSMHV2nVar[OUTNOIZ][HSMHV2TOTNOIZ] += tempOnoise; here->HSMHV2nVar[INNOIZ][i] += tempInoise; here->HSMHV2nVar[INNOIZ][HSMHV2TOTNOIZ] += tempInoise; } } } } if ( data->prtSummary ) { for (i = 0; i < HSMHV2NSRCS; 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 < HSMHV2NSRCS; i++ ) { data->outpVector[data->outNumber++] = here->HSMHV2nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = here->HSMHV2nVar[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); }
int B2noise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { B2model *firstModel = (B2model *) genmodel; B2model *model; B2instance *inst; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[B2NSRCS]; double lnNdens[B2NSRCS]; int i; /* define the names of the noise sources */ static char *B2nNames[B2NSRCS] = { /* Note that we have to keep the order */ "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ "_rs", /* noise due to rs */ /* in bsim1defs.h */ "_id", /* noise due to id */ "_1overf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for (model=firstModel; model != NULL; model=model->B2nextModel) { for (inst=model->B2instances; inst != NULL; inst=inst->B2nextInstance) { if (inst->B2owner != ARCHme) continue; 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 < B2NSRCS; i++) { (void)sprintf(name,"onoise_%s%s",inst->B2name,B2nNames[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 < B2NSRCS; i++) { (void)sprintf(name,"onoise_total_%s%s",inst->B2name,B2nNames[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",inst->B2name,B2nNames[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: switch (mode) { case N_DENS: NevalSrc(&noizDens[B2RDNOIZ],&lnNdens[B2RDNOIZ], ckt,THERMNOISE,inst->B2dNodePrime,inst->B2dNode, inst->B2drainConductance * inst->B2m); NevalSrc(&noizDens[B2RSNOIZ],&lnNdens[B2RSNOIZ], ckt,THERMNOISE,inst->B2sNodePrime,inst->B2sNode, inst->B2sourceConductance * inst->B2m); NevalSrc(&noizDens[B2IDNOIZ],&lnNdens[B2IDNOIZ], ckt,THERMNOISE,inst->B2dNodePrime,inst->B2sNodePrime, (2.0/3.0 * fabs(inst->B2gm * inst->B2m))); NevalSrc(&noizDens[B2FLNOIZ],(double*)NULL,ckt, N_GAIN,inst->B2dNodePrime, inst->B2sNodePrime, (double)0.0); noizDens[B2FLNOIZ] *= model->B2fNcoef * inst->B2m * exp(model->B2fNexp * log(MAX(fabs(inst->B2cd),N_MINLOG))) / (data->freq * (inst->B2w - model->B2deltaW * 1e-6) * (inst->B2l - model->B2deltaL * 1e-6) * model->B2Cox * model->B2Cox); lnNdens[B2FLNOIZ] = log(MAX(noizDens[B2FLNOIZ],N_MINLOG)); noizDens[B2TOTNOIZ] = noizDens[B2RDNOIZ] + noizDens[B2RSNOIZ] + noizDens[B2IDNOIZ] + noizDens[B2FLNOIZ]; lnNdens[B2TOTNOIZ] = log(MAX(noizDens[B2TOTNOIZ], N_MINLOG)); *OnDens += noizDens[B2TOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ for (i=0; i < B2NSRCS; i++) { inst->B2nVar[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 < B2NSRCS; i++) { inst->B2nVar[OUTNOIZ][i] = 0.0; inst->B2nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0 (we have to integrate) */ for (i=0; i < B2NSRCS; i++) { if (i != B2TOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], inst->B2nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , lnNdens[i] + data->lnGainInv, inst->B2nVar[LNLSTDENS][i] + data->lnGainInv, data); inst->B2nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { inst->B2nVar[OUTNOIZ][i] += tempOnoise; inst->B2nVar[OUTNOIZ][B2TOTNOIZ] += tempOnoise; inst->B2nVar[INNOIZ][i] += tempInoise; inst->B2nVar[INNOIZ][B2TOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i=0; i < B2NSRCS; 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 < B2NSRCS; i++) { data->outpVector[data->outNumber++] = inst->B2nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = inst->B2nVar[INNOIZ][i]; } } /* if */ break; } /* switch (mode) */ break; case N_CLOSE: return (OK); /* do nothing, the main calling routine will close */ break; /* the plots */ } /* switch (operation) */ } /* for inst */ } /* for model */ return(OK); }
int VDMOSnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; VDMOSmodel *firstModel = (VDMOSmodel *) genmodel; VDMOSmodel *model; VDMOSinstance *inst; double coxSquared; double tempOnoise; double tempInoise; double noizDens[VDMOSNSRCS]; double lnNdens[VDMOSNSRCS]; int i; /* define the names of the noise sources */ static char *VDMOSnNames[VDMOSNSRCS] = { /* Note that we have to keep the order */ "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ "_rs", /* noise due to rs */ /* in VDMOSdefs.h */ "_id", /* noise due to id */ "_1overf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for (model=firstModel; model != NULL; model=VDMOSnextModel(model)) { /* Oxide capacitance can be zero in MOS level 1. Since this will give us problems in our 1/f */ /* noise model, we ASSUME an actual "tox" of 1e-7 */ if (model->VDMOSoxideCapFactor == 0.0) { coxSquared = 3.9 * 8.854214871e-12 / 1e-7; } else { coxSquared = model->VDMOSoxideCapFactor; } coxSquared *= coxSquared; for (inst=VDMOSinstances(model); inst != NULL; inst=VDMOSnextInstance(inst)) { switch (operation) { case N_OPEN: /* see if we have to to produce a summary report */ /* if so, name all the noise generators */ if (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i=0; i < VDMOSNSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->VDMOSname, VDMOSnNames[i]); } break; case INT_NOIZ: for (i=0; i < VDMOSNSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->VDMOSname, VDMOSnNames[i]); NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->VDMOSname, VDMOSnNames[i]); } break; } } break; case N_CALC: switch (mode) { case N_DENS: NevalSrc(&noizDens[VDMOSRDNOIZ],&lnNdens[VDMOSRDNOIZ], ckt,THERMNOISE,inst->VDMOSdNodePrime,inst->VDMOSdNode, inst->VDMOSdrainConductance); NevalSrc(&noizDens[VDMOSRSNOIZ],&lnNdens[VDMOSRSNOIZ], ckt,THERMNOISE,inst->VDMOSsNodePrime,inst->VDMOSsNode, inst->VDMOSsourceConductance); NevalSrc(&noizDens[VDMOSIDNOIZ],&lnNdens[VDMOSIDNOIZ], ckt,THERMNOISE,inst->VDMOSdNodePrime,inst->VDMOSsNodePrime, (2.0/3.0 * fabs(inst->VDMOSgm))); NevalSrc(&noizDens[VDMOSFLNOIZ], NULL, ckt, N_GAIN,inst->VDMOSdNodePrime, inst->VDMOSsNodePrime, (double)0.0); noizDens[VDMOSFLNOIZ] *= model->VDMOSfNcoef * exp(model->VDMOSfNexp * log(MAX(fabs(inst->VDMOScd),N_MINLOG))) / (data->freq * inst->VDMOSw * inst->VDMOSm * inst->VDMOSl * coxSquared); lnNdens[VDMOSFLNOIZ] = log(MAX(noizDens[VDMOSFLNOIZ],N_MINLOG)); noizDens[VDMOSTOTNOIZ] = noizDens[VDMOSRDNOIZ] + noizDens[VDMOSRSNOIZ] + noizDens[VDMOSIDNOIZ] + noizDens[VDMOSFLNOIZ]; lnNdens[VDMOSTOTNOIZ] = log(MAX(noizDens[VDMOSTOTNOIZ], N_MINLOG)); *OnDens += noizDens[VDMOSTOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ for (i=0; i < VDMOSNSRCS; i++) { inst->VDMOSnVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i=0; i < VDMOSNSRCS; i++) { inst->VDMOSnVar[OUTNOIZ][i] = 0.0; inst->VDMOSnVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0 (we have to integrate) */ for (i=0; i < VDMOSNSRCS; i++) { if (i != VDMOSTOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], inst->VDMOSnVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , lnNdens[i] + data->lnGainInv, inst->VDMOSnVar[LNLSTDENS][i] + data->lnGainInv, data); inst->VDMOSnVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { inst->VDMOSnVar[OUTNOIZ][i] += tempOnoise; inst->VDMOSnVar[OUTNOIZ][VDMOSTOTNOIZ] += tempOnoise; inst->VDMOSnVar[INNOIZ][i] += tempInoise; inst->VDMOSnVar[INNOIZ][VDMOSTOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i=0; i < VDMOSNSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i=0; i < VDMOSNSRCS; i++) { data->outpVector[data->outNumber++] = inst->VDMOSnVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = inst->VDMOSnVar[INNOIZ][i]; } } /* if */ break; } /* switch (mode) */ break; case N_CLOSE: return (OK); /* do nothing, the main calling routine will close */ break; /* the plots */ } /* switch (operation) */ } /* for inst */ } /* for model */ return(OK); }
int MESnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; MESmodel *firstModel = (MESmodel *) genmodel; MESmodel *model; MESinstance *inst; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[MESNSRCS]; double lnNdens[MESNSRCS]; int i; /* define the names of the noise sources */ static char *MESnNames[MESNSRCS] = { /* Note that we have to keep the order */ "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ "_rs", /* noise due to rs */ /* in MESdefs.h */ "_id", /* noise due to id */ "_1overf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for (model=firstModel; model != NULL; model=model->MESnextModel) { for (inst=model->MESinstances; inst != NULL; inst=inst->MESnextInstance) { switch (operation) { case N_OPEN: /* see if we have to to produce a summary report */ /* if so, name all the noise generators */ if (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i=0; i < MESNSRCS; i++) { (void)sprintf(name,"onoise_%s%s",inst->MESname,MESnNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; case INT_NOIZ: for (i=0; i < MESNSRCS; i++) { (void)sprintf(name,"onoise_total_%s%s",inst->MESname,MESnNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ (void)sprintf(name,"inoise_total_%s%s",inst->MESname,MESnNames[i]); /* OUTname(name,SV_INPUT_NOISE_V_SQ); data->numPlots += 2; */ data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; } } break; case N_CALC: switch (mode) { case N_DENS: NevalSrc(&noizDens[MESRDNOIZ],&lnNdens[MESRDNOIZ], ckt,THERMNOISE,inst->MESdrainPrimeNode,inst->MESdrainNode, model->MESdrainConduct * inst->MESarea * inst->MESm); NevalSrc(&noizDens[MESRSNOIZ],&lnNdens[MESRSNOIZ], ckt,THERMNOISE,inst->MESsourcePrimeNode,inst->MESsourceNode, model->MESsourceConduct * inst->MESarea * inst->MESm); NevalSrc(&noizDens[MESIDNOIZ],&lnNdens[MESIDNOIZ], ckt,THERMNOISE,inst->MESdrainPrimeNode, inst->MESsourcePrimeNode, (2.0/3.0 * inst->MESm * fabs(*(ckt->CKTstate0 + inst->MESgm)))); NevalSrc(&noizDens[MESFLNOIZ], NULL, ckt, N_GAIN,inst->MESdrainPrimeNode, inst->MESsourcePrimeNode, (double)0.0); noizDens[MESFLNOIZ] *= inst->MESm * model->MESfNcoef * exp(model->MESfNexp * log(MAX(fabs(*(ckt->CKTstate0 + inst->MEScd)),N_MINLOG))) / data->freq; lnNdens[MESFLNOIZ] = log(MAX(noizDens[MESFLNOIZ],N_MINLOG)); noizDens[MESTOTNOIZ] = noizDens[MESRDNOIZ] + noizDens[MESRSNOIZ] + noizDens[MESIDNOIZ] + noizDens[MESFLNOIZ]; lnNdens[MESTOTNOIZ] = log(MAX(noizDens[MESTOTNOIZ], N_MINLOG)); *OnDens += noizDens[MESTOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ for (i=0; i < MESNSRCS; i++) { inst->MESnVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i=0; i < MESNSRCS; i++) { inst->MESnVar[OUTNOIZ][i] = 0.0; inst->MESnVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0 (we have to integrate) */ for (i=0; i < MESNSRCS; i++) { if (i != MESTOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], inst->MESnVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , lnNdens[i] + data->lnGainInv, inst->MESnVar[LNLSTDENS][i] + data->lnGainInv, data); inst->MESnVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { inst->MESnVar[OUTNOIZ][i] += tempOnoise; inst->MESnVar[OUTNOIZ][MESTOTNOIZ] += tempOnoise; inst->MESnVar[INNOIZ][i] += tempInoise; inst->MESnVar[INNOIZ][MESTOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i=0; i < MESNSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i=0; i < MESNSRCS; i++) { data->outpVector[data->outNumber++] = inst->MESnVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = inst->MESnVar[INNOIZ][i]; } } /* if */ break; } /* switch (mode) */ break; case N_CLOSE: return (OK); /* do nothing, the main calling routine will close */ break; /* the plots */ } /* switch (operation) */ } /* for inst */ } /* for model */ return(OK); }
int HSM2noise ( int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, Ndata *data, double *OnDens) { HSM2model *model = (HSM2model *)inModel; HSM2instance *here; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[HSM2NSRCS]; double lnNdens[HSM2NSRCS]; int i; double G = 0.0 ; double TTEMP = 0.0 ; /* for induced gate noise calculation: */ double omega = ckt->CKTomega; double sid, ci, sigrat, Qdrat; double realXds, imagXds, realXgs, imagXgs ; /* define the names of the noise sources */ static char * HSM2nNames[HSM2NSRCS] = { /* Note that we have to keep the order consistent with the index definitions in hsm2defs.h */ ".rd", /* noise due to rd */ ".rs", /* noise due to rs */ ".id", /* noise due to id */ ".1ovf", /* flicker (1/f) noise */ ".igs", /* shot noise due to Igs */ ".igd", /* shot noise due to Igd */ ".igb", /* shot noise due to Igb */ ".ign", /* induced gate noise component at the drain node */ "" /* total transistor noise */ }; for ( ;model != NULL; model = model->HSM2nextModel ) { for ( here = model->HSM2instances; here != NULL; here = here->HSM2nextInstance ) { 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 < HSM2NSRCS; i++ ) { (void) sprintf(name, "onoise.%s%s", (char *)here->HSM2name, HSM2nNames[i]); data->namelist = (IFuid *) trealloc((char *) data->namelist, ((long unsigned int)data->numPlots + 1) * sizeof(IFuid)); if (!data->namelist) return(E_NOMEM); (*(SPfrontEnd->IFnewUid)) (ckt, &(data->namelist[data->numPlots++]), (IFuid) NULL, name, UID_OTHER, NULL); } break; case INT_NOIZ: for ( i = 0; i < HSM2NSRCS; i++ ) { (void) sprintf(name, "onoise_total.%s%s", (char *)here->HSM2name, HSM2nNames[i]); data->namelist = (IFuid *) trealloc((char *) data->namelist, ((long unsigned int)data->numPlots + 1) * sizeof(IFuid)); if (!data->namelist) return(E_NOMEM); (*(SPfrontEnd->IFnewUid)) (ckt, &(data->namelist[data->numPlots++]), (IFuid) NULL, name, UID_OTHER, NULL); (void) sprintf(name, "inoise_total.%s%s", (char *)here->HSM2name, HSM2nNames[i]); data->namelist = (IFuid *) trealloc((char *) data->namelist, ((long unsigned int)data->numPlots + 1) * sizeof(IFuid)); if (!data->namelist) return(E_NOMEM); (*(SPfrontEnd->IFnewUid)) (ckt, &(data->namelist[data->numPlots++]), (IFuid) NULL, name, UID_OTHER, NULL); } break; } } break; case N_CALC: switch (mode) { case N_DENS: /* temperature */ TTEMP = ckt->CKTtemp ; if ( here->HSM2_temp_Given ) TTEMP = here->HSM2_ktemp ; if ( here->HSM2_dtemp_Given ) { TTEMP = TTEMP + here->HSM2_dtemp ; } /* rs/rd thermal noise */ if ( model->HSM2_corsrd < 0 ) { NevalSrc(&noizDens[HSM2RDNOIZ], (double*) NULL, ckt, N_GAIN, here->HSM2dNodePrime, here->HSM2dNode, (double) 0.0); noizDens[HSM2RDNOIZ] *= 4 * CONSTboltz * TTEMP * here->HSM2drainConductance ; lnNdens[HSM2RDNOIZ] = log( MAX(noizDens[HSM2RDNOIZ],N_MINLOG) ) ; NevalSrc(&noizDens[HSM2RSNOIZ], (double*) NULL, ckt, N_GAIN, here->HSM2sNodePrime, here->HSM2sNode, (double) 0.0); noizDens[HSM2RSNOIZ] *= 4 * CONSTboltz * TTEMP * here->HSM2sourceConductance ; lnNdens[HSM2RSNOIZ] = log( MAX(noizDens[HSM2RSNOIZ],N_MINLOG) ) ; /* NevalSrc(&noizDens[HSM2RDNOIZ], &lnNdens[HSM2RDNOIZ], ckt, THERMNOISE, here->HSM2dNodePrime, here->HSM2dNode, here->HSM2_weff / model->HSM2_rsh); NevalSrc(&noizDens[HSM2RSNOIZ], &lnNdens[HSM2RSNOIZ], ckt, THERMNOISE, here->HSM2sNodePrime, here->HSM2sNode, here->HSM2_weff / model->HSM2_rsh); */ } else { noizDens[HSM2RDNOIZ] = 0e0 ; lnNdens[HSM2RDNOIZ] = N_MINLOG ; noizDens[HSM2RSNOIZ] = 0e0 ; lnNdens[HSM2RSNOIZ] = N_MINLOG ; } /* channel thermal noise */ switch( model->HSM2_noise ) { case 1: /* HiSIM2 model */ if ( model->HSM2_corsrd <= 0 || here->HSM2internalGd <= 0.0 ) { G = here->HSM2_noithrml ; } else { if ( here->HSM2_noithrml * here->HSM2internalGd * here->HSM2internalGs > 0.0 ) { G = here->HSM2_noithrml * here->HSM2internalGd * here->HSM2internalGs / ( here->HSM2_noithrml * here->HSM2internalGd + here->HSM2internalGd * here->HSM2internalGs + here->HSM2_noithrml * here->HSM2internalGs ); } else { G = 0.0; } } NevalSrc(&noizDens[HSM2IDNOIZ], (double*) NULL, ckt, N_GAIN, here->HSM2dNodePrime, here->HSM2sNodePrime, (double) 0.0); noizDens[HSM2IDNOIZ] *= 4 * CONSTboltz * TTEMP * G ; lnNdens[HSM2IDNOIZ] = log( MAX(noizDens[HSM2IDNOIZ],N_MINLOG) ); break; } /* flicker noise */ NevalSrc(&noizDens[HSM2FLNOIZ], (double*) NULL, ckt, N_GAIN, here->HSM2dNodePrime, here->HSM2sNodePrime, (double) 0.0); switch ( model->HSM2_noise ) { case 1: /* HiSIM model */ noizDens[HSM2FLNOIZ] *= here->HSM2_noiflick / pow(data->freq, model->HSM2_falph) ; break; } lnNdens[HSM2FLNOIZ] = log(MAX(noizDens[HSM2FLNOIZ], N_MINLOG)); /* shot noise */ NevalSrc(&noizDens[HSM2IGSNOIZ], &lnNdens[HSM2IGSNOIZ], ckt, SHOTNOISE, here->HSM2gNodePrime, here->HSM2sNodePrime, here->HSM2_igs); NevalSrc(&noizDens[HSM2IGDNOIZ], &lnNdens[HSM2IGDNOIZ], ckt, SHOTNOISE, here->HSM2gNodePrime, here->HSM2dNodePrime, here->HSM2_igd); NevalSrc(&noizDens[HSM2IGBNOIZ], &lnNdens[HSM2IGBNOIZ], ckt, SHOTNOISE, here->HSM2gNodePrime, here->HSM2bNodePrime, here->HSM2_igb); /* induced gate noise */ switch ( model->HSM2_noise ) { case 1: /* HiSIM model */ sid = 4.0 * CONSTboltz * TTEMP * here->HSM2_noithrml ; ci = here->HSM2_noicross ; sigrat = (sid > 0.0 && here->HSM2_noiigate > 0.0) ? sqrt(here->HSM2_noiigate/sid) : 0.0 ; Qdrat = here->HSM2_Qdrat ; realXds = *(ckt->CKTrhs +here->HSM2dNodePrime) - *(ckt->CKTrhs +here->HSM2sNodePrime); imagXds = *(ckt->CKTirhs+here->HSM2dNodePrime) - *(ckt->CKTirhs+here->HSM2sNodePrime); realXgs = *(ckt->CKTrhs +here->HSM2gNodePrime) - *(ckt->CKTrhs +here->HSM2sNodePrime); imagXgs = *(ckt->CKTirhs+here->HSM2gNodePrime) - *(ckt->CKTirhs+here->HSM2sNodePrime); noizDens[HSM2IGNOIZ] = 2.0 * omega * ci * sigrat * sid * ( realXgs*imagXds - realXds*imagXgs ) + omega*omega * sigrat*sigrat * sid * ( (realXgs-Qdrat*realXds) * (realXgs-Qdrat*realXds) +(imagXgs-Qdrat*imagXds) * (imagXgs-Qdrat*imagXds) ) ; lnNdens[HSM2IGNOIZ] = log(MAX(noizDens[HSM2IGNOIZ], N_MINLOG)); break; } /* total */ noizDens[HSM2TOTNOIZ] = noizDens[HSM2RDNOIZ] + noizDens[HSM2RSNOIZ] + noizDens[HSM2IDNOIZ] + noizDens[HSM2FLNOIZ] + noizDens[HSM2IGSNOIZ] + noizDens[HSM2IGDNOIZ] + noizDens[HSM2IGBNOIZ] + noizDens[HSM2IGNOIZ]; lnNdens[HSM2TOTNOIZ] = log(MAX(noizDens[HSM2TOTNOIZ], N_MINLOG)); /* printf("f %e Sid %.16e Srd %.16e Srs %.16e Sflick %.16e Stherm %.16e Sign %.16e\n", */ /* data->freq,noizDens[HSM2TOTNOIZ],noizDens[HSM2RDNOIZ],noizDens[HSM2RSNOIZ],noizDens[HSM2FLNOIZ],noizDens[HSM2IDNOIZ],noizDens[HSM2IGNOIZ]); */ *OnDens += noizDens[HSM2TOTNOIZ]; if ( data->delFreq == 0.0 ) { /* if we haven't done any previous integration, we need to initialize our "history" variables. */ for ( i = 0; i < HSM2NSRCS; i++ ) here->HSM2nVar[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 < HSM2NSRCS; i++) { here->HSM2nVar[OUTNOIZ][i] = 0.0; here->HSM2nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0, we have to integrate. */ for ( i = 0; i < HSM2NSRCS; i++ ) { if ( i != HSM2TOTNOIZ ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], here->HSM2nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv, lnNdens[i] + data->lnGainInv, here->HSM2nVar[LNLSTDENS][i] + data->lnGainInv, data); here->HSM2nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if ( ((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0 ) { here->HSM2nVar[OUTNOIZ][i] += tempOnoise; here->HSM2nVar[OUTNOIZ][HSM2TOTNOIZ] += tempOnoise; here->HSM2nVar[INNOIZ][i] += tempInoise; here->HSM2nVar[INNOIZ][HSM2TOTNOIZ] += tempInoise; } } } } if ( data->prtSummary ) { for (i = 0; i < HSM2NSRCS; 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 < HSM2NSRCS; i++ ) { data->outpVector[data->outNumber++] = here->HSM2nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = here->HSM2nVar[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); }
int HSM1noise (int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, register Ndata *data, double *OnDens) { register HSM1model *model = (HSM1model *)inModel; register HSM1instance *here; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[HSM1NSRCS]; double lnNdens[HSM1NSRCS]; register int i; /* define the names of the noise sources */ static char * HSM1nNames[HSM1NSRCS] = { /* Note that we have to keep the order consistent with the index definitions in hsm1defs.h */ ".rd", /* noise due to rd */ ".rs", /* noise due to rs */ ".id", /* noise due to id */ ".1ovf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for ( ;model != NULL; model = model->HSM1nextModel ) { for ( here = model->HSM1instances; here != NULL; here = here->HSM1nextInstance ) { if (here->HSM1owner != ARCHme) continue; 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 < HSM1NSRCS; i++ ) { (void) sprintf(name, "onoise.%s%s", (char *)here->HSM1name, HSM1nNames[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); } break; case INT_NOIZ: for ( i = 0; i < HSM1NSRCS; i++ ) { (void) sprintf(name, "onoise_total.%s%s", (char *)here->HSM1name, HSM1nNames[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); (void) sprintf(name, "inoise_total.%s%s", (char *)here->HSM1name, HSM1nNames[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); } break; } } break; case N_CALC: switch (mode) { case N_DENS: NevalSrc(&noizDens[HSM1RDNOIZ], &lnNdens[HSM1RDNOIZ], ckt, THERMNOISE, here->HSM1dNodePrime, here->HSM1dNode, here->HSM1drainConductance * here->HSM1_m); NevalSrc(&noizDens[HSM1RSNOIZ], &lnNdens[HSM1RSNOIZ], ckt, THERMNOISE, here->HSM1sNodePrime, here->HSM1sNode, here->HSM1sourceConductance * here->HSM1_m); switch( model->HSM1_noise ) { double I; case 1: case 3: I = here->HSM1_gm + here->HSM1_gds + here->HSM1_gmbs; I *= (I < 0.0) ? -1.0 : 1.0; I *= 2.0/3.0; I *= here->HSM1_m; /* PN */ NevalSrc(&noizDens[HSM1IDNOIZ], &lnNdens[HSM1IDNOIZ], ckt, THERMNOISE, here->HSM1dNodePrime, here->HSM1sNodePrime, I); break; case 2: case 4: I = -1.0 * (here->HSM1_qg + here->HSM1_qb) / (here->HSM1_weff * here->HSM1_leff); I *= (I < 0.0) ? -1.0 : 1.0; I *= here->HSM1_mu; I *= here->HSM1_m; /* PN */ NevalSrc(&noizDens[HSM1IDNOIZ], &lnNdens[HSM1IDNOIZ], ckt, THERMNOISE, here->HSM1dNodePrime, here->HSM1sNodePrime, I); break; case 5: NevalSrc(&noizDens[HSM1IDNOIZ], &lnNdens[HSM1IDNOIZ], ckt, THERMNOISE, here->HSM1dNodePrime, here->HSM1sNodePrime, 0.0); break; } NevalSrc(&noizDens[HSM1FLNOIZ], (double*) NULL, ckt, N_GAIN, here->HSM1dNodePrime, here->HSM1sNodePrime, (double) 0.0); /* flicker noise */ switch ( model->HSM1_noise ) { case 1: case 4: /* SPICE2 model */ noizDens[HSM1FLNOIZ] *= here->HSM1_m * model->HSM1_kf * exp(model->HSM1_af * log(MAX(fabs(here->HSM1_ids), N_MINLOG))) / (pow(data->freq, model->HSM1_ef) * here->HSM1_leff * here->HSM1_leff * (3.453133e-11 / model->HSM1_tox)); /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cox */ break; case 2: case 3: case 5: /* from HiSIM */ noizDens[HSM1FLNOIZ] *= here->HSM1_nfc / data->freq; break; } lnNdens[HSM1FLNOIZ] = log(MAX(noizDens[HSM1FLNOIZ], N_MINLOG)); noizDens[HSM1TOTNOIZ] = noizDens[HSM1RDNOIZ] + noizDens[HSM1RSNOIZ] + noizDens[HSM1IDNOIZ] + noizDens[HSM1FLNOIZ]; lnNdens[HSM1TOTNOIZ] = log(MAX(noizDens[HSM1TOTNOIZ], N_MINLOG)); *OnDens += noizDens[HSM1TOTNOIZ]; if ( data->delFreq == 0.0 ) { /* if we haven't done any previous integration, we need to initialize our "history" variables. */ for ( i = 0; i < HSM1NSRCS; i++ ) here->HSM1nVar[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 < HSM1NSRCS; i++) { here->HSM1nVar[OUTNOIZ][i] = 0.0; here->HSM1nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0, we have to integrate. */ for ( i = 0; i < HSM1NSRCS; i++ ) { if ( i != HSM1TOTNOIZ ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], here->HSM1nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv, lnNdens[i] + data->lnGainInv, here->HSM1nVar[LNLSTDENS][i] + data->lnGainInv, data); here->HSM1nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if ( ((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0 ) { here->HSM1nVar[OUTNOIZ][i] += tempOnoise; here->HSM1nVar[OUTNOIZ][HSM1TOTNOIZ] += tempOnoise; here->HSM1nVar[INNOIZ][i] += tempInoise; here->HSM1nVar[INNOIZ][HSM1TOTNOIZ] += tempInoise; } } } } if ( data->prtSummary ) { for (i = 0; i < HSM1NSRCS; 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 < HSM1NSRCS; i++ ) { data->outpVector[data->outNumber++] = here->HSM1nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = here->HSM1nVar[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); }
int SWnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; SWmodel *firstModel = (SWmodel *) genmodel; SWmodel *model; SWinstance *inst; double tempOutNoise; double tempInNoise; double noizDens; double lnNdens; int current_state; for (model = firstModel; model; model = SWnextModel(model)) for (inst = SWinstances(model); inst; inst = SWnextInstance(inst)) { switch (operation) { case N_OPEN: /* see if we have to to produce a summary report */ /* if so, name the noise generator */ if (job->NStpsSm != 0) switch (mode) { case N_DENS: NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->SWname, ""); break; case INT_NOIZ: NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->SWname, ""); NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->SWname, ""); break; } break; case N_CALC: switch (mode) { case N_DENS: current_state = (int) ckt->CKTstate0[inst->SWswitchstate]; NevalSrc(&noizDens, &lnNdens, ckt, THERMNOISE, inst->SWposNode, inst->SWnegNode, current_state ? model->SWonConduct : model->SWoffConduct); *OnDens += noizDens; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ inst->SWnVar[LNLSTDENS] = lnNdens; /* clear out our integration variable if it's the first pass */ if (data->freq == job->NstartFreq) inst->SWnVar[OUTNOIZ] = 0.0; } else { /* data->delFreq != 0.0 (we have to integrate) */ tempOutNoise = Nintegrate(noizDens, lnNdens, inst->SWnVar[LNLSTDENS], data); tempInNoise = Nintegrate(noizDens * data->GainSqInv, lnNdens + data->lnGainInv, inst->SWnVar[LNLSTDENS] + data->lnGainInv, data); inst->SWnVar[OUTNOIZ] += tempOutNoise; inst->SWnVar[INNOIZ] += tempInNoise; data->outNoiz += tempOutNoise; data->inNoise += tempInNoise; inst->SWnVar[LNLSTDENS] = lnNdens; } if (data->prtSummary) data->outpVector[data->outNumber++] = noizDens; break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { data->outpVector[data->outNumber++] = inst->SWnVar[OUTNOIZ]; data->outpVector[data->outNumber++] = inst->SWnVar[INNOIZ]; } break; } break; case N_CLOSE: return OK; /* do nothing, the main calling routine will close */ break; /* the plots */ } } return OK; }
int JFETnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; JFETmodel *firstModel = (JFETmodel *) genmodel; JFETmodel *model; JFETinstance *inst; double tempOnoise; double tempInoise; double noizDens[JFETNSRCS]; double lnNdens[JFETNSRCS]; int i; double vgs, vds, vgst, alpha, beta; /* define the names of the noise sources */ static char *JFETnNames[JFETNSRCS] = { /* Note that we have to keep the order */ "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ "_rs", /* noise due to rs */ /* in JFETdefs.h */ "_id", /* noise due to id */ "_1overf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for (model=firstModel; model != NULL; model=JFETnextModel(model)) { for (inst=JFETinstances(model); inst != NULL; inst=JFETnextInstance(inst)) { switch (operation) { case N_OPEN: /* see if we have to to produce a summary report */ /* if so, name all the noise generators */ if (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i=0; i < JFETNSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->JFETname, JFETnNames[i]); } break; case INT_NOIZ: for (i=0; i < JFETNSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->JFETname, JFETnNames[i]); NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->JFETname, JFETnNames[i]); } break; } } break; case N_CALC: switch (mode) { case N_DENS: NevalSrc(&noizDens[JFETRDNOIZ],&lnNdens[JFETRDNOIZ], ckt,THERMNOISE,inst->JFETdrainPrimeNode,inst->JFETdrainNode, model->JFETdrainConduct * inst->JFETarea * inst->JFETm); NevalSrc(&noizDens[JFETRSNOIZ],&lnNdens[JFETRSNOIZ], ckt,THERMNOISE,inst->JFETsourcePrimeNode, inst->JFETsourceNode,model->JFETsourceConduct * inst->JFETarea * inst->JFETm); if (model->JFETnlev < 3) { NevalSrc(&noizDens[JFETIDNOIZ],&lnNdens[JFETIDNOIZ], ckt,THERMNOISE,inst->JFETdrainPrimeNode, inst->JFETsourcePrimeNode, (2.0/3.0 * inst->JFETm * fabs(*(ckt->CKTstate0 + inst->JFETgm)))); } else { vgs = *(ckt->CKTstate0 + inst->JFETvgs); vds = vgs - *(ckt->CKTstate0 + inst->JFETvgd); vgst = vgs - inst->JFETtThreshold; if (vgst >= vds) alpha = 1 - vds/vgst; /* linear region */ else alpha = 0; /* saturation region */ beta = inst->JFETtBeta * inst->JFETarea * inst->JFETm; NevalSrc(&noizDens[JFETIDNOIZ],&lnNdens[JFETIDNOIZ], ckt,THERMNOISE,inst->JFETdrainPrimeNode, inst->JFETsourcePrimeNode, (2.0/3.0 * beta*vgst*(1+alpha+alpha*alpha)/(1+alpha)*model->JFETgdsnoi)); } NevalSrc(&noizDens[JFETFLNOIZ], NULL, ckt, N_GAIN,inst->JFETdrainPrimeNode, inst->JFETsourcePrimeNode, (double)0.0); noizDens[JFETFLNOIZ] *= inst->JFETm * model->JFETfNcoef * exp(model->JFETfNexp * log(MAX(fabs(*(ckt->CKTstate0 + inst->JFETcd)),N_MINLOG))) / data->freq; lnNdens[JFETFLNOIZ] = log(MAX(noizDens[JFETFLNOIZ],N_MINLOG)); noizDens[JFETTOTNOIZ] = noizDens[JFETRDNOIZ] + noizDens[JFETRSNOIZ] + noizDens[JFETIDNOIZ] + noizDens[JFETFLNOIZ]; lnNdens[JFETTOTNOIZ] = log(MAX(noizDens[JFETTOTNOIZ], N_MINLOG)); *OnDens += noizDens[JFETTOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ for (i=0; i < JFETNSRCS; i++) { inst->JFETnVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i=0; i < JFETNSRCS; i++) { inst->JFETnVar[OUTNOIZ][i] = 0.0; inst->JFETnVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0 (we have to integrate) */ for (i=0; i < JFETNSRCS; i++) { if (i != JFETTOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], inst->JFETnVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , lnNdens[i] + data->lnGainInv, inst->JFETnVar[LNLSTDENS][i] + data->lnGainInv, data); inst->JFETnVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { inst->JFETnVar[OUTNOIZ][i] += tempOnoise; inst->JFETnVar[OUTNOIZ][JFETTOTNOIZ] += tempOnoise; inst->JFETnVar[INNOIZ][i] += tempInoise; inst->JFETnVar[INNOIZ][JFETTOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i=0; i < JFETNSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i=0; i < JFETNSRCS; i++) { data->outpVector[data->outNumber++] = inst->JFETnVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = inst->JFETnVar[INNOIZ][i]; } } /* if */ break; } /* switch (mode) */ break; case N_CLOSE: return (OK); /* do nothing, the main calling routine will close */ break; /* the plots */ } /* switch (operation) */ } /* for inst */ } /* for model */ return(OK); }
int BSIM4v5noise ( int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; BSIM4v5model *model = (BSIM4v5model *)inModel; BSIM4v5instance *here; struct bsim4v5SizeDependParam *pParam; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[BSIM4v5NSRCS]; double lnNdens[BSIM4v5NSRCS]; 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 *BSIM4v5nNames[BSIM4v5NSRCS] = { /* 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->BSIM4v5nextModel) { for (here = model->BSIM4v5instances; here != NULL; here = here->BSIM4v5nextInstance) { 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 (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i = 0; i < BSIM4v5NSRCS; i++) { (void) sprintf(name, "onoise.%s%s", here->BSIM4v5name, BSIM4v5nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; case INT_NOIZ: for (i = 0; i < BSIM4v5NSRCS; i++) { (void) sprintf(name, "onoise_total.%s%s", here->BSIM4v5name, BSIM4v5nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ (void) sprintf(name, "inoise_total.%s%s", here->BSIM4v5name, BSIM4v5nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; } } break; case N_CALC: m = here->BSIM4v5m; switch (mode) { case N_DENS: if (model->BSIM4v5tnoiMod == 0) { if (model->BSIM4v5rdsMod == 0) { gspr = here->BSIM4v5sourceConductance; gdpr = here->BSIM4v5drainConductance; if (here->BSIM4v5grdsw > 0.0) tmp = 1.0 / here->BSIM4v5grdsw; /* tmp used below */ else tmp = 0.0; } else { gspr = here->BSIM4v5gstot; gdpr = here->BSIM4v5gdtot; tmp = 0.0; } } else { T5 = here->BSIM4v5Vgsteff / here->BSIM4v5EsatL; T5 *= T5; npart_beta = model->BSIM4v5rnoia * (1.0 + T5 * model->BSIM4v5tnoia * pParam->BSIM4v5leff); npart_theta = model->BSIM4v5rnoib * (1.0 + T5 * model->BSIM4v5tnoib * pParam->BSIM4v5leff); if (model->BSIM4v5rdsMod == 0) { gspr = here->BSIM4v5sourceConductance; gdpr = here->BSIM4v5drainConductance; } else { gspr = here->BSIM4v5gstot; gdpr = here->BSIM4v5gdtot; } if ((*(ckt->CKTstates[0] + here->BSIM4v5vds)) >= 0.0) gspr = gspr / (1.0 + npart_theta * npart_theta * gspr / here->BSIM4v5IdovVds); /* bugfix */ else gdpr = gdpr / (1.0 + npart_theta * npart_theta * gdpr / here->BSIM4v5IdovVds); } NevalSrc(&noizDens[BSIM4v5RDNOIZ], &lnNdens[BSIM4v5RDNOIZ], ckt, THERMNOISE, here->BSIM4v5dNodePrime, here->BSIM4v5dNode, gdpr * m); NevalSrc(&noizDens[BSIM4v5RSNOIZ], &lnNdens[BSIM4v5RSNOIZ], ckt, THERMNOISE, here->BSIM4v5sNodePrime, here->BSIM4v5sNode, gspr * m); if ((here->BSIM4v5rgateMod == 1) || (here->BSIM4v5rgateMod == 2)) { NevalSrc(&noizDens[BSIM4v5RGNOIZ], &lnNdens[BSIM4v5RGNOIZ], ckt, THERMNOISE, here->BSIM4v5gNodePrime, here->BSIM4v5gNodeExt, here->BSIM4v5grgeltd * m); } else if (here->BSIM4v5rgateMod == 3) { NevalSrc(&noizDens[BSIM4v5RGNOIZ], &lnNdens[BSIM4v5RGNOIZ], ckt, THERMNOISE, here->BSIM4v5gNodeMid, here->BSIM4v5gNodeExt, here->BSIM4v5grgeltd * m); } else { noizDens[BSIM4v5RGNOIZ] = 0.0; lnNdens[BSIM4v5RGNOIZ] = log(MAX(noizDens[BSIM4v5RGNOIZ], N_MINLOG)); } bodymode = 5; if (here->BSIM4v5rbodyMod == 2) { if( ( !model->BSIM4v5rbps0Given) || ( !model->BSIM4v5rbpd0Given) ) bodymode = 1; else if( (!model->BSIM4v5rbsbx0Given && !model->BSIM4v5rbsby0Given) || (!model->BSIM4v5rbdbx0Given && !model->BSIM4v5rbdby0Given) ) bodymode = 3; } if (here->BSIM4v5rbodyMod) { if(bodymode == 5) { NevalSrc(&noizDens[BSIM4v5RBPSNOIZ], &lnNdens[BSIM4v5RBPSNOIZ], ckt, THERMNOISE, here->BSIM4v5bNodePrime, here->BSIM4v5sbNode, here->BSIM4v5grbps * m); NevalSrc(&noizDens[BSIM4v5RBPDNOIZ], &lnNdens[BSIM4v5RBPDNOIZ], ckt, THERMNOISE, here->BSIM4v5bNodePrime, here->BSIM4v5dbNode, here->BSIM4v5grbpd * m); NevalSrc(&noizDens[BSIM4v5RBPBNOIZ], &lnNdens[BSIM4v5RBPBNOIZ], ckt, THERMNOISE, here->BSIM4v5bNodePrime, here->BSIM4v5bNode, here->BSIM4v5grbpb * m); NevalSrc(&noizDens[BSIM4v5RBSBNOIZ], &lnNdens[BSIM4v5RBSBNOIZ], ckt, THERMNOISE, here->BSIM4v5bNode, here->BSIM4v5sbNode, here->BSIM4v5grbsb * m); NevalSrc(&noizDens[BSIM4v5RBDBNOIZ], &lnNdens[BSIM4v5RBDBNOIZ], ckt, THERMNOISE, here->BSIM4v5bNode, here->BSIM4v5dbNode, here->BSIM4v5grbdb * m); } if(bodymode == 3) { NevalSrc(&noizDens[BSIM4v5RBPSNOIZ], &lnNdens[BSIM4v5RBPSNOIZ], ckt, THERMNOISE, here->BSIM4v5bNodePrime, here->BSIM4v5sbNode, here->BSIM4v5grbps * m); NevalSrc(&noizDens[BSIM4v5RBPDNOIZ], &lnNdens[BSIM4v5RBPDNOIZ], ckt, THERMNOISE, here->BSIM4v5bNodePrime, here->BSIM4v5dbNode, here->BSIM4v5grbpd * m); NevalSrc(&noizDens[BSIM4v5RBPBNOIZ], &lnNdens[BSIM4v5RBPBNOIZ], ckt, THERMNOISE, here->BSIM4v5bNodePrime, here->BSIM4v5bNode, here->BSIM4v5grbpb * m); noizDens[BSIM4v5RBSBNOIZ] = noizDens[BSIM4v5RBDBNOIZ] = 0.0; lnNdens[BSIM4v5RBSBNOIZ] = log(MAX(noizDens[BSIM4v5RBSBNOIZ], N_MINLOG)); lnNdens[BSIM4v5RBDBNOIZ] = log(MAX(noizDens[BSIM4v5RBDBNOIZ], N_MINLOG)); } if(bodymode == 1) { NevalSrc(&noizDens[BSIM4v5RBPBNOIZ], &lnNdens[BSIM4v5RBPBNOIZ], ckt, THERMNOISE, here->BSIM4v5bNodePrime, here->BSIM4v5bNode, here->BSIM4v5grbpb * m); noizDens[BSIM4v5RBPSNOIZ] = noizDens[BSIM4v5RBPDNOIZ] = 0.0; noizDens[BSIM4v5RBSBNOIZ] = noizDens[BSIM4v5RBDBNOIZ] = 0.0; lnNdens[BSIM4v5RBPSNOIZ] = log(MAX(noizDens[BSIM4v5RBPSNOIZ], N_MINLOG)); lnNdens[BSIM4v5RBPDNOIZ] = log(MAX(noizDens[BSIM4v5RBPDNOIZ], N_MINLOG)); lnNdens[BSIM4v5RBSBNOIZ] = log(MAX(noizDens[BSIM4v5RBSBNOIZ], N_MINLOG)); lnNdens[BSIM4v5RBDBNOIZ] = log(MAX(noizDens[BSIM4v5RBDBNOIZ], N_MINLOG)); } } else { noizDens[BSIM4v5RBPSNOIZ] = noizDens[BSIM4v5RBPDNOIZ] = 0.0; noizDens[BSIM4v5RBPBNOIZ] = 0.0; noizDens[BSIM4v5RBSBNOIZ] = noizDens[BSIM4v5RBDBNOIZ] = 0.0; lnNdens[BSIM4v5RBPSNOIZ] = log(MAX(noizDens[BSIM4v5RBPSNOIZ], N_MINLOG)); lnNdens[BSIM4v5RBPDNOIZ] = log(MAX(noizDens[BSIM4v5RBPDNOIZ], N_MINLOG)); lnNdens[BSIM4v5RBPBNOIZ] = log(MAX(noizDens[BSIM4v5RBPBNOIZ], N_MINLOG)); lnNdens[BSIM4v5RBSBNOIZ] = log(MAX(noizDens[BSIM4v5RBSBNOIZ], N_MINLOG)); lnNdens[BSIM4v5RBDBNOIZ] = log(MAX(noizDens[BSIM4v5RBDBNOIZ], N_MINLOG)); } switch(model->BSIM4v5tnoiMod) { case 0: T0 = here->BSIM4v5ueff * fabs(here->BSIM4v5qinv); T1 = T0 * tmp + pParam->BSIM4v5leff * pParam->BSIM4v5leff; NevalSrc(&noizDens[BSIM4v5IDNOIZ], &lnNdens[BSIM4v5IDNOIZ], ckt, THERMNOISE, here->BSIM4v5dNodePrime, here->BSIM4v5sNodePrime, m * (T0 / T1) * model->BSIM4v5ntnoi); break; case 1: T0 = here->BSIM4v5gm + here->BSIM4v5gmbs + here->BSIM4v5gds; T0 *= T0; igsquare = npart_theta * npart_theta * T0 / here->BSIM4v5IdovVds; T1 = npart_beta * (here->BSIM4v5gm + here->BSIM4v5gmbs) + here->BSIM4v5gds; T2 = T1 * T1 / here->BSIM4v5IdovVds; NevalSrc(&noizDens[BSIM4v5IDNOIZ], &lnNdens[BSIM4v5IDNOIZ], ckt, THERMNOISE, here->BSIM4v5dNodePrime, here->BSIM4v5sNodePrime, m * (T2 - igsquare)); break; } NevalSrc(&noizDens[BSIM4v5FLNOIZ], NULL, ckt, N_GAIN, here->BSIM4v5dNodePrime, here->BSIM4v5sNodePrime, (double) 0.0); switch(model->BSIM4v5fnoiMod) { case 0: noizDens[BSIM4v5FLNOIZ] *= m * model->BSIM4v5kf * exp(model->BSIM4v5af * log(MAX(fabs(here->BSIM4v5cd), N_MINLOG))) / (pow(data->freq, model->BSIM4v5ef) * pParam->BSIM4v5leff * pParam->BSIM4v5leff * model->BSIM4v5coxe); break; case 1: Vds = *(ckt->CKTstates[0] + here->BSIM4v5vds); if (Vds < 0.0) Vds = -Vds; Ssi = BSIM4v5Eval1ovFNoise(Vds, model, here, data->freq, ckt->CKTtemp); T10 = model->BSIM4v5oxideTrapDensityA * CONSTboltz * ckt->CKTtemp; T11 = pParam->BSIM4v5weff * here->BSIM4v5nf * pParam->BSIM4v5leff * pow(data->freq, model->BSIM4v5ef) * 1.0e10 * here->BSIM4v5nstar * here->BSIM4v5nstar; Swi = T10 / T11 * here->BSIM4v5cd * here->BSIM4v5cd; T1 = Swi + Ssi; if (T1 > 0.0) noizDens[BSIM4v5FLNOIZ] *= m * (Ssi * Swi) / T1; else noizDens[BSIM4v5FLNOIZ] *= 0.0; break; } lnNdens[BSIM4v5FLNOIZ] = log(MAX(noizDens[BSIM4v5FLNOIZ], N_MINLOG)); if(here->BSIM4v5mode >= 0) { /* bugfix */ NevalSrc(&noizDens[BSIM4v5IGSNOIZ], &lnNdens[BSIM4v5IGSNOIZ], ckt, SHOTNOISE, here->BSIM4v5gNodePrime, here->BSIM4v5sNodePrime, m * (here->BSIM4v5Igs + here->BSIM4v5Igcs)); NevalSrc(&noizDens[BSIM4v5IGDNOIZ], &lnNdens[BSIM4v5IGDNOIZ], ckt, SHOTNOISE, here->BSIM4v5gNodePrime, here->BSIM4v5dNodePrime, m * (here->BSIM4v5Igd + here->BSIM4v5Igcd)); } else { NevalSrc(&noizDens[BSIM4v5IGSNOIZ], &lnNdens[BSIM4v5IGSNOIZ], ckt, SHOTNOISE, here->BSIM4v5gNodePrime, here->BSIM4v5sNodePrime, m * (here->BSIM4v5Igs + here->BSIM4v5Igcd)); NevalSrc(&noizDens[BSIM4v5IGDNOIZ], &lnNdens[BSIM4v5IGDNOIZ], ckt, SHOTNOISE, here->BSIM4v5gNodePrime, here->BSIM4v5dNodePrime, m * (here->BSIM4v5Igd + here->BSIM4v5Igcs)); } NevalSrc(&noizDens[BSIM4v5IGBNOIZ], &lnNdens[BSIM4v5IGBNOIZ], ckt, SHOTNOISE, here->BSIM4v5gNodePrime, here->BSIM4v5bNodePrime, m * here->BSIM4v5Igb); noizDens[BSIM4v5TOTNOIZ] = noizDens[BSIM4v5RDNOIZ] + noizDens[BSIM4v5RSNOIZ] + noizDens[BSIM4v5RGNOIZ] + noizDens[BSIM4v5RBPSNOIZ] + noizDens[BSIM4v5RBPDNOIZ] + noizDens[BSIM4v5RBPBNOIZ] + noizDens[BSIM4v5RBSBNOIZ] + noizDens[BSIM4v5RBDBNOIZ] + noizDens[BSIM4v5IDNOIZ] + noizDens[BSIM4v5FLNOIZ] + noizDens[BSIM4v5IGSNOIZ] + noizDens[BSIM4v5IGDNOIZ] + noizDens[BSIM4v5IGBNOIZ]; lnNdens[BSIM4v5TOTNOIZ] = log(MAX(noizDens[BSIM4v5TOTNOIZ], N_MINLOG)); *OnDens += noizDens[BSIM4v5TOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to initialize our "history" variables. */ for (i = 0; i < BSIM4v5NSRCS; i++) { here->BSIM4v5nVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i = 0; i < BSIM4v5NSRCS; i++) { here->BSIM4v5nVar[OUTNOIZ][i] = 0.0; here->BSIM4v5nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0, we have to integrate. */ for (i = 0; i < BSIM4v5NSRCS; i++) { if (i != BSIM4v5TOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], here->BSIM4v5nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv, lnNdens[i] + data->lnGainInv, here->BSIM4v5nVar[LNLSTDENS][i] + data->lnGainInv, data); here->BSIM4v5nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { here->BSIM4v5nVar[OUTNOIZ][i] += tempOnoise; here->BSIM4v5nVar[OUTNOIZ][BSIM4v5TOTNOIZ] += tempOnoise; here->BSIM4v5nVar[INNOIZ][i] += tempInoise; here->BSIM4v5nVar[INNOIZ][BSIM4v5TOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i = 0; i < BSIM4v5NSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i = 0; i < BSIM4v5NSRCS; i++) { data->outpVector[data->outNumber++] = here->BSIM4v5nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = here->BSIM4v5nVar[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); }
int BSIM3v0noise (int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, Ndata *data, double *OnDens) { BSIM3v0model *model = (BSIM3v0model *)inModel; BSIM3v0instance *here; struct bsim3v0SizeDependParam *pParam; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[BSIM3v0NSRCS]; double lnNdens[BSIM3v0NSRCS]; double vgs, vds, Slimit; double T1, T10, T11; double Ssi, Swi; int i; /* define the names of the noise sources */ static char *BSIM3v0nNames[BSIM3v0NSRCS] = { /* Note that we have to keep the order */ ".rd", /* noise due to rd */ /* consistent with the index definitions */ ".rs", /* noise due to rs */ /* in BSIM3v0defs.h */ ".id", /* noise due to id */ ".1overf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for (; model != NULL; model = model->BSIM3v0nextModel) { for (here = model->BSIM3v0instances; here != NULL; here = here->BSIM3v0nextInstance) { if (here->BSIM3v0owner != ARCHme) continue; 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 < BSIM3v0NSRCS; i++) { (void) sprintf(name, "onoise.%s%s", here->BSIM3v0name, BSIM3v0nNames[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 < BSIM3v0NSRCS; i++) { (void) sprintf(name, "onoise_total.%s%s", here->BSIM3v0name, BSIM3v0nNames[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->BSIM3v0name, BSIM3v0nNames[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: switch (mode) { case N_DENS: NevalSrc(&noizDens[BSIM3v0RDNOIZ], &lnNdens[BSIM3v0RDNOIZ], ckt, THERMNOISE, here->BSIM3v0dNodePrime, here->BSIM3v0dNode, here->BSIM3v0drainConductance * here->BSIM3v0m); NevalSrc(&noizDens[BSIM3v0RSNOIZ], &lnNdens[BSIM3v0RSNOIZ], ckt, THERMNOISE, here->BSIM3v0sNodePrime, here->BSIM3v0sNode, here->BSIM3v0sourceConductance * here->BSIM3v0m); if (model->BSIM3v0noiMod == 2) { NevalSrc(&noizDens[BSIM3v0IDNOIZ], &lnNdens[BSIM3v0IDNOIZ], ckt, THERMNOISE, here->BSIM3v0dNodePrime, here->BSIM3v0sNodePrime, (here->BSIM3v0ueff * fabs((here->BSIM3v0qinv * here->BSIM3v0m) / (pParam->BSIM3v0leff * pParam->BSIM3v0leff)))); } else { NevalSrc(&noizDens[BSIM3v0IDNOIZ], &lnNdens[BSIM3v0IDNOIZ], ckt, THERMNOISE, here->BSIM3v0dNodePrime, here->BSIM3v0sNodePrime, (2.0 / 3.0 * fabs(here->BSIM3v0gm + here->BSIM3v0gds) * here->BSIM3v0m)); } NevalSrc(&noizDens[BSIM3v0FLNOIZ], (double*) NULL, ckt, N_GAIN, here->BSIM3v0dNodePrime, here->BSIM3v0sNodePrime, (double) 0.0); if (model->BSIM3v0noiMod == 2) { vgs = *(ckt->CKTstates[0] + here->BSIM3v0vgs); vds = *(ckt->CKTstates[0] + here->BSIM3v0vds); if (vds < 0.0) { vds = -vds; vgs = vgs + vds; } if (vgs >= here->BSIM3v0von + 0.1) { Ssi = StrongInversionNoiseEval(vgs, vds, model, here, data->freq, ckt->CKTtemp); noizDens[BSIM3v0FLNOIZ] *= Ssi; } else { pParam = here->pParam; T10 = model->BSIM3v0oxideTrapDensityA * 8.62e-5 * (ckt->CKTtemp + CONSTCtoK); T11 = pParam->BSIM3v0weff * here->BSIM3v0m * pParam->BSIM3v0leff * pow(data->freq, model->BSIM3v0ef) * 4.0e36; Swi = T10 / T11 * here->BSIM3v0cd * here->BSIM3v0m * here->BSIM3v0cd * here->BSIM3v0m; Slimit = StrongInversionNoiseEval( here->BSIM3v0von + 0.1, vds, model, here, data->freq, ckt->CKTtemp); T1 = Swi + Slimit; if (T1 > 0.0) noizDens[BSIM3v0FLNOIZ] *= (Slimit * Swi) / T1; else noizDens[BSIM3v0FLNOIZ] *= 0.0; } } else { noizDens[BSIM3v0FLNOIZ] *= model->BSIM3v0kf * exp(model->BSIM3v0af * log(MAX(fabs(here->BSIM3v0cd * here->BSIM3v0m), N_MINLOG))) / (pow(data->freq, model->BSIM3v0ef) * pParam->BSIM3v0leff * pParam->BSIM3v0leff * model->BSIM3v0cox); } lnNdens[BSIM3v0FLNOIZ] = log(MAX(noizDens[BSIM3v0FLNOIZ], N_MINLOG)); noizDens[BSIM3v0TOTNOIZ] = noizDens[BSIM3v0RDNOIZ] + noizDens[BSIM3v0RSNOIZ] + noizDens[BSIM3v0IDNOIZ] + noizDens[BSIM3v0FLNOIZ]; lnNdens[BSIM3v0TOTNOIZ] = log(MAX(noizDens[BSIM3v0TOTNOIZ], N_MINLOG)); *OnDens += noizDens[BSIM3v0TOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to initialize our "history" variables. */ for (i = 0; i < BSIM3v0NSRCS; i++) { here->BSIM3v0nVar[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 < BSIM3v0NSRCS; i++) { here->BSIM3v0nVar[OUTNOIZ][i] = 0.0; here->BSIM3v0nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0, we have to integrate. */ for (i = 0; i < BSIM3v0NSRCS; i++) { if (i != BSIM3v0TOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], here->BSIM3v0nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv, lnNdens[i] + data->lnGainInv, here->BSIM3v0nVar[LNLSTDENS][i] + data->lnGainInv, data); here->BSIM3v0nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (((NOISEAN*) ckt->CKTcurJob)->NStpsSm != 0) { here->BSIM3v0nVar[OUTNOIZ][i] += tempOnoise; here->BSIM3v0nVar[OUTNOIZ][BSIM3v0TOTNOIZ] += tempOnoise; here->BSIM3v0nVar[INNOIZ][i] += tempInoise; here->BSIM3v0nVar[INNOIZ][BSIM3v0TOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i = 0; i < BSIM3v0NSRCS; 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 < BSIM3v0NSRCS; i++) { data->outpVector[data->outNumber++] = here->BSIM3v0nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = here->BSIM3v0nVar[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); }
int B3SOIDDnoise (int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; B3SOIDDmodel *model = (B3SOIDDmodel *)inModel; B3SOIDDinstance *here; struct b3soiddSizeDependParam *pParam; double tempOnoise; double tempInoise; double noizDens[B3SOIDDNSRCS]; double lnNdens[B3SOIDDNSRCS]; double vgs, vds, Slimit; double T1, T10, T11; double Ssi, Swi; int i; /* define the names of the noise sources */ static char *B3SOIDDnNames[B3SOIDDNSRCS] = { /* Note that we have to keep the order */ ".rd", /* noise due to rd */ /* consistent with the index definitions */ ".rs", /* noise due to rs */ /* in B3SOIDDdefs.h */ ".id", /* noise due to id */ ".1overf", /* flicker (1/f) noise */ ".fb", /* noise due to floating body */ "" /* total transistor noise */ }; for (; model != NULL; model = B3SOIDDnextModel(model)) { for (here = B3SOIDDinstances(model); here != NULL; here = B3SOIDDnextInstance(here)) { 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 (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i = 0; i < B3SOIDDNSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise.%s%s", here->B3SOIDDname, B3SOIDDnNames[i]); } break; case INT_NOIZ: for (i = 0; i < B3SOIDDNSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise_total.%s%s", here->B3SOIDDname, B3SOIDDnNames[i]); NOISE_ADD_OUTVAR(ckt, data, "inoise_total.%s%s", here->B3SOIDDname, B3SOIDDnNames[i]); } break; } } break; case N_CALC: switch (mode) { case N_DENS: NevalSrc(&noizDens[B3SOIDDRDNOIZ], &lnNdens[B3SOIDDRDNOIZ], ckt, THERMNOISE, here->B3SOIDDdNodePrime, here->B3SOIDDdNode, here->B3SOIDDdrainConductance * here->B3SOIDDm); NevalSrc(&noizDens[B3SOIDDRSNOIZ], &lnNdens[B3SOIDDRSNOIZ], ckt, THERMNOISE, here->B3SOIDDsNodePrime, here->B3SOIDDsNode, here->B3SOIDDsourceConductance * here->B3SOIDDm); switch( model->B3SOIDDnoiMod ) { case 1: case 3: NevalSrc(&noizDens[B3SOIDDIDNOIZ], &lnNdens[B3SOIDDIDNOIZ], ckt, THERMNOISE, here->B3SOIDDdNodePrime, here->B3SOIDDsNodePrime, (2.0 / 3.0 * fabs(here->B3SOIDDm * (here->B3SOIDDgm + here->B3SOIDDgds + here->B3SOIDDgmbs)))); break; case 2: case 4: NevalSrc(&noizDens[B3SOIDDIDNOIZ], &lnNdens[B3SOIDDIDNOIZ], ckt, THERMNOISE, here->B3SOIDDdNodePrime, here->B3SOIDDsNodePrime, (here->B3SOIDDueff * fabs((here->B3SOIDDqinv * here->B3SOIDDm) / (pParam->B3SOIDDleff * pParam->B3SOIDDleff)))); break; } NevalSrc(&noizDens[B3SOIDDFLNOIZ], NULL, ckt, N_GAIN, here->B3SOIDDdNodePrime, here->B3SOIDDsNodePrime, (double) 0.0); switch( model->B3SOIDDnoiMod ) { case 1: case 4: noizDens[B3SOIDDFLNOIZ] *= model->B3SOIDDkf * exp(model->B3SOIDDaf * log(MAX(fabs(here->B3SOIDDcd * here->B3SOIDDm), N_MINLOG))) / (pow(data->freq, model->B3SOIDDef) * pParam->B3SOIDDleff * pParam->B3SOIDDleff * model->B3SOIDDcox); break; case 2: case 3: vgs = *(ckt->CKTstates[0] + here->B3SOIDDvgs); vds = *(ckt->CKTstates[0] + here->B3SOIDDvds); if (vds < 0.0) { vds = -vds; vgs = vgs + vds; } if (vgs >= here->B3SOIDDvon + 0.1) { Ssi = B3SOIDDStrongInversionNoiseEval(vgs, vds, model, here, data->freq, ckt->CKTtemp); noizDens[B3SOIDDFLNOIZ] *= Ssi; } else { pParam = here->pParam; T10 = model->B3SOIDDoxideTrapDensityA * 8.62e-5 * ckt->CKTtemp; T11 = pParam->B3SOIDDweff * here->B3SOIDDm * pParam->B3SOIDDleff * pow(data->freq, model->B3SOIDDef) * 4.0e36; Swi = T10 / T11 * here->B3SOIDDcd * here->B3SOIDDm * here->B3SOIDDcd * here->B3SOIDDm; Slimit = B3SOIDDStrongInversionNoiseEval( here->B3SOIDDvon + 0.1, vds, model, here, data->freq, ckt->CKTtemp); T1 = Swi + Slimit; if (T1 > 0.0) noizDens[B3SOIDDFLNOIZ] *= (Slimit * Swi) / T1; else noizDens[B3SOIDDFLNOIZ] *= 0.0; } break; } lnNdens[B3SOIDDFLNOIZ] = log(MAX(noizDens[B3SOIDDFLNOIZ], N_MINLOG)); /* Low frequency excess noise due to FBE */ NevalSrc(&noizDens[B3SOIDDFBNOIZ], &lnNdens[B3SOIDDFBNOIZ], ckt, SHOTNOISE, here->B3SOIDDsNodePrime, here->B3SOIDDbNode, 2.0 * model->B3SOIDDnoif * here->B3SOIDDibs * here->B3SOIDDm); noizDens[B3SOIDDTOTNOIZ] = noizDens[B3SOIDDRDNOIZ] + noizDens[B3SOIDDRSNOIZ] + noizDens[B3SOIDDIDNOIZ] + noizDens[B3SOIDDFLNOIZ] + noizDens[B3SOIDDFBNOIZ]; lnNdens[B3SOIDDTOTNOIZ] = log(MAX(noizDens[B3SOIDDTOTNOIZ], N_MINLOG)); *OnDens += noizDens[B3SOIDDTOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to initialize our "history" variables. */ for (i = 0; i < B3SOIDDNSRCS; i++) { here->B3SOIDDnVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i = 0; i < B3SOIDDNSRCS; i++) { here->B3SOIDDnVar[OUTNOIZ][i] = 0.0; here->B3SOIDDnVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0, we have to integrate. */ for (i = 0; i < B3SOIDDNSRCS; i++) { if (i != B3SOIDDTOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], here->B3SOIDDnVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv, lnNdens[i] + data->lnGainInv, here->B3SOIDDnVar[LNLSTDENS][i] + data->lnGainInv, data); here->B3SOIDDnVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { here->B3SOIDDnVar[OUTNOIZ][i] += tempOnoise; here->B3SOIDDnVar[OUTNOIZ][B3SOIDDTOTNOIZ] += tempOnoise; here->B3SOIDDnVar[INNOIZ][i] += tempInoise; here->B3SOIDDnVar[INNOIZ][B3SOIDDTOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i = 0; i < B3SOIDDNSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i = 0; i < B3SOIDDNSRCS; i++) { data->outpVector[data->outNumber++] = here->B3SOIDDnVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = here->B3SOIDDnVar[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); }
int B1noise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; B1model *firstModel = (B1model *) genmodel; B1model *model; B1instance *inst; double tempOnoise; double tempInoise; double noizDens[B1NSRCS]; double lnNdens[B1NSRCS]; int i; /* define the names of the noise sources */ static char *B1nNames[B1NSRCS] = { /* Note that we have to keep the order */ "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ "_rs", /* noise due to rs */ /* in bsim1defs.h */ "_id", /* noise due to id */ "_1overf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for (model=firstModel; model != NULL; model=B1nextModel(model)) { for (inst=B1instances(model); inst != NULL; inst=B1nextInstance(inst)) { switch (operation) { case N_OPEN: /* see if we have to to produce a summary report */ /* if so, name all the noise generators */ if (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i=0; i < B1NSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->B1name, B1nNames[i]); } break; case INT_NOIZ: for (i=0; i < B1NSRCS; i++) { NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->B1name, B1nNames[i]); NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->B1name, B1nNames[i]); } break; } } break; case N_CALC: switch (mode) { case N_DENS: NevalSrc(&noizDens[B1RDNOIZ],&lnNdens[B1RDNOIZ], ckt,THERMNOISE,inst->B1dNodePrime,inst->B1dNode, inst->B1drainConductance * inst->B1m); NevalSrc(&noizDens[B1RSNOIZ],&lnNdens[B1RSNOIZ], ckt,THERMNOISE,inst->B1sNodePrime,inst->B1sNode, inst->B1sourceConductance * inst->B1m); NevalSrc(&noizDens[B1IDNOIZ],&lnNdens[B1IDNOIZ], ckt,THERMNOISE,inst->B1dNodePrime,inst->B1sNodePrime, (2.0/3.0 * fabs(inst->B1gm * inst->B1m))); NevalSrc(&noizDens[B1FLNOIZ], NULL, ckt, N_GAIN,inst->B1dNodePrime, inst->B1sNodePrime, (double)0.0); noizDens[B1FLNOIZ] *= model->B1fNcoef * inst->B1m * exp(model->B1fNexp * log(MAX(fabs(inst->B1cd),N_MINLOG))) / (data->freq * (inst->B1w - model->B1deltaW * 1e-6) * (inst->B1l - model->B1deltaL * 1e-6) * model->B1Cox * model->B1Cox); lnNdens[B1FLNOIZ] = log(MAX(noizDens[B1FLNOIZ],N_MINLOG)); noizDens[B1TOTNOIZ] = noizDens[B1RDNOIZ] + noizDens[B1RSNOIZ] + noizDens[B1IDNOIZ] + noizDens[B1FLNOIZ]; lnNdens[B1TOTNOIZ] = log(MAX(noizDens[B1TOTNOIZ], N_MINLOG)); *OnDens += noizDens[B1TOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ for (i=0; i < B1NSRCS; i++) { inst->B1nVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i=0; i < B1NSRCS; i++) { inst->B1nVar[OUTNOIZ][i] = 0.0; inst->B1nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0 (we have to integrate) */ for (i=0; i < B1NSRCS; i++) { if (i != B1TOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], inst->B1nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , lnNdens[i] + data->lnGainInv, inst->B1nVar[LNLSTDENS][i] + data->lnGainInv, data); inst->B1nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { inst->B1nVar[OUTNOIZ][i] += tempOnoise; inst->B1nVar[OUTNOIZ][B1TOTNOIZ] += tempOnoise; inst->B1nVar[INNOIZ][i] += tempInoise; inst->B1nVar[INNOIZ][B1TOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i=0; i < B1NSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i=0; i < B1NSRCS; i++) { data->outpVector[data->outNumber++] = inst->B1nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = inst->B1nVar[INNOIZ][i]; } } /* if */ break; } /* switch (mode) */ break; case N_CLOSE: return (OK); /* do nothing, the main calling routine will close */ break; /* the plots */ } /* switch (operation) */ } /* for inst */ } /* for model */ return(OK); }
int BSIM3v32noise (int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; BSIM3v32model *model = (BSIM3v32model *)inModel; BSIM3v32instance *here; struct bsim3v32SizeDependParam *pParam; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[BSIM3v32NSRCS]; double lnNdens[BSIM3v32NSRCS]; double vgs, vds, Slimit; double T1, T10, T11; double Ssi, Swi; double m; int i; /* define the names of the noise sources */ static char *BSIM3v32nNames[BSIM3v32NSRCS] = { /* Note that we have to keep the order */ ".rd", /* noise due to rd */ /* consistent with the index definitions */ ".rs", /* noise due to rs */ /* in BSIM3v32defs.h */ ".id", /* noise due to id */ ".1overf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for (; model != NULL; model = model->BSIM3v32nextModel) { for (here = model->BSIM3v32instances; here != NULL; here = here->BSIM3v32nextInstance) { 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 (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i = 0; i < BSIM3v32NSRCS; i++) { (void) sprintf(name, "onoise.%s%s", here->BSIM3v32name, BSIM3v32nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; case INT_NOIZ: for (i = 0; i < BSIM3v32NSRCS; i++) { (void) sprintf(name, "onoise_total.%s%s", here->BSIM3v32name, BSIM3v32nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ (void) sprintf(name, "inoise_total.%s%s", here->BSIM3v32name, BSIM3v32nNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; } } break; case N_CALC: m = here->BSIM3v32m; switch (mode) { case N_DENS: NevalSrc(&noizDens[BSIM3v32RDNOIZ], &lnNdens[BSIM3v32RDNOIZ], ckt, THERMNOISE, here->BSIM3v32dNodePrime, here->BSIM3v32dNode, here->BSIM3v32drainConductance * m); NevalSrc(&noizDens[BSIM3v32RSNOIZ], &lnNdens[BSIM3v32RSNOIZ], ckt, THERMNOISE, here->BSIM3v32sNodePrime, here->BSIM3v32sNode, here->BSIM3v32sourceConductance * m); switch( model->BSIM3v32noiMod ) { case 1: case 3: NevalSrc(&noizDens[BSIM3v32IDNOIZ], &lnNdens[BSIM3v32IDNOIZ], ckt, THERMNOISE, here->BSIM3v32dNodePrime, here->BSIM3v32sNodePrime, (2.0 / 3.0 * fabs(here->BSIM3v32gm + here->BSIM3v32gds + here->BSIM3v32gmbs)) * m); break; case 2: case 4: /* Added revision dependent code */ if (model->BSIM3v32intVersion == BSIM3v32V324) { NevalSrc(&noizDens[BSIM3v32IDNOIZ], &lnNdens[BSIM3v32IDNOIZ], ckt, THERMNOISE, here->BSIM3v32dNodePrime, here->BSIM3v32sNodePrime, (m * here->BSIM3v32ueff * fabs(here->BSIM3v32qinv) / (pParam->BSIM3v32leff * pParam->BSIM3v32leff + here->BSIM3v32ueff * fabs(here->BSIM3v32qinv) * here->BSIM3v32rds))); /* bugfix */ } else { /* for all versions lower then 3.2.4 */ NevalSrc(&noizDens[BSIM3v32IDNOIZ], &lnNdens[BSIM3v32IDNOIZ], ckt, THERMNOISE, here->BSIM3v32dNodePrime, here->BSIM3v32sNodePrime, (m * here->BSIM3v32ueff * fabs(here->BSIM3v32qinv / (pParam->BSIM3v32leff * pParam->BSIM3v32leff)))); } break; } NevalSrc(&noizDens[BSIM3v32FLNOIZ], NULL, ckt, N_GAIN, here->BSIM3v32dNodePrime, here->BSIM3v32sNodePrime, (double) 0.0); switch( model->BSIM3v32noiMod ) { case 1: case 4: noizDens[BSIM3v32FLNOIZ] *= m * model->BSIM3v32kf * exp(model->BSIM3v32af * log(MAX(fabs(here->BSIM3v32cd), N_MINLOG))) / (pow(data->freq, model->BSIM3v32ef) * pParam->BSIM3v32leff * pParam->BSIM3v32leff * model->BSIM3v32cox); break; case 2: case 3: vgs = *(ckt->CKTstates[0] + here->BSIM3v32vgs); vds = *(ckt->CKTstates[0] + here->BSIM3v32vds); if (vds < 0.0) { vds = -vds; vgs = vgs + vds; } /* Added revision dependent code */ if (model->BSIM3v32intVersion == BSIM3v32V324) { Ssi = StrongInversionNoiseEvalNew(vds, model, here, data->freq, ckt->CKTtemp); T10 = model->BSIM3v32oxideTrapDensityA * 8.62e-5 * ckt->CKTtemp; T11 = pParam->BSIM3v32weff * pParam->BSIM3v32leff * pow(data->freq, model->BSIM3v32ef) * 4.0e36; Swi = T10 / T11 * here->BSIM3v32cd * here->BSIM3v32cd; T1 = Swi + Ssi; if (T1 > 0.0) noizDens[BSIM3v32FLNOIZ] *= m * (Ssi * Swi) / T1; else noizDens[BSIM3v32FLNOIZ] *= 0.0; } else { /* for all versions lower then 3.2.4 */ if (vgs >= here->BSIM3v32von + 0.1) { Ssi = StrongInversionNoiseEvalOld(vgs, vds, model, here, data->freq, ckt->CKTtemp); noizDens[BSIM3v32FLNOIZ] *= m * Ssi; } else { pParam = here->pParam; T10 = model->BSIM3v32oxideTrapDensityA * 8.62e-5 * ckt->CKTtemp; T11 = pParam->BSIM3v32weff * pParam-> BSIM3v32leff * pow (data->freq, model->BSIM3v32ef) * 4.0e36; Swi = T10 / T11 * here->BSIM3v32cd * here->BSIM3v32cd; Slimit = StrongInversionNoiseEvalOld( here->BSIM3v32von + 0.1, vds, model, here, data->freq, ckt->CKTtemp); T1 = Swi + Slimit; if (T1 > 0.0) noizDens[BSIM3v32FLNOIZ] *= m * (Slimit * Swi) / T1; else noizDens[BSIM3v32FLNOIZ] *= 0.0; } } break; } lnNdens[BSIM3v32FLNOIZ] = log(MAX(noizDens[BSIM3v32FLNOIZ], N_MINLOG)); noizDens[BSIM3v32TOTNOIZ] = noizDens[BSIM3v32RDNOIZ] + noizDens[BSIM3v32RSNOIZ] + noizDens[BSIM3v32IDNOIZ] + noizDens[BSIM3v32FLNOIZ]; lnNdens[BSIM3v32TOTNOIZ] = log(MAX(noizDens[BSIM3v32TOTNOIZ], N_MINLOG)); *OnDens += noizDens[BSIM3v32TOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to initialize our "history" variables. */ for (i = 0; i < BSIM3v32NSRCS; i++) { here->BSIM3v32nVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i = 0; i < BSIM3v32NSRCS; i++) { here->BSIM3v32nVar[OUTNOIZ][i] = 0.0; here->BSIM3v32nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0, we have to integrate. */ for (i = 0; i < BSIM3v32NSRCS; i++) { if (i != BSIM3v32TOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], here->BSIM3v32nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv, lnNdens[i] + data->lnGainInv, here->BSIM3v32nVar[LNLSTDENS][i] + data->lnGainInv, data); here->BSIM3v32nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { here->BSIM3v32nVar[OUTNOIZ][i] += tempOnoise; here->BSIM3v32nVar[OUTNOIZ][BSIM3v32TOTNOIZ] += tempOnoise; here->BSIM3v32nVar[INNOIZ][i] += tempInoise; here->BSIM3v32nVar[INNOIZ][BSIM3v32TOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i = 0; i < BSIM3v32NSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i = 0; i < BSIM3v32NSRCS; i++) { data->outpVector[data->outNumber++] = here->BSIM3v32nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = here->BSIM3v32nVar[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); }
int VBICnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; VBICmodel *firstModel = (VBICmodel *) genmodel; VBICmodel *model; VBICinstance *inst; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[VBICNSRCS]; double lnNdens[VBICNSRCS]; int i; /* define the names of the noise sources */ static char *VBICnNames[VBICNSRCS] = { /* Note that we have to keep the order consistent with the strchr definitions in VBICdefs.h */ "_rc", /* noise due to rc */ "_rci", /* noise due to rci */ "_rb", /* noise due to rb */ "_rbi", /* noise due to rbi */ "_re", /* noise due to re */ "_rbp", /* noise due to rbp */ "_rs", /* noise due to rs */ "_ic", /* noise due to ic */ "_ib", /* noise due to ib */ "_ibep", /* noise due to ibep */ "_iccp", /* noise due to iccp */ "_1overfbe", /* flicker (1/f) noise ibe */ "_1overfbep", /* flicker (1/f) noise ibep */ "" /* total transistor noise */ }; for (model=firstModel; model != NULL; model=model->VBICnextModel) { for (inst=model->VBICinstances; inst != NULL; inst=inst->VBICnextInstance) { switch (operation) { case N_OPEN: /* see if we have to to produce a summary report */ /* if so, name all the noise generators */ if (job->NStpsSm != 0) { switch (mode) { case N_DENS: for (i=0; i < VBICNSRCS; i++) { (void)sprintf(name,"onoise_%s%s", inst->VBICname,VBICnNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; case INT_NOIZ: for (i=0; i < VBICNSRCS; i++) { (void)sprintf(name,"onoise_total_%s%s", inst->VBICname,VBICnNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ (void)sprintf(name,"inoise_total_%s%s", inst->VBICname,VBICnNames[i]); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ } break; } } break; case N_CALC: switch (mode) { case N_DENS: NevalSrc(&noizDens[VBICRCNOIZ],&lnNdens[VBICRCNOIZ], ckt,THERMNOISE,inst->VBICcollCXNode,inst->VBICcollNode, *(ckt->CKTstate0 + inst->VBICircx_Vrcx)); NevalSrc(&noizDens[VBICRCINOIZ],&lnNdens[VBICRCINOIZ], ckt,THERMNOISE,inst->VBICcollCXNode,inst->VBICcollCINode, *(ckt->CKTstate0 + inst->VBICirci_Vrci)); NevalSrc(&noizDens[VBICRBNOIZ],&lnNdens[VBICRBNOIZ], ckt,THERMNOISE,inst->VBICbaseBXNode,inst->VBICbaseNode, *(ckt->CKTstate0 + inst->VBICirbx_Vrbx)); NevalSrc(&noizDens[VBICRBINOIZ],&lnNdens[VBICRBINOIZ], ckt,THERMNOISE,inst->VBICbaseBXNode,inst->VBICbaseBINode, *(ckt->CKTstate0 + inst->VBICirbi_Vrbi)); NevalSrc(&noizDens[VBICRENOIZ],&lnNdens[VBICRENOIZ], ckt,THERMNOISE,inst->VBICemitEINode,inst->VBICemitNode, *(ckt->CKTstate0 + inst->VBICire_Vre)); NevalSrc(&noizDens[VBICRBPNOIZ],&lnNdens[VBICRBPNOIZ], ckt,THERMNOISE,inst->VBICemitEINode,inst->VBICemitNode, *(ckt->CKTstate0 + inst->VBICirbp_Vrbp)); NevalSrc(&noizDens[VBICRSNOIZ],&lnNdens[VBICRSNOIZ], ckt,THERMNOISE,inst->VBICsubsSINode,inst->VBICsubsNode, *(ckt->CKTstate0 + inst->VBICirs_Vrs)); NevalSrc(&noizDens[VBICICNOIZ],&lnNdens[VBICICNOIZ], ckt,SHOTNOISE,inst->VBICcollCINode, inst->VBICemitEINode, *(ckt->CKTstate0 + inst->VBICitzf)); NevalSrc(&noizDens[VBICIBNOIZ],&lnNdens[VBICIBNOIZ], ckt,SHOTNOISE,inst->VBICbaseBINode, inst->VBICemitEINode, *(ckt->CKTstate0 + inst->VBICibe)); NevalSrc(&noizDens[VBICIBEPNOIZ],&lnNdens[VBICIBEPNOIZ], ckt,SHOTNOISE,inst->VBICbaseBXNode, inst->VBICbaseBPNode, *(ckt->CKTstate0 + inst->VBICibep)); NevalSrc(&noizDens[VBICICCPNOIZ],&lnNdens[VBICICCPNOIZ], ckt,SHOTNOISE,inst->VBICbaseBXNode, inst->VBICsubsSINode, *(ckt->CKTstate0 + inst->VBICiccp)); NevalSrc(&noizDens[VBICFLBENOIZ], NULL, ckt, N_GAIN,inst->VBICbaseBINode, inst->VBICemitEINode, (double)0.0); noizDens[VBICFLBENOIZ] *= inst->VBICm * model->VBICfNcoef * exp(model->VBICfNexpA * log(MAX(fabs(*(ckt->CKTstate0 + inst->VBICibe)/inst->VBICm),N_MINLOG))) / pow(data->freq, model->VBICfNexpB); lnNdens[VBICFLBENOIZ] = log(MAX(noizDens[VBICFLBENOIZ],N_MINLOG)); NevalSrc(&noizDens[VBICFLBEPNOIZ], NULL, ckt, N_GAIN,inst->VBICbaseBXNode, inst->VBICbaseBPNode, (double)0.0); noizDens[VBICFLBEPNOIZ] *= inst->VBICm * model->VBICfNcoef * exp(model->VBICfNexpA * log(MAX(fabs(*(ckt->CKTstate0 + inst->VBICibep)/inst->VBICm),N_MINLOG))) / pow(data->freq, model->VBICfNexpB); lnNdens[VBICFLBEPNOIZ] = log(MAX(noizDens[VBICFLBEPNOIZ],N_MINLOG)); noizDens[VBICTOTNOIZ] = noizDens[VBICRCNOIZ] + noizDens[VBICRCINOIZ] + noizDens[VBICRBNOIZ] + noizDens[VBICRBINOIZ] + noizDens[VBICRENOIZ] + noizDens[VBICRBPNOIZ] + noizDens[VBICICNOIZ] + noizDens[VBICIBNOIZ] + noizDens[VBICIBEPNOIZ] + noizDens[VBICFLBENOIZ] + noizDens[VBICFLBEPNOIZ]; lnNdens[VBICTOTNOIZ] = log(noizDens[VBICTOTNOIZ]); *OnDens += noizDens[VBICTOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ for (i=0; i < VBICNSRCS; i++) { inst->VBICnVar[LNLSTDENS][i] = lnNdens[i]; } /* clear out our integration variables if it's the first pass */ if (data->freq == job->NstartFreq) { for (i=0; i < VBICNSRCS; i++) { inst->VBICnVar[OUTNOIZ][i] = 0.0; inst->VBICnVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0 (we have to integrate) */ /* In order to get the best curve fit, we have to integrate each component separately */ for (i=0; i < VBICNSRCS; i++) { if (i != VBICTOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], inst->VBICnVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , lnNdens[i] + data->lnGainInv, inst->VBICnVar[LNLSTDENS][i] + data->lnGainInv, data); inst->VBICnVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (job->NStpsSm != 0) { inst->VBICnVar[OUTNOIZ][i] += tempOnoise; inst->VBICnVar[OUTNOIZ][VBICTOTNOIZ] += tempOnoise; inst->VBICnVar[INNOIZ][i] += tempInoise; inst->VBICnVar[INNOIZ][VBICTOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i=0; i < VBICNSRCS; i++) { /* print a summary report */ data->outpVector[data->outNumber++] = noizDens[i]; } } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { for (i=0; i < VBICNSRCS; i++) { data->outpVector[data->outNumber++] = inst->VBICnVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = inst->VBICnVar[INNOIZ][i]; } } /* if */ break; } /* switch (mode) */ break; case N_CLOSE: return (OK); /* do nothing, the main calling routine will close */ break; /* the plots */ } /* switch (operation) */ } /* for inst */ } /* for model */ return(OK); }
int SWnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; SWmodel *firstModel = (SWmodel *) genmodel; SWmodel *model; SWinstance *inst; char name[N_MXVLNTH]; double tempOutNoise; double tempInNoise; double noizDens; double lnNdens; int current_state; for (model=firstModel; model != NULL; model=model->SWnextModel) { for (inst=model->SWinstances; inst != NULL; inst=inst->SWnextInstance) { switch (operation) { case N_OPEN: /* see if we have to to produce a summary report */ /* if so, name the noise generator */ if (job->NStpsSm != 0) { switch (mode) { case N_DENS: (void)sprintf(name,"onoise_%s",inst->SWname); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ break; case INT_NOIZ: (void)sprintf(name,"onoise_total_%s",inst->SWname); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ (void)sprintf(name,"inoise_total_%s",inst->SWname); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); if (!data->namelist) return(E_NOMEM); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, name, UID_OTHER, NULL); /* we've added one more plot */ break; } } break; case N_CALC: switch (mode) { case N_DENS: current_state = (int)*(ckt->CKTstate0 + inst->SWstate); NevalSrc(&noizDens,&lnNdens,ckt,THERMNOISE, inst->SWposNode,inst->SWnegNode, current_state?(model->SWonConduct):(model->SWoffConduct)); *OnDens += noizDens; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ inst->SWnVar[LNLSTDENS] = lnNdens; /* clear out our integration variable if it's the first pass */ if (data->freq == job->NstartFreq) { inst->SWnVar[OUTNOIZ] = 0.0; } } else { /* data->delFreq != 0.0 (we have to integrate) */ tempOutNoise = Nintegrate(noizDens, lnNdens, inst->SWnVar[LNLSTDENS], data); tempInNoise = Nintegrate(noizDens * data->GainSqInv ,lnNdens + data->lnGainInv, inst->SWnVar[LNLSTDENS] + data->lnGainInv, data); inst->SWnVar[OUTNOIZ] += tempOutNoise; inst->SWnVar[INNOIZ] += tempInNoise; data->outNoiz += tempOutNoise; data->inNoise += tempInNoise; inst->SWnVar[LNLSTDENS] = lnNdens; } if (data->prtSummary) { data->outpVector[data->outNumber++] = noizDens; } break; case INT_NOIZ: /* already calculated, just output */ if (job->NStpsSm != 0) { data->outpVector[data->outNumber++] = inst->SWnVar[OUTNOIZ]; data->outpVector[data->outNumber++] = inst->SWnVar[INNOIZ]; } /* if */ break; } /* switch (mode) */ break; case N_CLOSE: return (OK); /* do nothing, the main calling routine will close */ break; /* the plots */ } /* switch (operation) */ } /* for inst */ } /* for model */ return(OK); }
int BJT2noise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens) { BJT2model *firstModel = (BJT2model *) genmodel; BJT2model *model; BJT2instance *inst; char name[N_MXVLNTH]; double tempOnoise; double tempInoise; double noizDens[BJT2NSRCS]; double lnNdens[BJT2NSRCS]; int i; /* define the names of the noise sources */ static char *BJT2nNames[BJT2NSRCS] = { /* Note that we have to keep the order */ "_rc", /* noise due to rc */ /* consistent with the index definitions */ "_rb", /* noise due to rb */ /* in BJT2defs.h */ "_re", /* noise due to re */ "_ic", /* noise due to ic */ "_ib", /* noise due to ib */ "_1overf", /* flicker (1/f) noise */ "" /* total transistor noise */ }; for (model=firstModel; model != NULL; model=model->BJT2nextModel) { for (inst=model->BJT2instances; inst != NULL; inst=inst->BJT2nextInstance) { if (inst->BJT2owner != ARCHme) continue; 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 < BJT2NSRCS; i++) { (void)sprintf(name,"onoise_%s%s", inst->BJT2name,BJT2nNames[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 < BJT2NSRCS; i++) { (void)sprintf(name,"onoise_total_%s%s", inst->BJT2name,BJT2nNames[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", inst->BJT2name,BJT2nNames[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: switch (mode) { case N_DENS: NevalSrc(&noizDens[BJT2RCNOIZ],&lnNdens[BJT2RCNOIZ], ckt,THERMNOISE,inst->BJT2colPrimeNode,inst->BJT2colNode, model->BJT2collectorConduct * inst->BJT2area * inst->BJT2m); NevalSrc(&noizDens[BJT2RBNOIZ],&lnNdens[BJT2RBNOIZ], ckt,THERMNOISE,inst->BJT2basePrimeNode,inst->BJT2baseNode, *(ckt->CKTstate0 + inst->BJT2gx) * inst->BJT2m); NevalSrc(&noizDens[BJT2_RE_NOISE],&lnNdens[BJT2_RE_NOISE], ckt,THERMNOISE,inst->BJT2emitPrimeNode,inst->BJT2emitNode, model->BJT2emitterConduct * inst->BJT2area * inst->BJT2m); NevalSrc(&noizDens[BJT2ICNOIZ],&lnNdens[BJT2ICNOIZ], ckt,SHOTNOISE,inst->BJT2colPrimeNode, inst->BJT2emitPrimeNode, *(ckt->CKTstate0 + inst->BJT2cc) * inst->BJT2m); NevalSrc(&noizDens[BJT2IBNOIZ],&lnNdens[BJT2IBNOIZ], ckt,SHOTNOISE,inst->BJT2basePrimeNode, inst->BJT2emitPrimeNode, *(ckt->CKTstate0 + inst->BJT2cb) * inst->BJT2m); NevalSrc(&noizDens[BJT2FLNOIZ],(double*)NULL,ckt, N_GAIN,inst->BJT2basePrimeNode, inst->BJT2emitPrimeNode, (double)0.0); noizDens[BJT2FLNOIZ] *= inst->BJT2m * model->BJT2fNcoef * exp(model->BJT2fNexp * log(MAX(fabs(*(ckt->CKTstate0 + inst->BJT2cb)),N_MINLOG))) / data->freq; lnNdens[BJT2FLNOIZ] = log(MAX(noizDens[BJT2FLNOIZ],N_MINLOG)); noizDens[BJT2TOTNOIZ] = noizDens[BJT2RCNOIZ] + noizDens[BJT2RBNOIZ] + noizDens[BJT2_RE_NOISE] + noizDens[BJT2ICNOIZ] + noizDens[BJT2IBNOIZ] + noizDens[BJT2FLNOIZ]; lnNdens[BJT2TOTNOIZ] = log(noizDens[BJT2TOTNOIZ]); *OnDens += noizDens[BJT2TOTNOIZ]; if (data->delFreq == 0.0) { /* if we haven't done any previous integration, we need to */ /* initialize our "history" variables */ for (i=0; i < BJT2NSRCS; i++) { inst->BJT2nVar[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 < BJT2NSRCS; i++) { inst->BJT2nVar[OUTNOIZ][i] = 0.0; inst->BJT2nVar[INNOIZ][i] = 0.0; } } } else { /* data->delFreq != 0.0 (we have to integrate) */ /* In order to get the best curve fit, we have to integrate each component separately */ for (i=0; i < BJT2NSRCS; i++) { if (i != BJT2TOTNOIZ) { tempOnoise = Nintegrate(noizDens[i], lnNdens[i], inst->BJT2nVar[LNLSTDENS][i], data); tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , lnNdens[i] + data->lnGainInv, inst->BJT2nVar[LNLSTDENS][i] + data->lnGainInv, data); inst->BJT2nVar[LNLSTDENS][i] = lnNdens[i]; data->outNoiz += tempOnoise; data->inNoise += tempInoise; if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { inst->BJT2nVar[OUTNOIZ][i] += tempOnoise; inst->BJT2nVar[OUTNOIZ][BJT2TOTNOIZ] += tempOnoise; inst->BJT2nVar[INNOIZ][i] += tempInoise; inst->BJT2nVar[INNOIZ][BJT2TOTNOIZ] += tempInoise; } } } } if (data->prtSummary) { for (i=0; i < BJT2NSRCS; 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 < BJT2NSRCS; i++) { data->outpVector[data->outNumber++] = inst->BJT2nVar[OUTNOIZ][i]; data->outpVector[data->outNumber++] = inst->BJT2nVar[INNOIZ][i]; } } /* if */ break; } /* switch (mode) */ break; case N_CLOSE: return (OK); /* do nothing, the main calling routine will close */ break; /* the plots */ } /* switch (operation) */ } /* for inst */ } /* for model */ return(OK); }