Jspice3
mosnoi.c
Go to the documentation of this file.
1 /***************************************************************************
2 JSPICE3 adaptation of Spice3f2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California. All rights reserved.
4 Authors: 1987 Gary W. Ng
5  1993 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 #include "spice.h"
9 #include <stdio.h>
10 #include <math.h>
11 #include "mosdefs.h"
12 #include "noisedef.h"
13 #include "fteconst.h"
14 #include "iferrmsg.h"
15 #include "util.h"
16 
17 /*
18  * MOSnoise (mode, operation, firstModel, ckt, data, OnDens)
19  * This routine names and evaluates all of the noise sources
20  * associated with MOSFET's. It starts with the model *firstModel and
21  * traverses all of its insts. It then proceeds to any other models
22  * on the linked list. The total output noise density generated by
23  * all of the MOSFET's is summed with the variable "OnDens".
24  */
25 
26 /* define the names of the noise sources */
27 static char *MOSnNames[MOSNSRCS] = {
28  /* Note that we have to keep the order consistent with the index
29  * definitions in MOSdefs.h
30  */
31  ".rd", /* noise due to rd */
32  ".rs", /* noise due to rs */
33  ".id", /* noise due to id */
34  ".1overf", /* flicker (1/f) noise */
35  "" /* total transistor noise */
36 };
37 
38 
39 int
40 MOSnoise (mode, operation, genmodel, ckt, dataptr, OnDens)
41 
42 int mode;
43 int operation;
44 GENmodel *genmodel;
45 CKTcircuit *ckt;
46 GENERIC *dataptr;
47 double *OnDens;
48 {
49  Ndata *data = (Ndata*)dataptr;
50  MOSmodel *model = (MOSmodel *) genmodel;
51  MOSinstance *inst;
52  char name[N_MXVLNTH];
53  double tempOnoise;
54  double tempInoise;
55  double noizDens[MOSNSRCS];
56  double lnNdens[MOSNSRCS];
57  double coxSquared;
58  int error;
59  int i;
60 
61 
62  /* Oxide capacitance can be zero in MOS level 1. Since this will
63  * give us problems in our 1/f noise model, we ASSUME an actual "tox"
64  * of 1e-7
65  */
66 
67  if (operation == N_OPEN) {
68 
69  /* see if we have to to produce a summary report
70  * if so, name all the noise generators
71  */
72 
73  if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm == 0)
74  return (OK);
75 
76  if (mode == N_DENS) {
77 
78  for ( ; model; model = model->MOSnextModel) {
79 
80  if (model->MOSoxideCapFactor == 0.0) {
81  coxSquared = 3.9 * 8.854214871e-12 / 1e-7;
82  }
83  else {
84  coxSquared = model->MOSoxideCapFactor;
85  }
86  coxSquared *= coxSquared;
87 
88  for (inst = model->MOSinstances; inst != NULL;
89  inst = inst->MOSnextInstance) {
90 
91  for (i = 0; i < MOSNSRCS; i++) {
92  (void)sprintf(name,
93  "onoise.%s%s",inst->MOSname,MOSnNames[i]);
94 
95  data->namelist = (IFuid *)
96  trealloc((char *)data->namelist,
97  (data->numPlots + 1)*sizeof(IFuid));
98 
99  if (!data->namelist)
100  return (E_NOMEM);
101 
102  (*(SPfrontEnd->IFnewUid))(ckt,
103  &(data->namelist[data->numPlots++]),
104  (IFuid)NULL,name,UID_OTHER,(GENERIC **)NULL);
105  /* we've added one more plot */
106  }
107  }
108  }
109  return (OK);
110  }
111 
112  if (mode == INT_NOIZ) {
113 
114  for ( ; model; model = model->MOSnextModel) {
115 
116  if (model->MOSoxideCapFactor == 0.0) {
117  coxSquared = 3.9 * 8.854214871e-12 / 1e-7;
118  }
119  else {
120  coxSquared = model->MOSoxideCapFactor;
121  }
122  coxSquared *= coxSquared;
123 
124  for (inst = model->MOSinstances; inst != NULL;
125  inst = inst->MOSnextInstance) {
126 
127  for (i = 0; i < MOSNSRCS; i++) {
128  (void)sprintf(name,
129  "onoise_total.%s%s",inst->MOSname,MOSnNames[i]);
130 
131  data->namelist = (IFuid *)
132  trealloc((char *)data->namelist,
133  (data->numPlots + 1)*sizeof(IFuid));
134 
135  if (!data->namelist)
136  return (E_NOMEM);
137 
138  (*(SPfrontEnd->IFnewUid))(ckt,
139  &(data->namelist[data->numPlots++]),
140  (IFuid)NULL,name,UID_OTHER,(GENERIC **)NULL);
141  /* we've added one more plot */
142 
143  (void)sprintf(name,
144  "inoise_total.%s%s",inst->MOSname,MOSnNames[i]);
145 
146  data->namelist = (IFuid *)
147  trealloc((char *)data->namelist,
148  (data->numPlots + 1)*sizeof(IFuid));
149 
150  if (!data->namelist)
151  return (E_NOMEM);
152 
153  (*(SPfrontEnd->IFnewUid))(ckt,
154  &(data->namelist[data->numPlots++]),
155  (IFuid)NULL,name,UID_OTHER,(GENERIC **)NULL);
156  /* we've added one more plot */
157  }
158  }
159  }
160  }
161  return (OK);
162  }
163 
164  if (operation == N_CALC) {
165 
166  if (mode == N_DENS) {
167 
168  for ( ; model; model = model->MOSnextModel) {
169 
170  if (model->MOSoxideCapFactor == 0.0) {
171  coxSquared = 3.9 * 8.854214871e-12 / 1e-7;
172  }
173  else {
174  coxSquared = model->MOSoxideCapFactor;
175  }
176  coxSquared *= coxSquared;
177 
178  for (inst = model->MOSinstances; inst != NULL;
179  inst = inst->MOSnextInstance) {
180 
181  NevalSrc(&noizDens[MOSRDNOIZ],
182  &lnNdens[MOSRDNOIZ],
183  ckt,THERMNOISE,inst->MOSdNodePrime,
184  inst->MOSdNode,inst->MOSdrainConductance);
185 
186  NevalSrc(&noizDens[MOSRSNOIZ],
187  &lnNdens[MOSRSNOIZ],
188  ckt,THERMNOISE,inst->MOSsNodePrime,
189  inst->MOSsNode,inst->MOSsourceConductance);
190 
191  NevalSrc(&noizDens[MOSIDNOIZ],
192  &lnNdens[MOSIDNOIZ],
193  ckt,THERMNOISE,inst->MOSdNodePrime,
194  inst->MOSsNodePrime,
195  (2.0/3.0 * FABS(inst->MOSgm)));
196 
197  NevalSrc(&noizDens[MOSFLNOIZ],(double*)NULL,ckt,
198  N_GAIN,inst->MOSdNodePrime,
199  inst->MOSsNodePrime,(double)0.0);
200 
201  noizDens[MOSFLNOIZ] *= model->MOSfNcoef *
202  exp(model->MOSfNexp *
203  log(MAX(FABS(inst->MOScd),N_MINLOG))) /
204  (data->freq * inst->MOSw *
205  (inst->MOSl - 2*model->MOSlatDiff) *
206  coxSquared);
207 
208  lnNdens[MOSFLNOIZ] =
209  log(MAX(noizDens[MOSFLNOIZ],N_MINLOG));
210 
211  noizDens[MOSTOTNOIZ] = noizDens[MOSRDNOIZ] +
212  noizDens[MOSRSNOIZ] +
213  noizDens[MOSIDNOIZ] +
214  noizDens[MOSFLNOIZ];
215 
216  lnNdens[MOSTOTNOIZ] =
217  log(MAX(noizDens[MOSTOTNOIZ], N_MINLOG));
218 
219  *OnDens += noizDens[MOSTOTNOIZ];
220 
221  if (data->delFreq == 0.0) {
222 
223  /* if we haven't done any previous
224  * integration, we need to initialize
225  * our "history" variables
226  */
227 
228  for (i=0; i < MOSNSRCS; i++) {
229  inst->MOSnVar[LNLSTDENS][i] = lnNdens[i];
230  }
231 
232  /* clear out our integration variables if
233  * it's the first pass
234  */
235 
236  if (data->freq ==
237  ((NOISEAN*)ckt->CKTcurJob)->AC.fstart) {
238 
239  for (i = 0; i < MOSNSRCS; i++) {
240  inst->MOSnVar[OUTNOIZ][i] = 0.0;
241  inst->MOSnVar[INNOIZ][i] = 0.0;
242  }
243  }
244  }
245  else {
246  /* data->delFreq != 0.0
247  * (we have to integrate)
248  */
249  for (i = 0; i < MOSNSRCS; i++) {
250  if (i != MOSTOTNOIZ) {
251  tempOnoise =
252  Nintegrate(noizDens[i],lnNdens[i],
253  inst->MOSnVar[LNLSTDENS][i],data);
254  tempInoise =
255  Nintegrate(noizDens[i] *
256  data->GainSqInv,
257  lnNdens[i] + data->lnGainInv,
258  inst->MOSnVar[LNLSTDENS][i] +
259  data->lnGainInv,data);
260  inst->MOSnVar[LNLSTDENS][i] = lnNdens[i];
261  data->outNoiz += tempOnoise;
262  data->inNoise += tempInoise;
263  if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm
264  != 0) {
265  inst->MOSnVar[OUTNOIZ][i] += tempOnoise;
266  inst->MOSnVar[OUTNOIZ][MOSTOTNOIZ] +=
267  tempOnoise;
268  inst->MOSnVar[INNOIZ][i] += tempInoise;
269  inst->MOSnVar[INNOIZ][MOSTOTNOIZ] +=
270  tempInoise;
271 
272  }
273  }
274  }
275  }
276  if (data->prtSummary) {
277  for (i = 0; i < MOSNSRCS; i++) {
278  /* print a summary report */
279  data->outpVector[data->outNumber++] =
280  noizDens[i];
281  }
282  }
283  }
284  }
285  return (OK);
286  }
287 
288  if (mode == INT_NOIZ) {
289  /* already calculated, just output */
290 
291  if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm == 0)
292  return (OK);
293 
294  for ( ; model; model = model->MOSnextModel) {
295 
296  if (model->MOSoxideCapFactor == 0.0) {
297  coxSquared = 3.9 * 8.854214871e-12 / 1e-7;
298  }
299  else {
300  coxSquared = model->MOSoxideCapFactor;
301  }
302  coxSquared *= coxSquared;
303 
304  for (inst = model->MOSinstances; inst != NULL;
305  inst = inst->MOSnextInstance) {
306 
307  for (i = 0; i < MOSNSRCS; i++) {
308  data->outpVector[data->outNumber++] =
309  inst->MOSnVar[OUTNOIZ][i];
310  data->outpVector[data->outNumber++] =
311  inst->MOSnVar[INNOIZ][i];
312  }
313  }
314  }
315  }
316  }
317 
318  return (OK);
319 }
struct sMOSmodel * MOSnextModel
Definition: mosdefs.h:274
#define N_MXVLNTH
Definition: noisedef.h:124
MOSinstance * MOSinstances
Definition: mosdefs.h:276
#define N_GAIN
Definition: noisedef.h:90
double MOSlatDiff
Definition: mosdefs.h:303
double MOSgm
Definition: mosdefs.h:74
#define N_OPEN
Definition: noisedef.h:85
double * outpVector
Definition: noisedef.h:33
double MOScd
Definition: mosdefs.h:70
#define MAX(a, b)
Definition: spdefs.h:135
#define LNLSTDENS
Definition: noisedef.h:62
IFuid * namelist
Definition: noisedef.h:35
void NevalSrc()
static double e
Definition: vectors.c:17
IFfrontEnd * SPfrontEnd
Definition: main.c:917
double MOSl
Definition: mosdefs.h:34
double MOSoxideCapFactor
Definition: mosdefs.h:282
double MOSfNexp
Definition: mosdefs.h:310
int MOSdNodePrime
Definition: mosdefs.h:29
double lnGainInv
Definition: noisedef.h:25
#define INNOIZ
Definition: noisedef.h:64
#define MOSNSRCS
Definition: mosdefs.h:207
int MOSsNode
Definition: mosdefs.h:27
#define N_MINLOG
Definition: noisedef.h:95
double MOSw
Definition: mosdefs.h:35
#define OK
Definition: iferrmsg.h:17
GENERIC * IFuid
Definition: ifsim.h:72
unsigned int prtSummary
Definition: noisedef.h:32
#define MOSRDNOIZ
Definition: mosdefs.h:201
#define NULL
Definition: spdefs.h:121
#define INT_NOIZ
Definition: noisedef.h:84
#define E_NOMEM
Definition: iferrmsg.h:27
#define N_DENS
Definition: noisedef.h:83
int MOSdNode
Definition: mosdefs.h:25
double Nintegrate()
#define MOSIDNOIZ
Definition: mosdefs.h:203
#define MOSFLNOIZ
Definition: mosdefs.h:204
int MOSsNodePrime
Definition: mosdefs.h:30
double GainSqInv
Definition: noisedef.h:24
double MOSfNcoef
Definition: mosdefs.h:309
static char model[32]
Definition: subckt.c:76
#define FABS(a)
Definition: util.h:41
int outNumber
Definition: noisedef.h:29
#define THERMNOISE
Definition: noisedef.h:89
#define UID_OTHER
Definition: ifsim.h:85
int numPlots
Definition: noisedef.h:30
double MOSsourceConductance
Definition: mosdefs.h:42
int MOSnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, GENERIC *dataptr, double *OnDens)
Definition: mosnoi.c:40
double MOSnVar[NSTATVARS][MOSNSRCS]
Definition: mosdefs.h:210
IFuid MOSname
Definition: mosdefs.h:22
double delFreq
Definition: noisedef.h:21
double outNoiz
Definition: noisedef.h:22
double inNoise
Definition: noisedef.h:23
double freq
Definition: noisedef.h:19
#define N_CALC
Definition: noisedef.h:86
static char * MOSnNames[MOSNSRCS]
Definition: mosnoi.c:27
JOB * CKTcurJob
Definition: cktdefs.h:216
#define OUTNOIZ
Definition: noisedef.h:63
#define MOSTOTNOIZ
Definition: mosdefs.h:205
struct sMOSinstance * MOSnextInstance
Definition: mosdefs.h:20
char * trealloc()
char GENERIC
Definition: ifsim.h:27
#define MOSRSNOIZ
Definition: mosdefs.h:202
double MOSdrainConductance
Definition: mosdefs.h:43
Definition: noisedef.h:18