Merge branch 'pre-master-43' into bt_dev

This commit is contained in:
Brian Taylor 2024-02-13 09:02:29 -08:00
commit b5f96d68de
28 changed files with 907 additions and 600 deletions

View File

@ -118,7 +118,7 @@ LT_INIT([shared static])
LT_NGSPICE_CURRENT=0 LT_NGSPICE_CURRENT=0
LT_NGSPICE_REVISION=9 LT_NGSPICE_REVISION=9
LT_NGSPICE_AGE=2 LT_NGSPICE_AGE=0
LIBNGSPICE_SO_VERSION=$LT_NGSPICE_CURRENT.$LT_NGSPICE_REVISION.$LT_NGSPICE_AGE LIBNGSPICE_SO_VERSION=$LT_NGSPICE_CURRENT.$LT_NGSPICE_REVISION.$LT_NGSPICE_AGE
# Announce the libtool version # Announce the libtool version

View File

@ -6,6 +6,8 @@ V1 1 0 dc 0 ac 1 sin (0 1 1k)
Xtr1 1 0 2 0 tr1 Xtr1 1 0 2 0 tr1
Xtr1a 1 0 32 0 tr1a psr=1m ssr=1m lp=1m ls=4m kt=0.98
Xtr2 1 0 12 0 tr2 Xtr2 1 0 12 0 tr2
Xtr3 1 0 22 0 tr3 Xtr3 1 0 22 0 tr3
@ -22,6 +24,16 @@ Xtr3 1 0 22 0 tr3
K1 L1 L2 0.98 ; coupling constant K1 L1 L2 0.98 ; coupling constant
.ends .ends
* transformer 1a
* ngspice manual 3.3.10, with parameters replacing fixed values
.subckt tr1a p1 p2 s1 s2 psr=1m ssr=1m lp=100u ls=100u kt=1
Rp1 p1 pint1 {psr} ; primary series resistance
Rs1 s1 sint1 {ssr} ; secondary series resistance
L1 pint1 p2 {lp} ; primary inductance
L2 sint1 s2 {ls} ; secondary inductance
K1 L1 L2 {kt} ; coupling constant
.ends
* transformer 2 * transformer 2
* ngspice manual 12.2.20 and 12.2.21 * ngspice manual 12.2.20 and 12.2.21
* px primary nodes, sx secondary nodes of electric circuit * px primary nodes, sx secondary nodes of electric circuit
@ -53,7 +65,7 @@ Xtr3 1 0 22 0 tr3
.control .control
run run
set xbrushwidth=2 set xbrushwidth=2
plot V(1) v(2) V(1)+5 V(12)+5 V(1)+10 V(22)+10 plot V(1) v(2) V(1)+5 V(12)+5 V(1)+10 V(22)+10 V(1)+15 V(32)+15
.endc .endc
.end .end

View File

@ -649,7 +649,7 @@ endif
## if !SHWIN ## if !SHWIN
## if !SHCYG ## if !SHCYG
libngspice_la_LDFLAGS += -version-info $(LT_NGSPICE_CURRENT):$(LT_NGSPICE_REVISION):$(LT_LIBNGSPICE_AGE) libngspice_la_LDFLAGS += -version-info $(LT_NGSPICE_CURRENT):$(LT_NGSPICE_REVISION):$(LT_NGSPICE_AGE)
## endif ## endif
## endif ## endif

View File

@ -1085,14 +1085,23 @@ zoomin(GRAPH *graph)
if ((t = strchr(buf2, ':')) != NULL) if ((t = strchr(buf2, ':')) != NULL)
*t = '\0'; *t = '\0';
/* Set the foreground and background colors to the
* "calling" window's colors using undocumented keyword, "sgraphid".
*/
if (!eq(plot_cur->pl_typename, buf2)) { if (!eq(plot_cur->pl_typename, buf2)) {
/* Switch plot before and after "plot" command. */
(void) sprintf(buf, (void) sprintf(buf,
"setplot %s; %s xlimit %.20e %.20e ylimit %.20e %.20e sgraphid %d; setplot $curplot\n", "setplot %s; %s xlimit %.20e %.20e ylimit %.20e %.20e "
buf2, graph->commandline, fx0, fx1, fy0, fy1, graph->graphid); "sgraphid %d; setplot $curplot\n",
buf2, graph->commandline, fx0, fx1, fy0, fy1,
graph->graphid);
} else { } else {
/* set the foreground and background colors to the "calling" window's colors */ (void) sprintf(buf,
(void) sprintf(buf, "%s xlimit %e %e ylimit %e %e sgraphid %d\n", "%s xlimit %.20e %.20e ylimit %.20e %.20e "
graph->commandline, fx0, fx1, fy0, fy1, graph->graphid); "sgraphid %d\n",
graph->commandline, fx0, fx1, fy0, fy1,
graph->graphid);
} }
/* don't use the following if using GNU Readline or BSD EditLine */ /* don't use the following if using GNU Readline or BSD EditLine */

View File

@ -126,11 +126,6 @@ com_spec(wordlist *wl)
} }
} }
else if (eq(window, "blackman")) { else if (eq(window, "blackman")) {
int order;
if (!cp_getvar("specwindoworder", CP_NUM, &order, 0))
order = 2;
if (order < 2) /* only order 2 supported here */
order = 2;
for (i = 0; i < tlen; i++) { for (i = 0; i < tlen; i++) {
if (maxt-time[i] > span) { if (maxt-time[i] > span) {
win[i] = 0; win[i] = 0;

View File

@ -630,11 +630,13 @@ LRESULT CALLBACK PlotWindowProc(HWND hwnd, UINT uMsg,
if (!eq(plot_cur->pl_typename, buf2)) { if (!eq(plot_cur->pl_typename, buf2)) {
(void) sprintf(buf, (void) sprintf(buf,
// "setplot %s; %s xlimit %e %e ylimit %e %e; setplot $curplot\n", "setplot %s; %s xlimit %.20e %.20e ylimit %.20e "
"setplot %s; %s xlimit %e %e ylimit %e %e sgraphid %d\n", "%.20e sgraphid %d ; setplot $curplot\n",
buf2, gr->commandline, fx0, fxe, fy0, fye, gr->graphid); buf2, gr->commandline, fx0, fxe, fy0, fye,
gr->graphid);
} else { } else {
(void) sprintf(buf, "%s xlimit %e %e ylimit %e %e sgraphid %d\n", (void) sprintf(buf, "%s xlimit %.20e %.20e ylimit %.20e %.20e "
"sgraphid %d\n",
gr->commandline, fx0, fxe, fy0, fye, gr->graphid); gr->commandline, fx0, fxe, fy0, fye, gr->graphid);
} }

View File

@ -114,8 +114,10 @@ fft_windows(char *window, double *win, double *time, int length, double maxt, do
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
if (maxt-time[i] > span) if (maxt-time[i] > span)
win[i] = 0.0; win[i] = 0.0;
else if (maxt-time[i] < span/2)
win[i] = 4.0 * (maxt-time[i]) / span;
else else
win[i] = 2.0 - fabs(2+4*(time[i]-maxt)/span); win[i] = 4.0 - 4.0 * (maxt-time[i]) / span;
} }
else if (eq(window, "hann") || eq(window, "hanning") || eq(window, "cosine")) else if (eq(window, "hann") || eq(window, "hanning") || eq(window, "cosine"))
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
@ -141,6 +143,17 @@ fft_windows(char *window, double *win, double *time, int length, double maxt, do
win[i] += 0.08/0.42*cos(4*M_PI*(time[i]-maxt)/span); win[i] += 0.08/0.42*cos(4*M_PI*(time[i]-maxt)/span);
} }
} }
else if (eq(window, "blackmanharris"))
for (i = 0; i < length; i++) {
if (maxt-time[i] > span) {
win[i] = 0;
} else {
win[i] = 1.0;
win[i] -= 0.48829/0.35875*cos(2*M_PI*(time[i]-maxt)/span);
win[i] += 0.14128/0.35875*cos(4*M_PI*(time[i]-maxt)/span);
win[i] -= 0.01168/0.35875*cos(6*M_PI*(time[i]-maxt)/span);
}
}
else if (eq(window, "flattop")) else if (eq(window, "flattop"))
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
if (maxt-time[i] > span) { if (maxt-time[i] > span) {

View File

@ -126,7 +126,7 @@ CKTspnoise(CKTcircuit* ckt, int mode, int operation, Ndata* data, NOISEAN* noise
cplx Ycor = csubco(ckt->CKTYmat->d[0][0], cplx Ycor = csubco(ckt->CKTYmat->d[0][0],
cmultco( cmultco(
cdivco(tempCy->d[0][1], tempCy->d[1][1]), cdivco(tempCy->d[0][1], tempCy->d[1][1]),
tempCy->d[1][0] ckt->CKTYmat->d[1][0]
)); ));
double Y11_Ycor = cmodsqr(csubco(ckt->CKTYmat->d[0][0], Ycor)); double Y11_Ycor = cmodsqr(csubco(ckt->CKTYmat->d[0][0], Ycor));
@ -138,7 +138,7 @@ CKTspnoise(CKTcircuit* ckt, int mode, int operation, Ndata* data, NOISEAN* noise
caddco(Y0, Ysopt)); caddco(Y0, Ysopt));
Fmin = 1.0 + 2.0 * Rn * (Ycor.re + Ysopt.re); Fmin = 1.0 + 2.0 * Rn * (Ycor.re + Ysopt.re);
double Ysoptmod = cmodu(csubco(Y0, Ysopt)); double Ysoptmod = cmodu(csubco(Y0, Ysopt));
NF = Fmin + (Rn / Ysopt.re) * SQR(Ysoptmod); NF = Fmin + (Rn / Y0.re) * SQR(Ysoptmod);
Fmin = 10.0 * log10(Fmin); Fmin = 10.0 * log10(Fmin);
NF = 10.0 * log10(NF); NF = 10.0 * log10(NF);
} }

View File

@ -148,7 +148,9 @@ IFparm MOS1mPTable[] = { /* model parameters */
IOP("nss", MOS1_MOD_NSS, IF_REAL ,"Surface state density"), IOP("nss", MOS1_MOD_NSS, IF_REAL ,"Surface state density"),
IOP("tnom", MOS1_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), IOP("tnom", MOS1_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"),
IOP("kf", MOS1_MOD_KF, IF_REAL ,"Flicker noise coefficient"), IOP("kf", MOS1_MOD_KF, IF_REAL ,"Flicker noise coefficient"),
IOP("af", MOS1_MOD_AF, IF_REAL ,"Flicker noise exponent") IOP("af", MOS1_MOD_AF, IF_REAL ,"Flicker noise exponent"),
IOP("nlev", MOS1_MOD_NLEV, IF_INTEGER ,"Noise model selection"),
IOP("gdsnoi", MOS1_MOD_GDSNOI, IF_REAL ,"Channel shot noise coefficient")
}; };
char *MOS1names[] = { char *MOS1names[] = {

View File

@ -383,6 +383,8 @@ typedef struct sMOS1model { /* model structure for a resistor */
double MOS1surfaceMobility; /* input - use tSurfMob */ double MOS1surfaceMobility; /* input - use tSurfMob */
double MOS1fNcoef; double MOS1fNcoef;
double MOS1fNexp; double MOS1fNexp;
int MOS1nlev;
double MOS1gdsnoi;
unsigned MOS1typeGiven :1; unsigned MOS1typeGiven :1;
unsigned MOS1latDiffGiven :1; unsigned MOS1latDiffGiven :1;
@ -415,6 +417,8 @@ typedef struct sMOS1model { /* model structure for a resistor */
unsigned MOS1tnomGiven :1; unsigned MOS1tnomGiven :1;
unsigned MOS1fNcoefGiven :1; unsigned MOS1fNcoefGiven :1;
unsigned MOS1fNexpGiven :1; unsigned MOS1fNexpGiven :1;
unsigned MOS1nlevGiven :1;
unsigned MOS1gdsnoiGiven :1;
} MOS1model; } MOS1model;
@ -483,6 +487,8 @@ enum {
MOS1_MOD_TNOM, MOS1_MOD_TNOM,
MOS1_MOD_KF, MOS1_MOD_KF,
MOS1_MOD_AF, MOS1_MOD_AF,
MOS1_MOD_NLEV,
MOS1_MOD_GDSNOI,
MOS1_MOD_TYPE, MOS1_MOD_TYPE,
}; };

View File

@ -105,11 +105,17 @@ MOS1mAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
case MOS1_MOD_NSS: case MOS1_MOD_NSS:
value->rValue = model->MOS1surfaceStateDensity; value->rValue = model->MOS1surfaceStateDensity;
return(OK); return(OK);
case MOS1_MOD_NLEV:
value->iValue = model->MOS1nlev;
return(OK);
case MOS1_MOD_GDSNOI:
value->rValue = model->MOS1gdsnoi;
return(OK);
case MOS1_MOD_TYPE: case MOS1_MOD_TYPE:
if (model->MOS1type > 0) if (model->MOS1type > 0)
value->sValue = "nmos"; value->sValue = "nmos";
else else
value->sValue = "pmos"; value->sValue = "pmos";
return(OK); return(OK);
default: default:
return(E_BADPARM); return(E_BADPARM);

View File

@ -139,14 +139,22 @@ MOS1mParam(int param, IFvalue *value, GENmodel *inModel)
model->MOS1typeGiven = TRUE; model->MOS1typeGiven = TRUE;
} }
break; break;
case MOS1_MOD_KF: case MOS1_MOD_KF:
model->MOS1fNcoef = value->rValue; model->MOS1fNcoef = value->rValue;
model->MOS1fNcoefGiven = TRUE; model->MOS1fNcoefGiven = TRUE;
break; break;
case MOS1_MOD_AF: case MOS1_MOD_AF:
model->MOS1fNexp = value->rValue; model->MOS1fNexp = value->rValue;
model->MOS1fNexpGiven = TRUE; model->MOS1fNexpGiven = TRUE;
break; break;
case MOS1_MOD_NLEV:
model->MOS1nlev = value->iValue;
model->MOS1nlevGiven = TRUE;
break;
case MOS1_MOD_GDSNOI:
model->MOS1gdsnoi = value->rValue;
model->MOS1gdsnoiGiven = TRUE;
break;
default: default:
return(E_BADPARM); return(E_BADPARM);
} }

