void cm_analog_alloc( int tag, /* The user-specified tag for this block of memory */ int bytes) /* The number of bytes to allocate */ { MIFinstance *here; CKTcircuit *ckt; Mif_State_t *state; int doubles_needed; int i; /* Get the address of the ckt and instance structs from g_mif_info */ here = g_mif_info.instance; ckt = g_mif_info.ckt; /* Scan states in instance struct and see if tag has already been used */ for(i = 0; i < here->num_state; i++) { if(tag == here->state[i].tag) { g_mif_info.errmsg = "ERROR - cm_analog_alloc() - Tag already used in previous call\n"; return; } } /* Compute number of doubles needed and allocate space in ckt->CKTstates[i] */ doubles_needed = bytes / (int) sizeof(double) + 1; /* Allocate space in instance struct for this state descriptor */ if(here->num_state == 0) { here->num_state = 1; here->state = TMALLOC(Mif_State_t, 1); } else { here->num_state++; here->state = TREALLOC(Mif_State_t, here->state, here->num_state); } /* Fill in the members of the state descriptor struct */ state = &(here->state[here->num_state - 1]); state->tag = tag; state->index = ckt->CKTnumStates; state->doubles = doubles_needed; state->bytes = bytes; /* Add the states to the ckt->CKTstates vectors */ ckt->CKTnumStates += doubles_needed; for(i=0;i<=ckt->CKTmaxOrder+1;i++) { if(ckt->CKTnumStates == doubles_needed) ckt->CKTstates[i] = TMALLOC(double, ckt->CKTnumStates); else ckt->CKTstates[i] = TREALLOC(double, ckt->CKTstates[i], ckt->CKTnumStates); }
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); }
static int pack_vector(int vector) { int i, j, k, l; int t; int loc; int ok; Value_t *from; Value_t *to; int newmax; i = order[vector]; t = tally[i]; assert(t); from = froms[i]; to = tos[i]; j = lowzero - from[0]; for (k = 1; k < t; ++k) if (lowzero - from[k] > j) j = lowzero - from[k]; for (;; ++j) { if (j == 0) continue; ok = 1; for (k = 0; ok && k < t; k++) { loc = j + from[k]; if (loc >= maxtable - 1) { if (loc >= MAXTABLE - 1) fatal("maximum table size exceeded"); newmax = maxtable; do { newmax += 200; } while (newmax <= loc); table = TREALLOC(Value_t, table, newmax); NO_SPACE(table); check = TREALLOC(Value_t, check, newmax); NO_SPACE(check); for (l = maxtable; l < newmax; ++l) { table[l] = 0; check[l] = -1; } maxtable = newmax; } if (check[loc] != -1) ok = 0; } for (k = 0; ok && k < vector; k++) { if (pos[k] == j) ok = 0; } if (ok) { for (k = 0; k < t; k++) { loc = j + from[k]; table[loc] = to[k]; check[loc] = from[k]; if (loc > high) high = loc; } while (check[lowzero] != -1) ++lowzero; return (j); } } }
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 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 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 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 CKTnoise (CKTcircuit *ckt, int mode, int operation, Ndata *data) { NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; double outNdens; int i; IFvalue outData; /* output variable (points to list of outputs)*/ IFvalue refVal; /* reference variable (always 0)*/ int error; outNdens = 0.0; /* let each device decide how many and what type of noise sources it has */ for (i=0; i < DEVmaxnum; i++) { if ( DEVices[i] && DEVices[i]->DEVnoise && ckt->CKThead[i] ) { error = DEVices[i]->DEVnoise (mode, operation, ckt->CKThead[i], ckt,data, &outNdens); if (error) return (error); } } switch (operation) { case N_OPEN: /* take care of the noise for the circuit as a whole */ switch (mode) { case N_DENS: data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, "onoise_spectrum", UID_OTHER, NULL); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, "inoise_spectrum", UID_OTHER, NULL); /* we've added two more plots */ data->outpVector = TMALLOC(double, data->numPlots); break; case INT_NOIZ: data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, "onoise_total", UID_OTHER, NULL); data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]), NULL, "inoise_total", UID_OTHER, NULL); /* we've added two more plots */ data->outpVector = TMALLOC(double, data->numPlots); break; default: return (E_INTERN); } break; case N_CALC: switch (mode) { case N_DENS: if ((job->NStpsSm == 0) || data->prtSummary) { data->outpVector[data->outNumber++] = outNdens; data->outpVector[data->outNumber++] = (outNdens * data->GainSqInv); refVal.rValue = data->freq; /* the reference is the freq */ outData.v.numValue = data->outNumber; /* vector number */ outData.v.vec.rVec = data->outpVector; /* vector of outputs */ SPfrontEnd->OUTpData (data->NplotPtr, &refVal, &outData); } break; case INT_NOIZ: data->outpVector[data->outNumber++] = data->outNoiz; data->outpVector[data->outNumber++] = data->inNoise; outData.v.vec.rVec = data->outpVector; /* vector of outputs */ outData.v.numValue = data->outNumber; /* vector number */ SPfrontEnd->OUTpData (data->NplotPtr, &refVal, &outData); break; default: return (E_INTERN); } break; case N_CLOSE: SPfrontEnd->OUTendPlot (data->NplotPtr); FREE(data->namelist); FREE(data->outpVector); break; default: return (E_INTERN); } 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 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; char name[N_MXVLNTH]; 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=model->JFETnextModel) { for (inst=model->JFETinstances; inst != NULL; inst=inst->JFETnextInstance) { 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++) { (void)sprintf(name,"onoise_%s%s",inst->JFETname,JFETnNames[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 < JFETNSRCS; i++) { (void)sprintf(name,"onoise_total_%s%s",inst->JFETname,JFETnNames[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->JFETname,JFETnNames[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[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); }