Qucs-core
0.0.19
|
00001 /* 00002 * device.cpp - device class implementation 00003 * 00004 * Copyright (C) 2004, 2005, 2006 Stefan Jahn <stefan@lkcc.org> 00005 * 00006 * This is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2, or (at your option) 00009 * any later version. 00010 * 00011 * This software is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this package; see the file COPYING. If not, write to 00018 * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 * 00021 * $Id$ 00022 * 00023 */ 00024 00025 #if HAVE_CONFIG_H 00026 # include <config.h> 00027 #endif 00028 00029 #include <stdio.h> 00030 #include <stdlib.h> 00031 #include <cmath> 00032 #include <algorithm> 00033 00034 #include "complex.h" 00035 #include "object.h" 00036 #include "node.h" 00037 #include "circuit.h" 00038 #include "net.h" 00039 #include "constants.h" 00040 #include "device.h" 00041 #include "netdefs.h" 00042 #include "resistor.h" 00043 #include "capacitor.h" 00044 00045 using namespace qucs; 00046 using namespace qucs::device; 00047 00048 /* This function can be used to create an extra resistor circuit. If 00049 the 'res' argument is NULL then the new circuit is created, the 00050 nodes get re-arranged and it is inserted into the given 00051 netlist. The given arguments can be explained as follows. 00052 base: calling circuit (this) 00053 res: additional resistor circuit (can be NULL) 00054 c: name of the additional circuit 00055 n: name of the inserted (internal) node 00056 internal: number of new internal node (the original external node) */ 00057 circuit * device::splitResistor (circuit * base, circuit * res, 00058 const char * c, const char * n, 00059 int internal) { 00060 if (res == NULL) { 00061 res = new resistor (); 00062 const std::string &name = circuit::createInternal (c, base->getName ()); 00063 const std::string &node = circuit::createInternal (n, base->getName ()); 00064 res->setName (name); 00065 res->setNode (0, base->getNode(internal)->getName ()); 00066 res->setNode (1, node, 1); 00067 base->getNet()->insertCircuit (res); 00068 } 00069 base->setNode (internal, res->getNode(1)->getName (), 1); 00070 return res; 00071 } 00072 00073 /* This function is the counterpart of the above routine. It removes 00074 the resistor circuit from the netlist and re-assigns the original 00075 node. */ 00076 void device::disableResistor (circuit * base, circuit * res, int internal) { 00077 if (res != NULL) { 00078 base->getNet()->removeCircuit (res, 0); 00079 base->setNode (internal, res->getNode(1)->getName (), 0); 00080 } 00081 } 00082 00083 /* This function creates a new capacitor circuit if the given one is 00084 not NULL. The new circuit is connected between the given nodes and 00085 a name is applied based upon the parents (base) name and the given 00086 name 'c'. The circuit is then put into the netlist. */ 00087 circuit * device::splitCapacitor (circuit * base, circuit * cap, 00088 const char * c, node * n1, node * n2) { 00089 if (cap == NULL) { 00090 cap = new capacitor (); 00091 const std::string &name = circuit::createInternal (c, base->getName ()); 00092 cap->setName (name); 00093 cap->setNode (0, n1->getName ()); 00094 cap->setNode (1, n2->getName ()); 00095 } 00096 base->getNet()->insertCircuit (cap); 00097 return cap; 00098 } 00099 00100 // The function removes the given capacitor circuit from the netlist. 00101 void device::disableCapacitor (circuit * base, circuit * cap) { 00102 if (cap != NULL) { 00103 base->getNet()->removeCircuit (cap, 0); 00104 } 00105 } 00106 00107 /* This function checks whether the given circuit object exists and is 00108 chained within the current netlist. It returns non-zero if so and 00109 zero otherwise. */ 00110 int device::deviceEnabled (circuit * c) { 00111 if (c != NULL && c->isEnabled ()) 00112 return 1; 00113 return 0; 00114 } 00115 00116 /* The function limits the forward pn-voltage for each DC iteration in 00117 order to avoid numerical overflows and thereby improve the 00118 convergence. */ 00119 nr_double_t device::pnVoltage (nr_double_t Ud, nr_double_t Uold, 00120 nr_double_t Ut, nr_double_t Ucrit) { 00121 nr_double_t arg; 00122 if (Ud > Ucrit && fabs (Ud - Uold) > 2 * Ut) { 00123 if (Uold > 0) { 00124 arg = (Ud - Uold) / Ut; 00125 if (arg > 0) 00126 Ud = Uold + Ut * (2 + log (arg - 2)); 00127 else 00128 Ud = Uold - Ut * (2 + log (2 - arg)); 00129 } 00130 else Ud = Uold < 0 ? Ut * log (Ud / Ut) : Ucrit; 00131 } 00132 else { 00133 if (Ud < 0) { 00134 arg = Uold > 0 ? -1 - Uold : 2 * Uold - 1; 00135 if (Ud < arg) Ud = arg; 00136 } 00137 } 00138 return Ud; 00139 } 00140 00141 // Computes current and its derivative for a MOS pn-junction. 00142 void device::pnJunctionMOS (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute, 00143 nr_double_t& I, nr_double_t& g) { 00144 if (Upn <= 0) { 00145 g = Iss / Ute; 00146 I = g * Upn; 00147 } 00148 else { 00149 nr_double_t e = exp (std::min (Upn / Ute, 709.0)); 00150 I = Iss * (e - 1); 00151 g = Iss * e / Ute; 00152 } 00153 } 00154 00155 // Computes current and its derivative for a bipolar pn-junction. 00156 void device::pnJunctionBIP (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute, 00157 nr_double_t& I, nr_double_t& g) { 00158 if (Upn < -3 * Ute) { 00159 nr_double_t a = 3 * Ute / (Upn * euler); 00160 a = cubic (a); 00161 I = -Iss * (1 + a); 00162 g = +Iss * 3 * a / Upn; 00163 } 00164 else { 00165 nr_double_t e = exp (std::min (Upn / Ute, 709.0)); 00166 I = Iss * (e - 1); 00167 g = Iss * e / Ute; 00168 } 00169 } 00170 00171 // The function computes the exponential pn-junction current. 00172 nr_double_t 00173 device::pnCurrent (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute) { 00174 return Iss * (exp (std::min (Upn / Ute, 709.0)) - 1); 00175 } 00176 00177 // The function computes the exponential pn-junction current's derivative. 00178 nr_double_t 00179 device::pnConductance (nr_double_t Upn, nr_double_t Iss, nr_double_t Ute) { 00180 return Iss * exp (std::min (Upn / Ute, 709.0)) / Ute; 00181 } 00182 00183 // Computes pn-junction depletion capacitance. 00184 nr_double_t 00185 device::pnCapacitance (nr_double_t Uj, nr_double_t Cj, nr_double_t Vj, 00186 nr_double_t Mj, nr_double_t Fc) { 00187 nr_double_t c; 00188 if (Uj <= Fc * Vj) 00189 c = Cj * exp (-Mj * log (1 - Uj / Vj)); 00190 else 00191 c = Cj * exp (-Mj * log (1 - Fc)) * 00192 (1 + Mj * (Uj - Fc * Vj) / Vj / (1 - Fc)); 00193 return c; 00194 } 00195 00196 // Computes pn-junction depletion charge. 00197 nr_double_t device::pnCharge (nr_double_t Uj, nr_double_t Cj, nr_double_t Vj, 00198 nr_double_t Mj, nr_double_t Fc) { 00199 nr_double_t q, a, b; 00200 if (Uj <= Fc * Vj) { 00201 a = 1 - Uj / Vj; 00202 b = exp ((1 - Mj) * log (a)); 00203 q = Cj * Vj / (1 - Mj) * (1 - b); 00204 } 00205 else { 00206 #if 0 00207 a = 1 - Fc; 00208 b = exp ((1 - Mj) * log (a)); 00209 a = exp ((1 + Mj) * log (a)); 00210 nr_double_t c = 1 - Fc * (1 + Mj); 00211 nr_double_t d = Fc * Vj; 00212 nr_double_t e = Vj * (1 - b) / (1 - Mj); 00213 q = Cj * (e + (c * (Uj - d) + Mj / 2 / Vj * (sqr (Uj) - sqr (d))) / a); 00214 #else /* this variant is numerically more stable */ 00215 a = 1 - Fc; 00216 b = exp (-Mj * log (a)); 00217 nr_double_t f = Fc * Vj; 00218 nr_double_t c = Cj * (1 - Fc * (1 + Mj)) * b / a; 00219 nr_double_t d = Cj * Mj * b / a / Vj; 00220 nr_double_t e = Cj * Vj * (1 - a * b) / (1 - Mj) - d / 2 * f * f - f * c; 00221 q = e + Uj * (c + Uj * d / 2); 00222 #endif 00223 } 00224 return q; 00225 } 00226 00227 /* This function computes the pn-junction depletion capacitance with 00228 no linearization factor given. */ 00229 nr_double_t 00230 device::pnCapacitance (nr_double_t Uj, nr_double_t Cj, nr_double_t Vj, 00231 nr_double_t Mj) { 00232 nr_double_t c; 00233 if (Uj <= 0) 00234 c = Cj * exp (-Mj * log (1 - Uj / Vj)); 00235 else 00236 c = Cj * (1 + Mj * Uj / Vj); 00237 return c; 00238 } 00239 00240 /* This function computes the pn-junction depletion charge with no 00241 linearization factor given. */ 00242 nr_double_t device::pnCharge (nr_double_t Uj, nr_double_t Cj, nr_double_t Vj, 00243 nr_double_t Mj) { 00244 nr_double_t q; 00245 if (Uj <= 0) 00246 q = Cj * Vj / (1 - Mj) * (1 - exp ((1 - Mj) * log (1 - Uj / Vj))); 00247 else 00248 q = Cj * Uj * (1 + Mj * Uj / 2 / Vj); 00249 return q; 00250 } 00251 00252 // Compute critical voltage of pn-junction. 00253 nr_double_t device::pnCriticalVoltage (nr_double_t Iss, nr_double_t Ute) { 00254 return Ute * log (Ute / sqrt2 / Iss); 00255 } 00256 00257 /* The function limits the forward fet-voltage for each DC iteration 00258 in order to avoid numerical overflows and thereby improve the 00259 convergence. */ 00260 nr_double_t 00261 device::fetVoltage (nr_double_t Ufet, nr_double_t Uold, nr_double_t Uth) { 00262 nr_double_t Utsthi = fabs (2 * (Uold - Uth)) + 2.0; 00263 nr_double_t Utstlo = Utsthi / 2; 00264 nr_double_t Utox = Uth + 3.5; 00265 nr_double_t DeltaU = Ufet - Uold; 00266 00267 if (Uold >= Uth) { /* FET is on */ 00268 if (Uold >= Utox) { 00269 if (DeltaU <= 0) { /* going off */ 00270 if (Ufet >= Utox) { 00271 if (-DeltaU > Utstlo) { 00272 Ufet = Uold - Utstlo; 00273 } 00274 } else { 00275 Ufet = std::max (Ufet, Uth + 2); 00276 } 00277 } else { /* staying on */ 00278 if (DeltaU >= Utsthi) { 00279 Ufet = Uold + Utsthi; 00280 } 00281 } 00282 } else { /* middle region */ 00283 if (DeltaU <= 0) { /* decreasing */ 00284 Ufet = std::max (Ufet, Uth - 0.5); 00285 } else { /* increasing */ 00286 Ufet = std::min (Ufet, Uth + 4); 00287 } 00288 } 00289 } else { /* FET is off */ 00290 if (DeltaU <= 0) { /* staying off */ 00291 if (-DeltaU > Utsthi) { 00292 Ufet = Uold - Utsthi; 00293 } 00294 } else { /* going on */ 00295 if (Ufet <= Uth + 0.5) { 00296 if (DeltaU > Utstlo) { 00297 Ufet = Uold + Utstlo; 00298 } 00299 } else { 00300 Ufet = Uth + 0.5; 00301 } 00302 } 00303 } 00304 return Ufet; 00305 } 00306 00307 /* The function limits the drain-source voltage for each DC iteration 00308 in order to avoid numerical overflows and thereby improve the 00309 convergence. */ 00310 nr_double_t device::fetVoltageDS (nr_double_t Ufet, nr_double_t Uold) { 00311 if (Uold >= 3.5) { 00312 if (Ufet > Uold) { 00313 Ufet = std::min (Ufet, 3 * Uold + 2); 00314 } else if (Ufet < 3.5) { 00315 Ufet = std::max (Ufet, 2.0); 00316 } 00317 } else { 00318 if (Ufet > Uold) { 00319 Ufet = std::min (Ufet, 4.0); 00320 } else { 00321 Ufet = std::max (Ufet, -0.5); 00322 } 00323 } 00324 return Ufet; 00325 } 00326 00327 /* This function calculates the overlap capacitance for MOS based upon 00328 the given voltages, surface potential and the zero-bias oxide 00329 capacitance. */ 00330 void 00331 device::fetCapacitanceMeyer (nr_double_t Ugs, nr_double_t Ugd, nr_double_t Uth, 00332 nr_double_t Udsat, nr_double_t Phi, 00333 nr_double_t Cox, nr_double_t& Cgs, 00334 nr_double_t& Cgd, nr_double_t& Cgb) { 00335 00336 nr_double_t Utst = Ugs - Uth; 00337 if (Utst <= -Phi) { // cutoff regions 00338 Cgb = Cox; 00339 Cgs = 0; 00340 Cgd = 0; 00341 } else if (Utst <= -Phi / 2) { 00342 Cgb = -Utst * Cox / Phi; 00343 Cgs = 0; 00344 Cgd = 0; 00345 } else if (Utst <= 0) { // depletion region 00346 Cgb = -Utst * Cox / Phi; 00347 Cgs = Utst * Cox * 4 / 3 / Phi + 2 * Cox / 3; 00348 Cgd = 0; 00349 } else { 00350 Cgb = 0; 00351 nr_double_t Uds = Ugs - Ugd; 00352 if (Udsat <= Uds) { // saturation region 00353 Cgs = 2 * Cox / 3; 00354 Cgd = 0; 00355 } else { // linear region 00356 nr_double_t Sqr1 = sqr (Udsat - Uds); 00357 nr_double_t Sqr2 = sqr (2 * Udsat - Uds); 00358 Cgs = Cox * (1 - Sqr1 / Sqr2) * 2 / 3; 00359 Cgd = Cox * (1 - Udsat * Udsat / Sqr2) * 2 / 3; 00360 } 00361 } 00362 } 00363 00364 // Computes temperature dependency of energy bandgap. 00365 nr_double_t device::Egap (nr_double_t T, nr_double_t Eg0) { 00366 nr_double_t a = 7.02e-4; 00367 nr_double_t b = 1108; 00368 return Eg0 - (a * sqr (T)) / (T + b); 00369 } 00370 00371 // Computes temperature dependency of intrinsic density. 00372 nr_double_t device::intrinsicDensity (nr_double_t T, nr_double_t Eg0) { 00373 nr_double_t TR = 300.00; 00374 nr_double_t E1 = Egap (TR, Eg0); 00375 nr_double_t E2 = Egap (T, Eg0); 00376 nr_double_t NI = NiSi / 1e6; 00377 return NI * exp (1.5 * log (T / TR) + (E1 / TR - E2 / T) / kBoverQ / 2); 00378 } 00379 00380 // Calculates temperature dependence for saturation current. 00381 nr_double_t 00382 device::pnCurrent_T (nr_double_t T1, nr_double_t T2, nr_double_t Is, 00383 nr_double_t Eg, nr_double_t N, nr_double_t Xti) { 00384 nr_double_t Vt, TR; 00385 TR = T2 / T1; 00386 Vt = T2 * kBoverQ; 00387 return Is * exp (Xti / N * log (TR) - Eg / N / Vt * (1 - TR)); 00388 } 00389 00390 // Calculates temperature dependence for junction potential. 00391 nr_double_t 00392 device::pnPotential_T (nr_double_t T1, nr_double_t T2, nr_double_t Vj, 00393 nr_double_t Eg0) { 00394 nr_double_t Vt, TR, E1, E2; 00395 TR = T2 / T1; 00396 E1 = Egap (T1, Eg0); 00397 E2 = Egap (T2, Eg0); 00398 Vt = T2 * kBoverQ; 00399 return TR * Vj - 3 * Vt * log (TR) - (TR * E1 - E2); 00400 } 00401 00402 // Calculates temperature dependence for junction capacitance. 00403 nr_double_t 00404 device::pnCapacitance_T (nr_double_t T1, nr_double_t T2, nr_double_t M, 00405 nr_double_t VR, nr_double_t Cj) { 00406 return Cj * pnCapacitance_F (T1, T2, M, VR); 00407 } 00408 00409 // Calculates temperature dependence for junction capacitance. 00410 nr_double_t 00411 device::pnCapacitance_F (nr_double_t T1, nr_double_t T2, nr_double_t M, 00412 nr_double_t VR) { 00413 nr_double_t DT = T2 - T1; 00414 return 1 + M * (4e-4 * DT - VR + 1); 00415 }