View File

@ -10,6 +10,7 @@ Modified: 2000 AlansFixes
#include "ngspice/iferrmsg.h" #include "ngspice/iferrmsg.h"
#include "ngspice/noisedef.h" #include "ngspice/noisedef.h"
#include "ngspice/suffix.h" #include "ngspice/suffix.h"
#include "ngspice/compatmode.h"
/* /*
* MOS1noise (mode, operation, firstModel, ckt, data, OnDens) * MOS1noise (mode, operation, firstModel, ckt, data, OnDens)
@ -20,170 +21,234 @@ Modified: 2000 AlansFixes
* all of the MOSFET's is summed with the variable "OnDens". * all of the MOSFET's is summed with the variable "OnDens".
*/ */
int int
MOS1noise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, MOS1noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
Ndata *data, double *OnDens) Ndata * data, double * OnDens) {
{ NOISEAN * job = (NOISEAN * ) ckt->CKTcurJob;
NOISEAN *job = (NOISEAN *) ckt->CKTcurJob;
MOS1model *firstModel = (MOS1model *) genmodel; MOS1model * firstModel = (MOS1model * ) genmodel;
MOS1model *model; MOS1model * model;
MOS1instance *inst; MOS1instance * inst;
double coxSquared; double coxSquared;
double tempOnoise; double tempOnoise;
double tempInoise; double tempInoise;
double noizDens[MOS1NSRCS]; double noizDens[MOS1NSRCS];
double lnNdens[MOS1NSRCS]; double lnNdens[MOS1NSRCS];
int i; int i;
double vgs, vds, vgd, vgst, alpha, beta, Sid;
/* define the names of the noise sources */ /* define the names of the noise sources */
static char *MOS1nNames[MOS1NSRCS] = { /* Note that we have to keep the order */ static char * MOS1nNames[MOS1NSRCS] = {
"_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ /* Note that we have to keep the order */
"_rs", /* noise due to rs */ /* in MOS1defs.h */ "_rd",
"_id", /* noise due to id */ /* noise due to rd */ /* consistent with thestrchr definitions */
"_1overf", /* flicker (1/f) noise */ "_rs",
"" /* total transistor noise */ /* noise due to rs */ /* in MOS1defs.h */
"_id",
/* noise due to id */
"_1overf",
/* flicker (1/f) noise */
"" /* total transistor noise */
}; };
for (model=firstModel; model != NULL; model=MOS1nextModel(model)) { for (model = firstModel; model != NULL; model = MOS1nextModel(model)) {
/* Oxide capacitance can be zero in MOS level 1. Since this will give us problems in our 1/f */ /* 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 */ /* noise model, we ASSUME an actual "tox" of 1e-7 */
if (model->MOS1oxideCapFactor == 0.0) { if (model->MOS1oxideCapFactor == 0.0) {
coxSquared = 3.9 * 8.854214871e-12 / 1e-7; coxSquared = 3.9 * 8.854214871e-12 / 1e-7;
} else { } else {
coxSquared = model->MOS1oxideCapFactor; coxSquared = model->MOS1oxideCapFactor;
} }
coxSquared *= coxSquared; coxSquared *= coxSquared;
for (inst=MOS1instances(model); inst != NULL; inst=MOS1nextInstance(inst)) { for (inst = MOS1instances(model); inst != NULL; inst = MOS1nextInstance(inst)) {
switch (operation) {
case N_OPEN: switch (operation) {
/* see if we have to to produce a summary report */ case N_OPEN:
/* if so, name all the noise generators */
if (job->NStpsSm != 0) { /* see if we have to to produce a summary report */
switch (mode) { /* if so, name all the noise generators */
case N_DENS: if (job->NStpsSm != 0) {
for (i=0; i < MOS1NSRCS; i++) { switch (mode) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->MOS1name, MOS1nNames[i]);
}
break;
case INT_NOIZ: case N_DENS:
for (i=0; i < MOS1NSRCS; i++) { for (i = 0; i < MOS1NSRCS; i++) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->MOS1name, MOS1nNames[i]); NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->MOS1name, MOS1nNames[i]);
NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->MOS1name, MOS1nNames[i]); }
} break;
break;
}
}
break;
case N_CALC: case INT_NOIZ:
switch (mode) { for (i = 0; i < MOS1NSRCS; i++) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->MOS1name, MOS1nNames[i]);
NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->MOS1name, MOS1nNames[i]);
}
break;
}
}
break;
case N_DENS: case N_CALC:
NevalSrc(&noizDens[MOS1RDNOIZ],&lnNdens[MOS1RDNOIZ], switch (mode) {
ckt,THERMNOISE,inst->MOS1dNodePrime,inst->MOS1dNode,
inst->MOS1drainConductance);
NevalSrc(&noizDens[MOS1RSNOIZ],&lnNdens[MOS1RSNOIZ], case N_DENS:
ckt,THERMNOISE,inst->MOS1sNodePrime,inst->MOS1sNode, NevalSrc( & noizDens[MOS1RDNOIZ], & lnNdens[MOS1RDNOIZ],
inst->MOS1sourceConductance); ckt, THERMNOISE, inst->MOS1dNodePrime, inst->MOS1dNode,
inst->MOS1drainConductance);
NevalSrc(&noizDens[MOS1IDNOIZ],&lnNdens[MOS1IDNOIZ], NevalSrc( & noizDens[MOS1RSNOIZ], & lnNdens[MOS1RSNOIZ],
ckt,THERMNOISE,inst->MOS1dNodePrime,inst->MOS1sNodePrime, ckt, THERMNOISE, inst->MOS1sNodePrime, inst->MOS1sNode,
(2.0/3.0 * fabs(inst->MOS1gm))); inst->MOS1sourceConductance);
NevalSrc(&noizDens[MOS1FLNOIZ], NULL, ckt, if (model->MOS1nlev < 3) {
N_GAIN,inst->MOS1dNodePrime, inst->MOS1sNodePrime,
(double)0.0);
noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef *
exp(model->MOS1fNexp *
log(MAX(fabs(inst->MOS1cd),N_MINLOG))) /
(data->freq * inst->MOS1w *
(inst->MOS1l - 2*model->MOS1latDiff) * coxSquared);
lnNdens[MOS1FLNOIZ] =
log(MAX(noizDens[MOS1FLNOIZ],N_MINLOG));
noizDens[MOS1TOTNOIZ] = noizDens[MOS1RDNOIZ] + Sid = 2.0 / 3.0 * fabs(inst->MOS1gm);
noizDens[MOS1RSNOIZ] +
noizDens[MOS1IDNOIZ] +
noizDens[MOS1FLNOIZ];
lnNdens[MOS1TOTNOIZ] =
log(MAX(noizDens[MOS1TOTNOIZ], N_MINLOG));
*OnDens += noizDens[MOS1TOTNOIZ]; } else {
vds = *(ckt->CKTstate0 + inst->MOS1vds);
vgs = *(ckt->CKTstate0 + inst->MOS1vgs);
vgd = vgs - vds;
if (data->delFreq == 0.0) { vgst=(inst->MOS1mode==1?vgs:vgd) - model->MOS1type*inst->MOS1von;
if (vgst > 0) {
if (vgst <= (vds*inst->MOS1mode)) {
/* saturation region */
alpha = 0.0;
} else {
/* linear region */
alpha = 1.0 - (vds*inst->MOS1mode/(model->MOS1type*inst->MOS1vdsat));
}
}
beta = inst->MOS1tTransconductance * inst->MOS1m *
inst->MOS1w/(inst->MOS1l - 2 * model->MOS1latDiff);
Sid = 2.0 / 3.0 * beta * vgst * (1.0+alpha+alpha*alpha) / (1.0+alpha) * model->MOS1gdsnoi;
}
/* if we haven't done any previous integration, we need to */ NevalSrc( & noizDens[MOS1IDNOIZ], & lnNdens[MOS1IDNOIZ],
/* initialize our "history" variables */ ckt, THERMNOISE, inst->MOS1dNodePrime, inst->MOS1sNodePrime,
Sid);
for (i=0; i < MOS1NSRCS; i++) { NevalSrc( & noizDens[MOS1FLNOIZ], NULL, ckt,
inst->MOS1nVar[LNLSTDENS][i] = lnNdens[i]; N_GAIN, inst->MOS1dNodePrime, inst->MOS1sNodePrime,
} (double) 0.0);
if (newcompat.s3) {
noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef *
exp(model->MOS1fNexp *
log(MAX(fabs(inst->MOS1cd), N_MINLOG))) /
(data->freq *
inst->MOS1w *
(inst->MOS1l - 2 * model->MOS1latDiff) *
coxSquared);
} else {
switch (model->MOS1nlev) {
case 0:
noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef *
exp(model->MOS1fNexp *
log(MAX(fabs(inst->MOS1cd), N_MINLOG))) /
(data->freq *
(inst->MOS1l - 2 * model->MOS1latDiff) *
(inst->MOS1l - 2 * model->MOS1latDiff) *
sqrt(coxSquared));
break;
case 1:
noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef *
exp(model->MOS1fNexp *
log(MAX(fabs(inst->MOS1cd), N_MINLOG))) /
(data->freq *
inst->MOS1w *
(inst->MOS1l - 2 * model->MOS1latDiff) *
sqrt(coxSquared));
break;
case 2: case 3:
noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef *
inst->MOS1gm * inst->MOS1gm /
(pow(data->freq, model->MOS1fNexp) *
inst->MOS1w *
(inst->MOS1l - 2 * model->MOS1latDiff) *
sqrt(coxSquared));
break;
}
}
lnNdens[MOS1FLNOIZ] =
log(MAX(noizDens[MOS1FLNOIZ], N_MINLOG));
/* clear out our integration variables if it's the first pass */ noizDens[MOS1TOTNOIZ] = noizDens[MOS1RDNOIZ] +
noizDens[MOS1RSNOIZ] +
noizDens[MOS1IDNOIZ] +
noizDens[MOS1FLNOIZ];
lnNdens[MOS1TOTNOIZ] =
log(MAX(noizDens[MOS1TOTNOIZ], N_MINLOG));
if (data->freq == job->NstartFreq) { * OnDens += noizDens[MOS1TOTNOIZ];
for (i=0; i < MOS1NSRCS; i++) {
inst->MOS1nVar[OUTNOIZ][i] = 0.0; if (data->delFreq == 0.0) {
inst->MOS1nVar[INNOIZ][i] = 0.0;
} /* if we haven't done any previous integration, we need to */
} /* initialize our "history" variables */
} else { /* data->delFreq != 0.0 (we have to integrate) */
for (i=0; i < MOS1NSRCS; i++) { for (i = 0; i < MOS1NSRCS; i++) {
if (i != MOS1TOTNOIZ) { inst->MOS1nVar[LNLSTDENS][i] = lnNdens[i];
tempOnoise = Nintegrate(noizDens[i], lnNdens[i], }
inst->MOS1nVar[LNLSTDENS][i], data);
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , /* clear out our integration variables if it's the first pass */
lnNdens[i] + data->lnGainInv,
inst->MOS1nVar[LNLSTDENS][i] + data->lnGainInv, if (data->freq == job->NstartFreq) {
data); for (i = 0; i < MOS1NSRCS; i++) {
inst->MOS1nVar[LNLSTDENS][i] = lnNdens[i]; inst->MOS1nVar[OUTNOIZ][i] = 0.0;
data->outNoiz += tempOnoise; inst->MOS1nVar[INNOIZ][i] = 0.0;
data->inNoise += tempInoise; }
if (job->NStpsSm != 0) { }
inst->MOS1nVar[OUTNOIZ][i] += tempOnoise; } else {
inst->MOS1nVar[OUTNOIZ][MOS1TOTNOIZ] += tempOnoise; /* data->delFreq != 0.0 (we have to integrate) */
inst->MOS1nVar[INNOIZ][i] += tempInoise; for (i = 0; i < MOS1NSRCS; i++) {
inst->MOS1nVar[INNOIZ][MOS1TOTNOIZ] += tempInoise; if (i != MOS1TOTNOIZ) {
tempOnoise = Nintegrate(noizDens[i], lnNdens[i],
inst->MOS1nVar[LNLSTDENS][i], data);
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv,
lnNdens[i] + data->lnGainInv,
inst->MOS1nVar[LNLSTDENS][i] + data->lnGainInv,
data);
inst->MOS1nVar[LNLSTDENS][i] = lnNdens[i];
data->outNoiz += tempOnoise;
data->inNoise += tempInoise;
if (job->NStpsSm != 0) {
inst->MOS1nVar[OUTNOIZ][i] += tempOnoise;
inst->MOS1nVar[OUTNOIZ][MOS1TOTNOIZ] += tempOnoise;
inst->MOS1nVar[INNOIZ][i] += tempInoise;
inst->MOS1nVar[INNOIZ][MOS1TOTNOIZ] += tempInoise;
} }
} }
} }
} }
if (data->prtSummary) { if (data->prtSummary) {
for (i=0; i < MOS1NSRCS; i++) { /* print a summary report */ for (i = 0; i < MOS1NSRCS; i++) {
data->outpVector[data->outNumber++] = noizDens[i]; /* print a summary report */
} data->outpVector[data->outNumber++] = noizDens[i];
} }
break; }
break;
case INT_NOIZ: /* already calculated, just output */ case INT_NOIZ:
if (job->NStpsSm != 0) { /* already calculated, just output */
for (i=0; i < MOS1NSRCS; i++) { if (job->NStpsSm != 0) {
data->outpVector[data->outNumber++] = inst->MOS1nVar[OUTNOIZ][i]; for (i = 0; i < MOS1NSRCS; i++) {
data->outpVector[data->outNumber++] = inst->MOS1nVar[INNOIZ][i]; data->outpVector[data->outNumber++] = inst->MOS1nVar[OUTNOIZ][i];
} data->outpVector[data->outNumber++] = inst->MOS1nVar[INNOIZ][i];
} /* if */ }
break; } /* if */
} /* switch (mode) */ break;
break; } /* switch (mode) */
break;
case N_CLOSE: case N_CLOSE:
return (OK); /* do nothing, the main calling routine will close */ return (OK); /* do nothing, the main calling routine will close */
break; /* the plots */ break; /* the plots */
} /* switch (operation) */ } /* switch (operation) */
} /* for inst */ } /* for inst */
} /* for model */ } /* for model */
return(OK); return (OK);
} }

