Branch data Line data Source code
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 : 8126 : circuit * device::splitResistor (circuit * base, circuit * res,
57 : : const char * c, const char * n,
58 : : int internal) {
59 [ + + ]: 8126 : if (res == NULL) {
60 [ + - ]: 70 : res = new resistor ();
61 : 70 : char * name = circuit::createInternal (c, base->getName ());
62 : 70 : char * node = circuit::createInternal (n, base->getName ());
63 : 70 : res->setName (name);
64 : 70 : res->setNode (0, base->getNode(internal)->getName ());
65 : 70 : res->setNode (1, node, 1);
66 : 70 : base->getNet()->insertCircuit (res);
67 : 70 : free (name);
68 : 70 : free (node);
69 : : }
70 : 8126 : base->setNode (internal, res->getNode(1)->getName (), 1);
71 : 8126 : 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 : 23561 : void device::disableResistor (circuit * base, circuit * res, int internal) {
78 [ - + ]: 23561 : if (res != NULL) {
79 : 0 : base->getNet()->removeCircuit (res, 0);
80 : 0 : base->setNode (internal, res->getNode(1)->getName (), 0);
81 : : }
82 : 23561 : }
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 : 0 : circuit * device::splitCapacitor (circuit * base, circuit * cap,
89 : : const char * c, node * n1, node * n2) {
90 [ # # ]: 0 : if (cap == NULL) {
91 [ # # ]: 0 : cap = new capacitor ();
92 : 0 : char * name = circuit::createInternal (c, base->getName ());
93 : 0 : cap->setName (name);
94 : 0 : cap->setNode (0, n1->getName ());
95 : 0 : cap->setNode (1, n2->getName ());
96 : 0 : free (name);
97 : : }
98 : 0 : base->getNet()->insertCircuit (cap);
99 : 0 : return cap;
100 : : }
101 : :
102 : : // The function removes the given capacitor circuit from the netlist.
103 : 38 : void device::disableCapacitor (circuit * base, circuit * cap) {
104 [ - + ]: 38 : if (cap != NULL) {
105 : 0 : base->getNet()->removeCircuit (cap, 0);
106 : : }
107 : 38 : }
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 : 121424 : int device::deviceEnabled (circuit * c) {
113 [ - + ][ # # ]: 121424 : if (c != NULL && c->isEnabled ())
[ - + ]
114 : 0 : return 1;
115 : 121424 : 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 : 755116 : 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 [ + + ][ + + ]: 755116 : if (Ud > Ucrit && fabs (Ud - Uold) > 2 * Ut) {
125 [ + + ]: 78144 : if (Uold > 0) {
126 : 16874 : arg = (Ud - Uold) / Ut;
127 [ + + ]: 16874 : if (arg > 0)
128 : 16852 : Ud = Uold + Ut * (2 + log (arg - 2));
129 : : else
130 : 22 : Ud = Uold - Ut * (2 + log (2 - arg));
131 : : }
132 [ + + ]: 22198 : else Ud = Uold < 0 ? Ut * log (Ud / Ut) : Ucrit;
133 : : }
134 : : else {
135 [ + + ]: 716044 : if (Ud < 0) {
136 [ + + ]: 282585 : arg = Uold > 0 ? -1 - Uold : 2 * Uold - 1;
137 [ + + ]: 282585 : if (Ud < arg) Ud = arg;
138 : : }
139 : : }
140 : 755116 : return Ud;
141 : : }
142 : :
143 : : // Computes current and its derivative for a MOS pn-junction.
144 : 167290 : 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 [ + + ]: 167290 : if (Upn <= 0) {
147 : 157255 : g = Iss / Ute;
148 : 157255 : I = g * Upn;
149 : : }
150 : : else {
151 [ + - ]: 10035 : nr_double_t e = exp (MIN (Upn / Ute, 709));
152 : 10035 : I = Iss * (e - 1);
153 : 10035 : g = Iss * e / Ute;
154 : : }
155 : 167290 : }
156 : :
157 : : // Computes current and its derivative for a bipolar pn-junction.
158 : 583024 : 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 [ + + ]: 583024 : if (Upn < -3 * Ute) {
161 : 176679 : nr_double_t a = 3 * Ute / (Upn * M_E);
162 : 176679 : a = cubic (a);
163 : 176679 : I = -Iss * (1 + a);
164 : 176679 : g = +Iss * 3 * a / Upn;
165 : : }
166 : : else {
167 [ + - ]: 406345 : nr_double_t e = exp (MIN (Upn / Ute, 709));
168 : 406345 : I = Iss * (e - 1);
169 : 406345 : g = Iss * e / Ute;
170 : : }
171 : 583024 : }
172 : :
173 : : // The function computes the exponential pn-junction current.
174 : : nr_double_t
175 : 478258 : device::pnCurrent (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute) {
176 [ + - ]: 478258 : 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 : 478258 : device::pnConductance (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute) {
182 [ + - ]: 478258 : return Iss * exp (MIN (Upn / Ute, 709)) / Ute;
183 : : }
184 : :
185 : : // Computes pn-junction depletion capacitance.
186 : : nr_double_t
187 : 827775 : 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 [ + + ]: 827775 : if (Uj <= Fc * Vj)
191 : 609686 : c = Cj * exp (-Mj * log (1 - Uj / Vj));
192 : : else
193 : 218089 : c = Cj * exp (-Mj * log (1 - Fc)) *
194 : 218089 : (1 + Mj * (Uj - Fc * Vj) / Vj / (1 - Fc));
195 : 827775 : return c;
196 : : }
197 : :
198 : : // Computes pn-junction depletion charge.
199 : 827775 : 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 [ + + ]: 827775 : if (Uj <= Fc * Vj) {
203 : 609686 : a = 1 - Uj / Vj;
204 : 609686 : b = exp ((1 - Mj) * log (a));
205 : 609686 : 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 : 218089 : a = 1 - Fc;
218 : 218089 : b = exp (-Mj * log (a));
219 : 218089 : nr_double_t f = Fc * Vj;
220 : 218089 : nr_double_t c = Cj * (1 - Fc * (1 + Mj)) * b / a;
221 : 218089 : nr_double_t d = Cj * Mj * b / a / Vj;
222 : 218089 : nr_double_t e = Cj * Vj * (1 - a * b) / (1 - Mj) - d / 2 * f * f - f * c;
223 : 218089 : q = e + Uj * (c + Uj * d / 2);
224 : : #endif
225 : : }
226 : 827775 : return q;
227 : : }
228 : :
229 : : /* This function computes the pn-junction depletion capacitance with
230 : : no linearization factor given. */
231 : : nr_double_t
232 : 72862 : 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 [ + + ]: 72862 : if (Uj <= 0)
236 : 54971 : c = Cj * exp (-Mj * log (1 - Uj / Vj));
237 : : else
238 : 17891 : c = Cj * (1 + Mj * Uj / Vj);
239 : 72862 : return c;
240 : : }
241 : :
242 : : /* This function computes the pn-junction depletion charge with no
243 : : linearization factor given. */
244 : 72862 : 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 [ + + ]: 72862 : if (Uj <= 0)
248 : 54971 : q = Cj * Vj / (1 - Mj) * (1 - exp ((1 - Mj) * log (1 - Uj / Vj)));
249 : : else
250 : 17891 : q = Cj * Uj * (1 + Mj * Uj / 2 / Vj);
251 : 72862 : return q;
252 : : }
253 : :
254 : : // Compute critical voltage of pn-junction.
255 : 838761 : nr_double_t device::pnCriticalVoltage (nr_double_t Iss, nr_double_t Ute) {
256 : 838761 : 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 : 83645 : device::fetVoltage (nr_double_t Ufet, nr_double_t Uold, nr_double_t Uth) {
264 : 83645 : nr_double_t Utsthi = fabs (2 * (Uold - Uth)) + 2.0;
265 : 83645 : nr_double_t Utstlo = Utsthi / 2;
266 : 83645 : nr_double_t Utox = Uth + 3.5;
267 : 83645 : nr_double_t DeltaU = Ufet - Uold;
268 : :
269 [ + + ]: 83645 : if (Uold >= Uth) { /* FET is on */
270 [ + + ]: 65343 : if (Uold >= Utox) {
271 [ + + ]: 20877 : if (DeltaU <= 0) { /* going off */
272 [ + + ]: 11158 : if (Ufet >= Utox) {
273 [ - + ]: 10450 : if (-DeltaU > Utstlo) {
274 : 0 : Ufet = Uold - Utstlo;
275 : : }
276 : : } else {
277 [ + + ]: 708 : Ufet = MAX (Ufet, Uth + 2);
278 : : }
279 : : } else { /* staying on */
280 [ - + ]: 9719 : if (DeltaU >= Utsthi) {
281 : 0 : Ufet = Uold + Utsthi;
282 : : }
283 : : }
284 : : } else { /* middle region */
285 [ + + ]: 44466 : if (DeltaU <= 0) { /* decreasing */
286 [ + + ]: 26141 : Ufet = MAX (Ufet, Uth - 0.5);
287 : : } else { /* increasing */
288 [ + + ]: 18325 : Ufet = MIN (Ufet, Uth + 4);
289 : : }
290 : : }
291 : : } else { /* FET is off */
292 [ + + ]: 18302 : if (DeltaU <= 0) { /* staying off */
293 [ + + ]: 9550 : if (-DeltaU > Utsthi) {
294 : 2 : Ufet = Uold - Utsthi;
295 : : }
296 : : } else { /* going on */
297 [ + + ]: 8752 : if (Ufet <= Uth + 0.5) {
298 [ - + ]: 7706 : if (DeltaU > Utstlo) {
299 : 0 : Ufet = Uold + Utstlo;
300 : : }
301 : : } else {
302 : 1046 : Ufet = Uth + 0.5;
303 : : }
304 : : }
305 : : }
306 : 83645 : 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 : 83645 : nr_double_t device::fetVoltageDS (nr_double_t Ufet, nr_double_t Uold) {
313 [ + + ]: 83645 : if (Uold >= 3.5) {
314 [ + + ]: 34612 : if (Ufet > Uold) {
315 [ + + ]: 15100 : Ufet = MIN (Ufet, 3 * Uold + 2);
316 [ + + ]: 19512 : } else if (Ufet < 3.5) {
317 [ + + ]: 171 : Ufet = MAX (Ufet, 2);
318 : : }
319 : : } else {
320 [ + + ]: 49033 : if (Ufet > Uold) {
321 [ + + ]: 25754 : Ufet = MIN (Ufet, 4);
322 : : } else {
323 [ + + ]: 23279 : Ufet = MAX (Ufet, -0.5);
324 : : }
325 : : }
326 : 83645 : 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 : 83504 : 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 : 83504 : nr_double_t Utst = Ugs - Uth;
339 [ + + ]: 83504 : if (Utst <= -Phi) { // cutoff regions
340 : 14965 : Cgb = Cox;
341 : 14965 : Cgs = 0;
342 : 14965 : Cgd = 0;
343 [ + + ]: 68539 : } else if (Utst <= -Phi / 2) {
344 : 1443 : Cgb = -Utst * Cox / Phi;
345 : 1443 : Cgs = 0;
346 : 1443 : Cgd = 0;
347 [ + + ]: 67096 : } else if (Utst <= 0) { // depletion region
348 : 863 : Cgb = -Utst * Cox / Phi;
349 : 863 : Cgs = Utst * Cox * 4 / 3 / Phi + 2 * Cox / 3;
350 : 863 : Cgd = 0;
351 : : } else {
352 : 66233 : Cgb = 0;
353 : 66233 : nr_double_t Uds = Ugs - Ugd;
354 [ + + ]: 66233 : if (Udsat <= Uds) { // saturation region
355 : 46319 : Cgs = 2 * Cox / 3;
356 : 46319 : Cgd = 0;
357 : : } else { // linear region
358 : 19914 : nr_double_t Sqr1 = sqr (Udsat - Uds);
359 : 19914 : nr_double_t Sqr2 = sqr (2 * Udsat - Uds);
360 : 19914 : Cgs = Cox * (1 - Sqr1 / Sqr2) * 2 / 3;
361 : 19914 : Cgd = Cox * (1 - Udsat * Udsat / Sqr2) * 2 / 3;
362 : : }
363 : : }
364 : 83504 : }
365 : :
366 : : // Computes temperature dependency of energy bandgap.
367 : 63372 : nr_double_t device::Egap (nr_double_t T, nr_double_t Eg0) {
368 : 63372 : nr_double_t a = 7.02e-4;
369 : 63372 : nr_double_t b = 1108;
370 : 63372 : return Eg0 - (a * sqr (T)) / (T + b);
371 : : }
372 : :
373 : : // Computes temperature dependency of intrinsic density.
374 : 0 : nr_double_t device::intrinsicDensity (nr_double_t T, nr_double_t Eg0) {
375 : 0 : nr_double_t TR = 300.00;
376 : 0 : nr_double_t E1 = Egap (TR, Eg0);
377 : 0 : nr_double_t E2 = Egap (T, Eg0);
378 : 0 : nr_double_t NI = NiSi / 1e6;
379 : 0 : 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 : 30790 : 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 : 30790 : TR = T2 / T1;
388 : 30790 : Vt = T2 * kBoverQ;
389 : 30790 : 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 : 31655 : 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 : 31655 : TR = T2 / T1;
398 : 31655 : E1 = Egap (T1, Eg0);
399 : 31655 : E2 = Egap (T2, Eg0);
400 : 31655 : Vt = T2 * kBoverQ;
401 : 31655 : return TR * Vj - 3 * Vt * log (TR) - (TR * E1 - E2);
402 : : }
403 : :
404 : : // Calculates temperature dependence for junction capacitance.
405 : : nr_double_t
406 : 31593 : 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 : 31593 : return Cj * pnCapacitance_F (T1, T2, M, VR);
409 : : }
410 : :
411 : : // Calculates temperature dependence for junction capacitance.
412 : : nr_double_t
413 : 31655 : device::pnCapacitance_F (nr_double_t T1, nr_double_t T2, nr_double_t M,
414 : : nr_double_t VR) {
415 : 31655 : nr_double_t DT = T2 - T1;
416 : 31655 : return 1 + M * (4e-4 * DT - VR + 1);
417 : : }
|