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