View File

@ -4,8 +4,8 @@ Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes Modified: 2000 AlansFixes
**********/ **********/
/* load the MOS1 device structure with those pointers needed later /* load the MOS1 device structure with those pointers needed later
* for fast matrix loading * for fast matrix loading
*/ */
#include "ngspice/ngspice.h" #include "ngspice/ngspice.h"
@ -81,12 +81,18 @@ MOS1setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
if(!model->MOS1gammaGiven) { if(!model->MOS1gammaGiven) {
model->MOS1gamma = 0; model->MOS1gamma = 0;
} }
if(!model->MOS1fNcoefGiven) { if(!model->MOS1fNcoefGiven) {
model->MOS1fNcoef = 0; model->MOS1fNcoef = 0;
} }
if(!model->MOS1fNexpGiven) { if(!model->MOS1fNexpGiven) {
model->MOS1fNexp = 1; model->MOS1fNexp = 1;
} }
if(!model->MOS1nlevGiven) {
model->MOS1nlev = 2;
}
if(!model->MOS1gdsnoiGiven) {
model->MOS1gdsnoi = 1;
}
/* loop through all the instances of the model */ /* loop through all the instances of the model */
for (here = MOS1instances(model); here != NULL ; for (here = MOS1instances(model); here != NULL ;
@ -121,34 +127,34 @@ MOS1setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
if(!here->MOS1vonGiven) { if(!here->MOS1vonGiven) {
here->MOS1von = 0; here->MOS1von = 0;
} }
if(!here->MOS1drainSquaresGiven) { if(!here->MOS1drainSquaresGiven) {
here->MOS1drainSquares=1; here->MOS1drainSquares=1;
} }
if(!here->MOS1sourceSquaresGiven) { if(!here->MOS1sourceSquaresGiven) {
here->MOS1sourceSquares=1; here->MOS1sourceSquares=1;
} }
if ((model->MOS1drainResistance != 0 if ((model->MOS1drainResistance != 0
|| (model->MOS1sheetResistance != 0 || (model->MOS1sheetResistance != 0
&& here->MOS1drainSquares != 0) )) { && here->MOS1drainSquares != 0) )) {
if (here->MOS1dNodePrime == 0) { if (here->MOS1dNodePrime == 0) {
error = CKTmkVolt(ckt,&tmp,here->MOS1name,"drain"); error = CKTmkVolt(ckt,&tmp,here->MOS1name,"drain");
if(error) return(error); if(error) return(error);
here->MOS1dNodePrime = tmp->number; here->MOS1dNodePrime = tmp->number;
if (ckt->CKTcopyNodesets) { if (ckt->CKTcopyNodesets) {
CKTnode *tmpNode; CKTnode *tmpNode;
IFuid tmpName; IFuid tmpName;
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) { if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset; tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven; tmp->nsGiven=tmpNode->nsGiven;
} }
} }
} }
} }
} else { } else {
here->MOS1dNodePrime = here->MOS1dNode; here->MOS1dNodePrime = here->MOS1dNode;
} }
@ -160,19 +166,19 @@ MOS1setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
error = CKTmkVolt(ckt,&tmp,here->MOS1name,"source"); error = CKTmkVolt(ckt,&tmp,here->MOS1name,"source");
if(error) return(error); if(error) return(error);
here->MOS1sNodePrime = tmp->number; here->MOS1sNodePrime = tmp->number;
if (ckt->CKTcopyNodesets) { if (ckt->CKTcopyNodesets) {
CKTnode *tmpNode; CKTnode *tmpNode;
IFuid tmpName; IFuid tmpName;
if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) { if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) { if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset; tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven; tmp->nsGiven=tmpNode->nsGiven;
} }
} }
} }
} }
} else { } else {
here->MOS1sNodePrime = here->MOS1sNode; here->MOS1sNodePrime = here->MOS1sNode;
@ -218,21 +224,21 @@ MOS1unsetup(GENmodel *inModel, CKTcircuit *ckt)
MOS1instance *here; MOS1instance *here;
for (model = (MOS1model *)inModel; model != NULL; for (model = (MOS1model *)inModel; model != NULL;
model = MOS1nextModel(model)) model = MOS1nextModel(model))
{ {
for (here = MOS1instances(model); here != NULL; for (here = MOS1instances(model); here != NULL;
here=MOS1nextInstance(here)) here=MOS1nextInstance(here))
{ {
if (here->MOS1sNodePrime > 0 if (here->MOS1sNodePrime > 0
&& here->MOS1sNodePrime != here->MOS1sNode) && here->MOS1sNodePrime != here->MOS1sNode)
CKTdltNNum(ckt, here->MOS1sNodePrime); CKTdltNNum(ckt, here->MOS1sNodePrime);
here->MOS1sNodePrime= 0; here->MOS1sNodePrime= 0;
if (here->MOS1dNodePrime > 0 if (here->MOS1dNodePrime > 0
&& here->MOS1dNodePrime != here->MOS1dNode) && here->MOS1dNodePrime != here->MOS1dNode)
CKTdltNNum(ckt, here->MOS1dNodePrime); CKTdltNNum(ckt, here->MOS1dNodePrime);
here->MOS1dNodePrime= 0; here->MOS1dNodePrime= 0;
} }
} }
return OK; return OK;
} }

View File

