My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
jfet.cpp
Go to the documentation of this file.
1 /*
2  * jfet.cpp - jfet 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: jfet.cpp 1825 2011-03-11 20:42:14Z ela $
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 "jfet.h"
32 
33 #define NODE_G 0 /* gate node */
34 #define NODE_D 1 /* drain node */
35 #define NODE_S 2 /* source node */
36 
37 using namespace device;
38 
39 jfet::jfet () : circuit (3) {
40  rs = rd = NULL;
41  type = CIR_JFET;
42 }
43 
44 void jfet::calcSP (nr_double_t frequency) {
45  setMatrixS (ytos (calcMatrixY (frequency)));
46 }
47 
48 matrix jfet::calcMatrixY (nr_double_t frequency) {
49 
50  // fetch computed operating points
51  nr_double_t Cgd = getOperatingPoint ("Cgd");
52  nr_double_t Cgs = getOperatingPoint ("Cgs");
53  nr_double_t ggs = getOperatingPoint ("ggs");
54  nr_double_t ggd = getOperatingPoint ("ggd");
55  nr_double_t gds = getOperatingPoint ("gds");
56  nr_double_t gm = getOperatingPoint ("gm");
57 
58  // compute the models admittances
59  nr_complex_t Ygd = rect (ggd, 2.0 * M_PI * frequency * Cgd);
60  nr_complex_t Ygs = rect (ggs, 2.0 * M_PI * frequency * Cgs);
61  nr_complex_t Yds = gds;
62 
63  // build admittance matrix and convert it to S-parameter matrix
64  matrix y (3);
65  y.set (NODE_G, NODE_G, Ygd + Ygs);
66  y.set (NODE_G, NODE_D, -Ygd);
67  y.set (NODE_G, NODE_S, -Ygs);
68  y.set (NODE_D, NODE_G, gm - Ygd);
69  y.set (NODE_D, NODE_D, Ygd + Yds);
70  y.set (NODE_D, NODE_S, -Yds - gm);
71  y.set (NODE_S, NODE_G, -Ygs - gm);
72  y.set (NODE_S, NODE_D, -Yds);
73  y.set (NODE_S, NODE_S, Ygs + Yds + gm);
74  return y;
75 }
76 
77 void jfet::calcNoiseSP (nr_double_t frequency) {
78  setMatrixN (cytocs (calcMatrixCy (frequency) * z0, getMatrixS ()));
79 }
80 
81 matrix jfet::calcMatrixCy (nr_double_t frequency) {
82  /* get operating points and noise properties */
83  nr_double_t Kf = getPropertyDouble ("Kf");
84  nr_double_t Af = getPropertyDouble ("Af");
85  nr_double_t Ffe = getPropertyDouble ("Ffe");
86  nr_double_t gm = fabs (getOperatingPoint ("gm"));
87  nr_double_t Ids = fabs (getOperatingPoint ("Id"));
88  nr_double_t T = getPropertyDouble ("Temp");
89 
90  /* compute channel noise and flicker noise generated by the DC
91  transconductance and current flow from drain to source */
92  nr_double_t i = 8 * kelvin (T) / T0 * gm / 3 +
93  Kf * pow (Ids, Af) / pow (frequency, Ffe) / kB / T0;
94 
95  /* build noise current correlation matrix and convert it to
96  noise-wave correlation matrix */
97  matrix cy = matrix (3);
98  cy.set (NODE_D, NODE_D, +i);
99  cy.set (NODE_S, NODE_S, +i);
100  cy.set (NODE_D, NODE_S, -i);
101  cy.set (NODE_S, NODE_D, -i);
102  return cy;
103 }
104 
105 void jfet::initModel (void) {
106  // fetch necessary device properties
107  nr_double_t T = getPropertyDouble ("Temp");
108  nr_double_t Tn = getPropertyDouble ("Tnom");
109  nr_double_t A = getPropertyDouble ("Area");
110 
111  // compute Is temperature and area dependency
112  nr_double_t Is = getPropertyDouble ("Is");
113  nr_double_t N = getPropertyDouble ("N");
114  nr_double_t Xti = getPropertyDouble ("Xti");
115  nr_double_t T1, T2, Eg;
116  T2 = kelvin (T);
117  T1 = kelvin (Tn);
118  Eg = Egap (300);
119  Is = pnCurrent_T (T1, T2, Is, Eg, N, Xti);
120  setScaledProperty ("Is", Is * A);
121 
122  // compute Isr temperature and area dependency
123  nr_double_t Isr = getPropertyDouble ("Isr");
124  nr_double_t Nr = getPropertyDouble ("Nr");
125  Isr = pnCurrent_T (T1, T2, Isr, Eg, Nr, Xti);
126  setScaledProperty ("Isr", Isr * A);
127 
128  // compute Pb temperature dependency
129  nr_double_t Pb = getPropertyDouble ("Pb");
130  nr_double_t PbT;
131  PbT = pnPotential_T (T1,T2, Pb);
132  setScaledProperty ("Pb", PbT);
133 
134  // compute Cgs and Cgd temperature and area dependency
135  nr_double_t Cgs = getPropertyDouble ("Cgs");
136  nr_double_t Cgd = getPropertyDouble ("Cgd");
137  nr_double_t M = getPropertyDouble ("M");
138  nr_double_t F;
139  F = A * pnCapacitance_F (T1, T2, M, PbT / Pb);
140  setScaledProperty ("Cgs", Cgs * F);
141  setScaledProperty ("Cgd", Cgd * F);
142 
143  // compute Vth temperature dependency
144  nr_double_t Vt0 = getPropertyDouble ("Vt0");
145  nr_double_t Vt0tc = getPropertyDouble ("Vt0tc");
146  nr_double_t DT = T2 - T1;
147  Vt0 = Vt0 + Vt0tc * DT;
148  setScaledProperty ("Vt0", Vt0);
149 
150  // compute Beta temperature and area dependency
151  nr_double_t Beta = getPropertyDouble ("Beta");
152  nr_double_t Betatce = getPropertyDouble ("Betatce");
153  Beta = Beta * exp (Betatce * DT * log (1.01));
154  setScaledProperty ("Beta", Beta * A);
155 
156  // compute Rs and Rd area dependency
157  nr_double_t Rs = getPropertyDouble ("Rs");
158  nr_double_t Rd = getPropertyDouble ("Rd");
159  setScaledProperty ("Rs", Rs / A);
160  setScaledProperty ("Rd", Rd / A);
161 }
162 
163 void jfet::restartDC (void) {
164  // apply starting values to previous iteration values
165  UgdPrev = real (getV (NODE_G) - getV (NODE_D));
166  UgsPrev = real (getV (NODE_G) - getV (NODE_S));
167 }
168 
169 void jfet::initDC (void) {
170 
171  // allocate MNA matrices
172  allocMatrixMNA ();
173 
174  // initialize scalability
175  initModel ();
176 
177  // initialize starting values
178  restartDC ();
179 
180  // apply polarity of JFET
181  char * type = getPropertyString ("Type");
182  pol = !strcmp (type, "pfet") ? -1 : 1;
183 
184  // get device temperature
185  nr_double_t T = getPropertyDouble ("Temp");
186 
187  // possibly insert series resistance at source
188  nr_double_t Rs = getScaledProperty ("Rs");
189  if (Rs != 0.0) {
190  // create additional circuit if necessary and reassign nodes
191  rs = splitResistor (this, rs, "Rs", "source", NODE_S);
192  rs->setProperty ("Temp", T);
193  rs->setProperty ("R", Rs);
194  rs->setProperty ("Controlled", getName ());
195  rs->initDC ();
196  }
197  // no series resistance at source
198  else {
199  disableResistor (this, rs, NODE_S);
200  }
201 
202  // possibly insert series resistance at drain
203  nr_double_t Rd = getScaledProperty ("Rd");
204  if (Rd != 0.0) {
205  // create additional circuit if necessary and reassign nodes
206  rd = splitResistor (this, rd, "Rd", "drain", NODE_D);
207  rd->setProperty ("Temp", T);
208  rd->setProperty ("R", Rd);
209  rd->setProperty ("Controlled", getName ());
210  rd->initDC ();
211  }
212  // no series resistance at drain
213  else {
214  disableResistor (this, rd, NODE_D);
215  }
216 }
217 
218 void jfet::calcDC (void) {
219 
220  // fetch device model parameters
221  nr_double_t Is = getScaledProperty ("Is");
222  nr_double_t n = getPropertyDouble ("N");
223  nr_double_t Isr = getScaledProperty ("Isr");
224  nr_double_t nr = getPropertyDouble ("Nr");
225  nr_double_t Vt0 = getScaledProperty ("Vt0");
226  nr_double_t l = getPropertyDouble ("Lambda");
227  nr_double_t beta = getScaledProperty ("Beta");
228  nr_double_t T = getPropertyDouble ("Temp");
229 
230  nr_double_t Ut, IeqG, IeqD, IeqS, UgsCrit, UgdCrit;
231  nr_double_t Igs, Igd, gtiny;
232 
233  T = kelvin (T);
234  Ut = T * kBoverQ;
235  Ugd = real (getV (NODE_G) - getV (NODE_D)) * pol;
236  Ugs = real (getV (NODE_G) - getV (NODE_S)) * pol;
237 
238  // critical voltage necessary for bad start values
239  UgsCrit = pnCriticalVoltage (Is, Ut * n);
240  UgdCrit = pnCriticalVoltage (Is, Ut * n);
241  UgsPrev = Ugs = pnVoltage (Ugs, UgsPrev, Ut * n, UgsCrit);
242  UgdPrev = Ugd = pnVoltage (Ugd, UgdPrev, Ut * n, UgdCrit);
243 
244  Uds = Ugs - Ugd;
245 
246  // gate-source diode
247  gtiny = Ugs < - 10 * Ut * n ? (Is + Isr) : 0;
248  ggs = pnConductance (Ugs, Is, Ut * n) +
249  pnConductance (Ugs, Isr, Ut * nr) + gtiny;
250  Igs = pnCurrent (Ugs, Is, Ut * n) +
251  pnCurrent (Ugs, Isr, Ut * nr) + gtiny * Ugs;
252 
253  // gate-drain diode
254  gtiny = Ugd < - 10 * Ut * n ? (Is + Isr) : 0;
255  ggd = pnConductance (Ugd, Is, Ut * n) +
256  pnConductance (Ugd, Isr, Ut * nr) + gtiny;
257  Igd = pnCurrent (Ugd, Is, Ut * n) +
258  pnCurrent (Ugd, Isr, Ut * nr) + gtiny * Ugd;
259 
260  // normal (forward) mode of operation
261  if (Uds >= 0) {
262  nr_double_t Ugst = Ugs - Vt0;
263  // normal mode, cutoff region
264  if (Ugst <= 0) {
265  Ids = 0;
266  gm = 0;
267  gds = 0;
268  }
269  else {
270  nr_double_t b = beta * (1 + l * Uds);
271  // normal mode, saturation region
272  if (Ugst <= Uds) {
273  Ids = b * Ugst * Ugst;
274  gm = b * 2 * Ugst;
275  gds = l * beta * Ugst * Ugst;
276  }
277  // normal mode, linear region
278  else {
279  Ids = b * Uds * (2 * Ugst - Uds);
280  gm = b * 2 * Uds;
281  gds = b * 2 * (Ugst - Uds) + l * beta * Uds * (2 * Ugst - Uds);
282  }
283  }
284  }
285  // inverse (backward) mode of operation
286  else {
287  nr_double_t Ugdt = Ugd - Vt0;
288  // inverse mode, cutoff region
289  if (Ugdt <= 0) {
290  Ids = 0;
291  gm = 0;
292  gds = 0;
293  }
294  else {
295  nr_double_t b = beta * (1 - l * Uds);
296  // inverse mode, saturation region
297  if (Ugdt <= -Uds) {
298  Ids = - b * Ugdt * Ugdt;
299  gm = - b * 2 * Ugdt;
300  gds = beta * l * Ugdt * Ugdt + b * 2 * Ugdt;
301  }
302  // inverse mode, linear region
303  else {
304  Ids = b * Uds * (2 * Ugdt + Uds);
305  gm = b * 2 * Uds;
306  gds = 2 * b * Ugdt - beta * l * Uds * (2 * Ugdt + Uds);
307  }
308  }
309  }
310 
311  // compute autonomic current sources
312  IeqG = Igs - ggs * Ugs;
313  IeqD = Igd - ggd * Ugd;
314  IeqS = Ids - gm * Ugs - gds * Uds;
315  setI (NODE_G, (-IeqG - IeqD) * pol);
316  setI (NODE_D, (+IeqD - IeqS) * pol);
317  setI (NODE_S, (+IeqG + IeqS) * pol);
318 
319  // apply admittance matrix elements
320  setY (NODE_G, NODE_G, ggs + ggd);
321  setY (NODE_G, NODE_D, -ggd);
322  setY (NODE_G, NODE_S, -ggs);
323  setY (NODE_D, NODE_G, -ggd + gm);
324  setY (NODE_D, NODE_D, gds + ggd);
325  setY (NODE_D, NODE_S, -gm - gds);
326  setY (NODE_S, NODE_G, -ggs - gm);
327  setY (NODE_S, NODE_D, -gds);
328  setY (NODE_S, NODE_S, ggs + gds + gm);
329 }
330 
332  Ugs = getOperatingPoint ("Vgs");
333  Ugd = getOperatingPoint ("Vgd");
334  Uds = getOperatingPoint ("Vds");
335 }
336 
338  nr_double_t Vgs, Vgd;
339  Vgd = real (getV (NODE_G) - getV (NODE_D)) * pol;
340  Vgs = real (getV (NODE_G) - getV (NODE_S)) * pol;
341  setOperatingPoint ("Vgs", Vgs);
342  setOperatingPoint ("Vgd", Vgd);
343  setOperatingPoint ("Vds", Vgs - Vgd);
344 }
345 
347 
348  // fetch device model parameters
349  nr_double_t z = getPropertyDouble ("M");
350  nr_double_t Cgd0 = getScaledProperty ("Cgd");
351  nr_double_t Cgs0 = getScaledProperty ("Cgs");
352  nr_double_t Pb = getScaledProperty ("Pb");
353  nr_double_t Fc = getPropertyDouble ("Fc");
354 
355  nr_double_t Cgs, Cgd;
356 
357  // capacitance of gate-drain diode
358  Cgd = pnCapacitance (Ugd, Cgd0, Pb, z, Fc);
359  Qgd = pnCharge (Ugd, Cgd0, Pb, z, Fc);
360 
361  // capacitance of gate-source diode
362  Cgs = pnCapacitance (Ugs, Cgs0, Pb, z, Fc);
363  Qgs = pnCharge (Ugs, Cgs0, Pb, z, Fc);
364 
365  // save operating points
366  setOperatingPoint ("ggs", ggs);
367  setOperatingPoint ("ggd", ggd);
368  setOperatingPoint ("gds", gds);
369  setOperatingPoint ("gm", gm);
370  setOperatingPoint ("Id", Ids);
371  setOperatingPoint ("Cgd", Cgd);
372  setOperatingPoint ("Cgs", Cgs);
373 }
374 
375 void jfet::initAC (void) {
376  allocMatrixMNA ();
377  clearI ();
378 }
379 
380 void jfet::calcAC (nr_double_t frequency) {
381  setMatrixY (calcMatrixY (frequency));
382 }
383 
384 void jfet::calcNoiseAC (nr_double_t frequency) {
385  setMatrixN (calcMatrixCy (frequency));
386 }
387 
388 #define qgdState 0 // gate-drain charge state
389 #define cgdState 1 // gate-drain current state
390 #define qgsState 2 // gate-source charge state
391 #define cgsState 3 // gate-source current state
392 
393 void jfet::initTR (void) {
394  setStates (4);
395  initDC ();
396 }
397 
398 void jfet::calcTR (nr_double_t) {
399  calcDC ();
403 
404  nr_double_t Cgs = getOperatingPoint ("Cgs");
405  nr_double_t Cgd = getOperatingPoint ("Cgd");
406 
407  transientCapacitance (qgsState, NODE_G, NODE_S, Cgs, Ugs, Qgs);
408  transientCapacitance (qgdState, NODE_G, NODE_D, Cgd, Ugd, Qgd);
409 }
410 
411 // properties
412 PROP_REQ [] = {
413  { "Is", PROP_REAL, { 1e-14, PROP_NO_STR }, PROP_POS_RANGE },
414  { "N", PROP_REAL, { 1, PROP_NO_STR }, PROP_RNGII (1, 100) },
415  { "Vt0", PROP_REAL, { -2, PROP_NO_STR }, PROP_NEG_RANGE },
416  { "Lambda", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
417  { "Beta", PROP_REAL, { 1e-4, PROP_NO_STR }, PROP_POS_RANGE },
418  { "M", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGII (0, 1) },
419  { "Pb", PROP_REAL, { 1.0, PROP_NO_STR }, PROP_RNGXI (0, 10) },
420  { "Fc", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGIX (0, 1) },
421  { "Cgs", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
422  { "Cgd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
423  PROP_NO_PROP };
424 PROP_OPT [] = {
425  { "Rd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
426  { "Rs", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
427  { "Isr", PROP_REAL, { 1e-14, PROP_NO_STR }, PROP_POS_RANGE },
428  { "Nr", PROP_REAL, { 2, PROP_NO_STR }, PROP_RNGII (1, 100) },
429  { "Kf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
430  { "Af", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
431  { "Ffe", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
432  { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
433  { "Type", PROP_STR, { PROP_NO_VAL, "nfet" }, PROP_RNG_FET },
434  { "Xti", PROP_REAL, { 3, PROP_NO_STR }, PROP_POS_RANGE },
435  { "Vt0tc", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
436  { "Betatce", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
437  { "Tnom", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
438  { "Area", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGEX },
439  PROP_NO_PROP };
440 struct define_t jfet::cirdef =