Qucs-core  0.0.18
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mosfet.cpp
Go to the documentation of this file.
1 /*
2  * mosfet.cpp - mosfet class implementation
3  *
4  * Copyright (C) 2004, 2005, 2006, 2008 Stefan Jahn <stefan@lkcc.org>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this package; see the file COPYING. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * $Id$
22  *
23  */
24 
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #include "component.h"
30 #include "device.h"
31 #include "mosfet.h"
32 
33 #define NODE_G 0 /* gate node */
34 #define NODE_D 1 /* drain node */
35 #define NODE_S 2 /* source node */
36 #define NODE_B 3 /* bulk node */
37 
38 using namespace qucs;
39 using namespace qucs::device;
40 
41 mosfet::mosfet () : circuit (4) {
42  transientMode = 0;
43  rg = rs = rd = NULL;
44  type = CIR_MOSFET;
45 }
46 
47 void mosfet::calcSP (nr_double_t frequency) {
48  setMatrixS (ytos (calcMatrixY (frequency)));
49 }
50 
51 matrix mosfet::calcMatrixY (nr_double_t frequency) {
52 
53  // fetch computed operating points
54  nr_double_t Cgd = getOperatingPoint ("Cgd");
55  nr_double_t Cgs = getOperatingPoint ("Cgs");
56  nr_double_t Cbd = getOperatingPoint ("Cbd");
57  nr_double_t Cbs = getOperatingPoint ("Cbs");
58  nr_double_t Cgb = getOperatingPoint ("Cgb");
59  nr_double_t gbs = getOperatingPoint ("gbs");
60  nr_double_t gbd = getOperatingPoint ("gbd");
61  nr_double_t gds = getOperatingPoint ("gds");
62  nr_double_t gm = getOperatingPoint ("gm");
63  nr_double_t gmb = getOperatingPoint ("gmb");
64 
65  // compute the models admittances
66  nr_complex_t Ygd = nr_complex_t (0.0, 2.0 * M_PI * frequency * Cgd);
67  nr_complex_t Ygs = nr_complex_t (0.0, 2.0 * M_PI * frequency * Cgs);
68  nr_complex_t Yds = gds;
69  nr_complex_t Ybd = nr_complex_t (gbd, 2.0 * M_PI * frequency * Cbd);
70  nr_complex_t Ybs = nr_complex_t (gbs, 2.0 * M_PI * frequency * Cbs);
71  nr_complex_t Ygb = nr_complex_t (0.0, 2.0 * M_PI * frequency * Cgb);
72 
73  // build admittance matrix and convert it to S-parameter matrix
74  matrix y (4);
75  y.set (NODE_G, NODE_G, Ygd + Ygs + Ygb);
76  y.set (NODE_G, NODE_D, -Ygd);
77  y.set (NODE_G, NODE_S, -Ygs);
78  y.set (NODE_G, NODE_B, -Ygb);
79  y.set (NODE_D, NODE_G, gm - Ygd);
80  y.set (NODE_D, NODE_D, Ygd + Yds + Ybd - DrainControl);
81  y.set (NODE_D, NODE_S, -Yds - SourceControl);
82  y.set (NODE_D, NODE_B, -Ybd + gmb);
83  y.set (NODE_S, NODE_G, -Ygs - gm);
84  y.set (NODE_S, NODE_D, -Yds + DrainControl);
85  y.set (NODE_S, NODE_S, Ygs + Yds + Ybs + SourceControl);
86  y.set (NODE_S, NODE_B, -Ybs - gmb);
87  y.set (NODE_B, NODE_G, -Ygb);
88  y.set (NODE_B, NODE_D, -Ybd);
89  y.set (NODE_B, NODE_S, -Ybs);
90  y.set (NODE_B, NODE_B, Ybd + Ybs + Ygb);
91 
92  return y;
93 }
94 
95 void mosfet::calcNoiseSP (nr_double_t frequency) {
96  setMatrixN (cytocs (calcMatrixCy (frequency) * z0, getMatrixS ()));
97 }
98 
99 matrix mosfet::calcMatrixCy (nr_double_t frequency) {
100  /* get operating points and noise properties */
101  nr_double_t Kf = getPropertyDouble ("Kf");
102  nr_double_t Af = getPropertyDouble ("Af");
103  nr_double_t Ffe = getPropertyDouble ("Ffe");
104  nr_double_t gm = fabs (getOperatingPoint ("gm"));
105  nr_double_t Ids = fabs (getOperatingPoint ("Id"));
106  nr_double_t T = getPropertyDouble ("Temp");
107 
108  /* compute channel noise and flicker noise generated by the DC
109  transconductance and current flow from drain to source */
110  nr_double_t i = 8 * kelvin (T) / T0 * gm / 3 +
111  Kf * qucs::pow (Ids, Af) / qucs::pow (frequency, Ffe) / kB / T0;
112 
113  /* build noise current correlation matrix and convert it to
114  noise-wave correlation matrix */
115  matrix cy = matrix (4);
116  cy.set (NODE_D, NODE_D, +i);
117  cy.set (NODE_S, NODE_S, +i);
118  cy.set (NODE_D, NODE_S, -i);
119  cy.set (NODE_S, NODE_D, -i);
120  return cy;
121 }
122 
123 void mosfet::restartDC (void) {
124  // apply starting values to previous iteration values
125  UgdPrev = real (getV (NODE_G) - getV (NODE_D));
126  UgsPrev = real (getV (NODE_G) - getV (NODE_S));
127  UbsPrev = real (getV (NODE_B) - getV (NODE_S));
128  UbdPrev = real (getV (NODE_B) - getV (NODE_D));
129  UdsPrev = UgsPrev - UgdPrev;
130 }
131 
132 void mosfet::initDC (void) {
133 
134  // allocate MNA matrices
135  allocMatrixMNA ();
136 
137  // initialize starting values
138  restartDC ();
139 
140  // initialize the MOSFET
141  initModel ();
142 
143  // get device temperature
144  nr_double_t T = getPropertyDouble ("Temp");
145 
146  // possibly insert series resistance at source
147  if (Rs != 0.0) {
148  // create additional circuit if necessary and reassign nodes
149  rs = splitResistor (this, rs, "Rs", "source", NODE_S);
150  rs->setProperty ("Temp", T);
151  rs->setProperty ("R", Rs);
152  rs->setProperty ("Controlled", getName ());
153  rs->initDC ();
154  }
155  // no series resistance at source
156  else {
157  disableResistor (this, rs, NODE_S);
158  }
159 
160  // possibly insert series resistance at gate
161  nr_double_t Rg = getPropertyDouble ("Rg");
162  if (Rg != 0.0) {
163  // create additional circuit if necessary and reassign nodes
164  rg = splitResistor (this, rg, "Rg", "gate", NODE_G);
165  rg->setProperty ("Temp", T);
166  rg->setProperty ("R", Rg);
167  rg->setProperty ("Controlled", getName ());
168  rg->initDC ();
169  }
170  // no series resistance at source
171  else {
172  disableResistor (this, rg, NODE_G);
173  }
174 
175  // possibly insert series resistance at drain
176  if (Rd != 0.0) {
177  // create additional circuit if necessary and reassign nodes
178  rd = splitResistor (this, rd, "Rd", "drain", NODE_D);
179  rd->setProperty ("Temp", T);
180  rd->setProperty ("R", Rd);
181  rd->setProperty ("Controlled", getName ());
182  rd->initDC ();
183  }
184  // no series resistance at drain
185  else {
186  disableResistor (this, rd, NODE_D);
187  }
188 }
189 
190 void mosfet::initModel (void) {
191 
192  // get device temperature
193  nr_double_t T = getPropertyDouble ("Temp");
194  nr_double_t T2 = kelvin (getPropertyDouble ("Temp"));
195  nr_double_t T1 = kelvin (getPropertyDouble ("Tnom"));
196 
197  // apply polarity of MOSFET
198  char * type = getPropertyString ("Type");
199  pol = !strcmp (type, "pfet") ? -1 : 1;
200 
201  // calculate effective channel length
202  nr_double_t L = getPropertyDouble ("L");
203  nr_double_t Ld = getPropertyDouble ("Ld");
204  if ((Leff = L - 2 * Ld) <= 0) {
205  logprint (LOG_STATUS, "WARNING: effective MOSFET channel length %g <= 0, "
206  "set to L = %g\n", Leff, L);
207  Leff = L;
208  }
209 
210  // calculate gate oxide overlap capacitance
211  nr_double_t W = getPropertyDouble ("W");
212  nr_double_t Tox = getPropertyDouble ("Tox");
213  if (Tox <= 0) {
214  logprint (LOG_STATUS, "WARNING: disabling gate oxide capacitance, "
215  "Cox = 0\n");
216  Cox = 0;
217  } else {
218  Cox = (ESiO2 * E0 / Tox);
219  }
220 
221  // calculate DC transconductance coefficient
222  nr_double_t Kp = getPropertyDouble ("Kp");
223  nr_double_t Uo = getPropertyDouble ("Uo");
224  nr_double_t F1 = qucs::exp (1.5 * qucs::log (T1 / T2));
225  Kp = Kp * F1;
226  Uo = Uo * F1;
227  setScaledProperty ("Kp", Kp);
228  setScaledProperty ("Uo", Uo);
229  if (Kp > 0) {
230  beta = Kp * W / Leff;
231  } else {
232  if (Cox > 0 && Uo > 0) {
233  beta = Uo * 1e-4 * Cox * W / Leff;
234  } else {
235  logprint (LOG_STATUS, "WARNING: adjust Tox, Uo or Kp to get a valid "
236  "transconductance coefficient\n");
237  beta = 2e-5 * W / Leff;
238  }
239  }
240 
241  // calculate surface potential
242  nr_double_t P = getPropertyDouble ("Phi");
243  nr_double_t Nsub = getPropertyDouble ("Nsub");
244  nr_double_t Ut = T0 * kBoverQ;
245  P = pnPotential_T (T1,T2, P);
246  setScaledProperty ("Phi", P);
247  if ((Phi = P) <= 0) {
248  if (Nsub > 0) {
249  if (Nsub * 1e6 >= NiSi) {
250  Phi = 2 * Ut * qucs::log (Nsub * 1e6 / NiSi);
251  } else {
252  logprint (LOG_STATUS, "WARNING: substrate doping less than instrinsic "
253  "density, adjust Nsub >= %g\n", NiSi / 1e6);
254  Phi = 0.6;
255  }
256  } else {
257  logprint (LOG_STATUS, "WARNING: adjust Nsub or Phi to get a valid "
258  "surface potential\n");
259  Phi = 0.6;
260  }
261  }
262 
263  // calculate bulk threshold
264  nr_double_t G = getPropertyDouble ("Gamma");
265  if ((Ga = G) < 0) {
266  if (Cox > 0 && Nsub > 0) {
267  Ga = qucs::sqrt (2 * Q_e * ESi * E0 * Nsub * 1e6) / Cox;
268  } else {
269  logprint (LOG_STATUS, "WARNING: adjust Tox, Nsub or Gamma to get a "
270  "valid bulk threshold\n");
271  Ga = 0.0;
272  }
273  }
274 
275  // calculate threshold voltage
276  nr_double_t Vt0 = getPropertyDouble ("Vt0");
277  if ((Vto = Vt0) == 0.0) {
278  nr_double_t Tpg = getPropertyDouble ("Tpg");
279  nr_double_t Nss = getPropertyDouble ("Nss");
280  nr_double_t PhiMS, PhiG, Eg;
281  // bandgap for silicon
282  Eg = Egap (kelvin (T));
283  if (Tpg != 0.0) { // n-poly or p-poly
284  PhiG = 4.15 + Eg / 2 - pol * Tpg * Eg / 2;
285  } else { // alumina
286  PhiG = 4.1;
287  }
288  PhiMS = PhiG - (4.15 + Eg / 2 + pol * Phi / 2);
289  if (Nss >= 0 && Cox > 0) {
290  Vto = PhiMS - Q_e * Nss * 1e4 / Cox + pol * (Phi + Ga * qucs::sqrt (Phi));
291  } else {
292  logprint (LOG_STATUS, "WARNING: adjust Tox, Nss or Vt0 to get a "
293  "valid threshold voltage\n");
294  Vto = 0.0;
295  }
296  }
297 
298  Cox = Cox * W * Leff;
299 
300  // calculate drain and source resistance if necessary
301  nr_double_t Rsh = getPropertyDouble ("Rsh");
302  nr_double_t Nrd = getPropertyDouble ("Nrd");
303  nr_double_t Nrs = getPropertyDouble ("Nrs");
304  Rd = getPropertyDouble ("Rd");
305  Rs = getPropertyDouble ("Rs");
306  if (Rsh > 0) {
307  if (Nrd > 0) Rd += Rsh * Nrd;
308  if (Nrs > 0) Rs += Rsh * Nrs;
309  }
310 
311  // calculate zero-bias junction capacitance
312  nr_double_t Cj = getPropertyDouble ("Cj");
313  nr_double_t Mj = getPropertyDouble ("Mj");
314  nr_double_t Mjs = getPropertyDouble ("Mjsw");
315  nr_double_t Pb = getPropertyDouble ("Pb");
316  nr_double_t PbT, F2, F3;
317  PbT = pnPotential_T (T1,T2, Pb);
318  F2 = pnCapacitance_F (T1, T2, Mj, PbT / Pb);
319  F3 = pnCapacitance_F (T1, T2, Mjs, PbT / Pb);
320  Pb = PbT;
321  setScaledProperty ("Pb", Pb);
322  if (Cj <= 0) {
323  if (Pb > 0 && Nsub >= 0) {
324  Cj = qucs::sqrt (ESi * E0 * Q_e * Nsub * 1e6 / 2 / Pb);
325  }
326  else {
327  logprint (LOG_STATUS, "WARNING: adjust Pb, Nsub or Cj to get a "
328  "valid square junction capacitance\n");
329  Cj = 0.0;
330  }
331  }
332  Cj = Cj * F2;
333  setScaledProperty ("Cj", Cj);
334 
335  // calculate junction capacitances
336  nr_double_t Cbd0 = getPropertyDouble ("Cbd");
337  nr_double_t Cbs0 = getPropertyDouble ("Cbs");
338  nr_double_t Ad = getPropertyDouble ("Ad");
339  nr_double_t As = getPropertyDouble ("As");
340  Cbd0 = Cbd0 * F2;
341  if (Cbd0 <= 0) {
342  Cbd0 = Cj * Ad;
343  }
344  setScaledProperty ("Cbd", Cbd0);
345  Cbs0 = Cbs0 * F2;
346  if (Cbs0 <= 0) {
347  Cbs0 = Cj * As;
348  }
349  setScaledProperty ("Cbs", Cbs0);
350 
351  // calculate periphery junction capacitances
352  nr_double_t Cjs = getPropertyDouble ("Cjsw");
353  nr_double_t Pd = getPropertyDouble ("Pd");
354  nr_double_t Ps = getPropertyDouble ("Ps");
355  Cjs = Cjs * F3;
356  setProperty ("Cbds", Cjs * Pd);
357  setProperty ("Cbss", Cjs * Ps);
358 
359  // calculate junction capacitances and saturation currents
360  nr_double_t Js = getPropertyDouble ("Js");
361  nr_double_t Is = getPropertyDouble ("Is");
362  nr_double_t F4, E1, E2;
363  E1 = Egap (T1);
364  E2 = Egap (T2);
365  F4 = qucs::exp (- QoverkB / T2 * (T2 / T1 * E1 - E2));
366  Is = Is * F4;
367  Js = Js * F4;
368  nr_double_t Isd = (Ad > 0) ? Js * Ad : Is;
369  nr_double_t Iss = (As > 0) ? Js * As : Is;
370  setProperty ("Isd", Isd);
371  setProperty ("Iss", Iss);
372 
373 #if DEBUG
374  logprint (LOG_STATUS, "NOTIFY: Cox=%g, Beta=%g Ga=%g, Phi=%g, Vto=%g\n",
375  Cox, beta, Ga, Phi, Vto);
376 #endif /* DEBUG */
377 }
378 
379 void mosfet::calcDC (void) {
380 
381  // fetch device model parameters
382  nr_double_t Isd = getPropertyDouble ("Isd");
383  nr_double_t Iss = getPropertyDouble ("Iss");
384  nr_double_t n = getPropertyDouble ("N");
385  nr_double_t l = getPropertyDouble ("Lambda");
386  nr_double_t T = getPropertyDouble ("Temp");
387 
388  nr_double_t Ut, IeqBS, IeqBD, IeqDS, UbsCrit, UbdCrit, gtiny;
389 
390  T = kelvin (T);
391  Ut = T * kBoverQ;
392  Ugd = real (getV (NODE_G) - getV (NODE_D)) * pol;
393  Ugs = real (getV (NODE_G) - getV (NODE_S)) * pol;
394  Ubs = real (getV (NODE_B) - getV (NODE_S)) * pol;
395  Ubd = real (getV (NODE_B) - getV (NODE_D)) * pol;
396  Uds = Ugs - Ugd;
397 
398  // critical voltage necessary for bad start values
399  UbsCrit = pnCriticalVoltage (Iss, Ut * n);
400  UbdCrit = pnCriticalVoltage (Isd, Ut * n);
401 
402  // for better convergence
403  if (Uds >= 0) {
404  Ugs = fetVoltage (Ugs, UgsPrev, Vto * pol);
405  Uds = Ugs - Ugd;
407  Ugd = Ugs - Uds;
408  }
409  else {
410  Ugd = fetVoltage (Ugd, UgdPrev, Vto * pol);
411  Uds = Ugs - Ugd;
412  Uds = -fetVoltageDS (-Uds, -UdsPrev);
413  Ugs = Ugd + Uds;
414  }
415  if (Uds >= 0) {
416  Ubs = pnVoltage (Ubs, UbsPrev, Ut * n, UbsCrit);
417  Ubd = Ubs - Uds;
418  }
419  else {
420  Ubd = pnVoltage (Ubd, UbdPrev, Ut * n, UbdCrit);
421  Ubs = Ubd + Uds;
422  }
424 
425  // parasitic bulk-source diode
426  gtiny = Iss;
427  pnJunctionMOS (Ubs, Iss, Ut * n, Ibs, gbs);
428  Ibs += gtiny * Ubs;
429  gbs += gtiny;
430 
431  // parasitic bulk-drain diode
432  gtiny = Isd;
433  pnJunctionMOS (Ubd, Isd, Ut * n, Ibd, gbd);
434  Ibd += gtiny * Ubd;
435  gbd += gtiny;
436 
437  // differentiate inverse and forward mode
438  MOSdir = (Uds >= 0) ? +1 : -1;
439 
440  // first calculate sqrt (Upn - Phi)
441  nr_double_t Upn = (MOSdir > 0) ? Ubs : Ubd;
442  nr_double_t Sarg, Sphi = qucs::sqrt (Phi);
443  if (Upn <= 0) {
444  // take equation as is
445  Sarg = qucs::sqrt (Phi - Upn);
446  }
447  else {
448  // taylor series of "sqrt (x - 1)" -> continual at Ubs/Ubd = 0
449  Sarg = Sphi - Upn / Sphi / 2;
450  Sarg = MAX (Sarg, 0);
451  }
452 
453  // calculate bias-dependent threshold voltage
454  Uon = Vto * pol + Ga * (Sarg - Sphi);
455  nr_double_t Utst = ((MOSdir > 0) ? Ugs : Ugd) - Uon;
456  // no infinite backgate transconductance (if non-zero Ga)
457  nr_double_t arg = (Sarg != 0.0) ? (Ga / Sarg / 2) : 0;
458 
459  // cutoff region
460  if (Utst <= 0) {
461  Ids = 0;
462  gm = 0;
463  gds = 0;
464  gmb = 0;
465  }
466  else {
467  nr_double_t Vds = Uds * MOSdir;
468  nr_double_t b = beta * (1 + l * Vds);
469  // saturation region
470  if (Utst <= Vds) {
471  Ids = b * Utst * Utst / 2;
472  gm = b * Utst;
473  gds = l * beta * Utst * Utst / 2;
474  }
475  // linear region
476  else {
477  Ids = b * Vds * (Utst - Vds / 2);
478  gm = b * Vds;
479  gds = b * (Utst - Vds) + l * beta * Vds * (Utst - Vds / 2);
480  }
481  gmb = gm * arg;
482  }
483  Udsat = pol * MAX (Utst, 0);
484  Ids = MOSdir * Ids;
485  Uon = pol * Uon;
486 
487  // compute autonomic current sources
488  IeqBD = Ibd - gbd * Ubd;
489  IeqBS = Ibs - gbs * Ubs;
490 
491  // exchange controlling nodes if necessary
492  SourceControl = (MOSdir > 0) ? (gm + gmb) : 0;
493  DrainControl = (MOSdir < 0) ? (gm + gmb) : 0;
494  if (MOSdir > 0) {
495  IeqDS = Ids - gm * Ugs - gmb * Ubs - gds * Uds;
496  } else {
497  IeqDS = Ids - gm * Ugd - gmb * Ubd - gds * Uds;
498  }
499 
500  setI (NODE_G, 0);
501  setI (NODE_D, (+IeqBD - IeqDS) * pol);
502  setI (NODE_S, (+IeqBS + IeqDS) * pol);
503  setI (NODE_B, (-IeqBD - IeqBS) * pol);
504 
505  // apply admittance matrix elements
506  setY (NODE_G, NODE_G, 0);
507  setY (NODE_G, NODE_D, 0);
508  setY (NODE_G, NODE_S, 0);
509  setY (NODE_G, NODE_B, 0);
510  setY (NODE_D, NODE_G, gm);
513  setY (NODE_D, NODE_B, gmb - gbd);
514  setY (NODE_S, NODE_G, -gm);
517  setY (NODE_S, NODE_B, -gbs - gmb);
518  setY (NODE_B, NODE_G, 0);
519  setY (NODE_B, NODE_D, -gbd);
520  setY (NODE_B, NODE_S, -gbs);
521  setY (NODE_B, NODE_B, gbs + gbd);
522 }
523 
524 /* Usual and additional state definitions. */
525 
526 #define qgdState 0 // gate-drain charge state
527 #define igdState 1 // gate-drain current state
528 #define vgdState 2 // gate-drain voltage state
529 #define cgdState 3 // gate-drain capacitance state
530 #define qgsState 4 // gate-source charge state
531 #define igsState 5 // gate-source current state
532 #define vgsState 6 // gate-source voltage state
533 #define cgsState 7 // gate-source capacitance state
534 #define qbdState 8 // bulk-drain charge state
535 #define ibdState 9 // bulk-drain current state
536 #define qbsState 10 // bulk-source charge state
537 #define ibsState 11 // bulk-source current state
538 #define qgbState 12 // gate-bulk charge state
539 #define igbState 13 // gate-bulk current state
540 #define vgbState 14 // gate-bulk voltage state
541 #define cgbState 15 // gate-bulk capacitance state
542 
544  nr_double_t Vgs, Vgd, Vbs, Vbd;
545  Vgd = real (getV (NODE_G) - getV (NODE_D)) * pol;
546  Vgs = real (getV (NODE_G) - getV (NODE_S)) * pol;
547  Vbs = real (getV (NODE_B) - getV (NODE_S)) * pol;
548  Vbd = real (getV (NODE_B) - getV (NODE_D)) * pol;
549  setOperatingPoint ("Vgs", Vgs);
550  setOperatingPoint ("Vgd", Vgd);
551  setOperatingPoint ("Vbs", Vbs);
552  setOperatingPoint ("Vbd", Vbd);
553  setOperatingPoint ("Vds", Vgs - Vgd);
554  setOperatingPoint ("Vgb", Vgs - Vbs);
555 }
556 
558  Ugs = getOperatingPoint ("Vgs");
559  Ugd = getOperatingPoint ("Vgd");
560  Ubs = getOperatingPoint ("Vbs");
561  Ubd = getOperatingPoint ("Vbd");
562  Uds = getOperatingPoint ("Vds");
563  Ugb = getOperatingPoint ("Vgb");
564 }
565 
567 
568  // fetch device model parameters
569  nr_double_t Cbd0 = getScaledProperty ("Cbd");
570  nr_double_t Cbs0 = getScaledProperty ("Cbs");
571  nr_double_t Cbds = getPropertyDouble ("Cbds");
572  nr_double_t Cbss = getPropertyDouble ("Cbss");
573  nr_double_t Cgso = getPropertyDouble ("Cgso");
574  nr_double_t Cgdo = getPropertyDouble ("Cgdo");
575  nr_double_t Cgbo = getPropertyDouble ("Cgbo");
576  nr_double_t Pb = getScaledProperty ("Pb");
577  nr_double_t M = getPropertyDouble ("Mj");
578  nr_double_t Ms = getPropertyDouble ("Mjsw");
579  nr_double_t Fc = getPropertyDouble ("Fc");
580  nr_double_t Tt = getPropertyDouble ("Tt");
581  nr_double_t W = getPropertyDouble ("W");
582 
583  nr_double_t Cbs, Cbd, Cgd, Cgb, Cgs;
584 
585  // capacitance of bulk-drain diode
586  Cbd = gbd * Tt + pnCapacitance (Ubd, Cbd0, Pb, M, Fc) +
587  pnCapacitance (Ubd, Cbds, Pb, Ms, Fc);
588  Qbd = Ibd * Tt + pnCharge (Ubd, Cbd0, Pb, M, Fc) +
589  pnCharge (Ubd, Cbds, Pb, Ms, Fc);
590 
591  // capacitance of bulk-source diode
592  Cbs = gbs * Tt + pnCapacitance (Ubs, Cbs0, Pb, M, Fc) +
593  pnCapacitance (Ubs, Cbss, Pb, Ms, Fc);
594  Qbs = Ibs * Tt + pnCharge (Ubs, Cbs0, Pb, M, Fc) +
595  pnCharge (Ubs, Cbss, Pb, Ms, Fc);
596 
597  // calculate bias-dependent MOS overlap capacitances
598  if (MOSdir > 0) {
599  fetCapacitanceMeyer (Ugs, Ugd, Uon, Udsat, Phi, Cox, Cgs, Cgd, Cgb);
600  } else {
601  fetCapacitanceMeyer (Ugd, Ugs, Uon, Udsat, Phi, Cox, Cgd, Cgs, Cgb);
602  }
603 
604  // charge approximation
605  if (transientMode) {
606  if (transientMode == 1) { // by trapezoidal rule
607  // gate-source charge
608  Qgs = transientChargeTR (qgsState, Cgs, Ugs, Cgso * W);
609  // gate-drain charge
610  Qgd = transientChargeTR (qgdState, Cgd, Ugd, Cgdo * W);
611  // gate-bulk charge
612  Qgb = transientChargeTR (qgbState, Cgb, Ugb, Cgbo * Leff);
613  }
614  else if (transientMode == 2) { // by simpson's rule
615  Qgs = transientChargeSR (qgsState, Cgs, Ugs, Cgso * W);
616  Qgd = transientChargeSR (qgdState, Cgd, Ugd, Cgdo * W);
617  Qgb = transientChargeSR (qgbState, Cgb, Ugb, Cgbo * Leff);
618  }
619  }
620  // usual operating point
621  else {
622  Cgs += Cgso * W;
623  Cgd += Cgdo * W;
624  Cgb += Cgbo * Leff;
625  }
626 
627  // save operating points
628  setOperatingPoint ("Id", Ids);
629  setOperatingPoint ("gm", gm);
630  setOperatingPoint ("gmb", gmb);
631  setOperatingPoint ("gds", gds);
632  setOperatingPoint ("Vth", Vto);
633  setOperatingPoint ("Vdsat", Udsat);
634  setOperatingPoint ("gbs", gbs);
635  setOperatingPoint ("gbd", gbd);
636  setOperatingPoint ("Cbd", Cbd);
637  setOperatingPoint ("Cbs", Cbs);
638  setOperatingPoint ("Cgs", Cgs);
639  setOperatingPoint ("Cgd", Cgd);
640  setOperatingPoint ("Cgb", Cgb);
641 }
642 
643 void mosfet::initAC (void) {
644  allocMatrixMNA ();
645 }
646 
647 void mosfet::calcAC (nr_double_t frequency) {
648  setMatrixY (calcMatrixY (frequency));
649 }
650 
651 void mosfet::calcNoiseAC (nr_double_t frequency) {
652  setMatrixN (calcMatrixCy (frequency));
653 }
654 
655 void mosfet::initTR (void) {
656  setStates (16);
657  initDC ();
658 }
659 
660 void mosfet::calcTR (nr_double_t) {
661  calcDC ();
662  transientMode = getPropertyInteger ("capModel");
666  transientMode = 0;
667 
668  nr_double_t Cgd = getOperatingPoint ("Cgd");
669  nr_double_t Cgs = getOperatingPoint ("Cgs");
670  nr_double_t Cbd = getOperatingPoint ("Cbd");
671  nr_double_t Cbs = getOperatingPoint ("Cbs");
672  nr_double_t Cgb = getOperatingPoint ("Cgb");
673 
674  Uds = Ugs - Ugd;
675  Ugb = Ugs - Ubs;
676 
679 
680  // handle Meyer charges and capacitances
684 }
685 
686 /* The function uses the trapezoidal rule to compute the current
687  capacitance and charge. The approximation is necessary because the
688  Meyer model is a capacitance model and not a charge model. */
689 nr_double_t mosfet::transientChargeTR (int qstate, nr_double_t& cap,
690  nr_double_t voltage, nr_double_t ccap) {
691  int vstate = qstate + 2, cstate = qstate + 3;
692  setState (cstate, cap);
693  cap = (cap + getState (cstate, 1)) / 2 + ccap;
694  setState (vstate, voltage);
695  return cap * (voltage - getState (vstate, 1)) + getState (qstate, 1);
696 }
697 
698 /* The function uses Simpson's numerical integration rule to compute
699  the current capacitance and charge. */
700 nr_double_t mosfet::transientChargeSR (int qstate, nr_double_t& cap,
701  nr_double_t voltage, nr_double_t ccap) {
702  int vstate = qstate + 2, cstate = qstate + 3;
703  setState (cstate, cap);
704  cap = (cap + 4 * getState (cstate, 1) + getState (cstate, 2)) / 6 + ccap;
705  setState (vstate, voltage);
706  return cap * (voltage - getState (vstate, 1)) + getState (qstate, 1);
707 }
708 
709 // properties
710 PROP_REQ [] = {
711  { "Is", PROP_REAL, { 1e-14, PROP_NO_STR }, PROP_POS_RANGE },
712  { "N", PROP_REAL, { 1, PROP_NO_STR }, PROP_RNGII (0.1, 100) },
713  { "Vt0", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
714  { "Lambda", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
715  { "Kp", PROP_REAL, { 2e-5, PROP_NO_STR }, PROP_POS_RANGE },
716  { "Gamma", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
717  { "Phi", PROP_REAL, { 0.6, PROP_NO_STR }, PROP_POS_RANGE },
718  PROP_NO_PROP };
719 PROP_OPT [] = {
720  { "Rd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
721  { "Rs", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
722  { "Rg", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
723  { "L", PROP_REAL, { 100e-6, PROP_NO_STR }, PROP_RNG_X01I },
724  { "Ld", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
725  { "W", PROP_REAL, { 100e-6, PROP_NO_STR }, PROP_POS_RANGEX },
726  { "Tox", PROP_REAL, { 1e-7, PROP_NO_STR }, PROP_RNG_X01I },
727  { "Cgso", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
728  { "Cgdo", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
729  { "Cgbo", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
730  { "Cbd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
731  { "Cbs", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
732  { "Pb", PROP_REAL, { 0.8, PROP_NO_STR }, PROP_RNGXI (0, 10) },
733  { "Mj", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGII (0, 1) },
734  { "Fc", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGIX (0, 1) },
735  { "Cjsw", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
736  { "Mjsw", PROP_REAL, { 0.33, PROP_NO_STR }, PROP_RNGII (0, 1) },
737  { "Tt", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
738  { "Kf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
739  { "Af", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
740  { "Ffe", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
741  { "Nsub", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
742  { "Nss", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
743  { "Tpg", PROP_INT, { 1, PROP_NO_STR }, PROP_RNGII (-1 , 1) },
744  { "Uo", PROP_REAL, { 600, PROP_NO_STR }, PROP_POS_RANGE },
745  { "Rsh", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
746  { "Nrd", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
747  { "Nrs", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
748  { "Cj", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
749  { "Js", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
750  { "Ad", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
751  { "As", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
752  { "Pd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
753  { "Ps", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
754  { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
755  { "Tnom", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
756  { "Type", PROP_STR, { PROP_NO_VAL, "nfet" }, PROP_RNG_FET },
757  { "capModel", PROP_INT, { 2, PROP_NO_STR }, PROP_RNGII (1 , 2) },
758  PROP_NO_PROP };
759 struct define_t mosfet::cirdef =
void setProperty(const char *, char *)
Definition: object.cpp:104
nr_double_t Ugs
Definition: mosfet.h:58
std::complex< nr_double_t > nr_complex_t
Definition: complex.h:31
#define NODE_D
Definition: mosfet.cpp:34
nr_double_t transientChargeTR(int, nr_double_t &, nr_double_t, nr_double_t)
Definition: mosfet.cpp:689
nr_double_t getOperatingPoint(const char *)
Definition: circuit.cpp:525
#define PROP_POS_RANGE
Definition: netdefs.h:129
l
Definition: parse_vcd.y:213
#define ESi
Relative permittivity of Silicon.
Definition: constants.h:75
matrix ytos(matrix y, qucs::vector z0)
Admittance matrix to scattering parameters.
Definition: matrix.cpp:1133
PROP_OPT[]
Definition: mosfet.cpp:719
matrix real(matrix a)
Real part matrix.
Definition: matrix.cpp:568
#define T0
standard temperature
Definition: constants.h:61
#define PROP_RNGII(f, t)
Definition: netdefs.h:138
nr_double_t DrainControl
Definition: mosfet.h:55
#define qgbState
Definition: mosfet.cpp:538
#define kelvin(x)
Definition: constants.h:108
#define NiSi
Intrinsic carrier concentration in 1/m^3 of Silicon.
Definition: constants.h:81
nr_double_t UgsPrev
Definition: mosfet.h:54
#define PROP_DEF
Definition: netdefs.h:189
nr_double_t Phi
Definition: mosfet.h:56
void calcNoiseSP(nr_double_t)
Definition: mosfet.cpp:95
nr_double_t gds
Definition: mosfet.h:55
nr_double_t Uon
Definition: mosfet.h:54
circuit * splitResistor(circuit *base, circuit *res, const char *c, const char *n, int internal)
Definition: device.cpp:56
nr_double_t getPropertyDouble(const char *)
Definition: object.cpp:176
nr_complex_t pow(const nr_complex_t z, const nr_double_t d)
Compute power function with real exponent.
Definition: complex.cpp:238
nr_double_t Rs
Definition: mosfet.h:56
#define E0
Electric constant of vacuum .
Definition: constants.h:51
#define PROP_REAL
Definition: netdefs.h:174
int transientMode
Definition: mosfet.h:59
void setStates(int n)
Definition: states.h:52
#define PROP_NO_PROP
Definition: netdefs.h:122
nr_double_t Ga
Definition: mosfet.h:56
#define QoverkB
Elementary charge over Boltzmann constant ( )
Definition: constants.h:70
#define K
Absolute 0 in centigrade.
Definition: constants.h:59
#define PROP_NO_RANGE
Definition: netdefs.h:126
int getPropertyInteger(const char *)
Definition: object.cpp:198
nr_double_t beta
Definition: mosfet.h:56
#define PROP_NO_STR
Definition: netdefs.h:125
void pnJunctionMOS(nr_double_t Upn, nr_double_t Iss, nr_double_t Ute, nr_double_t &I, nr_double_t &g)
Definition: device.cpp:144
nr_double_t Qbd
Definition: mosfet.h:57
nr_double_t getScaledProperty(const char *)
Definition: object.cpp:185
#define NODE_S
Definition: mosfet.cpp:35
n
Definition: parse_citi.y:147
static const nr_double_t z0
Definition: circuit.h:320
nr_double_t Ubs
Definition: mosfet.h:58
void restartDC(void)
Definition: mosfet.cpp:123
nr_double_t Udsat
Definition: mosfet.h:54
void fetCapacitanceMeyer(nr_double_t Ugs, nr_double_t Ugd, nr_double_t Uth, nr_double_t Udsat, nr_double_t Phi, nr_double_t Cox, nr_double_t &Cgs, nr_double_t &Cgd, nr_double_t &Cgb)
Definition: device.cpp:333
#define PROP_INT
Definition: netdefs.h:173
nr_double_t pnCapacitance(nr_double_t Uj, nr_double_t Cj, nr_double_t Vj, nr_double_t Mj, nr_double_t Fc)
Definition: device.cpp:187
nr_double_t UgdPrev
Definition: mosfet.h:54
void setScaledProperty(const char *, nr_double_t)
Definition: object.cpp:133
virtual void initDC(void)
Definition: circuit.h:113
#define PROP_RNG_X01I
Definition: netdefs.h:137
#define ESiO2
Relative permittivity of Silicon dioxide (Silica)
Definition: constants.h:73
nr_double_t gbs
Definition: mosfet.h:55
i
Definition: parse_mdl.y:516
nr_double_t gmb
Definition: mosfet.h:55
void initAC(void)
Definition: mosfet.cpp:643
nr_double_t gm
Definition: mosfet.h:55
qucs::circuit * rg
Definition: mosfet.h:62
nr_complex_t sqrt(const nr_complex_t z)
Compute principal value of square root.
Definition: complex.cpp:271
nr_double_t MOSdir
Definition: mosfet.h:56
nr_double_t SourceControl
Definition: mosfet.h:55
void transientCapacitance(int, int, int, nr_double_t, nr_double_t, nr_double_t)
Definition: circuit.cpp:759
nr_double_t Ugb
Definition: mosfet.h:58
nr_double_t Egap(nr_double_t T, nr_double_t Eg0=Eg0Si)
Definition: device.cpp:367
void calcDC(void)
Definition: mosfet.cpp:379
nr_double_t Rd
Definition: mosfet.h:56
#define Q_e
Elementary charge ( )
Definition: constants.h:66
nr_double_t fetVoltage(nr_double_t Ufet, nr_double_t Uold, nr_double_t Uth)
Definition: device.cpp:263
qucs::circuit * rd
Definition: mosfet.h:61
#define qgdState
Definition: mosfet.cpp:526
void calcTR(nr_double_t)
Definition: mosfet.cpp:660
qucs::matrix calcMatrixCy(nr_double_t)
Definition: mosfet.cpp:99
#define kBoverQ
Boltzmann constant over Elementary charge ( )
Definition: constants.h:68
#define PROP_COMPONENT
Definition: netdefs.h:116
qucs::circuit * rs
Definition: mosfet.h:60
void initDC(void)
Definition: mosfet.cpp:132
#define kB
Boltzmann constant ( )
Definition: constants.h:64
nr_double_t Qgb
Definition: mosfet.h:57
void setMatrixY(matrix)
Definition: circuit.cpp:685
nr_double_t Ubd
Definition: mosfet.h:58
nr_double_t Vto
Definition: mosfet.h:56
void disableResistor(circuit *base, circuit *res, int internal)
Definition: device.cpp:77
nr_double_t Ibd
Definition: mosfet.h:57
#define M_PI
Archimedes' constant ( )
Definition: consts.h:47
nr_double_t UbdPrev
Definition: mosfet.h:54
state_type_t getState(int, int n=0)
Definition: states.cpp:99
void calcSP(nr_double_t)
Definition: mosfet.cpp:47
void saveOperatingPoints(void)
Definition: mosfet.cpp:543
nr_double_t Qgs
Definition: mosfet.h:57
nr_double_t pnCapacitance_F(nr_double_t T1, nr_double_t T2, nr_double_t M, nr_double_t VR)
Definition: device.cpp:413
void setI(int, nr_complex_t)
Definition: circuit.cpp:397
#define qgsState
Definition: mosfet.cpp:530
nr_double_t Ugd
Definition: mosfet.h:58
nr_double_t pnPotential_T(nr_double_t T1, nr_double_t T2, nr_double_t Vj, nr_double_t Eg0=Eg0Si)
Definition: device.cpp:394
void setMatrixS(matrix)
Definition: circuit.cpp:643
type
Definition: parse_vcd.y:164
matrix getMatrixS(void)
Definition: circuit.cpp:654
nr_double_t pnCharge(nr_double_t Uj, nr_double_t Cj, nr_double_t Vj, nr_double_t Mj, nr_double_t Fc)
Definition: device.cpp:199
void setY(int, int, nr_complex_t)
Definition: circuit.cpp:452
#define PROP_MIN_VAL(k)
Definition: netdefs.h:133
matrix cytocs(matrix cy, matrix s)
Admittance noise correlation matrix to S-parameter noise correlation matrix.
Definition: matrix.cpp:1404
void initTR(void)
Definition: mosfet.cpp:655
nr_double_t Ibs
Definition: mosfet.h:57
nr_double_t transientChargeSR(int, nr_double_t &, nr_double_t, nr_double_t)
Definition: mosfet.cpp:700
nr_double_t fetVoltageDS(nr_double_t Ufet, nr_double_t Uold)
Definition: device.cpp:312
void allocMatrixMNA(void)
Definition: circuit.cpp:267
nr_double_t Qgd
Definition: mosfet.h:57
void calcAC(nr_double_t)
Definition: mosfet.cpp:647
void calcOperatingPoints(void)
Definition: mosfet.cpp:566
#define PROP_POS_RANGEX
Definition: netdefs.h:131
nr_double_t Ids
Definition: mosfet.h:55
#define PROP_RNGIX(f, t)
Definition: netdefs.h:140
#define PROP_STR
Definition: netdefs.h:175
#define qbdState
Definition: mosfet.cpp:534
nr_double_t getV(int, nr_double_t)
Definition: circuit.cpp:941
y
Definition: parse_mdl.y:499
nr_double_t UdsPrev
Definition: mosfet.h:54
nr_double_t Uds
Definition: mosfet.h:58
void setMatrixN(matrix)
Definition: circuit.cpp:664
nr_complex_t exp(const nr_complex_t z)
Compute complex exponential.
Definition: complex.cpp:205
char * getName(void)
Definition: object.cpp:84
nr_double_t UbsPrev
Definition: mosfet.h:54
void initModel(void)
Definition: mosfet.cpp:190
#define NODE_B
Definition: mosfet.cpp:36
void setOperatingPoint(const char *, nr_double_t)
Definition: circuit.cpp:533
#define PROP_NO_VAL
Definition: netdefs.h:124
#define LOG_STATUS
Definition: logging.h:29
nr_double_t gbd
Definition: mosfet.h:55
nr_double_t pnCriticalVoltage(nr_double_t Iss, nr_double_t Ute)
Definition: device.cpp:255
#define PROP_RNGXI(f, t)
Definition: netdefs.h:139
char * getPropertyString(const char *)
Definition: object.cpp:159
void setState(int, state_type_t, int n=0)
Definition: states.cpp:109
#define M(con)
Definition: evaluate.cpp:64
void logprint(int level, const char *format,...)
Definition: logging.c:37
nr_complex_t log(const nr_complex_t z)
Compute principal value of natural logarithm of z.
Definition: complex.cpp:215
PROP_NONLINEAR
Definition: mosfet.cpp:760
#define PROP_RNG_FET
Definition: netdefs.h:160
void calcNoiseAC(nr_double_t)
Definition: mosfet.cpp:651
#define NODE_G
Definition: mosfet.cpp:33
PROP_REQ[]
Definition: mosfet.cpp:710
#define qbsState
Definition: mosfet.cpp:536
nr_double_t Cox
Definition: mosfet.h:56
nr_double_t Qbs
Definition: mosfet.h:57
void loadOperatingPoints(void)
Definition: mosfet.cpp:557
matrix arg(matrix a)
Computes the argument of each matrix element.
Definition: matrix.cpp:555
nr_double_t Leff
Definition: mosfet.h:56
#define PROP_NO_SUBSTRATE
Definition: netdefs.h:118
#define MAX(x, y)
Maximum of x and y.
Definition: constants.h:127
qucs::matrix calcMatrixY(nr_double_t)
Definition: mosfet.cpp:51
nr_double_t pnVoltage(nr_double_t Ud, nr_double_t Uold, nr_double_t Ut, nr_double_t Ucrit)
Definition: device.cpp:121