@ -156,7 +156,9 @@ IFparm MOS2mPTable[] = { /* model parameters */
IOP("nfs", MOS2_MOD_NFS, IF_REAL ,"Fast surface state density"), IOP("nfs", MOS2_MOD_NFS, IF_REAL ,"Fast surface state density"),
IOPU("tnom", MOS2_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), IOPU("tnom", MOS2_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"),
IOP("kf", MOS2_MOD_KF, IF_REAL ,"Flicker noise coefficient"), IOP("kf", MOS2_MOD_KF, IF_REAL ,"Flicker noise coefficient"),
IOP("af", MOS2_MOD_AF, IF_REAL ,"Flicker noise exponent") IOP("af", MOS2_MOD_AF, IF_REAL ,"Flicker noise exponent"),
IOP("nlev", MOS2_MOD_NLEV, IF_INTEGER ,"Noise model selection"),
IOP("gdsnoi", MOS2_MOD_GDSNOI, IF_REAL ,"Channel shot noise coefficient")
}; };
char *MOS2names[] = { char *MOS2names[] = {

View File

@ -390,6 +390,8 @@ typedef struct sMOS2model { /* model structure for a resistor */
double MOS2surfaceMobility; double MOS2surfaceMobility;
double MOS2fNcoef; double MOS2fNcoef;
double MOS2fNexp; double MOS2fNexp;
int MOS2nlev;
double MOS2gdsnoi;
double MOS2narrowFactor; /* delta */ double MOS2narrowFactor; /* delta */
double MOS2critFieldExp; /* uexp */ double MOS2critFieldExp; /* uexp */
@ -437,6 +439,8 @@ typedef struct sMOS2model { /* model structure for a resistor */
unsigned MOS2channelChargeGiven :1; /* neff */ unsigned MOS2channelChargeGiven :1; /* neff */
unsigned MOS2fNcoefGiven :1; unsigned MOS2fNcoefGiven :1;
unsigned MOS2fNexpGiven :1; unsigned MOS2fNexpGiven :1;
unsigned MOS2nlevGiven :1;
unsigned MOS2gdsnoiGiven :1;
} MOS2model; } MOS2model;
@ -574,6 +578,8 @@ enum {
enum { enum {
MOS2_MOD_KF = 139, MOS2_MOD_KF = 139,
MOS2_MOD_AF, MOS2_MOD_AF,
MOS2_MOD_NLEV,
MOS2_MOD_GDSNOI,
MOS2_MOD_TYPE, MOS2_MOD_TYPE,
}; };

View File

@ -124,18 +124,24 @@ MOS2mAsk(CKTcircuit *ckt, GENmodel *inModel, int param,
case MOS2_MOD_UCRIT: case MOS2_MOD_UCRIT:
value->rValue = model->MOS2critField; value->rValue = model->MOS2critField;
break; break;
case MOS2_MOD_KF: case MOS2_MOD_KF:
value->rValue = model->MOS2fNcoef; value->rValue = model->MOS2fNcoef;
break; break;
case MOS2_MOD_AF: case MOS2_MOD_AF:
value->rValue = model->MOS2fNexp; value->rValue = model->MOS2fNexp;
break; break;
case MOS2_MOD_TYPE: case MOS2_MOD_NLEV:
if (model->MOS2type > 0) value->iValue = model->MOS2nlev;
value->sValue = "nmos"; break;
else case MOS2_MOD_GDSNOI:
value->sValue = "pmos"; value->rValue = model->MOS2gdsnoi;
break; return(OK);
case MOS2_MOD_TYPE:
if (model->MOS2type > 0)
value->sValue = "nmos";
else
value->sValue = "pmos";
break;
default: default:
return(E_BADPARM); return(E_BADPARM);
} }

View File

@ -170,14 +170,22 @@ MOS2mParam(int param, IFvalue *value, GENmodel *inModel)
model->MOS2typeGiven = TRUE; model->MOS2typeGiven = TRUE;
} }
break; break;
case MOS2_MOD_KF: case MOS2_MOD_KF:
model->MOS2fNcoef = value->rValue; model->MOS2fNcoef = value->rValue;
model->MOS2fNcoefGiven = TRUE; model->MOS2fNcoefGiven = TRUE;
break; break;
case MOS2_MOD_AF: case MOS2_MOD_AF:
model->MOS2fNexp = value->rValue; model->MOS2fNexp = value->rValue;
model->MOS2fNexpGiven = TRUE; model->MOS2fNexpGiven = TRUE;
break; break;
case MOS2_MOD_NLEV:
model->MOS2nlev = value->iValue;
model->MOS2nlevGiven = TRUE;
break;
case MOS2_MOD_GDSNOI:
model->MOS2gdsnoi = value->rValue;
model->MOS2gdsnoiGiven = TRUE;
break;
default: default:
return(E_BADPARM); return(E_BADPARM);
} }

View File

@ -10,6 +10,7 @@ Modified: 2000 AlansFixes
#include "ngspice/iferrmsg.h" #include "ngspice/iferrmsg.h"
#include "ngspice/noisedef.h" #include "ngspice/noisedef.h"
#include "ngspice/suffix.h" #include "ngspice/suffix.h"
#include "ngspice/compatmode.h"
/* /*
* MOS2noise (mode, operation, firstModel, ckt, data, OnDens) * MOS2noise (mode, operation, firstModel, ckt, data, OnDens)
@ -20,160 +21,223 @@ Modified: 2000 AlansFixes
* all of the MOSFET's is summed with the variable "OnDens". * all of the MOSFET's is summed with the variable "OnDens".
*/ */
int int
MOS2noise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, MOS2noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
Ndata *data, double *OnDens) Ndata * data, double * OnDens) {
{ NOISEAN * job = (NOISEAN * ) ckt->CKTcurJob;
NOISEAN *job = (NOISEAN *) ckt->CKTcurJob;
MOS2model *firstModel = (MOS2model *) genmodel; MOS2model * firstModel = (MOS2model * ) genmodel;
MOS2model *model; MOS2model * model;
MOS2instance *inst; MOS2instance * inst;
double tempOnoise; double tempOnoise;
double tempInoise; double tempInoise;
double noizDens[MOS2NSRCS]; double noizDens[MOS2NSRCS];
double lnNdens[MOS2NSRCS]; double lnNdens[MOS2NSRCS];
int i; int i;
double vgs, vds, vgd, vgst, alpha, beta, Sid;
/* define the names of the noise sources */ /* define the names of the noise sources */
static char *MOS2nNames[MOS2NSRCS] = { /* Note that we have to keep the order */ static char * MOS2nNames[MOS2NSRCS] = {
"_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ /* Note that we have to keep the order */
"_rs", /* noise due to rs */ /* in MOS2defs.h */ "_rd",
"_id", /* noise due to id */ /* noise due to rd */ /* consistent with thestrchr definitions */
"_1overf", /* flicker (1/f) noise */ "_rs",
"" /* total transistor noise */ /* noise due to rs */ /* in MOS2defs.h */
"_id",
/* noise due to id */
"_1overf",
/* flicker (1/f) noise */
"" /* total transistor noise */
}; };
for (model=firstModel; model != NULL; model=MOS2nextModel(model)) { for (model = firstModel; model != NULL; model = MOS2nextModel(model)) {
for (inst=MOS2instances(model); inst != NULL; inst=MOS2nextInstance(inst)) { for (inst = MOS2instances(model); inst != NULL; inst = MOS2nextInstance(inst)) {
switch (operation) { switch (operation) {
case N_OPEN: case N_OPEN:
/* see if we have to to produce a summary report */ /* see if we have to to produce a summary report */
/* if so, name all the noise generators */ /* if so, name all the noise generators */
if (job->NStpsSm != 0) { if (job->NStpsSm != 0) {
switch (mode) { switch (mode) {
case N_DENS: case N_DENS:
for (i=0; i < MOS2NSRCS; i++) { for (i = 0; i < MOS2NSRCS; i++) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->MOS2name, MOS2nNames[i]); NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->MOS2name, MOS2nNames[i]);
} }
break; break;
case INT_NOIZ: case INT_NOIZ:
for (i=0; i < MOS2NSRCS; i++) { for (i = 0; i < MOS2NSRCS; i++) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->MOS2name, MOS2nNames[i]); NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->MOS2name, MOS2nNames[i]);
NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->MOS2name, MOS2nNames[i]); NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->MOS2name, MOS2nNames[i]);
} }
break; break;
} }
} }
break; break;
case N_CALC: case N_CALC:
switch (mode) { switch (mode) {
case N_DENS: case N_DENS:
NevalSrc(&noizDens[MOS2RDNOIZ],&lnNdens[MOS2RDNOIZ], NevalSrc( & noizDens[MOS2RDNOIZ], & lnNdens[MOS2RDNOIZ],
ckt,THERMNOISE,inst->MOS2dNodePrime,inst->MOS2dNode, ckt, THERMNOISE, inst->MOS2dNodePrime, inst->MOS2dNode,
inst->MOS2drainConductance); inst->MOS2drainConductance);
NevalSrc(&noizDens[MOS2RSNOIZ],&lnNdens[MOS2RSNOIZ], NevalSrc( & noizDens[MOS2RSNOIZ], & lnNdens[MOS2RSNOIZ],
ckt,THERMNOISE,inst->MOS2sNodePrime,inst->MOS2sNode, ckt, THERMNOISE, inst->MOS2sNodePrime, inst->MOS2sNode,
inst->MOS2sourceConductance); inst->MOS2sourceConductance);
NevalSrc(&noizDens[MOS2IDNOIZ],&lnNdens[MOS2IDNOIZ], if (model->MOS2nlev < 3) {
ckt,THERMNOISE,inst->MOS2dNodePrime,inst->MOS2sNodePrime,
(2.0/3.0 * fabs(inst->MOS2gm)));
NevalSrc(&noizDens[MOS2FLNOIZ], NULL, ckt, Sid = 2.0 / 3.0 * fabs(inst->MOS2gm);
N_GAIN,inst->MOS2dNodePrime, inst->MOS2sNodePrime,
(double)0.0);
noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef *
exp(model->MOS2fNexp *
log(MAX(fabs(inst->MOS2cd),N_MINLOG))) /
(data->freq * inst->MOS2w *
(inst->MOS2l - 2*model->MOS2latDiff) *
model->MOS2oxideCapFactor * model->MOS2oxideCapFactor);
lnNdens[MOS2FLNOIZ] =
log(MAX(noizDens[MOS2FLNOIZ],N_MINLOG));
noizDens[MOS2TOTNOIZ] = noizDens[MOS2RDNOIZ] + } else {
noizDens[MOS2RSNOIZ] + vds = *(ckt->CKTstate0 + inst->MOS2vds);
noizDens[MOS2IDNOIZ] + vgs = *(ckt->CKTstate0 + inst->MOS2vgs);
noizDens[MOS2FLNOIZ]; vgd = vgs - vds;
lnNdens[MOS2TOTNOIZ] =
log(MAX(noizDens[MOS2TOTNOIZ], N_MINLOG));
*OnDens += noizDens[MOS2TOTNOIZ]; vgst=(inst->MOS2mode==1?vgs:vgd) - model->MOS2type*inst->MOS2von;
if (vgst > 0) {
if (vgst <= (vds*inst->MOS2mode)) {
/* saturation region */
alpha = 0.0;
} else {
/* linear region */
alpha = 1.0 - (vds*inst->MOS2mode/(model->MOS2type*inst->MOS2vdsat));
}
}
beta = inst->MOS2tTransconductance * inst->MOS2m *
inst->MOS2w/(inst->MOS2l - 2 * model->MOS2latDiff);
Sid = 2.0 / 3.0 * beta * vgst * (1.0+alpha+alpha*alpha) / (1.0+alpha) * model->MOS2gdsnoi;
}
if (data->delFreq == 0.0) { NevalSrc( & noizDens[MOS2IDNOIZ], & lnNdens[MOS2IDNOIZ],
ckt, THERMNOISE, inst->MOS2dNodePrime, inst->MOS2sNodePrime,
Sid);
/* if we haven't done any previous integration, we need to */ NevalSrc( & noizDens[MOS2FLNOIZ], NULL, ckt,
/* initialize our "history" variables */ N_GAIN, inst->MOS2dNodePrime, inst->MOS2sNodePrime,
(double) 0.0);
if (newcompat.s3) {
noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef *
exp(model->MOS2fNexp *
log(MAX(fabs(inst->MOS2cd), N_MINLOG))) /
(data->freq *
inst->MOS2w *
(inst->MOS2l - 2 * model->MOS2latDiff) *
model->MOS2oxideCapFactor * model->MOS2oxideCapFactor);
} else {
switch (model->MOS2nlev) {
case 0:
noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef *
exp(model->MOS2fNexp *
log(MAX(fabs(inst->MOS2cd), N_MINLOG))) /
(data->freq *
(inst->MOS2l - 2 * model->MOS2latDiff) *
(inst->MOS2l - 2 * model->MOS2latDiff) *
model->MOS2oxideCapFactor);
break;
case 1:
noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef *
exp(model->MOS2fNexp *
log(MAX(fabs(inst->MOS2cd), N_MINLOG))) /
(data->freq *
inst->MOS2w *
(inst->MOS2l - 2 * model->MOS2latDiff) *
model->MOS2oxideCapFactor);
break;
case 2: case 3:
noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef *
inst->MOS2gm * inst->MOS2gm /
(pow(data->freq, model->MOS2fNexp) *
inst->MOS2w *
(inst->MOS2l - 2 * model->MOS2latDiff) *
model->MOS2oxideCapFactor);
break;
}
}
lnNdens[MOS2FLNOIZ] =
log(MAX(noizDens[MOS2FLNOIZ], N_MINLOG));
for (i=0; i < MOS2NSRCS; i++) { noizDens[MOS2TOTNOIZ] = noizDens[MOS2RDNOIZ] +
inst->MOS2nVar[LNLSTDENS][i] = lnNdens[i]; noizDens[MOS2RSNOIZ] +
} noizDens[MOS2IDNOIZ] +
noizDens[MOS2FLNOIZ];
lnNdens[MOS2TOTNOIZ] =
log(MAX(noizDens[MOS2TOTNOIZ], N_MINLOG));
/* clear out our integration variables if it's the first pass */ * OnDens += noizDens[MOS2TOTNOIZ];
if (data->freq == job->NstartFreq) { if (data->delFreq == 0.0) {
for (i=0; i < MOS2NSRCS; i++) {
inst->MOS2nVar[OUTNOIZ][i] = 0.0; /* if we haven't done any previous integration, we need to */
inst->MOS2nVar[INNOIZ][i] = 0.0; /* initialize our "history" variables */
}
} for (i = 0; i < MOS2NSRCS; i++) {
} else { /* data->delFreq != 0.0 (we have to integrate) */ inst->MOS2nVar[LNLSTDENS][i] = lnNdens[i];
for (i=0; i < MOS2NSRCS; i++) { }
if (i != MOS2TOTNOIZ) {
tempOnoise = Nintegrate(noizDens[i], lnNdens[i], /* clear out our integration variables if it's the first pass */
inst->MOS2nVar[LNLSTDENS][i], data);
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , if (data->freq == job->NstartFreq) {
lnNdens[i] + data->lnGainInv, for (i = 0; i < MOS2NSRCS; i++) {
inst->MOS2nVar[LNLSTDENS][i] + data->lnGainInv, inst->MOS2nVar[OUTNOIZ][i] = 0.0;
data); inst->MOS2nVar[INNOIZ][i] = 0.0;
inst->MOS2nVar[LNLSTDENS][i] = lnNdens[i]; }
data->outNoiz += tempOnoise; }
data->inNoise += tempInoise; } else {
if (job->NStpsSm != 0) { /* data->delFreq != 0.0 (we have to integrate) */
inst->MOS2nVar[OUTNOIZ][i] += tempOnoise; for (i = 0; i < MOS2NSRCS; i++) {
inst->MOS2nVar[OUTNOIZ][MOS2TOTNOIZ] += tempOnoise; if (i != MOS2TOTNOIZ) {
inst->MOS2nVar[INNOIZ][i] += tempInoise; tempOnoise = Nintegrate(noizDens[i], lnNdens[i],
inst->MOS2nVar[INNOIZ][MOS2TOTNOIZ] += tempInoise; inst->MOS2nVar[LNLSTDENS][i], data);
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv,
lnNdens[i] + data->lnGainInv,
inst->MOS2nVar[LNLSTDENS][i] + data->lnGainInv,
data);
inst->MOS2nVar[LNLSTDENS][i] = lnNdens[i];
data->outNoiz += tempOnoise;
data->inNoise += tempInoise;
if (job->NStpsSm != 0) {
inst->MOS2nVar[OUTNOIZ][i] += tempOnoise;
inst->MOS2nVar[OUTNOIZ][MOS2TOTNOIZ] += tempOnoise;
inst->MOS2nVar[INNOIZ][i] += tempInoise;
inst->MOS2nVar[INNOIZ][MOS2TOTNOIZ] += tempInoise;
} }
} }
} }
} }
if (data->prtSummary) { if (data->prtSummary) {
for (i=0; i < MOS2NSRCS; i++) { /* print a summary report */ for (i = 0; i < MOS2NSRCS; i++) {
data->outpVector[data->outNumber++] = noizDens[i]; /* print a summary report */
} data->outpVector[data->outNumber++] = noizDens[i];
} }
break; }
break;
case INT_NOIZ: /* already calculated, just output */ case INT_NOIZ:
if (job->NStpsSm != 0) { /* already calculated, just output */
for (i=0; i < MOS2NSRCS; i++) { if (job->NStpsSm != 0) {
data->outpVector[data->outNumber++] = inst->MOS2nVar[OUTNOIZ][i]; for (i = 0; i < MOS2NSRCS; i++) {
data->outpVector[data->outNumber++] = inst->MOS2nVar[INNOIZ][i]; data->outpVector[data->outNumber++] = inst->MOS2nVar[OUTNOIZ][i];
} data->outpVector[data->outNumber++] = inst->MOS2nVar[INNOIZ][i];
} /* if */ }
break; } /* if */
} /* switch (mode) */ break;
break; } /* switch (mode) */
break;
case N_CLOSE: case N_CLOSE:
return (OK); /* do nothing, the main calling routine will close */ return (OK); /* do nothing, the main calling routine will close */
break; /* the plots */ break; /* the plots */
} /* switch (operation) */ } /* switch (operation) */
} /* for inst */ } /* for inst */
} /* for model */ } /* for model */
return(OK); return (OK);
} }

