Qucs-core
0.0.19
|
00001 /* 00002 * jfet.cpp - jfet class implementation 00003 * 00004 * Copyright (C) 2004, 2005, 2006, 2008 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 "component.h" 00030 #include "device.h" 00031 #include "jfet.h" 00032 00033 #define NODE_G 0 /* gate node */ 00034 #define NODE_D 1 /* drain node */ 00035 #define NODE_S 2 /* source node */ 00036 00037 using namespace qucs; 00038 using namespace qucs::device; 00039 00040 jfet::jfet () : circuit (3) { 00041 rs = rd = NULL; 00042 type = CIR_JFET; 00043 } 00044 00045 void jfet::calcSP (nr_double_t frequency) { 00046 setMatrixS (ytos (calcMatrixY (frequency))); 00047 } 00048 00049 matrix jfet::calcMatrixY (nr_double_t frequency) { 00050 00051 // fetch computed operating points 00052 nr_double_t Cgd = getOperatingPoint ("Cgd"); 00053 nr_double_t Cgs = getOperatingPoint ("Cgs"); 00054 nr_double_t ggs = getOperatingPoint ("ggs"); 00055 nr_double_t ggd = getOperatingPoint ("ggd"); 00056 nr_double_t gds = getOperatingPoint ("gds"); 00057 nr_double_t gm = getOperatingPoint ("gm"); 00058 00059 // compute the models admittances 00060 nr_complex_t Ygd = nr_complex_t (ggd, 2.0 * pi * frequency * Cgd); 00061 nr_complex_t Ygs = nr_complex_t (ggs, 2.0 * pi * frequency * Cgs); 00062 nr_complex_t Yds = gds; 00063 00064 // build admittance matrix and convert it to S-parameter matrix 00065 matrix y (3); 00066 y.set (NODE_G, NODE_G, Ygd + Ygs); 00067 y.set (NODE_G, NODE_D, -Ygd); 00068 y.set (NODE_G, NODE_S, -Ygs); 00069 y.set (NODE_D, NODE_G, gm - Ygd); 00070 y.set (NODE_D, NODE_D, Ygd + Yds); 00071 y.set (NODE_D, NODE_S, -Yds - gm); 00072 y.set (NODE_S, NODE_G, -Ygs - gm); 00073 y.set (NODE_S, NODE_D, -Yds); 00074 y.set (NODE_S, NODE_S, Ygs + Yds + gm); 00075 return y; 00076 } 00077 00078 void jfet::calcNoiseSP (nr_double_t frequency) { 00079 setMatrixN (cytocs (calcMatrixCy (frequency) * z0, getMatrixS ())); 00080 } 00081 00082 matrix jfet::calcMatrixCy (nr_double_t frequency) { 00083 /* get operating points and noise properties */ 00084 nr_double_t Kf = getPropertyDouble ("Kf"); 00085 nr_double_t Af = getPropertyDouble ("Af"); 00086 nr_double_t Ffe = getPropertyDouble ("Ffe"); 00087 nr_double_t gm = fabs (getOperatingPoint ("gm")); 00088 nr_double_t Ids = fabs (getOperatingPoint ("Id")); 00089 nr_double_t T = getPropertyDouble ("Temp"); 00090 00091 /* compute channel noise and flicker noise generated by the DC 00092 transconductance and current flow from drain to source */ 00093 nr_double_t i = 8 * celsius2kelvin (T) / T0 * gm / 3 + 00094 Kf * qucs::pow (Ids, Af) / qucs::pow (frequency, Ffe) / kB / T0; 00095 00096 /* build noise current correlation matrix and convert it to 00097 noise-wave correlation matrix */ 00098 matrix cy = matrix (3); 00099 cy.set (NODE_D, NODE_D, +i); 00100 cy.set (NODE_S, NODE_S, +i); 00101 cy.set (NODE_D, NODE_S, -i); 00102 cy.set (NODE_S, NODE_D, -i); 00103 return cy; 00104 } 00105 00106 void jfet::initModel (void) { 00107 // fetch necessary device properties 00108 nr_double_t T = getPropertyDouble ("Temp"); 00109 nr_double_t Tn = getPropertyDouble ("Tnom"); 00110 nr_double_t A = getPropertyDouble ("Area"); 00111 00112 // compute Is temperature and area dependency 00113 nr_double_t Is = getPropertyDouble ("Is"); 00114 nr_double_t N = getPropertyDouble ("N"); 00115 nr_double_t Xti = getPropertyDouble ("Xti"); 00116 nr_double_t T1, T2, Eg; 00117 T2 = celsius2kelvin (T); 00118 T1 = celsius2kelvin (Tn); 00119 Eg = Egap (300); 00120 Is = pnCurrent_T (T1, T2, Is, Eg, N, Xti); 00121 setScaledProperty ("Is", Is * A); 00122 00123 // compute Isr temperature and area dependency 00124 nr_double_t Isr = getPropertyDouble ("Isr"); 00125 nr_double_t Nr = getPropertyDouble ("Nr"); 00126 Isr = pnCurrent_T (T1, T2, Isr, Eg, Nr, Xti); 00127 setScaledProperty ("Isr", Isr * A); 00128 00129 // compute Pb temperature dependency 00130 nr_double_t Pb = getPropertyDouble ("Pb"); 00131 nr_double_t PbT; 00132 PbT = pnPotential_T (T1,T2, Pb); 00133 setScaledProperty ("Pb", PbT); 00134 00135 // compute Cgs and Cgd temperature and area dependency 00136 nr_double_t Cgs = getPropertyDouble ("Cgs"); 00137 nr_double_t Cgd = getPropertyDouble ("Cgd"); 00138 nr_double_t M = getPropertyDouble ("M"); 00139 nr_double_t F; 00140 F = A * pnCapacitance_F (T1, T2, M, PbT / Pb); 00141 setScaledProperty ("Cgs", Cgs * F); 00142 setScaledProperty ("Cgd", Cgd * F); 00143 00144 // compute Vth temperature dependency 00145 nr_double_t Vt0 = getPropertyDouble ("Vt0"); 00146 nr_double_t Vt0tc = getPropertyDouble ("Vt0tc"); 00147 nr_double_t DT = T2 - T1; 00148 Vt0 = Vt0 + Vt0tc * DT; 00149 setScaledProperty ("Vt0", Vt0); 00150 00151 // compute Beta temperature and area dependency 00152 nr_double_t Beta = getPropertyDouble ("Beta"); 00153 nr_double_t Betatce = getPropertyDouble ("Betatce"); 00154 Beta = Beta * qucs::exp (Betatce * DT * qucs::log (1.01)); 00155 setScaledProperty ("Beta", Beta * A); 00156 00157 // compute Rs and Rd area dependency 00158 nr_double_t Rs = getPropertyDouble ("Rs"); 00159 nr_double_t Rd = getPropertyDouble ("Rd"); 00160 setScaledProperty ("Rs", Rs / A); 00161 setScaledProperty ("Rd", Rd / A); 00162 } 00163 00164 void jfet::restartDC (void) { 00165 // apply starting values to previous iteration values 00166 UgdPrev = real (getV (NODE_G) - getV (NODE_D)); 00167 UgsPrev = real (getV (NODE_G) - getV (NODE_S)); 00168 } 00169 00170 void jfet::initDC (void) { 00171 00172 // allocate MNA matrices 00173 allocMatrixMNA (); 00174 00175 // initialize scalability 00176 initModel (); 00177 00178 // initialize starting values 00179 restartDC (); 00180 00181 // apply polarity of JFET 00182 const char * const type = getPropertyString ("Type"); 00183 pol = !strcmp (type, "pfet") ? -1 : 1; 00184 00185 // get device temperature 00186 nr_double_t T = getPropertyDouble ("Temp"); 00187 00188 // possibly insert series resistance at source 00189 nr_double_t Rs = getScaledProperty ("Rs"); 00190 if (Rs != 0.0) { 00191 // create additional circuit if necessary and reassign nodes 00192 rs = splitResistor (this, rs, "Rs", "source", NODE_S); 00193 rs->setProperty ("Temp", T); 00194 rs->setProperty ("R", Rs); 00195 rs->setProperty ("Controlled", getName ()); 00196 rs->initDC (); 00197 } 00198 // no series resistance at source 00199 else { 00200 disableResistor (this, rs, NODE_S); 00201 } 00202 00203 // possibly insert series resistance at drain 00204 nr_double_t Rd = getScaledProperty ("Rd"); 00205 if (Rd != 0.0) { 00206 // create additional circuit if necessary and reassign nodes 00207 rd = splitResistor (this, rd, "Rd", "drain", NODE_D); 00208 rd->setProperty ("Temp", T); 00209 rd->setProperty ("R", Rd); 00210 rd->setProperty ("Controlled", getName ()); 00211 rd->initDC (); 00212 } 00213 // no series resistance at drain 00214 else { 00215 disableResistor (this, rd, NODE_D); 00216 } 00217 } 00218 00219 void jfet::calcDC (void) { 00220 00221 // fetch device model parameters 00222 nr_double_t Is = getScaledProperty ("Is"); 00223 nr_double_t n = getPropertyDouble ("N"); 00224 nr_double_t Isr = getScaledProperty ("Isr"); 00225 nr_double_t nr = getPropertyDouble ("Nr"); 00226 nr_double_t Vt0 = getScaledProperty ("Vt0"); 00227 nr_double_t l = getPropertyDouble ("Lambda"); 00228 nr_double_t beta = getScaledProperty ("Beta"); 00229 nr_double_t T = getPropertyDouble ("Temp"); 00230 00231 nr_double_t Ut, IeqG, IeqD, IeqS, UgsCrit, UgdCrit; 00232 nr_double_t Igs, Igd, gtiny; 00233 00234 T = celsius2kelvin (T); 00235 Ut = T * kBoverQ; 00236 Ugd = real (getV (NODE_G) - getV (NODE_D)) * pol; 00237 Ugs = real (getV (NODE_G) - getV (NODE_S)) * pol; 00238 00239 // critical voltage necessary for bad start values 00240 UgsCrit = pnCriticalVoltage (Is, Ut * n); 00241 UgdCrit = pnCriticalVoltage (Is, Ut * n); 00242 UgsPrev = Ugs = pnVoltage (Ugs, UgsPrev, Ut * n, UgsCrit); 00243 UgdPrev = Ugd = pnVoltage (Ugd, UgdPrev, Ut * n, UgdCrit); 00244 00245 Uds = Ugs - Ugd; 00246 00247 // gate-source diode 00248 gtiny = Ugs < - 10 * Ut * n ? (Is + Isr) : 0; 00249 ggs = pnConductance (Ugs, Is, Ut * n) + 00250 pnConductance (Ugs, Isr, Ut * nr) + gtiny; 00251 Igs = pnCurrent (Ugs, Is, Ut * n) + 00252 pnCurrent (Ugs, Isr, Ut * nr) + gtiny * Ugs; 00253 00254 // gate-drain diode 00255 gtiny = Ugd < - 10 * Ut * n ? (Is + Isr) : 0; 00256 ggd = pnConductance (Ugd, Is, Ut * n) + 00257 pnConductance (Ugd, Isr, Ut * nr) + gtiny; 00258 Igd = pnCurrent (Ugd, Is, Ut * n) + 00259 pnCurrent (Ugd, Isr, Ut * nr) + gtiny * Ugd; 00260 00261 // normal (forward) mode of operation 00262 if (Uds >= 0) { 00263 nr_double_t Ugst = Ugs - Vt0; 00264 // normal mode, cutoff region 00265 if (Ugst <= 0) { 00266 Ids = 0; 00267 gm = 0; 00268 gds = 0; 00269 } 00270 else { 00271 nr_double_t b = beta * (1 + l * Uds); 00272 // normal mode, saturation region 00273 if (Ugst <= Uds) { 00274 Ids = b * Ugst * Ugst; 00275 gm = b * 2 * Ugst; 00276 gds = l * beta * Ugst * Ugst; 00277 } 00278 // normal mode, linear region 00279 else { 00280 Ids = b * Uds * (2 * Ugst - Uds); 00281 gm = b * 2 * Uds; 00282 gds = b * 2 * (Ugst - Uds) + l * beta * Uds * (2 * Ugst - Uds); 00283 } 00284 } 00285 } 00286 // inverse (backward) mode of operation 00287 else { 00288 nr_double_t Ugdt = Ugd - Vt0; 00289 // inverse mode, cutoff region 00290 if (Ugdt <= 0) { 00291 Ids = 0; 00292 gm = 0; 00293 gds = 0; 00294 } 00295 else { 00296 nr_double_t b = beta * (1 - l * Uds); 00297 // inverse mode, saturation region 00298 if (Ugdt <= -Uds) { 00299 Ids = - b * Ugdt * Ugdt; 00300 gm = - b * 2 * Ugdt; 00301 gds = beta * l * Ugdt * Ugdt + b * 2 * Ugdt; 00302 } 00303 // inverse mode, linear region 00304 else { 00305 Ids = b * Uds * (2 * Ugdt + Uds); 00306 gm = b * 2 * Uds; 00307 gds = 2 * b * Ugdt - beta * l * Uds * (2 * Ugdt + Uds); 00308 } 00309 } 00310 } 00311 00312 // compute autonomic current sources 00313 IeqG = Igs - ggs * Ugs; 00314 IeqD = Igd - ggd * Ugd; 00315 IeqS = Ids - gm * Ugs - gds * Uds; 00316 setI (NODE_G, (-IeqG - IeqD) * pol); 00317 setI (NODE_D, (+IeqD - IeqS) * pol); 00318 setI (NODE_S, (+IeqG + IeqS) * pol); 00319 00320 // apply admittance matrix elements 00321 setY (NODE_G, NODE_G, ggs + ggd); 00322 setY (NODE_G, NODE_D, -ggd); 00323 setY (NODE_G, NODE_S, -ggs); 00324 setY (NODE_D, NODE_G, -ggd + gm); 00325 setY (NODE_D, NODE_D, gds + ggd); 00326 setY (NODE_D, NODE_S, -gm - gds); 00327 setY (NODE_S, NODE_G, -ggs - gm); 00328 setY (NODE_S, NODE_D, -gds); 00329 setY (NODE_S, NODE_S, ggs + gds + gm); 00330 } 00331 00332 void jfet::loadOperatingPoints (void) { 00333 Ugs = getOperatingPoint ("Vgs"); 00334 Ugd = getOperatingPoint ("Vgd"); 00335 Uds = getOperatingPoint ("Vds"); 00336 } 00337 00338 void jfet::saveOperatingPoints (void) { 00339 nr_double_t Vgs, Vgd; 00340 Vgd = real (getV (NODE_G) - getV (NODE_D)) * pol; 00341 Vgs = real (getV (NODE_G) - getV (NODE_S)) * pol; 00342 setOperatingPoint ("Vgs", Vgs); 00343 setOperatingPoint ("Vgd", Vgd); 00344 setOperatingPoint ("Vds", Vgs - Vgd); 00345 } 00346 00347 void jfet::calcOperatingPoints (void) { 00348 00349 // fetch device model parameters 00350 nr_double_t z = getPropertyDouble ("M"); 00351 nr_double_t Cgd0 = getScaledProperty ("Cgd"); 00352 nr_double_t Cgs0 = getScaledProperty ("Cgs"); 00353 nr_double_t Pb = getScaledProperty ("Pb"); 00354 nr_double_t Fc = getPropertyDouble ("Fc"); 00355 00356 nr_double_t Cgs, Cgd; 00357 00358 // capacitance of gate-drain diode 00359 Cgd = pnCapacitance (Ugd, Cgd0, Pb, z, Fc); 00360 Qgd = pnCharge (Ugd, Cgd0, Pb, z, Fc); 00361 00362 // capacitance of gate-source diode 00363 Cgs = pnCapacitance (Ugs, Cgs0, Pb, z, Fc); 00364 Qgs = pnCharge (Ugs, Cgs0, Pb, z, Fc); 00365 00366 // save operating points 00367 setOperatingPoint ("ggs", ggs); 00368 setOperatingPoint ("ggd", ggd); 00369 setOperatingPoint ("gds", gds); 00370 setOperatingPoint ("gm", gm); 00371 setOperatingPoint ("Id", Ids); 00372 setOperatingPoint ("Cgd", Cgd); 00373 setOperatingPoint ("Cgs", Cgs); 00374 } 00375 00376 void jfet::initAC (void) { 00377 allocMatrixMNA (); 00378 clearI (); 00379 } 00380 00381 void jfet::calcAC (nr_double_t frequency) { 00382 setMatrixY (calcMatrixY (frequency)); 00383 } 00384 00385 void jfet::calcNoiseAC (nr_double_t frequency) { 00386 setMatrixN (calcMatrixCy (frequency)); 00387 } 00388 00389 #define qgdState 0 // gate-drain charge state 00390 #define cgdState 1 // gate-drain current state 00391 #define qgsState 2 // gate-source charge state 00392 #define cgsState 3 // gate-source current state 00393 00394 void jfet::initTR (void) { 00395 setStates (4); 00396 initDC (); 00397 } 00398 00399 void jfet::calcTR (nr_double_t) { 00400 calcDC (); 00401 saveOperatingPoints (); 00402 loadOperatingPoints (); 00403 calcOperatingPoints (); 00404 00405 nr_double_t Cgs = getOperatingPoint ("Cgs"); 00406 nr_double_t Cgd = getOperatingPoint ("Cgd"); 00407 00408 transientCapacitance (qgsState, NODE_G, NODE_S, Cgs, Ugs, Qgs); 00409 transientCapacitance (qgdState, NODE_G, NODE_D, Cgd, Ugd, Qgd); 00410 } 00411 00412 // properties 00413 PROP_REQ [] = { 00414 { "Is", PROP_REAL, { 1e-14, PROP_NO_STR }, PROP_POS_RANGE }, 00415 { "N", PROP_REAL, { 1, PROP_NO_STR }, PROP_RNGII (1, 100) }, 00416 { "Vt0", PROP_REAL, { -2, PROP_NO_STR }, PROP_NEG_RANGE }, 00417 { "Lambda", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE }, 00418 { "Beta", PROP_REAL, { 1e-4, PROP_NO_STR }, PROP_POS_RANGE }, 00419 { "M", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGII (0, 1) }, 00420 { "Pb", PROP_REAL, { 1.0, PROP_NO_STR }, PROP_RNGXI (0, 10) }, 00421 { "Fc", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGIX (0, 1) }, 00422 { "Cgs", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE }, 00423 { "Cgd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE }, 00424 PROP_NO_PROP }; 00425 PROP_OPT [] = { 00426 { "Rd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE }, 00427 { "Rs", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE }, 00428 { "Isr", PROP_REAL, { 1e-14, PROP_NO_STR }, PROP_POS_RANGE }, 00429 { "Nr", PROP_REAL, { 2, PROP_NO_STR }, PROP_RNGII (1, 100) }, 00430 { "Kf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE }, 00431 { "Af", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE }, 00432 { "Ffe", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE }, 00433 { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) }, 00434 { "Type", PROP_STR, { PROP_NO_VAL, "nfet" }, PROP_RNG_FET }, 00435 { "Xti", PROP_REAL, { 3, PROP_NO_STR }, PROP_POS_RANGE }, 00436 { "Vt0tc", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00437 { "Betatce", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE }, 00438 { "Tnom", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) }, 00439 { "Area", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGEX }, 00440 PROP_NO_PROP }; 00441 struct define_t jfet::cirdef = 00442 { "JFET", 3, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR, PROP_DEF };