LCOV - code coverage report
Current view: top level - src/components/devices - mosfet.cpp (source / functions) Hit Total Coverage
Test: qucs-core-0.0.19 Code Coverage Lines: 355 423 83.9 %
Date: 2015-01-05 16:01:02 Functions: 14 20 70.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 180 372 48.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * mosfet.cpp - mosfet class implementation
       3                 :            :  *
       4                 :            :  * Copyright (C) 2004, 2005, 2006, 2008 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 "component.h"
      30                 :            : #include "device.h"
      31                 :            : #include "mosfet.h"
      32                 :            : 
      33                 :            : #define NODE_G 0 /* gate node   */
      34                 :            : #define NODE_D 1 /* drain node  */
      35                 :            : #define NODE_S 2 /* source node */
      36                 :            : #define NODE_B 3 /* bulk node   */
      37                 :            : 
      38                 :            : using namespace qucs;
      39                 :            : using namespace qucs::device;
      40                 :            : 
      41                 :         19 : mosfet::mosfet () : circuit (4) {
      42                 :         19 :   transientMode = 0;
      43                 :         19 :   rg = rs = rd = NULL;
      44                 :         19 :   type = CIR_MOSFET;
      45                 :         19 : }
      46                 :            : 
      47                 :          0 : void mosfet::calcSP (nr_double_t frequency) {
      48 [ #  # ][ #  # ]:          0 :   setMatrixS (ytos (calcMatrixY (frequency)));
         [ #  # ][ #  # ]
                 [ #  # ]
      49                 :          0 : }
      50                 :            : 
      51                 :       1600 : matrix mosfet::calcMatrixY (nr_double_t frequency) {
      52                 :            : 
      53                 :            :   // fetch computed operating points
      54         [ +  - ]:       1600 :   nr_double_t Cgd = getOperatingPoint ("Cgd");
      55         [ +  - ]:       1600 :   nr_double_t Cgs = getOperatingPoint ("Cgs");
      56         [ +  - ]:       1600 :   nr_double_t Cbd = getOperatingPoint ("Cbd");
      57         [ +  - ]:       1600 :   nr_double_t Cbs = getOperatingPoint ("Cbs");
      58         [ +  - ]:       1600 :   nr_double_t Cgb = getOperatingPoint ("Cgb");
      59         [ +  - ]:       1600 :   nr_double_t gbs = getOperatingPoint ("gbs");
      60         [ +  - ]:       1600 :   nr_double_t gbd = getOperatingPoint ("gbd");
      61         [ +  - ]:       1600 :   nr_double_t gds = getOperatingPoint ("gds");
      62         [ +  - ]:       1600 :   nr_double_t gm  = getOperatingPoint ("gm");
      63         [ +  - ]:       1600 :   nr_double_t gmb = getOperatingPoint ("gmb");
      64                 :            : 
      65                 :            :   // compute the models admittances
      66                 :       1600 :   nr_complex_t Ygd = nr_complex_t (0.0, 2.0 * M_PI * frequency * Cgd);
      67                 :       1600 :   nr_complex_t Ygs = nr_complex_t (0.0, 2.0 * M_PI * frequency * Cgs);
      68                 :       1600 :   nr_complex_t Yds = gds;
      69                 :       1600 :   nr_complex_t Ybd = nr_complex_t (gbd, 2.0 * M_PI * frequency * Cbd);
      70                 :       1600 :   nr_complex_t Ybs = nr_complex_t (gbs, 2.0 * M_PI * frequency * Cbs);
      71                 :       1600 :   nr_complex_t Ygb = nr_complex_t (0.0, 2.0 * M_PI * frequency * Cgb);
      72                 :            : 
      73                 :            :   // build admittance matrix and convert it to S-parameter matrix
      74         [ +  - ]:       1600 :   matrix y (4);
      75 [ +  - ][ +  - ]:       1600 :   y.set (NODE_G, NODE_G, Ygd + Ygs + Ygb);
                 [ +  - ]
      76         [ +  - ]:       1600 :   y.set (NODE_G, NODE_D, -Ygd);
      77         [ +  - ]:       1600 :   y.set (NODE_G, NODE_S, -Ygs);
      78         [ +  - ]:       1600 :   y.set (NODE_G, NODE_B, -Ygb);
      79         [ +  - ]:       1600 :   y.set (NODE_D, NODE_G, gm - Ygd);
      80 [ +  - ][ +  - ]:       1600 :   y.set (NODE_D, NODE_D, Ygd + Yds + Ybd - DrainControl);
                 [ +  - ]
      81         [ +  - ]:       1600 :   y.set (NODE_D, NODE_S, -Yds - SourceControl);
      82         [ +  - ]:       1600 :   y.set (NODE_D, NODE_B, -Ybd + gmb);
      83         [ +  - ]:       1600 :   y.set (NODE_S, NODE_G, -Ygs - gm);
      84         [ +  - ]:       1600 :   y.set (NODE_S, NODE_D, -Yds + DrainControl);
      85 [ +  - ][ +  - ]:       1600 :   y.set (NODE_S, NODE_S, Ygs + Yds + Ybs + SourceControl);
                 [ +  - ]
      86         [ +  - ]:       1600 :   y.set (NODE_S, NODE_B, -Ybs - gmb);
      87         [ +  - ]:       1600 :   y.set (NODE_B, NODE_G, -Ygb);
      88         [ +  - ]:       1600 :   y.set (NODE_B, NODE_D, -Ybd);
      89         [ +  - ]:       1600 :   y.set (NODE_B, NODE_S, -Ybs);
      90 [ +  - ][ +  - ]:       1600 :   y.set (NODE_B, NODE_B, Ybd + Ybs + Ygb);
                 [ +  - ]
      91                 :            : 
      92                 :       1600 :   return y;
      93                 :            : }
      94                 :            : 
      95                 :          0 : void mosfet::calcNoiseSP (nr_double_t frequency) {
      96 [ #  # ][ #  # ]:          0 :   setMatrixN (cytocs (calcMatrixCy (frequency) * z0, getMatrixS ()));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      97                 :          0 : }
      98                 :            : 
      99                 :          0 : matrix mosfet::calcMatrixCy (nr_double_t frequency) {
     100                 :            :   /* get operating points and noise properties */
     101                 :          0 :   nr_double_t Kf  = getPropertyDouble ("Kf");
     102                 :          0 :   nr_double_t Af  = getPropertyDouble ("Af");
     103                 :          0 :   nr_double_t Ffe = getPropertyDouble ("Ffe");
     104                 :          0 :   nr_double_t gm  = fabs (getOperatingPoint ("gm"));
     105                 :          0 :   nr_double_t Ids = fabs (getOperatingPoint ("Id"));
     106                 :          0 :   nr_double_t T   = getPropertyDouble ("Temp");
     107                 :            : 
     108                 :            :   /* compute channel noise and flicker noise generated by the DC
     109                 :            :      transconductance and current flow from drain to source */
     110                 :            :   nr_double_t i = 8 * kelvin (T) / T0 * gm / 3 +
     111                 :          0 :     Kf * qucs::pow (Ids, Af) / qucs::pow (frequency, Ffe) / kB / T0;
     112                 :            : 
     113                 :            :   /* build noise current correlation matrix and convert it to
     114                 :            :      noise-wave correlation matrix */
     115                 :          0 :   matrix cy = matrix (4);
     116         [ #  # ]:          0 :   cy.set (NODE_D, NODE_D, +i);
     117         [ #  # ]:          0 :   cy.set (NODE_S, NODE_S, +i);
     118         [ #  # ]:          0 :   cy.set (NODE_D, NODE_S, -i);
     119         [ #  # ]:          0 :   cy.set (NODE_S, NODE_D, -i);
     120                 :          0 :   return cy;
     121                 :            : }
     122                 :            : 
     123                 :       3898 : void mosfet::restartDC (void) {
     124                 :            :   // apply starting values to previous iteration values
     125 [ +  - ][ +  - ]:       3898 :   UgdPrev = real (getV (NODE_G) - getV (NODE_D));
     126 [ +  - ][ +  - ]:       3898 :   UgsPrev = real (getV (NODE_G) - getV (NODE_S));
     127 [ +  - ][ +  - ]:       3898 :   UbsPrev = real (getV (NODE_B) - getV (NODE_S));
     128 [ +  - ][ +  - ]:       3898 :   UbdPrev = real (getV (NODE_B) - getV (NODE_D));
     129                 :       3898 :   UdsPrev = UgsPrev - UgdPrev;
     130                 :       3898 : }
     131                 :            : 
     132                 :         30 : void mosfet::initDC (void) {
     133                 :            : 
     134                 :            :   // allocate MNA matrices
     135                 :         30 :   allocMatrixMNA ();
     136                 :            : 
     137                 :            :   // initialize starting values
     138                 :         30 :   restartDC ();
     139                 :            : 
     140                 :            :   // initialize the MOSFET
     141                 :         30 :   initModel ();
     142                 :            : 
     143                 :            :   // get device temperature
     144                 :         30 :   nr_double_t T = getPropertyDouble ("Temp");
     145                 :            : 
     146                 :            :   // possibly insert series resistance at source
     147         [ +  + ]:         30 :   if (Rs != 0.0) {
     148                 :            :     // create additional circuit if necessary and reassign nodes
     149                 :         10 :     rs = splitResistor (this, rs, "Rs", "source", NODE_S);
     150                 :         10 :     rs->setProperty ("Temp", T);
     151                 :         10 :     rs->setProperty ("R", Rs);
     152                 :         10 :     rs->setProperty ("Controlled", getName ());
     153                 :         10 :     rs->initDC ();
     154                 :            :   }
     155                 :            :   // no series resistance at source
     156                 :            :   else {
     157                 :         20 :     disableResistor (this, rs, NODE_S);
     158                 :            :   }
     159                 :            : 
     160                 :            :   // possibly insert series resistance at gate
     161                 :         30 :   nr_double_t Rg = getPropertyDouble ("Rg");
     162         [ -  + ]:         30 :   if (Rg != 0.0) {
     163                 :            :     // create additional circuit if necessary and reassign nodes
     164                 :          0 :     rg = splitResistor (this, rg, "Rg", "gate", NODE_G);
     165                 :          0 :     rg->setProperty ("Temp", T);
     166                 :          0 :     rg->setProperty ("R", Rg);
     167                 :          0 :     rg->setProperty ("Controlled", getName ());
     168                 :          0 :     rg->initDC ();
     169                 :            :   }
     170                 :            :   // no series resistance at source
     171                 :            :   else {
     172                 :         30 :     disableResistor (this, rg, NODE_G);
     173                 :            :   }
     174                 :            : 
     175                 :            :   // possibly insert series resistance at drain
     176         [ +  + ]:         30 :   if (Rd != 0.0) {
     177                 :            :     // create additional circuit if necessary and reassign nodes
     178                 :         10 :     rd = splitResistor (this, rd, "Rd", "drain", NODE_D);
     179                 :         10 :     rd->setProperty ("Temp", T);
     180                 :         10 :     rd->setProperty ("R", Rd);
     181                 :         10 :     rd->setProperty ("Controlled", getName ());
     182                 :         10 :     rd->initDC ();
     183                 :            :   }
     184                 :            :   // no series resistance at drain
     185                 :            :   else {
     186                 :         20 :     disableResistor (this, rd, NODE_D);
     187                 :            :   }
     188                 :         30 : }
     189                 :            : 
     190                 :         30 : void mosfet::initModel (void) {
     191                 :            : 
     192                 :            :   // get device temperature
     193                 :         30 :   nr_double_t T  = getPropertyDouble ("Temp");
     194                 :         30 :   nr_double_t T2 = kelvin (getPropertyDouble ("Temp"));
     195                 :         30 :   nr_double_t T1 = kelvin (getPropertyDouble ("Tnom"));
     196                 :            : 
     197                 :            :   // apply polarity of MOSFET
     198                 :         30 :   const char * const type = getPropertyString ("Type");
     199         [ +  + ]:         30 :   pol = !strcmp (type, "pfet") ? -1 : 1;
     200                 :            : 
     201                 :            :   // calculate effective channel length
     202                 :         30 :   nr_double_t L  = getPropertyDouble ("L");
     203                 :         30 :   nr_double_t Ld = getPropertyDouble ("Ld");
     204         [ -  + ]:         30 :   if ((Leff = L - 2 * Ld) <= 0) {
     205                 :            :     logprint (LOG_STATUS, "WARNING: effective MOSFET channel length %g <= 0, "
     206                 :          0 :               "set to L = %g\n", Leff, L);
     207                 :          0 :     Leff = L;
     208                 :            :   }
     209                 :            : 
     210                 :            :   // calculate gate oxide overlap capacitance
     211                 :         30 :   nr_double_t W   = getPropertyDouble ("W");
     212                 :         30 :   nr_double_t Tox = getPropertyDouble ("Tox");
     213         [ -  + ]:         30 :   if (Tox <= 0) {
     214                 :            :     logprint (LOG_STATUS, "WARNING: disabling gate oxide capacitance, "
     215                 :          0 :               "Cox = 0\n");
     216                 :          0 :     Cox = 0;
     217                 :            :   } else {
     218                 :         30 :     Cox = (ESiO2 * E0 / Tox);
     219                 :            :   }
     220                 :            : 
     221                 :            :   // calculate DC transconductance coefficient
     222                 :         30 :   nr_double_t Kp = getPropertyDouble ("Kp");
     223                 :         30 :   nr_double_t Uo = getPropertyDouble ("Uo");
     224                 :         30 :   nr_double_t F1 = qucs::exp (1.5 * qucs::log (T1 / T2));
     225                 :         30 :   Kp = Kp * F1;
     226                 :         30 :   Uo = Uo * F1;
     227                 :         30 :   setScaledProperty ("Kp", Kp);
     228                 :         30 :   setScaledProperty ("Uo", Uo);
     229         [ +  - ]:         30 :   if (Kp > 0) {
     230                 :         30 :     beta = Kp * W / Leff;
     231                 :            :   } else {
     232 [ #  # ][ #  # ]:          0 :     if (Cox > 0 && Uo > 0) {
     233                 :          0 :       beta = Uo * 1e-4 * Cox * W / Leff;
     234                 :            :     } else {
     235                 :            :       logprint (LOG_STATUS, "WARNING: adjust Tox, Uo or Kp to get a valid "
     236                 :          0 :                 "transconductance coefficient\n");
     237                 :          0 :       beta = 2e-5 * W / Leff;
     238                 :            :     }
     239                 :            :   }
     240                 :            : 
     241                 :            :   // calculate surface potential
     242                 :         30 :   nr_double_t P    = getPropertyDouble ("Phi");
     243                 :         30 :   nr_double_t Nsub = getPropertyDouble ("Nsub");
     244                 :         30 :   nr_double_t Ut   = T0 * kBoverQ;
     245                 :         30 :   P = pnPotential_T (T1,T2, P);
     246                 :         30 :   setScaledProperty ("Phi", P);
     247         [ -  + ]:         30 :   if ((Phi = P) <= 0) {
     248         [ #  # ]:          0 :     if (Nsub > 0) {
     249         [ #  # ]:          0 :       if (Nsub * 1e6 >= NiSi) {
     250                 :          0 :         Phi = 2 * Ut * qucs::log (Nsub * 1e6 / NiSi);
     251                 :            :       } else {
     252                 :            :         logprint (LOG_STATUS, "WARNING: substrate doping less than instrinsic "
     253                 :          0 :                   "density, adjust Nsub >= %g\n", NiSi / 1e6);
     254                 :          0 :         Phi = 0.6;
     255                 :            :       }
     256                 :            :     } else {
     257                 :            :       logprint (LOG_STATUS, "WARNING: adjust Nsub or Phi to get a valid "
     258                 :          0 :                 "surface potential\n");
     259                 :          0 :       Phi = 0.6;
     260                 :            :     }
     261                 :            :   }
     262                 :            : 
     263                 :            :   // calculate bulk threshold
     264                 :         30 :   nr_double_t G = getPropertyDouble ("Gamma");
     265         [ -  + ]:         30 :   if ((Ga = G) < 0) {
     266 [ #  # ][ #  # ]:          0 :     if (Cox > 0 && Nsub > 0) {
     267                 :          0 :       Ga = qucs::sqrt (2 * Q_e * ESi * E0 * Nsub * 1e6) / Cox;
     268                 :            :     } else {
     269                 :            :       logprint (LOG_STATUS, "WARNING: adjust Tox, Nsub or Gamma to get a "
     270                 :          0 :                 "valid bulk threshold\n");
     271                 :          0 :       Ga = 0.0;
     272                 :            :     }
     273                 :            :   }
     274                 :            : 
     275                 :            :   // calculate threshold voltage
     276                 :         30 :   nr_double_t Vt0 = getPropertyDouble ("Vt0");
     277         [ -  + ]:         30 :   if ((Vto = Vt0) == 0.0) {
     278                 :          0 :     nr_double_t Tpg = getPropertyDouble ("Tpg");
     279                 :          0 :     nr_double_t Nss = getPropertyDouble ("Nss");
     280                 :            :     nr_double_t PhiMS, PhiG, Eg;
     281                 :            :     // bandgap for silicon
     282                 :          0 :     Eg = Egap (kelvin (T));
     283         [ #  # ]:          0 :     if (Tpg != 0.0) { // n-poly or p-poly
     284                 :          0 :       PhiG = 4.15 + Eg / 2 - pol * Tpg * Eg / 2;
     285                 :            :     } else {          // alumina
     286                 :          0 :       PhiG = 4.1;
     287                 :            :     }
     288                 :          0 :     PhiMS = PhiG - (4.15 + Eg / 2 + pol * Phi / 2);
     289 [ #  # ][ #  # ]:          0 :     if (Nss >= 0 && Cox > 0) {
     290                 :          0 :       Vto = PhiMS - Q_e * Nss * 1e4 / Cox + pol * (Phi + Ga * qucs::sqrt (Phi));
     291                 :            :     } else {
     292                 :            :       logprint (LOG_STATUS, "WARNING: adjust Tox, Nss or Vt0 to get a "
     293                 :          0 :                 "valid threshold voltage\n");
     294                 :          0 :       Vto = 0.0;
     295                 :            :     }
     296                 :            :   }
     297                 :            : 
     298                 :         30 :   Cox = Cox * W * Leff;
     299                 :            : 
     300                 :            :   // calculate drain and source resistance if necessary
     301                 :         30 :   nr_double_t Rsh = getPropertyDouble ("Rsh");
     302                 :         30 :   nr_double_t Nrd = getPropertyDouble ("Nrd");
     303                 :         30 :   nr_double_t Nrs = getPropertyDouble ("Nrs");
     304                 :         30 :   Rd = getPropertyDouble ("Rd");
     305                 :         30 :   Rs = getPropertyDouble ("Rs");
     306         [ +  + ]:         30 :   if (Rsh > 0) {
     307         [ +  - ]:         10 :     if (Nrd > 0) Rd += Rsh * Nrd;
     308         [ +  - ]:         10 :     if (Nrs > 0) Rs += Rsh * Nrs;
     309                 :            :   }
     310                 :            : 
     311                 :            :   // calculate zero-bias junction capacitance
     312                 :         30 :   nr_double_t Cj  = getPropertyDouble ("Cj");
     313                 :         30 :   nr_double_t Mj  = getPropertyDouble ("Mj");
     314                 :         30 :   nr_double_t Mjs = getPropertyDouble ("Mjsw");
     315                 :         30 :   nr_double_t Pb  = getPropertyDouble ("Pb");
     316                 :            :   nr_double_t PbT, F2, F3;
     317                 :         30 :   PbT = pnPotential_T (T1,T2, Pb);
     318                 :         30 :   F2  = pnCapacitance_F (T1, T2, Mj, PbT / Pb);
     319                 :         30 :   F3  = pnCapacitance_F (T1, T2, Mjs, PbT / Pb);
     320                 :         30 :   Pb  = PbT;
     321                 :         30 :   setScaledProperty ("Pb", Pb);
     322         [ +  + ]:         30 :   if (Cj <= 0) {
     323 [ +  - ][ +  - ]:         14 :     if (Pb > 0 && Nsub >= 0) {
     324                 :         14 :       Cj = qucs::sqrt (ESi * E0 * Q_e * Nsub * 1e6 / 2 / Pb);
     325                 :            :     }
     326                 :            :     else {
     327                 :            :       logprint (LOG_STATUS, "WARNING: adjust Pb, Nsub or Cj to get a "
     328                 :          0 :                 "valid square junction capacitance\n");
     329                 :         14 :       Cj = 0.0;
     330                 :            :     }
     331                 :            :   }
     332                 :         30 :   Cj = Cj * F2;
     333                 :         30 :   setScaledProperty ("Cj", Cj);
     334                 :            : 
     335                 :            :   // calculate junction capacitances
     336                 :         30 :   nr_double_t Cbd0 = getPropertyDouble ("Cbd");
     337                 :         30 :   nr_double_t Cbs0 = getPropertyDouble ("Cbs");
     338                 :         30 :   nr_double_t Ad   = getPropertyDouble ("Ad");
     339                 :         30 :   nr_double_t As   = getPropertyDouble ("As");
     340                 :         30 :   Cbd0 = Cbd0 * F2;
     341         [ +  + ]:         30 :   if (Cbd0 <= 0) {
     342                 :         22 :     Cbd0 = Cj * Ad;
     343                 :            :   }
     344                 :         30 :   setScaledProperty ("Cbd", Cbd0);
     345                 :         30 :   Cbs0 = Cbs0 * F2;
     346         [ +  + ]:         30 :   if (Cbs0 <= 0) {
     347                 :         22 :     Cbs0 = Cj * As;
     348                 :            :   }
     349                 :         30 :   setScaledProperty ("Cbs", Cbs0);
     350                 :            : 
     351                 :            :   // calculate periphery junction capacitances
     352                 :         30 :   nr_double_t Cjs = getPropertyDouble ("Cjsw");
     353                 :         30 :   nr_double_t Pd  = getPropertyDouble ("Pd");
     354                 :         30 :   nr_double_t Ps  = getPropertyDouble ("Ps");
     355                 :         30 :   Cjs = Cjs * F3;
     356                 :         30 :   setProperty ("Cbds", Cjs * Pd);
     357                 :         30 :   setProperty ("Cbss", Cjs * Ps);
     358                 :            : 
     359                 :            :   // calculate junction capacitances and saturation currents
     360                 :         30 :   nr_double_t Js  = getPropertyDouble ("Js");
     361                 :         30 :   nr_double_t Is  = getPropertyDouble ("Is");
     362                 :            :   nr_double_t F4, E1, E2;
     363                 :         30 :   E1 = Egap (T1);
     364                 :         30 :   E2 = Egap (T2);
     365                 :         30 :   F4 = qucs::exp (- QoverkB / T2 * (T2 / T1 * E1 - E2));
     366                 :         30 :   Is = Is * F4;
     367                 :         30 :   Js = Js * F4;
     368         [ +  + ]:         30 :   nr_double_t Isd = (Ad > 0) ? Js * Ad : Is;
     369         [ +  + ]:         30 :   nr_double_t Iss = (As > 0) ? Js * As : Is;
     370                 :         30 :   setProperty ("Isd", Isd);
     371                 :         30 :   setProperty ("Iss", Iss);
     372                 :            : 
     373                 :            : #if DEBUG
     374                 :            :   logprint (LOG_STATUS, "NOTIFY: Cox=%g, Beta=%g Ga=%g, Phi=%g, Vto=%g\n",
     375                 :         30 :             Cox, beta, Ga, Phi, Vto);
     376                 :            : #endif /* DEBUG */
     377                 :         30 : }
     378                 :            : 
     379                 :      83645 : void mosfet::calcDC (void) {
     380                 :            : 
     381                 :            :   // fetch device model parameters
     382                 :      83645 :   nr_double_t Isd = getPropertyDouble ("Isd");
     383                 :      83645 :   nr_double_t Iss = getPropertyDouble ("Iss");
     384                 :      83645 :   nr_double_t n   = getPropertyDouble ("N");
     385                 :      83645 :   nr_double_t l   = getPropertyDouble ("Lambda");
     386                 :      83645 :   nr_double_t T   = getPropertyDouble ("Temp");
     387                 :            : 
     388                 :            :   nr_double_t Ut, IeqBS, IeqBD, IeqDS, UbsCrit, UbdCrit, gtiny;
     389                 :            : 
     390                 :      83645 :   T = kelvin (T);
     391                 :      83645 :   Ut = T * kBoverQ;
     392 [ +  - ][ +  - ]:      83645 :   Ugd = real (getV (NODE_G) - getV (NODE_D)) * pol;
     393 [ +  - ][ +  - ]:      83645 :   Ugs = real (getV (NODE_G) - getV (NODE_S)) * pol;
     394 [ +  - ][ +  - ]:      83645 :   Ubs = real (getV (NODE_B) - getV (NODE_S)) * pol;
     395 [ +  - ][ +  - ]:      83645 :   Ubd = real (getV (NODE_B) - getV (NODE_D)) * pol;
     396                 :      83645 :   Uds = Ugs - Ugd;
     397                 :            : 
     398                 :            :   // critical voltage necessary for bad start values
     399                 :      83645 :   UbsCrit = pnCriticalVoltage (Iss, Ut * n);
     400                 :      83645 :   UbdCrit = pnCriticalVoltage (Isd, Ut * n);
     401                 :            : 
     402                 :            :   // for better convergence
     403         [ +  + ]:      83645 :   if (Uds >= 0) {
     404                 :      74705 :     Ugs = fetVoltage (Ugs, UgsPrev, Vto * pol);
     405                 :      74705 :     Uds = Ugs - Ugd;
     406                 :      74705 :     Uds = fetVoltageDS (Uds, UdsPrev);
     407                 :      74705 :     Ugd = Ugs - Uds;
     408                 :            :   }
     409                 :            :   else {
     410                 :       8940 :     Ugd = fetVoltage (Ugd, UgdPrev, Vto * pol);
     411                 :       8940 :     Uds = Ugs - Ugd;
     412                 :       8940 :     Uds = -fetVoltageDS (-Uds, -UdsPrev);
     413                 :       8940 :     Ugs = Ugd + Uds;
     414                 :            :   }
     415         [ +  + ]:      83645 :   if (Uds >= 0) {
     416                 :      74425 :     Ubs = pnVoltage (Ubs, UbsPrev, Ut * n, UbsCrit);
     417                 :      74425 :     Ubd = Ubs - Uds;
     418                 :            :   }
     419                 :            :   else {
     420                 :       9220 :     Ubd = pnVoltage (Ubd, UbdPrev, Ut * n, UbdCrit);
     421                 :       9220 :     Ubs = Ubd + Uds;
     422                 :            :   }
     423                 :      83645 :   UgsPrev = Ugs; UgdPrev = Ugd; UbdPrev = Ubd; UdsPrev = Uds; UbsPrev = Ubs;
     424                 :            : 
     425                 :            :   // parasitic bulk-source diode
     426                 :      83645 :   gtiny = Iss;
     427                 :      83645 :   pnJunctionMOS (Ubs, Iss, Ut * n, Ibs, gbs);
     428                 :      83645 :   Ibs += gtiny * Ubs;
     429                 :      83645 :   gbs += gtiny;
     430                 :            : 
     431                 :            :   // parasitic bulk-drain diode
     432                 :      83645 :   gtiny = Isd;
     433                 :      83645 :   pnJunctionMOS (Ubd, Isd, Ut * n, Ibd, gbd);
     434                 :      83645 :   Ibd += gtiny * Ubd;
     435                 :      83645 :   gbd += gtiny;
     436                 :            : 
     437                 :            :   // differentiate inverse and forward mode
     438         [ +  + ]:      83645 :   MOSdir = (Uds >= 0) ? +1 : -1;
     439                 :            : 
     440                 :            :   // first calculate sqrt (Upn - Phi)
     441         [ +  + ]:      83645 :   nr_double_t Upn = (MOSdir > 0) ? Ubs : Ubd;
     442                 :      83645 :   nr_double_t Sarg, Sphi = qucs::sqrt (Phi);
     443         [ +  + ]:      83645 :   if (Upn <= 0) {
     444                 :            :     // take equation as is
     445                 :      75987 :     Sarg = qucs::sqrt (Phi - Upn);
     446                 :            :   }
     447                 :            :   else {
     448                 :            :     // taylor series of "sqrt (x - 1)" -> continual at Ubs/Ubd = 0
     449                 :       7658 :     Sarg = Sphi - Upn / Sphi / 2;
     450         [ +  - ]:       7658 :     Sarg = MAX (Sarg, 0);
     451                 :            :   }
     452                 :            : 
     453                 :            :   // calculate bias-dependent threshold voltage
     454                 :      83645 :   Uon = Vto * pol + Ga * (Sarg - Sphi);
     455         [ +  + ]:      83645 :   nr_double_t Utst = ((MOSdir > 0) ? Ugs : Ugd) - Uon;
     456                 :            :   // no infinite backgate transconductance (if non-zero Ga)
     457         [ +  - ]:      83645 :   nr_double_t arg = (Sarg != 0.0) ? (Ga / Sarg / 2) : 0;
     458                 :            : 
     459                 :            :   // cutoff region
     460         [ +  + ]:      83645 :   if (Utst <= 0) {
     461                 :      17520 :     Ids = 0;
     462                 :      17520 :     gm  = 0;
     463                 :      17520 :     gds = 0;
     464                 :      17520 :     gmb = 0;
     465                 :            :   }
     466                 :            :   else {
     467                 :      66125 :     nr_double_t Vds = Uds * MOSdir;
     468                 :      66125 :     nr_double_t b   = beta * (1 + l * Vds);
     469                 :            :     // saturation region
     470         [ +  + ]:      66125 :     if (Utst <= Vds) {
     471                 :      39742 :       Ids = b * Utst * Utst / 2;
     472                 :      39742 :       gm  = b * Utst;
     473                 :      39742 :       gds = l * beta * Utst * Utst / 2;
     474                 :            :     }
     475                 :            :     // linear region
     476                 :            :     else {
     477                 :      26383 :       Ids = b * Vds * (Utst - Vds / 2);
     478                 :      26383 :       gm  = b * Vds;
     479                 :      26383 :       gds = b * (Utst - Vds) + l * beta * Vds * (Utst - Vds / 2);
     480                 :            :     }
     481                 :      66125 :     gmb = gm * arg;
     482                 :            :   }
     483         [ +  + ]:      83645 :   Udsat = pol * MAX (Utst, 0);
     484                 :      83645 :   Ids = MOSdir * Ids;
     485                 :      83645 :   Uon = pol * Uon;
     486                 :            : 
     487                 :            :   // compute autonomic current sources
     488                 :      83645 :   IeqBD = Ibd - gbd * Ubd;
     489                 :      83645 :   IeqBS = Ibs - gbs * Ubs;
     490                 :            : 
     491                 :            :   // exchange controlling nodes if necessary
     492         [ +  + ]:      83645 :   SourceControl = (MOSdir > 0) ? (gm + gmb) : 0;
     493         [ +  + ]:      83645 :   DrainControl  = (MOSdir < 0) ? (gm + gmb) : 0;
     494         [ +  + ]:      83645 :   if (MOSdir > 0) {
     495                 :      74425 :     IeqDS = Ids - gm * Ugs - gmb * Ubs - gds * Uds;
     496                 :            :   } else {
     497                 :       9220 :     IeqDS = Ids - gm * Ugd - gmb * Ubd - gds * Uds;
     498                 :            :   }
     499                 :            : 
     500         [ +  - ]:      83645 :   setI (NODE_G, 0);
     501         [ +  - ]:      83645 :   setI (NODE_D, (+IeqBD - IeqDS) * pol);
     502         [ +  - ]:      83645 :   setI (NODE_S, (+IeqBS + IeqDS) * pol);
     503         [ +  - ]:      83645 :   setI (NODE_B, (-IeqBD - IeqBS) * pol);
     504                 :            : 
     505                 :            :   // apply admittance matrix elements
     506         [ +  - ]:      83645 :   setY (NODE_G, NODE_G, 0);
     507         [ +  - ]:      83645 :   setY (NODE_G, NODE_D, 0);
     508         [ +  - ]:      83645 :   setY (NODE_G, NODE_S, 0);
     509         [ +  - ]:      83645 :   setY (NODE_G, NODE_B, 0);
     510         [ +  - ]:      83645 :   setY (NODE_D, NODE_G, gm);
     511         [ +  - ]:      83645 :   setY (NODE_D, NODE_D, gds + gbd - DrainControl);
     512         [ +  - ]:      83645 :   setY (NODE_D, NODE_S, -gds - SourceControl);
     513         [ +  - ]:      83645 :   setY (NODE_D, NODE_B, gmb - gbd);
     514         [ +  - ]:      83645 :   setY (NODE_S, NODE_G, -gm);
     515         [ +  - ]:      83645 :   setY (NODE_S, NODE_D, -gds + DrainControl);
     516         [ +  - ]:      83645 :   setY (NODE_S, NODE_S, gbs + gds + SourceControl);
     517         [ +  - ]:      83645 :   setY (NODE_S, NODE_B, -gbs - gmb);
     518         [ +  - ]:      83645 :   setY (NODE_B, NODE_G, 0);
     519         [ +  - ]:      83645 :   setY (NODE_B, NODE_D, -gbd);
     520         [ +  - ]:      83645 :   setY (NODE_B, NODE_S, -gbs);
     521         [ +  - ]:      83645 :   setY (NODE_B, NODE_B, gbs + gbd);
     522                 :      83645 : }
     523                 :            : 
     524                 :            : /* Usual and additional state definitions. */
     525                 :            : 
     526                 :            : #define qgdState  0 // gate-drain charge state
     527                 :            : #define igdState  1 // gate-drain current state
     528                 :            : #define vgdState  2 // gate-drain voltage state
     529                 :            : #define cgdState  3 // gate-drain capacitance state
     530                 :            : #define qgsState  4 // gate-source charge state
     531                 :            : #define igsState  5 // gate-source current state
     532                 :            : #define vgsState  6 // gate-source voltage state
     533                 :            : #define cgsState  7 // gate-source capacitance state
     534                 :            : #define qbdState  8 // bulk-drain charge state
     535                 :            : #define ibdState  9 // bulk-drain current state
     536                 :            : #define qbsState 10 // bulk-source charge state
     537                 :            : #define ibsState 11 // bulk-source current state
     538                 :            : #define qgbState 12 // gate-bulk charge state
     539                 :            : #define igbState 13 // gate-bulk current state
     540                 :            : #define vgbState 14 // gate-bulk voltage state
     541                 :            : #define cgbState 15 // gate-bulk capacitance state
     542                 :            : 
     543                 :      83504 : void mosfet::saveOperatingPoints (void) {
     544                 :            :   nr_double_t Vgs, Vgd, Vbs, Vbd;
     545 [ +  - ][ +  - ]:      83504 :   Vgd = real (getV (NODE_G) - getV (NODE_D)) * pol;
     546 [ +  - ][ +  - ]:      83504 :   Vgs = real (getV (NODE_G) - getV (NODE_S)) * pol;
     547 [ +  - ][ +  - ]:      83504 :   Vbs = real (getV (NODE_B) - getV (NODE_S)) * pol;
     548 [ +  - ][ +  - ]:      83504 :   Vbd = real (getV (NODE_B) - getV (NODE_D)) * pol;
     549                 :      83504 :   setOperatingPoint ("Vgs", Vgs);
     550                 :      83504 :   setOperatingPoint ("Vgd", Vgd);
     551                 :      83504 :   setOperatingPoint ("Vbs", Vbs);
     552                 :      83504 :   setOperatingPoint ("Vbd", Vbd);
     553                 :      83504 :   setOperatingPoint ("Vds", Vgs - Vgd);
     554                 :      83504 :   setOperatingPoint ("Vgb", Vgs - Vbs);
     555                 :      83504 : }
     556                 :            : 
     557                 :      83496 : void mosfet::loadOperatingPoints (void) {
     558                 :      83496 :   Ugs = getOperatingPoint ("Vgs");
     559                 :      83496 :   Ugd = getOperatingPoint ("Vgd");
     560                 :      83496 :   Ubs = getOperatingPoint ("Vbs");
     561                 :      83496 :   Ubd = getOperatingPoint ("Vbd");
     562                 :      83496 :   Uds = getOperatingPoint ("Vds");
     563                 :      83496 :   Ugb = getOperatingPoint ("Vgb");
     564                 :      83496 : }
     565                 :            : 
     566                 :      83504 : void mosfet::calcOperatingPoints (void) {
     567                 :            : 
     568                 :            :   // fetch device model parameters
     569         [ +  - ]:      83504 :   nr_double_t Cbd0 = getScaledProperty ("Cbd");
     570         [ +  - ]:      83504 :   nr_double_t Cbs0 = getScaledProperty ("Cbs");
     571         [ +  - ]:      83504 :   nr_double_t Cbds = getPropertyDouble ("Cbds");
     572         [ +  - ]:      83504 :   nr_double_t Cbss = getPropertyDouble ("Cbss");
     573         [ +  - ]:      83504 :   nr_double_t Cgso = getPropertyDouble ("Cgso");
     574         [ +  - ]:      83504 :   nr_double_t Cgdo = getPropertyDouble ("Cgdo");
     575         [ +  - ]:      83504 :   nr_double_t Cgbo = getPropertyDouble ("Cgbo");
     576         [ +  - ]:      83504 :   nr_double_t Pb   = getScaledProperty ("Pb");
     577         [ +  - ]:      83504 :   nr_double_t M    = getPropertyDouble ("Mj");
     578         [ +  - ]:      83504 :   nr_double_t Ms   = getPropertyDouble ("Mjsw");
     579         [ +  - ]:      83504 :   nr_double_t Fc   = getPropertyDouble ("Fc");
     580         [ +  - ]:      83504 :   nr_double_t Tt   = getPropertyDouble ("Tt");
     581         [ +  - ]:      83504 :   nr_double_t W    = getPropertyDouble ("W");
     582                 :            : 
     583                 :            :   nr_double_t Cbs, Cbd, Cgd, Cgb, Cgs;
     584                 :            : 
     585                 :            :   // capacitance of bulk-drain diode
     586         [ +  - ]:      83504 :   Cbd = gbd * Tt + pnCapacitance (Ubd, Cbd0, Pb, M, Fc) +
     587         [ +  - ]:      83504 :     pnCapacitance (Ubd, Cbds, Pb, Ms, Fc);
     588         [ +  - ]:      83504 :   Qbd = Ibd * Tt + pnCharge (Ubd, Cbd0, Pb, M, Fc) +
     589         [ +  - ]:      83504 :     pnCharge (Ubd, Cbds, Pb, Ms, Fc);
     590                 :            : 
     591                 :            :   // capacitance of bulk-source diode
     592         [ +  - ]:      83504 :   Cbs = gbs * Tt + pnCapacitance (Ubs, Cbs0, Pb, M, Fc) +
     593         [ +  - ]:      83504 :     pnCapacitance (Ubs, Cbss, Pb, Ms, Fc);
     594         [ +  - ]:      83504 :   Qbs = Ibs * Tt + pnCharge (Ubs, Cbs0, Pb, M, Fc) +
     595         [ +  - ]:      83504 :     pnCharge (Ubs, Cbss, Pb, Ms, Fc);
     596                 :            : 
     597                 :            :   // calculate bias-dependent MOS overlap capacitances
     598         [ +  + ]:      83504 :   if (MOSdir > 0) {
     599         [ +  - ]:      74286 :     fetCapacitanceMeyer (Ugs, Ugd, Uon, Udsat, Phi, Cox, Cgs, Cgd, Cgb);
     600                 :            :   } else {
     601         [ +  - ]:       9218 :     fetCapacitanceMeyer (Ugd, Ugs, Uon, Udsat, Phi, Cox, Cgd, Cgs, Cgb);
     602                 :            :   }
     603                 :            : 
     604                 :            :   // charge approximation
     605         [ +  + ]:      83504 :   if (transientMode) {
     606         [ -  + ]:      83496 :     if (transientMode == 1) {      // by trapezoidal rule
     607                 :            :       // gate-source charge
     608         [ #  # ]:          0 :       Qgs = transientChargeTR (qgsState, Cgs, Ugs, Cgso * W);
     609                 :            :       // gate-drain charge
     610         [ #  # ]:          0 :       Qgd = transientChargeTR (qgdState, Cgd, Ugd, Cgdo * W);
     611                 :            :       // gate-bulk charge
     612         [ #  # ]:          0 :       Qgb = transientChargeTR (qgbState, Cgb, Ugb, Cgbo * Leff);
     613                 :            :     }
     614         [ +  - ]:      83496 :     else if (transientMode == 2) { // by simpson's rule
     615         [ +  - ]:      83496 :       Qgs = transientChargeSR (qgsState, Cgs, Ugs, Cgso * W);
     616         [ +  - ]:      83496 :       Qgd = transientChargeSR (qgdState, Cgd, Ugd, Cgdo * W);
     617         [ +  - ]:      83496 :       Qgb = transientChargeSR (qgbState, Cgb, Ugb, Cgbo * Leff);
     618                 :            :     }
     619                 :            :   }
     620                 :            :   // usual operating point
     621                 :            :   else {
     622                 :          8 :     Cgs += Cgso * W;
     623                 :          8 :     Cgd += Cgdo * W;
     624                 :          8 :     Cgb += Cgbo * Leff;
     625                 :            :   }
     626                 :            : 
     627                 :            :   // save operating points
     628         [ +  - ]:      83504 :   setOperatingPoint ("Id", Ids);
     629         [ +  - ]:      83504 :   setOperatingPoint ("gm", gm);
     630         [ +  - ]:      83504 :   setOperatingPoint ("gmb", gmb);
     631         [ +  - ]:      83504 :   setOperatingPoint ("gds", gds);
     632         [ +  - ]:      83504 :   setOperatingPoint ("Vth", Vto);
     633         [ +  - ]:      83504 :   setOperatingPoint ("Vdsat", Udsat);
     634         [ +  - ]:      83504 :   setOperatingPoint ("gbs", gbs);
     635         [ +  - ]:      83504 :   setOperatingPoint ("gbd", gbd);
     636         [ +  - ]:      83504 :   setOperatingPoint ("Cbd", Cbd);
     637         [ +  - ]:      83504 :   setOperatingPoint ("Cbs", Cbs);
     638         [ +  - ]:      83504 :   setOperatingPoint ("Cgs", Cgs);
     639         [ +  - ]:      83504 :   setOperatingPoint ("Cgd", Cgd);
     640         [ +  - ]:      83504 :   setOperatingPoint ("Cgb", Cgb);
     641                 :      83504 : }
     642                 :            : 
     643                 :          8 : void mosfet::initAC (void) {
     644                 :          8 :   allocMatrixMNA ();
     645                 :          8 : }
     646                 :            : 
     647                 :       1600 : void mosfet::calcAC (nr_double_t frequency) {
     648         [ +  - ]:       1600 :   setMatrixY (calcMatrixY (frequency));
     649                 :       1600 : }
     650                 :            : 
     651                 :          0 : void mosfet::calcNoiseAC (nr_double_t frequency) {
     652         [ #  # ]:          0 :   setMatrixN (calcMatrixCy (frequency));
     653                 :          0 : }
     654                 :            : 
     655                 :         11 : void mosfet::initTR (void) {
     656                 :         11 :   setStates (16);
     657                 :         11 :   initDC ();
     658                 :         11 : }
     659                 :            : 
     660                 :      83496 : void mosfet::calcTR (nr_double_t) {
     661                 :      83496 :   calcDC ();
     662                 :      83496 :   transientMode = getPropertyInteger ("capModel");
     663                 :      83496 :   saveOperatingPoints ();
     664                 :      83496 :   loadOperatingPoints ();
     665                 :      83496 :   calcOperatingPoints ();
     666                 :      83496 :   transientMode = 0;
     667                 :            : 
     668                 :      83496 :   nr_double_t Cgd = getOperatingPoint ("Cgd");
     669                 :      83496 :   nr_double_t Cgs = getOperatingPoint ("Cgs");
     670                 :      83496 :   nr_double_t Cbd = getOperatingPoint ("Cbd");
     671                 :      83496 :   nr_double_t Cbs = getOperatingPoint ("Cbs");
     672                 :      83496 :   nr_double_t Cgb = getOperatingPoint ("Cgb");
     673                 :            : 
     674                 :      83496 :   Uds = Ugs - Ugd;
     675                 :      83496 :   Ugb = Ugs - Ubs;
     676                 :            : 
     677                 :      83496 :   transientCapacitance (qbdState, NODE_B, NODE_D, Cbd, Ubd, Qbd);
     678                 :      83496 :   transientCapacitance (qbsState, NODE_B, NODE_S, Cbs, Ubs, Qbs);
     679                 :            : 
     680                 :            :   // handle Meyer charges and capacitances
     681                 :      83496 :   transientCapacitance (qgdState, NODE_G, NODE_D, Cgd, Ugd, Qgd);
     682                 :      83496 :   transientCapacitance (qgsState, NODE_G, NODE_S, Cgs, Ugs, Qgs);
     683                 :      83496 :   transientCapacitance (qgbState, NODE_G, NODE_B, Cgb, Ugb, Qgb);
     684                 :      83496 : }
     685                 :            : 
     686                 :            : /* The function uses the trapezoidal rule to compute the current
     687                 :            :    capacitance and charge.  The approximation is necessary because the
     688                 :            :    Meyer model is a capacitance model and not a charge model. */
     689                 :          0 : nr_double_t mosfet::transientChargeTR (int qstate, nr_double_t& cap,
     690                 :            :                                        nr_double_t voltage, nr_double_t ccap) {
     691                 :          0 :   int vstate = qstate + 2, cstate = qstate + 3;
     692                 :          0 :   setState (cstate, cap);
     693                 :          0 :   cap = (cap + getState (cstate, 1)) / 2 + ccap;
     694                 :          0 :   setState (vstate, voltage);
     695                 :          0 :   return cap * (voltage - getState (vstate, 1)) + getState (qstate, 1);
     696                 :            : }
     697                 :            : 
     698                 :            : /* The function uses Simpson's numerical integration rule to compute
     699                 :            :    the current capacitance and charge. */
     700                 :     250488 : nr_double_t mosfet::transientChargeSR (int qstate, nr_double_t& cap,
     701                 :            :                                        nr_double_t voltage, nr_double_t ccap) {
     702                 :     250488 :   int vstate = qstate + 2, cstate = qstate + 3;
     703                 :     250488 :   setState (cstate, cap);
     704                 :     250488 :   cap = (cap + 4 * getState (cstate, 1) + getState (cstate, 2)) / 6 + ccap;
     705                 :     250488 :   setState (vstate, voltage);
     706                 :     250488 :   return cap * (voltage - getState (vstate, 1)) + getState (qstate, 1);
     707                 :            : }
     708                 :            : 
     709                 :            : // properties
     710                 :            : PROP_REQ [] = {
     711                 :            :   { "Is", PROP_REAL, { 1e-14, PROP_NO_STR }, PROP_POS_RANGE },
     712                 :            :   { "N", PROP_REAL, { 1, PROP_NO_STR }, PROP_RNGII (0.1, 100) },
     713                 :            :   { "Vt0", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
     714                 :            :   { "Lambda", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     715                 :            :   { "Kp", PROP_REAL, { 2e-5, PROP_NO_STR }, PROP_POS_RANGE },
     716                 :            :   { "Gamma", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     717                 :            :   { "Phi", PROP_REAL, { 0.6, PROP_NO_STR }, PROP_POS_RANGE },
     718                 :            :   PROP_NO_PROP };
     719                 :            : PROP_OPT [] = {
     720                 :            :   { "Rd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     721                 :            :   { "Rs", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     722                 :            :   { "Rg", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     723                 :            :   { "L", PROP_REAL, { 100e-6, PROP_NO_STR }, PROP_RNG_X01I },
     724                 :            :   { "Ld", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     725                 :            :   { "W", PROP_REAL, { 100e-6, PROP_NO_STR }, PROP_POS_RANGEX },
     726                 :            :   { "Tox", PROP_REAL, { 1e-7, PROP_NO_STR }, PROP_RNG_X01I },
     727                 :            :   { "Cgso", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     728                 :            :   { "Cgdo", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     729                 :            :   { "Cgbo", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     730                 :            :   { "Cbd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     731                 :            :   { "Cbs", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     732                 :            :   { "Pb", PROP_REAL, { 0.8, PROP_NO_STR }, PROP_RNGXI (0, 10) },
     733                 :            :   { "Mj", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGII (0, 1) },
     734                 :            :   { "Fc", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGIX (0, 1) },
     735                 :            :   { "Cjsw", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     736                 :            :   { "Mjsw", PROP_REAL, { 0.33, PROP_NO_STR }, PROP_RNGII (0, 1) },
     737                 :            :   { "Tt", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     738                 :            :   { "Kf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     739                 :            :   { "Af", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
     740                 :            :   { "Ffe", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
     741                 :            :   { "Nsub", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     742                 :            :   { "Nss", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     743                 :            :   { "Tpg", PROP_INT, { 1, PROP_NO_STR }, PROP_RNGII (-1 , 1) },
     744                 :            :   { "Uo", PROP_REAL, { 600, PROP_NO_STR }, PROP_POS_RANGE },
     745                 :            :   { "Rsh", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     746                 :            :   { "Nrd", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
     747                 :            :   { "Nrs", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
     748                 :            :   { "Cj", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     749                 :            :   { "Js", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     750                 :            :   { "Ad", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     751                 :            :   { "As", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     752                 :            :   { "Pd", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     753                 :            :   { "Ps", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     754                 :            :   { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
     755                 :            :   { "Tnom", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
     756                 :            :   { "Type", PROP_STR, { PROP_NO_VAL, "nfet" }, PROP_RNG_FET },
     757                 :            :   { "capModel", PROP_INT, { 2, PROP_NO_STR }, PROP_RNGII (1 , 2) },
     758                 :            :   PROP_NO_PROP };
     759                 :            : struct define_t mosfet::cirdef =
     760                 :            :   { "MOSFET", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR, PROP_DEF };

Generated by: LCOV version 1.11