View File

@ -14,8 +14,8 @@ Modified: 2000 AlansFixes
int int
MOS2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) MOS2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
/* load the MOS2 device structure with those pointers needed later /* load the MOS2 device structure with those pointers needed later
* for fast matrix loading * for fast matrix loading
*/ */
{ {
MOS2model *model = (MOS2model *)inModel; MOS2model *model = (MOS2model *)inModel;
@ -110,20 +110,26 @@ MOS2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
if(!model->MOS2fastSurfaceStateDensityGiven) { if(!model->MOS2fastSurfaceStateDensityGiven) {
model->MOS2fastSurfaceStateDensity = 0; model->MOS2fastSurfaceStateDensity = 0;
} }
if(!model->MOS2fNcoefGiven) { if(!model->MOS2fNcoefGiven) {
model->MOS2fNcoef = 0; model->MOS2fNcoef = 0;
} }
if(!model->MOS2fNexpGiven) { if(!model->MOS2fNexpGiven) {
model->MOS2fNexp = 1; model->MOS2fNexp = 1;
} }
if(!model->MOS2nlevGiven) {
model->MOS2nlev = 2;
}
if(!model->MOS2gdsnoiGiven) {
model->MOS2gdsnoi = 1;
}
/* loop through all the instances of the model */ /* loop through all the instances of the model */
for (here = MOS2instances(model); here != NULL ; for (here = MOS2instances(model); here != NULL ;
here=MOS2nextInstance(here)) { here=MOS2nextInstance(here)) {
CKTnode *tmpNode; CKTnode *tmpNode;
IFuid tmpName; IFuid tmpName;
/* allocate a chunk of the state vector */ /* allocate a chunk of the state vector */
here->MOS2states = *states; here->MOS2states = *states;
*states += MOS2numStates; *states += MOS2numStates;
@ -150,52 +156,52 @@ MOS2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
if(!here->MOS2vdsatGiven) { if(!here->MOS2vdsatGiven) {
here->MOS2vdsat = 0; here->MOS2vdsat = 0;
} }
if (!here->MOS2drainSquaresGiven) { if (!here->MOS2drainSquaresGiven) {
here->MOS2drainSquares=1; here->MOS2drainSquares=1;
} }
if (!here->MOS2sourceSquaresGiven) { if (!here->MOS2sourceSquaresGiven) {
here->MOS2sourceSquares=1; here->MOS2sourceSquares=1;
} }
if ((model->MOS2drainResistance != 0 if ((model->MOS2drainResistance != 0
|| (here->MOS2drainSquares != 0 || (here->MOS2drainSquares != 0
&& model->MOS2sheetResistance != 0))) { && model->MOS2sheetResistance != 0))) {
if (here->MOS2dNodePrime == 0) { if (here->MOS2dNodePrime == 0) {
error = CKTmkVolt(ckt,&tmp,here->MOS2name,"internal#drain"); error = CKTmkVolt(ckt,&tmp,here->MOS2name,"internal#drain");
if(error) return(error); if(error) return(error);
here->MOS2dNodePrime = tmp->number; here->MOS2dNodePrime = tmp->number;
if (ckt->CKTcopyNodesets) { if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) { if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset; tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven; tmp->nsGiven=tmpNode->nsGiven;
} }
} }
} }
} }
} else { } else {
here->MOS2dNodePrime = here->MOS2dNode; here->MOS2dNodePrime = here->MOS2dNode;
} }
if( ( (model->MOS2sourceResistance != 0) || if( ( (model->MOS2sourceResistance != 0) ||
((here->MOS2sourceSquares != 0) && ((here->MOS2sourceSquares != 0) &&
(model->MOS2sheetResistance != 0)) )) { (model->MOS2sheetResistance != 0)) )) {
if (here->MOS2sNodePrime == 0) { if (here->MOS2sNodePrime == 0) {
error = CKTmkVolt(ckt,&tmp,here->MOS2name,"internal#source"); error = CKTmkVolt(ckt,&tmp,here->MOS2name,"internal#source");
if(error) return(error); if(error) return(error);
here->MOS2sNodePrime = tmp->number; here->MOS2sNodePrime = tmp->number;
if (ckt->CKTcopyNodesets) { if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) { if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) { if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset; tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven; tmp->nsGiven=tmpNode->nsGiven;
} }
} }
} }
} }
} else { } else {
here->MOS2sNodePrime = here->MOS2sNode; here->MOS2sNodePrime = here->MOS2sNode;
} }
@ -241,21 +247,21 @@ MOS2unsetup(GENmodel *inModel, CKTcircuit *ckt)
MOS2instance *here; MOS2instance *here;
for (model = (MOS2model *)inModel; model != NULL; for (model = (MOS2model *)inModel; model != NULL;
model = MOS2nextModel(model)) model = MOS2nextModel(model))
{ {
for (here = MOS2instances(model); here != NULL; for (here = MOS2instances(model); here != NULL;
here=MOS2nextInstance(here)) here=MOS2nextInstance(here))
{ {
if (here->MOS2sNodePrime > 0 if (here->MOS2sNodePrime > 0
&& here->MOS2sNodePrime != here->MOS2sNode) && here->MOS2sNodePrime != here->MOS2sNode)
CKTdltNNum(ckt, here->MOS2sNodePrime); CKTdltNNum(ckt, here->MOS2sNodePrime);
here->MOS2sNodePrime = 0; here->MOS2sNodePrime = 0;
if (here->MOS2dNodePrime > 0 if (here->MOS2dNodePrime > 0
&& here->MOS2dNodePrime != here->MOS2dNode) && here->MOS2dNodePrime != here->MOS2dNode)
CKTdltNNum(ckt, here->MOS2dNodePrime); CKTdltNNum(ckt, here->MOS2dNodePrime);
here->MOS2dNodePrime = 0; here->MOS2dNodePrime = 0;
} }
} }
return OK; return OK;
} }

