Qucs-core  0.0.18
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
device.cpp
Go to the documentation of this file.
1 /*
2  * device.cpp - device class implementation
3  *
4  * Copyright (C) 2004, 2005, 2006 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 <stdio.h>
30 #include <stdlib.h>
31 #include <cmath>
32 
33 #include "complex.h"
34 #include "object.h"
35 #include "node.h"
36 #include "circuit.h"
37 #include "net.h"
38 #include "constants.h"
39 #include "device.h"
40 #include "netdefs.h"
41 #include "resistor.h"
42 #include "capacitor.h"
43 
44 using namespace qucs;
45 using namespace qucs::device;
46 
47 /* This function can be used to create an extra resistor circuit. If
48  the 'res' argument is NULL then the new circuit is created, the
49  nodes get re-arranged and it is inserted into the given
50  netlist. The given arguments can be explained as follows.
51  base: calling circuit (this)
52  res: additional resistor circuit (can be NULL)
53  c: name of the additional circuit
54  n: name of the inserted (internal) node
55  internal: number of new internal node (the original external node) */
56 circuit * device::splitResistor (circuit * base, circuit * res,
57  const char * c, const char * n,
58  int internal) {
59  if (res == NULL) {
60  res = new resistor ();
61  char * name = circuit::createInternal (c, base->getName ());
62  char * node = circuit::createInternal (n, base->getName ());
63  res->setName (name);
64  res->setNode (0, base->getNode(internal)->getName ());
65  res->setNode (1, node, 1);
66  base->getNet()->insertCircuit (res);
67  free (name);
68  free (node);
69  }
70  base->setNode (internal, res->getNode(1)->getName (), 1);
71  return res;
72 }
73 
74 /* This function is the counterpart of the above routine. It removes
75  the resistor circuit from the netlist and re-assigns the original
76  node. */
77 void device::disableResistor (circuit * base, circuit * res, int internal) {
78  if (res != NULL) {
79  base->getNet()->removeCircuit (res, 0);
80  base->setNode (internal, res->getNode(1)->getName (), 0);
81  }
82 }
83 
84 /* This function creates a new capacitor circuit if the given one is
85  not NULL. The new circuit is connected between the given nodes and
86  a name is applied based upon the parents (base) name and the given
87  name 'c'. The circuit is then put into the netlist. */
88 circuit * device::splitCapacitor (circuit * base, circuit * cap,
89  const char * c, node * n1, node * n2) {
90  if (cap == NULL) {
91  cap = new capacitor ();
92  char * name = circuit::createInternal (c, base->getName ());
93  cap->setName (name);
94  cap->setNode (0, n1->getName ());
95  cap->setNode (1, n2->getName ());
96  free (name);
97  }
98  base->getNet()->insertCircuit (cap);
99  return cap;
100 }
101 
102 // The function removes the given capacitor circuit from the netlist.
103 void device::disableCapacitor (circuit * base, circuit * cap) {
104  if (cap != NULL) {
105  base->getNet()->removeCircuit (cap, 0);
106  }
107 }
108 
109 /* This function checks whether the given circuit object exists and is
110  chained within the current netlist. It returns non-zero if so and
111  zero otherwise. */
112 int device::deviceEnabled (circuit * c) {
113  if (c != NULL && c->isEnabled ())
114  return 1;
115  return 0;
116 }
117 
118 /* The function limits the forward pn-voltage for each DC iteration in
119  order to avoid numerical overflows and thereby improve the
120  convergence. */
121 nr_double_t device::pnVoltage (nr_double_t Ud, nr_double_t Uold,
122  nr_double_t Ut, nr_double_t Ucrit) {
123  nr_double_t arg;
124  if (Ud > Ucrit && fabs (Ud - Uold) > 2 * Ut) {
125  if (Uold > 0) {
126  arg = (Ud - Uold) / Ut;
127  if (arg > 0)
128  Ud = Uold + Ut * (2 + log (arg - 2));
129  else
130  Ud = Uold - Ut * (2 + log (2 - arg));
131  }
132  else Ud = Uold < 0 ? Ut * log (Ud / Ut) : Ucrit;
133  }
134  else {
135  if (Ud < 0) {
136  arg = Uold > 0 ? -1 - Uold : 2 * Uold - 1;
137  if (Ud < arg) Ud = arg;
138  }
139  }
140  return Ud;
141 }
142 
143 // Computes current and its derivative for a MOS pn-junction.
144 void device::pnJunctionMOS (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute,
145  nr_double_t& I, nr_double_t& g) {
146  if (Upn <= 0) {
147  g = Iss / Ute;
148  I = g * Upn;
149  }
150  else {
151  nr_double_t e = exp (MIN (Upn / Ute, 709));
152  I = Iss * (e - 1);
153  g = Iss * e / Ute;
154  }
155 }
156 
157 // Computes current and its derivative for a bipolar pn-junction.
158 void device::pnJunctionBIP (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute,
159  nr_double_t& I, nr_double_t& g) {
160  if (Upn < -3 * Ute) {
161  nr_double_t a = 3 * Ute / (Upn * M_E);
162  a = cubic (a);
163  I = -Iss * (1 + a);
164  g = +Iss * 3 * a / Upn;
165  }
166  else {
167  nr_double_t e = exp (MIN (Upn / Ute, 709));
168  I = Iss * (e - 1);
169  g = Iss * e / Ute;
170  }
171 }
172 
173 // The function computes the exponential pn-junction current.
174 nr_double_t
175 device::pnCurrent (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute) {
176  return Iss * (exp (MIN (Upn / Ute, 709)) - 1);
177 }
178 
179 // The function computes the exponential pn-junction current's derivative.
180 nr_double_t
181 device::pnConductance (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute) {
182  return Iss * exp (MIN (Upn / Ute, 709)) / Ute;
183 }
184 
185 // Computes pn-junction depletion capacitance.
186 nr_double_t
187 device::pnCapacitance (nr_double_t Uj, nr_double_t Cj, nr_double_t Vj,
188  nr_double_t Mj, nr_double_t Fc) {
189  nr_double_t c;
190  if (Uj <= Fc * Vj)
191  c = Cj * exp (-Mj * log (1 - Uj / Vj));
192  else
193  c = Cj * exp (-Mj * log (1 - Fc)) *
194  (1 + Mj * (Uj - Fc * Vj) / Vj / (1 - Fc));
195  return c;
196 }
197 
198 // Computes pn-junction depletion charge.
199 nr_double_t device::pnCharge (nr_double_t Uj, nr_double_t Cj, nr_double_t Vj,
200  nr_double_t Mj, nr_double_t Fc) {
201  nr_double_t q, a, b;
202  if (Uj <= Fc * Vj) {
203  a = 1 - Uj / Vj;
204  b = exp ((1 - Mj) * log (a));
205  q = Cj * Vj / (1 - Mj) * (1 - b);
206  }
207  else {
208 #if 0
209  a = 1 - Fc;
210  b = exp ((1 - Mj) * log (a));
211  a = exp ((1 + Mj) * log (a));
212  nr_double_t c = 1 - Fc * (1 + Mj);
213  nr_double_t d = Fc * Vj;
214  nr_double_t e = Vj * (1 - b) / (1 - Mj);
215  q = Cj * (e + (c * (Uj - d) + Mj / 2 / Vj * (sqr (Uj) - sqr (d))) / a);
216 #else /* this variant is numerically more stable */
217  a = 1 - Fc;
218  b = exp (-Mj * log (a));
219  nr_double_t f = Fc * Vj;
220  nr_double_t c = Cj * (1 - Fc * (1 + Mj)) * b / a;
221  nr_double_t d = Cj * Mj * b / a / Vj;
222  nr_double_t e = Cj * Vj * (1 - a * b) / (1 - Mj) - d / 2 * f * f - f * c;
223  q = e + Uj * (c + Uj * d / 2);
224 #endif
225  }
226  return q;
227 }
228 
229 /* This function computes the pn-junction depletion capacitance with
230  no linearization factor given. */
231 nr_double_t
232 device::pnCapacitance (nr_double_t Uj, nr_double_t Cj, nr_double_t Vj,
233  nr_double_t Mj) {
234  nr_double_t c;
235  if (Uj <= 0)
236  c = Cj * exp (-Mj * log (1 - Uj / Vj));
237  else
238  c = Cj * (1 + Mj * Uj / Vj);
239  return c;
240 }
241 
242 /* This function computes the pn-junction depletion charge with no
243  linearization factor given. */
244 nr_double_t device::pnCharge (nr_double_t Uj, nr_double_t Cj, nr_double_t Vj,
245  nr_double_t Mj) {
246  nr_double_t q;
247  if (Uj <= 0)
248  q = Cj * Vj / (1 - Mj) * (1 - exp ((1 - Mj) * log (1 - Uj / Vj)));
249  else
250  q = Cj * Uj * (1 + Mj * Uj / 2 / Vj);
251  return q;
252 }
253 
254 // Compute critical voltage of pn-junction.
255 nr_double_t device::pnCriticalVoltage (nr_double_t Iss, nr_double_t Ute) {
256  return Ute * log (Ute / M_SQRT2 / Iss);
257 }
258 
259 /* The function limits the forward fet-voltage for each DC iteration
260  in order to avoid numerical overflows and thereby improve the
261  convergence. */
262 nr_double_t
263 device::fetVoltage (nr_double_t Ufet, nr_double_t Uold, nr_double_t Uth) {
264  nr_double_t Utsthi = fabs (2 * (Uold - Uth)) + 2.0;
265  nr_double_t Utstlo = Utsthi / 2;
266  nr_double_t Utox = Uth + 3.5;
267  nr_double_t DeltaU = Ufet - Uold;
268 
269  if (Uold >= Uth) { /* FET is on */
270  if (Uold >= Utox) {
271  if (DeltaU <= 0) { /* going off */
272  if (Ufet >= Utox) {
273  if (-DeltaU > Utstlo) {
274  Ufet = Uold - Utstlo;
275  }
276  } else {
277  Ufet = MAX (Ufet, Uth + 2);
278  }
279  } else { /* staying on */
280  if (DeltaU >= Utsthi) {
281  Ufet = Uold + Utsthi;
282  }
283  }
284  } else { /* middle region */
285  if (DeltaU <= 0) { /* decreasing */
286  Ufet = MAX (Ufet, Uth - 0.5);
287  } else { /* increasing */
288  Ufet = MIN (Ufet, Uth + 4);
289  }
290  }
291  } else { /* FET is off */
292  if (DeltaU <= 0) { /* staying off */
293  if (-DeltaU > Utsthi) {
294  Ufet = Uold - Utsthi;
295  }
296  } else { /* going on */
297  if (Ufet <= Uth + 0.5) {
298  if (DeltaU > Utstlo) {
299  Ufet = Uold + Utstlo;
300  }
301  } else {
302  Ufet = Uth + 0.5;
303  }
304  }
305  }
306  return Ufet;
307 }
308 
309 /* The function limits the drain-source voltage for each DC iteration
310  in order to avoid numerical overflows and thereby improve the
311  convergence. */
312 nr_double_t device::fetVoltageDS (nr_double_t Ufet, nr_double_t Uold) {
313  if (Uold >= 3.5) {
314  if (Ufet > Uold) {
315  Ufet = MIN (Ufet, 3 * Uold + 2);
316  } else if (Ufet < 3.5) {
317  Ufet = MAX (Ufet, 2);
318  }
319  } else {
320  if (Ufet > Uold) {
321  Ufet = MIN (Ufet, 4);
322  } else {
323  Ufet = MAX (Ufet, -0.5);
324  }
325  }
326  return Ufet;
327 }
328 
329 /* This function calculates the overlap capacitance for MOS based upon
330  the given voltages, surface potential and the zero-bias oxide
331  capacitance. */
332 void
333 device::fetCapacitanceMeyer (nr_double_t Ugs, nr_double_t Ugd, nr_double_t Uth,
334  nr_double_t Udsat, nr_double_t Phi,
335  nr_double_t Cox, nr_double_t& Cgs,
336  nr_double_t& Cgd, nr_double_t& Cgb) {
337 
338  nr_double_t Utst = Ugs - Uth;
339  if (Utst <= -Phi) { // cutoff regions
340  Cgb = Cox;
341  Cgs = 0;
342  Cgd = 0;
343  } else if (Utst <= -Phi / 2) {
344  Cgb = -Utst * Cox / Phi;
345  Cgs = 0;
346  Cgd = 0;
347  } else if (Utst <= 0) { // depletion region
348  Cgb = -Utst * Cox / Phi;
349  Cgs = Utst * Cox * 4 / 3 / Phi + 2 * Cox / 3;
350  Cgd = 0;
351  } else {
352  Cgb = 0;
353  nr_double_t Uds = Ugs - Ugd;
354  if (Udsat <= Uds) { // saturation region
355  Cgs = 2 * Cox / 3;
356  Cgd = 0;
357  } else { // linear region
358  nr_double_t Sqr1 = sqr (Udsat - Uds);
359  nr_double_t Sqr2 = sqr (2 * Udsat - Uds);
360  Cgs = Cox * (1 - Sqr1 / Sqr2) * 2 / 3;
361  Cgd = Cox * (1 - Udsat * Udsat / Sqr2) * 2 / 3;
362  }
363  }
364 }
365 
366 // Computes temperature dependency of energy bandgap.
367 nr_double_t device::Egap (nr_double_t T, nr_double_t Eg0) {
368  nr_double_t a = 7.02e-4;
369  nr_double_t b = 1108;
370  return Eg0 - (a * sqr (T)) / (T + b);
371 }
372 
373 // Computes temperature dependency of intrinsic density.
374 nr_double_t device::intrinsicDensity (nr_double_t T, nr_double_t Eg0) {
375  nr_double_t TR = 300.00;
376  nr_double_t E1 = Egap (TR, Eg0);
377  nr_double_t E2 = Egap (T, Eg0);
378  nr_double_t NI = NiSi / 1e6;
379  return NI * exp (1.5 * log (T / TR) + (E1 / TR - E2 / T) / kBoverQ / 2);
380 }
381 
382 // Calculates temperature dependence for saturation current.
383 nr_double_t
384 device::pnCurrent_T (nr_double_t T1, nr_double_t T2, nr_double_t Is,
385  nr_double_t Eg, nr_double_t N, nr_double_t Xti) {
386  nr_double_t Vt, TR;
387  TR = T2 / T1;
388  Vt = T2 * kBoverQ;
389  return Is * exp (Xti / N * log (TR) - Eg / N / Vt * (1 - TR));
390 }
391 
392 // Calculates temperature dependence for junction potential.
393 nr_double_t
394 device::pnPotential_T (nr_double_t T1, nr_double_t T2, nr_double_t Vj,
395  nr_double_t Eg0) {
396  nr_double_t Vt, TR, E1, E2;
397  TR = T2 / T1;
398  E1 = Egap (T1, Eg0);
399  E2 = Egap (T2, Eg0);
400  Vt = T2 * kBoverQ;
401  return TR * Vj - 3 * Vt * log (TR) - (TR * E1 - E2);
402 }
403 
404 // Calculates temperature dependence for junction capacitance.
405 nr_double_t
406 device::pnCapacitance_T (nr_double_t T1, nr_double_t T2, nr_double_t M,
407  nr_double_t VR, nr_double_t Cj) {
408  return Cj * pnCapacitance_F (T1, T2, M, VR);
409 }
410 
411 // Calculates temperature dependence for junction capacitance.
412 nr_double_t
413 device::pnCapacitance_F (nr_double_t T1, nr_double_t T2, nr_double_t M,
414  nr_double_t VR) {
415  nr_double_t DT = T2 - T1;
416  return 1 + M * (4e-4 * DT - VR + 1);
417 }
#define M_E
Euler's constant ( )
Definition: consts.h:71
#define N(n)
Definition: equation.cpp:58
#define NiSi
Intrinsic carrier concentration in 1/m^3 of Silicon.
Definition: constants.h:81
name
Definition: parse_mdl.y:352
void disableCapacitor(circuit *base, circuit *cap)
Definition: device.cpp:103
nr_double_t pnConductance(nr_double_t Upn, nr_double_t Iss, nr_double_t Ute)
Definition: device.cpp:181
circuit * splitResistor(circuit *base, circuit *res, const char *c, const char *n, int internal)
Definition: device.cpp:56
int deviceEnabled(circuit *c)
Definition: device.cpp:112
Global physical constants header file.
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
n
Definition: parse_citi.y:147
circuit * splitCapacitor(circuit *base, circuit *cap, const char *c, node *n1, node *n2)
Definition: device.cpp:88
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
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
n2
Definition: parse_zvr.y:187
nr_complex_t sqr(const nr_complex_t z)
Square of complex number.
Definition: complex.cpp:673
nr_double_t Egap(nr_double_t T, nr_double_t Eg0=Eg0Si)
Definition: device.cpp:367
nr_double_t pnCurrent_T(nr_double_t T1, nr_double_t T2, nr_double_t Is, nr_double_t Eg, nr_double_t N=1, nr_double_t Xti=0)
Definition: device.cpp:384
nr_double_t fetVoltage(nr_double_t Ufet, nr_double_t Uold, nr_double_t Uth)
Definition: device.cpp:263
nr_double_t pnCapacitance_T(nr_double_t T1, nr_double_t T2, nr_double_t M, nr_double_t VR, nr_double_t Cj)
Definition: device.cpp:406
#define kBoverQ
Boltzmann constant over Elementary charge ( )
Definition: constants.h:68
free($1)
void disableResistor(circuit *base, circuit *res, int internal)
Definition: device.cpp:77
void pnJunctionBIP(nr_double_t Upn, nr_double_t Iss, nr_double_t Ute, nr_double_t &I, nr_double_t &g)
Definition: device.cpp:158
The circuit class header file.
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
static char * createInternal(const char *, const char *)
Definition: circuit.cpp:626
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
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
#define MIN(x, y)
Minimum of x and y.
Definition: constants.h:132
nr_double_t intrinsicDensity(nr_double_t T, nr_double_t Eg0=Eg0Si)
Definition: device.cpp:374
n1
Definition: parse_zvr.y:179
nr_double_t fetVoltageDS(nr_double_t Ufet, nr_double_t Uold)
Definition: device.cpp:312
nr_complex_t exp(const nr_complex_t z)
Compute complex exponential.
Definition: complex.cpp:205
nr_double_t pnCriticalVoltage(nr_double_t Iss, nr_double_t Ute)
Definition: device.cpp:255
#define M(con)
Definition: evaluate.cpp:64
nr_complex_t log(const nr_complex_t z)
Compute principal value of natural logarithm of z.
Definition: complex.cpp:215
#define M_SQRT2
Square root of 2 ( )
Definition: consts.h:91
#define cubic(x)
Definition: constants.h:106
nr_double_t pnCurrent(nr_double_t Upn, nr_double_t Iss, nr_double_t Ute)
Definition: device.cpp:175
matrix arg(matrix a)
Computes the argument of each matrix element.
Definition: matrix.cpp:555
#define MAX(x, y)
Maximum of x and y.
Definition: constants.h:127
nr_double_t pnVoltage(nr_double_t Ud, nr_double_t Uold, nr_double_t Ut, nr_double_t Ucrit)
Definition: device.cpp:121