View File

@ -156,7 +156,9 @@ IFparm MOS3mPTable[] = { /* model parameters */
IOP("kappa", MOS3_MOD_KAPPA, IF_REAL ,"Kappa"), IOP("kappa", MOS3_MOD_KAPPA, IF_REAL ,"Kappa"),
IOPU("tnom", MOS3_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), IOPU("tnom", MOS3_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"),
IOP("kf", MOS3_MOD_KF, IF_REAL ,"Flicker noise coefficient"), IOP("kf", MOS3_MOD_KF, IF_REAL ,"Flicker noise coefficient"),
IOP("af", MOS3_MOD_AF, IF_REAL ,"Flicker noise exponent") IOP("af", MOS3_MOD_AF, IF_REAL ,"Flicker noise exponent"),
IOP("nlev", MOS3_MOD_NLEV, IF_INTEGER ,"Noise model selection"),
IOP("gdsnoi", MOS3_MOD_GDSNOI, IF_REAL ,"Channel shot noise coefficient")
}; };
char *MOS3names[] = { char *MOS3names[] = {

View File

@ -400,6 +400,8 @@ typedef struct sMOS3model { /* model structure for a resistor */
double MOS3kappa; /* kappa */ double MOS3kappa; /* kappa */
double MOS3fNcoef; double MOS3fNcoef;
double MOS3fNexp; double MOS3fNexp;
int MOS3nlev;
double MOS3gdsnoi;
unsigned MOS3typeGiven :1; unsigned MOS3typeGiven :1;
unsigned MOS3latDiffGiven :1; unsigned MOS3latDiffGiven :1;
@ -442,6 +444,8 @@ typedef struct sMOS3model { /* model structure for a resistor */
unsigned MOS3tnomGiven :1; /* Tnom was given? */ unsigned MOS3tnomGiven :1; /* Tnom was given? */
unsigned MOS3fNcoefGiven :1; unsigned MOS3fNcoefGiven :1;
unsigned MOS3fNexpGiven :1; unsigned MOS3fNexpGiven :1;
unsigned MOS3nlevGiven :1;
unsigned MOS3gdsnoiGiven :1;
} MOS3model; } MOS3model;
@ -580,6 +584,8 @@ enum {
MOS3_MOD_TNOM, MOS3_MOD_TNOM,
MOS3_MOD_KF, MOS3_MOD_KF,
MOS3_MOD_AF, MOS3_MOD_AF,
MOS3_MOD_NLEV,
MOS3_MOD_GDSNOI,
MOS3_MOD_TYPE, MOS3_MOD_TYPE,
MOS3_MOD_XL, MOS3_MOD_XL,
MOS3_MOD_WD, MOS3_MOD_WD,

View File

@ -18,148 +18,154 @@ Modified: 2000 AlansFixes
/*ARGSUSED*/ /*ARGSUSED*/
int int
MOS3mAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) MOS3mAsk(CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value)
{ {
MOS3model *here = (MOS3model *)inst; MOS3model *model = (MOS3model *)inModel;
NG_IGNORE(ckt); NG_IGNORE(ckt);
switch(which) { switch(which) {
case MOS3_MOD_TNOM: case MOS3_MOD_TNOM:
value->rValue = here->MOS3tnom-CONSTCtoK; value->rValue = model->MOS3tnom-CONSTCtoK;
return(OK); return(OK);
case MOS3_MOD_VTO: case MOS3_MOD_VTO:
value->rValue = here->MOS3vt0; value->rValue = model->MOS3vt0;
return(OK); return(OK);
case MOS3_MOD_KP: case MOS3_MOD_KP:
value->rValue = here->MOS3transconductance; value->rValue = model->MOS3transconductance;
return(OK); return(OK);
case MOS3_MOD_GAMMA: case MOS3_MOD_GAMMA:
value->rValue = here->MOS3gamma; value->rValue = model->MOS3gamma;
return(OK); return(OK);
case MOS3_MOD_PHI: case MOS3_MOD_PHI:
value->rValue = here->MOS3phi; value->rValue = model->MOS3phi;
return(OK); return(OK);
case MOS3_MOD_RD: case MOS3_MOD_RD:
value->rValue = here->MOS3drainResistance; value->rValue = model->MOS3drainResistance;
return(OK); return(OK);
case MOS3_MOD_RS: case MOS3_MOD_RS:
value->rValue = here->MOS3sourceResistance; value->rValue = model->MOS3sourceResistance;
return(OK); return(OK);
case MOS3_MOD_CBD: case MOS3_MOD_CBD:
value->rValue = here->MOS3capBD; value->rValue = model->MOS3capBD;
return(OK); return(OK);
case MOS3_MOD_CBS: case MOS3_MOD_CBS:
value->rValue = here->MOS3capBS; value->rValue = model->MOS3capBS;
return(OK); return(OK);
case MOS3_MOD_IS: case MOS3_MOD_IS:
value->rValue = here->MOS3jctSatCur; value->rValue = model->MOS3jctSatCur;
return(OK); return(OK);
case MOS3_MOD_PB: case MOS3_MOD_PB:
value->rValue = here->MOS3bulkJctPotential; value->rValue = model->MOS3bulkJctPotential;
return(OK); return(OK);
case MOS3_MOD_CGSO: case MOS3_MOD_CGSO:
value->rValue = here->MOS3gateSourceOverlapCapFactor; value->rValue = model->MOS3gateSourceOverlapCapFactor;
return(OK); return(OK);
case MOS3_MOD_CGDO: case MOS3_MOD_CGDO:
value->rValue = here->MOS3gateDrainOverlapCapFactor; value->rValue = model->MOS3gateDrainOverlapCapFactor;
return(OK); return(OK);
case MOS3_MOD_CGBO: case MOS3_MOD_CGBO:
value->rValue = here->MOS3gateBulkOverlapCapFactor; value->rValue = model->MOS3gateBulkOverlapCapFactor;
return(OK); return(OK);
case MOS3_MOD_CJ: case MOS3_MOD_CJ:
value->rValue = here->MOS3bulkCapFactor; value->rValue = model->MOS3bulkCapFactor;
return(OK); return(OK);
case MOS3_MOD_MJ: case MOS3_MOD_MJ:
value->rValue = here->MOS3bulkJctBotGradingCoeff; value->rValue = model->MOS3bulkJctBotGradingCoeff;
return(OK); return(OK);
case MOS3_MOD_CJSW: case MOS3_MOD_CJSW:
value->rValue = here->MOS3sideWallCapFactor; value->rValue = model->MOS3sideWallCapFactor;
return(OK); return(OK);
case MOS3_MOD_MJSW: case MOS3_MOD_MJSW:
value->rValue = here->MOS3bulkJctSideGradingCoeff; value->rValue = model->MOS3bulkJctSideGradingCoeff;
return(OK); return(OK);
case MOS3_MOD_JS: case MOS3_MOD_JS:
value->rValue = here->MOS3jctSatCurDensity; value->rValue = model->MOS3jctSatCurDensity;
return(OK); return(OK);
case MOS3_MOD_TOX: case MOS3_MOD_TOX:
value->rValue = here->MOS3oxideThickness; value->rValue = model->MOS3oxideThickness;
return(OK); return(OK);
case MOS3_MOD_LD: case MOS3_MOD_LD:
value->rValue = here->MOS3latDiff; value->rValue = model->MOS3latDiff;
return(OK); return(OK);
case MOS3_MOD_XL: case MOS3_MOD_XL:
value->rValue = here->MOS3lengthAdjust; value->rValue = model->MOS3lengthAdjust;
return(OK); return(OK);
case MOS3_MOD_WD: case MOS3_MOD_WD:
value->rValue = here->MOS3widthNarrow; value->rValue = model->MOS3widthNarrow;
return(OK); return(OK);
case MOS3_MOD_XW: case MOS3_MOD_XW:
value->rValue = here->MOS3widthAdjust; value->rValue = model->MOS3widthAdjust;
return(OK); return(OK);
case MOS3_MOD_DELVTO: case MOS3_MOD_DELVTO:
value->rValue = here->MOS3delvt0; value->rValue = model->MOS3delvt0;
return(OK); return(OK);
case MOS3_MOD_RSH: case MOS3_MOD_RSH:
value->rValue = here->MOS3sheetResistance; value->rValue = model->MOS3sheetResistance;
return(OK); return(OK);
case MOS3_MOD_U0: case MOS3_MOD_U0:
value->rValue = here->MOS3surfaceMobility; value->rValue = model->MOS3surfaceMobility;
return(OK); return(OK);
case MOS3_MOD_FC: case MOS3_MOD_FC:
value->rValue = here->MOS3fwdCapDepCoeff; value->rValue = model->MOS3fwdCapDepCoeff;
return(OK); return(OK);
case MOS3_MOD_NSUB: case MOS3_MOD_NSUB:
value->rValue = here->MOS3substrateDoping; value->rValue = model->MOS3substrateDoping;
return(OK); return(OK);
case MOS3_MOD_TPG: case MOS3_MOD_TPG:
value->iValue = here->MOS3gateType; value->iValue = model->MOS3gateType;
return(OK); return(OK);
case MOS3_MOD_NSS: case MOS3_MOD_NSS:
value->rValue = here->MOS3surfaceStateDensity; value->rValue = model->MOS3surfaceStateDensity;
return(OK); return(OK);
case MOS3_MOD_NFS: case MOS3_MOD_NFS:
value->rValue = here->MOS3fastSurfaceStateDensity; value->rValue = model->MOS3fastSurfaceStateDensity;
return(OK); return(OK);
case MOS3_MOD_DELTA: case MOS3_MOD_DELTA:
value->rValue = here->MOS3narrowFactor; value->rValue = model->MOS3narrowFactor;
return(OK); return(OK);
case MOS3_MOD_VMAX: case MOS3_MOD_VMAX:
value->rValue = here->MOS3maxDriftVel; value->rValue = model->MOS3maxDriftVel;
return(OK); return(OK);
case MOS3_MOD_XJ: case MOS3_MOD_XJ:
value->rValue = here->MOS3junctionDepth; value->rValue = model->MOS3junctionDepth;
return(OK); return(OK);
case MOS3_MOD_ETA: case MOS3_MOD_ETA:
value->rValue = here->MOS3eta; value->rValue = model->MOS3eta;
return(OK); return(OK);
case MOS3_MOD_XD: case MOS3_MOD_XD:
value->rValue = here->MOS3coeffDepLayWidth; value->rValue = model->MOS3coeffDepLayWidth;
return(OK); return(OK);
case MOS3_DELTA: case MOS3_DELTA:
value->rValue = here->MOS3delta; value->rValue = model->MOS3delta;
return(OK); return(OK);
case MOS3_MOD_THETA: case MOS3_MOD_THETA:
value->rValue = here->MOS3theta; value->rValue = model->MOS3theta;
return(OK); return(OK);
case MOS3_MOD_ALPHA: case MOS3_MOD_ALPHA:
value->rValue = here->MOS3alpha; value->rValue = model->MOS3alpha;
return(OK); return(OK);
case MOS3_MOD_KAPPA: case MOS3_MOD_KAPPA:
value->rValue = here->MOS3kappa; value->rValue = model->MOS3kappa;
return(OK); return(OK);
case MOS3_MOD_KF: case MOS3_MOD_KF:
value->rValue = here->MOS3fNcoef; value->rValue = model->MOS3fNcoef;
return(OK); return(OK);
case MOS3_MOD_AF: case MOS3_MOD_AF:
value->rValue = here->MOS3fNexp; value->rValue = model->MOS3fNexp;
return(OK); return(OK);
case MOS3_MOD_TYPE: case MOS3_MOD_NLEV:
if (here->MOS3type > 0) value->iValue = model->MOS3nlev;
value->sValue = "nmos"; return(OK);
else case MOS3_MOD_GDSNOI:
value->sValue = "pmos"; value->rValue = model->MOS3gdsnoi;
return(OK); return(OK);
case MOS3_MOD_TYPE:
if (model->MOS3type > 0)
value->sValue = "nmos";
else
value->sValue = "pmos";
return(OK);
default: default:
return(E_BADPARM); return(E_BADPARM);
} }

View File

@ -118,7 +118,7 @@ MOS3mParam(int param, IFvalue *value, GENmodel *inModel)
case MOS3_MOD_DELVTO: case MOS3_MOD_DELVTO:
model->MOS3delvt0 = value->rValue; model->MOS3delvt0 = value->rValue;
model->MOS3delvt0Given = TRUE; model->MOS3delvt0Given = TRUE;
break; break;
case MOS3_MOD_U0: case MOS3_MOD_U0:
model->MOS3surfaceMobility = value->rValue; model->MOS3surfaceMobility = value->rValue;
model->MOS3surfaceMobilityGiven = TRUE; model->MOS3surfaceMobilityGiven = TRUE;
@ -183,14 +183,22 @@ MOS3mParam(int param, IFvalue *value, GENmodel *inModel)
model->MOS3tnom = value->rValue+CONSTCtoK; model->MOS3tnom = value->rValue+CONSTCtoK;
model->MOS3tnomGiven = TRUE; model->MOS3tnomGiven = TRUE;
break; break;
case MOS3_MOD_KF: case MOS3_MOD_KF:
model->MOS3fNcoef = value->rValue; model->MOS3fNcoef = value->rValue;
model->MOS3fNcoefGiven = TRUE; model->MOS3fNcoefGiven = TRUE;
break; break;
case MOS3_MOD_AF: case MOS3_MOD_AF:
model->MOS3fNexp = value->rValue; model->MOS3fNexp = value->rValue;
model->MOS3fNexpGiven = TRUE; model->MOS3fNexpGiven = TRUE;
break; break;
case MOS3_MOD_NLEV:
model->MOS3nlev = value->iValue;
model->MOS3nlevGiven = TRUE;
break;
case MOS3_MOD_GDSNOI:
model->MOS3gdsnoi = value->rValue;
model->MOS3gdsnoiGiven = TRUE;
break;
default: default:
return(E_BADPARM); return(E_BADPARM);
} }

View File

@ -10,6 +10,7 @@ Modified: 2000 AlansFixes
#include "ngspice/iferrmsg.h" #include "ngspice/iferrmsg.h"
#include "ngspice/noisedef.h" #include "ngspice/noisedef.h"
#include "ngspice/suffix.h" #include "ngspice/suffix.h"
#include "ngspice/compatmode.h"
/* /*
* MOS3noise (mode, operation, firstModel, ckt, data, OnDens) * MOS3noise (mode, operation, firstModel, ckt, data, OnDens)
@ -20,161 +21,223 @@ Modified: 2000 AlansFixes
* all of the MOSFET's is summed with the variable "OnDens". * all of the MOSFET's is summed with the variable "OnDens".
*/ */
int int
MOS3noise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, MOS3noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
Ndata *data, double *OnDens) Ndata * data, double * OnDens) {
{ NOISEAN * job = (NOISEAN * ) ckt->CKTcurJob;
NOISEAN *job = (NOISEAN *) ckt->CKTcurJob;
MOS3model *firstModel = (MOS3model *) genmodel; MOS3model * firstModel = (MOS3model * ) genmodel;
MOS3model *model; MOS3model * model;
MOS3instance *inst; MOS3instance * inst;
double tempOnoise; double tempOnoise;
double tempInoise; double tempInoise;
double noizDens[MOS3NSRCS]; double noizDens[MOS3NSRCS];
double lnNdens[MOS3NSRCS]; double lnNdens[MOS3NSRCS];
int i; int i;
double vgs, vds, vgd, vgst, alpha, beta, Sid;
/* define the names of the noise sources */ /* define the names of the noise sources */
static char *MOS3nNames[MOS3NSRCS] = { /* Note that we have to keep the order */ static char * MOS3nNames[MOS3NSRCS] = {
"_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ /* Note that we have to keep the order */
"_rs", /* noise due to rs */ /* in MOS3defs.h */ "_rd",
"_id", /* noise due to id */ /* noise due to rd */ /* consistent with thestrchr definitions */
"_1overf", /* flicker (1/f) noise */ "_rs",
"" /* total transistor noise */ /* noise due to rs */ /* in MOS3defs.h */
"_id",
/* noise due to id */
"_1overf",
/* flicker (1/f) noise */
"" /* total transistor noise */
}; };
for (model=firstModel; model != NULL; model=MOS3nextModel(model)) { for (model = firstModel; model != NULL; model = MOS3nextModel(model)) {
for (inst=MOS3instances(model); inst != NULL; inst=MOS3nextInstance(inst)) { for (inst = MOS3instances(model); inst != NULL; inst = MOS3nextInstance(inst)) {
switch (operation) {
case N_OPEN: switch (operation) {
/* see if we have to to produce a summary report */ case N_OPEN:
/* if so, name all the noise generators */
if (job->NStpsSm != 0) { /* see if we have to to produce a summary report */
switch (mode) { /* if so, name all the noise generators */
case N_DENS: if (job->NStpsSm != 0) {
for (i=0; i < MOS3NSRCS; i++) { switch (mode) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->MOS3name, MOS3nNames[i]);
}
break;
case INT_NOIZ: case N_DENS:
for (i=0; i < MOS3NSRCS; i++) { for (i = 0; i < MOS3NSRCS; i++) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->MOS3name, MOS3nNames[i]); NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->MOS3name, MOS3nNames[i]);
NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->MOS3name, MOS3nNames[i]); }
} break;
break;
}
}
break;
case N_CALC: case INT_NOIZ:
switch (mode) { for (i = 0; i < MOS3NSRCS; i++) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->MOS3name, MOS3nNames[i]);
NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->MOS3name, MOS3nNames[i]);
}
break;
}
}
break;
case N_DENS: case N_CALC:
NevalSrc(&noizDens[MOS3RDNOIZ],&lnNdens[MOS3RDNOIZ], switch (mode) {
ckt,THERMNOISE,inst->MOS3dNodePrime,inst->MOS3dNode,
inst->MOS3drainConductance);
NevalSrc(&noizDens[MOS3RSNOIZ],&lnNdens[MOS3RSNOIZ], case N_DENS:
ckt,THERMNOISE,inst->MOS3sNodePrime,inst->MOS3sNode, NevalSrc( & noizDens[MOS3RDNOIZ], & lnNdens[MOS3RDNOIZ],
inst->MOS3sourceConductance); ckt, THERMNOISE, inst->MOS3dNodePrime, inst->MOS3dNode,
inst->MOS3drainConductance);
NevalSrc(&noizDens[MOS3IDNOIZ],&lnNdens[MOS3IDNOIZ], NevalSrc( & noizDens[MOS3RSNOIZ], & lnNdens[MOS3RSNOIZ],
ckt,THERMNOISE,inst->MOS3dNodePrime,inst->MOS3sNodePrime, ckt, THERMNOISE, inst->MOS3sNodePrime, inst->MOS3sNode,
(2.0/3.0 * fabs(inst->MOS3gm))); inst->MOS3sourceConductance);
NevalSrc(&noizDens[MOS3FLNOIZ], NULL, ckt, if (model->MOS3nlev < 3) {
N_GAIN,inst->MOS3dNodePrime, inst->MOS3sNodePrime,
(double)0.0);
noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef *
exp(model->MOS3fNexp *
log(MAX(fabs(inst->MOS3cd),N_MINLOG))) /
(data->freq *
(inst->MOS3w - 2*model->MOS3widthNarrow) *
(inst->MOS3l - 2*model->MOS3latDiff) *
model->MOS3oxideCapFactor * model->MOS3oxideCapFactor);
lnNdens[MOS3FLNOIZ] =
log(MAX(noizDens[MOS3FLNOIZ],N_MINLOG));
noizDens[MOS3TOTNOIZ] = noizDens[MOS3RDNOIZ] + Sid = 2.0 / 3.0 * fabs(inst->MOS3gm);
noizDens[MOS3RSNOIZ] +
noizDens[MOS3IDNOIZ] +
noizDens[MOS3FLNOIZ];
lnNdens[MOS3TOTNOIZ] =
log(MAX(noizDens[MOS3TOTNOIZ], N_MINLOG));
*OnDens += noizDens[MOS3TOTNOIZ]; } else {
vds = *(ckt->CKTstate0 + inst->MOS3vds);
vgs = *(ckt->CKTstate0 + inst->MOS3vgs);
vgd = vgs - vds;
if (data->delFreq == 0.0) { vgst=(inst->MOS3mode==1?vgs:vgd) - model->MOS3type*inst->MOS3von;
if (vgst > 0) {
if (vgst <= (vds*inst->MOS3mode)) {
/* saturation region */
alpha = 0.0;
} else {
/* linear region */
alpha = 1.0 - (vds*inst->MOS3mode/(model->MOS3type*inst->MOS3vdsat));
}
}
beta = inst->MOS3tTransconductance * inst->MOS3m *
inst->MOS3w/(inst->MOS3l - 2 * model->MOS3latDiff);
Sid = 2.0 / 3.0 * beta * vgst * (1.0+alpha+alpha*alpha) / (1.0+alpha) * model->MOS3gdsnoi;
}
/* if we haven't done any previous integration, we need to */ NevalSrc( & noizDens[MOS3IDNOIZ], & lnNdens[MOS3IDNOIZ],
/* initialize our "history" variables */ ckt, THERMNOISE, inst->MOS3dNodePrime, inst->MOS3sNodePrime,
Sid);
for (i=0; i < MOS3NSRCS; i++) { NevalSrc( & noizDens[MOS3FLNOIZ], NULL, ckt,
inst->MOS3nVar[LNLSTDENS][i] = lnNdens[i]; N_GAIN, inst->MOS3dNodePrime, inst->MOS3sNodePrime,
} (double) 0.0);
if (newcompat.s3) {
noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef *
exp(model->MOS3fNexp *
log(MAX(fabs(inst->MOS3cd), N_MINLOG))) /
(data->freq *
(inst->MOS3w - 2 * model->MOS3widthNarrow) *
(inst->MOS3l - 2 * model->MOS3latDiff) *
model->MOS3oxideCapFactor * model->MOS3oxideCapFactor);
} else {
switch (model->MOS3nlev) {
case 0:
noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef *
exp(model->MOS3fNexp *
log(MAX(fabs(inst->MOS3cd), N_MINLOG))) /
(data->freq *
(inst->MOS3l - 2 * model->MOS3latDiff) *
(inst->MOS3l - 2 * model->MOS3latDiff) *
model->MOS3oxideCapFactor);
break;
case 1:
noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef *
exp(model->MOS3fNexp *
log(MAX(fabs(inst->MOS3cd), N_MINLOG))) /
(data->freq *
(inst->MOS3w - 2 * model->MOS3widthNarrow) *
(inst->MOS3l - 2 * model->MOS3latDiff) *
model->MOS3oxideCapFactor);
break;
case 2: case 3:
noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef *
inst->MOS3gm * inst->MOS3gm /
(pow(data->freq, model->MOS3fNexp) *
(inst->MOS3w - 2 * model->MOS3widthNarrow) *
(inst->MOS3l - 2 * model->MOS3latDiff) *
model->MOS3oxideCapFactor);
break;
}
}
lnNdens[MOS3FLNOIZ] =
log(MAX(noizDens[MOS3FLNOIZ], N_MINLOG));
/* clear out our integration variables if it's the first pass */ noizDens[MOS3TOTNOIZ] = noizDens[MOS3RDNOIZ] +
noizDens[MOS3RSNOIZ] +
noizDens[MOS3IDNOIZ] +
noizDens[MOS3FLNOIZ];
lnNdens[MOS3TOTNOIZ] =
log(MAX(noizDens[MOS3TOTNOIZ], N_MINLOG));
if (data->freq == job->NstartFreq) { * OnDens += noizDens[MOS3TOTNOIZ];
for (i=0; i < MOS3NSRCS; i++) {
inst->MOS3nVar[OUTNOIZ][i] = 0.0; if (data->delFreq == 0.0) {
inst->MOS3nVar[INNOIZ][i] = 0.0;
} /* if we haven't done any previous integration, we need to */
} /* initialize our "history" variables */
} else { /* data->delFreq != 0.0 (we have to integrate) */
for (i=0; i < MOS3NSRCS; i++) { for (i = 0; i < MOS3NSRCS; i++) {
if (i != MOS3TOTNOIZ) { inst->MOS3nVar[LNLSTDENS][i] = lnNdens[i];
tempOnoise = Nintegrate(noizDens[i], lnNdens[i], }
inst->MOS3nVar[LNLSTDENS][i], data);
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , /* clear out our integration variables if it's the first pass */
lnNdens[i] + data->lnGainInv,
inst->MOS3nVar[LNLSTDENS][i] + data->lnGainInv, if (data->freq == job->NstartFreq) {
data); for (i = 0; i < MOS3NSRCS; i++) {
inst->MOS3nVar[LNLSTDENS][i] = lnNdens[i]; inst->MOS3nVar[OUTNOIZ][i] = 0.0;
data->outNoiz += tempOnoise; inst->MOS3nVar[INNOIZ][i] = 0.0;
data->inNoise += tempInoise; }
if (job->NStpsSm != 0) { }
inst->MOS3nVar[OUTNOIZ][i] += tempOnoise; } else {
inst->MOS3nVar[OUTNOIZ][MOS3TOTNOIZ] += tempOnoise; /* data->delFreq != 0.0 (we have to integrate) */
inst->MOS3nVar[INNOIZ][i] += tempInoise; for (i = 0; i < MOS3NSRCS; i++) {
inst->MOS3nVar[INNOIZ][MOS3TOTNOIZ] += tempInoise; if (i != MOS3TOTNOIZ) {
tempOnoise = Nintegrate(noizDens[i], lnNdens[i],
inst->MOS3nVar[LNLSTDENS][i], data);
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv,
lnNdens[i] + data->lnGainInv,
inst->MOS3nVar[LNLSTDENS][i] + data->lnGainInv,
data);
inst->MOS3nVar[LNLSTDENS][i] = lnNdens[i];
data->outNoiz += tempOnoise;
data->inNoise += tempInoise;
if (job->NStpsSm != 0) {
inst->MOS3nVar[OUTNOIZ][i] += tempOnoise;
inst->MOS3nVar[OUTNOIZ][MOS3TOTNOIZ] += tempOnoise;
inst->MOS3nVar[INNOIZ][i] += tempInoise;
inst->MOS3nVar[INNOIZ][MOS3TOTNOIZ] += tempInoise;
} }
} }
} }
} }
if (data->prtSummary) { if (data->prtSummary) {
for (i=0; i < MOS3NSRCS; i++) { /* print a summary report */ for (i = 0; i < MOS3NSRCS; i++) {
data->outpVector[data->outNumber++] = noizDens[i]; /* print a summary report */
} data->outpVector[data->outNumber++] = noizDens[i];
} }
break; }
break;
case INT_NOIZ: /* already calculated, just output */ case INT_NOIZ:
if (job->NStpsSm != 0) { /* already calculated, just output */
for (i=0; i < MOS3NSRCS; i++) { if (job->NStpsSm != 0) {
data->outpVector[data->outNumber++] = inst->MOS3nVar[OUTNOIZ][i]; for (i = 0; i < MOS3NSRCS; i++) {
data->outpVector[data->outNumber++] = inst->MOS3nVar[INNOIZ][i]; data->outpVector[data->outNumber++] = inst->MOS3nVar[OUTNOIZ][i];
} data->outpVector[data->outNumber++] = inst->MOS3nVar[INNOIZ][i];
} /* if */ }
break; } /* if */
} /* switch (mode) */ break;
break; } /* switch (mode) */
break;
case N_CLOSE: case N_CLOSE:
return (OK); /* do nothing, the main calling routine will close */ return (OK); /* do nothing, the main calling routine will close */
break; /* the plots */ break; /* the plots */
} /* switch (operation) */ } /* switch (operation) */
} /* for inst */ } /* for inst */
} /* for model */ } /* for model */
return(OK); return (OK);
} }

View File

@ -17,8 +17,8 @@ Modified: 2000 AlansFixes
int int
MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
/* load the MOS3 device structure with those pointers needed later /* load the MOS3 device structure with those pointers needed later
* for fast matrix loading * for fast matrix loading
*/ */
{ {
@ -48,7 +48,7 @@ MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
} }
if(!model->MOS3delvt0Given) { if(!model->MOS3delvt0Given) {
model->MOS3delvt0 = 0; model->MOS3delvt0 = 0;
} }
if(!model->MOS3jctSatCurDensityGiven) { if(!model->MOS3jctSatCurDensityGiven) {
model->MOS3jctSatCurDensity = 0; model->MOS3jctSatCurDensity = 0;
} }
@ -132,21 +132,27 @@ MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
} }
if(!model->MOS3oxideThicknessGiven) { if(!model->MOS3oxideThicknessGiven) {
model->MOS3oxideThickness = 1e-7; model->MOS3oxideThickness = 1e-7;
} }
if(!model->MOS3fNcoefGiven) { if(!model->MOS3fNcoefGiven) {
model->MOS3fNcoef = 0; model->MOS3fNcoef = 0;
} }
if(!model->MOS3fNexpGiven) { if(!model->MOS3fNexpGiven) {
model->MOS3fNexp = 1; model->MOS3fNexp = 1;
} }
if(!model->MOS3nlevGiven) {
model->MOS3nlev = 2;
}
if(!model->MOS3gdsnoiGiven) {
model->MOS3gdsnoi = 1;
}
/* loop through all the instances of the model */ /* loop through all the instances of the model */
for (here = MOS3instances(model); here != NULL ; for (here = MOS3instances(model); here != NULL ;
here=MOS3nextInstance(here)) { here=MOS3nextInstance(here)) {
CKTnode *tmpNode; CKTnode *tmpNode;
IFuid tmpName; IFuid tmpName;
/* allocate a chunk of the state vector */ /* allocate a chunk of the state vector */
here->MOS3states = *states; here->MOS3states = *states;
*states += MOS3NUMSTATES; *states += MOS3NUMSTATES;
@ -195,8 +201,8 @@ MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
if (ckt->CKTcopyNodesets) { if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) { if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset; tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven; tmp->nsGiven=tmpNode->nsGiven;
} }
} }
} }
@ -206,7 +212,7 @@ MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
} }
if((model->MOS3sourceResistance != 0 || if((model->MOS3sourceResistance != 0 ||
(model->MOS3sheetResistance != 0 && (model->MOS3sheetResistance != 0 &&
here->MOS3sourceSquares != 0 ) )) { here->MOS3sourceSquares != 0 ) )) {
if (here->MOS3sNodePrime == 0) { if (here->MOS3sNodePrime == 0) {
error = CKTmkVolt(ckt,&tmp,here->MOS3name,"internal#source"); error = CKTmkVolt(ckt,&tmp,here->MOS3name,"internal#source");
@ -215,8 +221,8 @@ MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
if (ckt->CKTcopyNodesets) { if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) { if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) { if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset; tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven; tmp->nsGiven=tmpNode->nsGiven;
} }
} }
} }
@ -266,21 +272,21 @@ MOS3unsetup(GENmodel *inModel, CKTcircuit *ckt)
MOS3instance *here; MOS3instance *here;
for (model = (MOS3model *)inModel; model != NULL; for (model = (MOS3model *)inModel; model != NULL;
model = MOS3nextModel(model)) model = MOS3nextModel(model))
{ {
for (here = MOS3instances(model); here != NULL; for (here = MOS3instances(model); here != NULL;
here=MOS3nextInstance(here)) here=MOS3nextInstance(here))
{ {
if (here->MOS3sNodePrime > 0 if (here->MOS3sNodePrime > 0
&& here->MOS3sNodePrime != here->MOS3sNode) && here->MOS3sNodePrime != here->MOS3sNode)
CKTdltNNum(ckt, here->MOS3sNodePrime); CKTdltNNum(ckt, here->MOS3sNodePrime);
here->MOS3sNodePrime= 0; here->MOS3sNodePrime= 0;
if (here->MOS3dNodePrime > 0 if (here->MOS3dNodePrime > 0
&& here->MOS3dNodePrime != here->MOS3dNode) && here->MOS3dNodePrime != here->MOS3dNode)
CKTdltNNum(ckt, here->MOS3dNodePrime); CKTdltNNum(ckt, here->MOS3dNodePrime);
here->MOS3dNodePrime= 0; here->MOS3dNodePrime= 0;
} }
} }
return OK; return OK;
} }

View File

@ -89,7 +89,7 @@ INPgetValue(CKTcircuit *ckt, char **line, int type, INPtables *tab)
INPgetNetTok(line, &word, 1); INPgetNetTok(line, &word, 1);
INPtermInsert(ckt, &word, tab, &(temp.nValue)); INPtermInsert(ckt, &word, tab, &(temp.nValue));
} else if (type == IF_INSTANCE) { } else if (type == IF_INSTANCE) {
INPgetTok(line, &word, 1); INPgetNetTok(line, &word, 1);
INPinsert(&word, tab); INPinsert(&word, tab);
temp.uValue = word; temp.uValue = word;
} else if (type == IF_STRING) { } else if (type == IF_STRING) {

View File

@ -2433,7 +2433,7 @@ tmeasure TCL_CMDPROCARGS(clientData, interp, argc, argv)
return TCL_ERROR; return TCL_ERROR;
} }
wl = wl_build((char **)argv); wl = wl_build((const char * const *)argv);
get_measure2(wl, &mvalue, NULL, FALSE); get_measure2(wl, &mvalue, NULL, FALSE);