LCOV - code coverage report
Current view: top level - src/components/devices - bjt.cpp (source / functions) Hit Total Coverage
Test: qucs-core-0.0.19 Code Coverage Lines: 388 435 89.2 %
Date: 2015-01-05 16:01:02 Functions: 17 21 81.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 173 338 51.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * bjt.cpp - bipolar junction transistor 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 "bjt.h"
      32                 :            : 
      33                 :            : #define NEWSGP 0
      34                 :            : 
      35                 :            : #define NODE_B 0 /* base node       */
      36                 :            : #define NODE_C 1 /* collector node  */
      37                 :            : #define NODE_E 2 /* emitter node    */
      38                 :            : #define NODE_S 3 /* substrate node  */
      39                 :            : 
      40                 :            : using namespace qucs;
      41                 :            : using namespace qucs::device;
      42                 :            : 
      43                 :         51 : bjt::bjt () : circuit (4) {
      44                 :         51 :   cbcx = rb = re = rc = NULL;
      45                 :         51 :   type = CIR_BJT;
      46                 :         51 : }
      47                 :            : 
      48                 :        400 : void bjt::calcSP (nr_double_t frequency) {
      49                 :            :   // build admittance matrix and convert it to S-parameter matrix
      50 [ +  - ][ +  - ]:        400 :   setMatrixS (ytos (calcMatrixY (frequency)));
         [ +  - ][ +  - ]
                 [ +  - ]
      51                 :        400 : }
      52                 :            : 
      53                 :       1400 : matrix bjt::calcMatrixY (nr_double_t frequency) {
      54                 :            : 
      55                 :            :   // fetch computed operating points
      56         [ +  - ]:       1400 :   nr_double_t Cbe  = getOperatingPoint ("Cbe");
      57         [ +  - ]:       1400 :   nr_double_t gbe  = getOperatingPoint ("gpi");
      58         [ +  - ]:       1400 :   nr_double_t Cbci = getOperatingPoint ("Cbci");
      59         [ +  - ]:       1400 :   nr_double_t gbc  = getOperatingPoint ("gmu");
      60         [ +  - ]:       1400 :   nr_double_t Ccs  = getOperatingPoint ("Ccs");
      61                 :            : #if NEWSGP
      62                 :            :   nr_double_t gm   = getOperatingPoint ("gmf");
      63                 :            :   nr_double_t gmr  = getOperatingPoint ("gmr");
      64                 :            : #else
      65         [ +  - ]:       1400 :   nr_double_t gm   = getOperatingPoint ("gm");
      66         [ +  - ]:       1400 :   nr_double_t go   = getOperatingPoint ("go");
      67                 :            : #endif
      68         [ +  - ]:       1400 :   nr_double_t Ptf  = getPropertyDouble ("Ptf");
      69         [ +  - ]:       1400 :   nr_double_t Tf   = getPropertyDouble ("Tf");
      70                 :            : 
      71                 :            :   // compute admittance matrix entries
      72                 :       1400 :   nr_complex_t Ybe = nr_complex_t (gbe, 2.0 * M_PI * frequency * Cbe);
      73                 :       1400 :   nr_complex_t Ybc = nr_complex_t (gbc, 2.0 * M_PI * frequency * Cbci);
      74                 :       1400 :   nr_complex_t Ycs = nr_complex_t (0.0, 2.0 * M_PI * frequency * Ccs);
      75                 :            : 
      76                 :            :   // admittance matrix entries for "transcapacitance"
      77                 :       1400 :   nr_complex_t Ybebc = nr_complex_t (0.0, 2.0 * M_PI * frequency * dQbedUbc);
      78                 :            : 
      79                 :            :   // compute influence of excess phase
      80                 :       1400 :   nr_double_t phase = rad (Ptf) * Tf * 2 * M_PI * frequency;
      81                 :            : #if NEWSGP
      82                 :            :   nr_complex_t gmf = qucs::polar (gm, -phase);
      83                 :            : #else
      84         [ +  - ]:       1400 :   nr_complex_t gmf = qucs::polar (gm + go, -phase) - go;
      85                 :            : #endif
      86                 :            : 
      87                 :            :   // build admittance matrix
      88         [ +  - ]:       1400 :   matrix y (4);
      89                 :            : #if NEWSGP
      90                 :            :   // for some reason this small signal equivalent can't be used
      91                 :            :   y.set (NODE_B, NODE_B, Ybc + Ybe + Ybebc);
      92                 :            :   y.set (NODE_B, NODE_C, -Ybc - Ybebc);
      93                 :            :   y.set (NODE_B, NODE_E, -Ybe);
      94                 :            :   y.set (NODE_B, NODE_S, 0);
      95                 :            :   y.set (NODE_C, NODE_B, -Ybc + gmf + gmr);
      96                 :            :   y.set (NODE_C, NODE_C, Ybc - gmr + Ycs);
      97                 :            :   y.set (NODE_C, NODE_E, -gmf);
      98                 :            :   y.set (NODE_C, NODE_S, -Ycs);
      99                 :            :   y.set (NODE_E, NODE_B, -Ybe - gmf - gmr - Ybebc);
     100                 :            :   y.set (NODE_E, NODE_C, gmr + Ybebc);
     101                 :            :   y.set (NODE_E, NODE_E, Ybe + gmf);
     102                 :            :   y.set (NODE_E, NODE_S, 0);
     103                 :            :   y.set (NODE_S, NODE_B, 0);
     104                 :            :   y.set (NODE_S, NODE_C, -Ycs);
     105                 :            :   y.set (NODE_S, NODE_E, 0);
     106                 :            :   y.set (NODE_S, NODE_S, Ycs);
     107                 :            : #else /* !NEWSGP */
     108 [ +  - ][ +  - ]:       1400 :   y.set (NODE_B, NODE_B, Ybc + Ybe + Ybebc);
                 [ +  - ]
     109 [ +  - ][ +  - ]:       1400 :   y.set (NODE_B, NODE_C, -Ybc - Ybebc);
     110         [ +  - ]:       1400 :   y.set (NODE_B, NODE_E, -Ybe);
     111         [ +  - ]:       1400 :   y.set (NODE_B, NODE_S, 0);
     112 [ +  - ][ +  - ]:       1400 :   y.set (NODE_C, NODE_B, -Ybc + gmf);
     113 [ +  - ][ +  - ]:       1400 :   y.set (NODE_C, NODE_C, Ybc + Ycs + go);
     114         [ +  - ]:       1400 :   y.set (NODE_C, NODE_E, -gmf - go);
     115         [ +  - ]:       1400 :   y.set (NODE_C, NODE_S, -Ycs);
     116 [ +  - ][ +  - ]:       1400 :   y.set (NODE_E, NODE_B, -Ybe - gmf - Ybebc);
                 [ +  - ]
     117         [ +  - ]:       1400 :   y.set (NODE_E, NODE_C, -go + Ybebc);
     118 [ +  - ][ +  - ]:       1400 :   y.set (NODE_E, NODE_E, Ybe + gmf + go);
     119         [ +  - ]:       1400 :   y.set (NODE_E, NODE_S, 0);
     120         [ +  - ]:       1400 :   y.set (NODE_S, NODE_B, 0);
     121         [ +  - ]:       1400 :   y.set (NODE_S, NODE_C, -Ycs);
     122         [ +  - ]:       1400 :   y.set (NODE_S, NODE_E, 0);
     123         [ +  - ]:       1400 :   y.set (NODE_S, NODE_S, Ycs);
     124                 :            : #endif /* !NEWSGP */
     125                 :       1400 :   return y;
     126                 :            : }
     127                 :            : 
     128                 :          0 : void bjt::calcNoiseSP (nr_double_t frequency) {
     129 [ #  # ][ #  # ]:          0 :   setMatrixN (cytocs (calcMatrixCy (frequency) * z0, getMatrixS ()));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     130                 :          0 : }
     131                 :            : 
     132                 :          0 : matrix bjt::calcMatrixCy (nr_double_t frequency) {
     133                 :            : 
     134                 :            :   // fetch computed operating points
     135                 :          0 :   nr_double_t Ibe = fabs (getOperatingPoint ("Ibe"));
     136                 :          0 :   nr_double_t Ice = fabs (getOperatingPoint ("Ice"));
     137                 :            : 
     138                 :            :   // get model properties
     139                 :          0 :   nr_double_t Kf  = getPropertyDouble ("Kf");
     140                 :          0 :   nr_double_t Af  = getPropertyDouble ("Af");
     141                 :          0 :   nr_double_t Ffe = getPropertyDouble ("Ffe");
     142                 :          0 :   nr_double_t Kb  = getPropertyDouble ("Kb");
     143                 :          0 :   nr_double_t Ab  = getPropertyDouble ("Ab");
     144                 :          0 :   nr_double_t Fb  = getPropertyDouble ("Fb");
     145                 :            : 
     146                 :            :   nr_double_t ib = 2 * Ibe * QoverkB / T0 +            // shot noise
     147                 :          0 :     (Kf * qucs::pow (Ibe, Af) / qucs::pow (frequency, Ffe) +       // flicker noise
     148                 :          0 :      Kb * qucs::pow (Ibe, Ab) / (1 + sqr (frequency / Fb)))  // burst noise
     149                 :          0 :     / kB / T0;
     150                 :          0 :   nr_double_t ic = 2 * Ice * QoverkB / T0;             // shot noise
     151                 :            : 
     152                 :            :   /* build noise current correlation matrix and convert it to
     153                 :            :      noise-wave correlation matrix */
     154                 :          0 :   matrix cy = matrix (4);
     155         [ #  # ]:          0 :   cy.set (NODE_B, NODE_B, ib);
     156         [ #  # ]:          0 :   cy.set (NODE_B, NODE_E, -ib);
     157         [ #  # ]:          0 :   cy.set (NODE_C, NODE_C, ic);
     158         [ #  # ]:          0 :   cy.set (NODE_C, NODE_E, -ic);
     159         [ #  # ]:          0 :   cy.set (NODE_E, NODE_B, -ib);
     160         [ #  # ]:          0 :   cy.set (NODE_E, NODE_C, -ic);
     161         [ #  # ]:          0 :   cy.set (NODE_E, NODE_E, ic + ib);
     162                 :          0 :   return cy;
     163                 :            : }
     164                 :            : 
     165                 :       6480 : void bjt::initModel (void) {
     166                 :            :   // fetch necessary device properties
     167                 :       6480 :   nr_double_t T  = getPropertyDouble ("Temp");
     168                 :       6480 :   nr_double_t Tn = getPropertyDouble ("Tnom");
     169                 :       6480 :   nr_double_t A  = getPropertyDouble ("Area");
     170                 :            : 
     171                 :            :   // compute Is temperature and area dependency
     172                 :       6480 :   nr_double_t Is  = getPropertyDouble ("Is");
     173                 :       6480 :   nr_double_t Xti = getPropertyDouble ("Xti");
     174                 :       6480 :   nr_double_t Eg  = getPropertyDouble ("Eg");
     175                 :            :   nr_double_t T1, T2, IsT;
     176                 :       6480 :   T2 = kelvin (T);
     177                 :       6480 :   T1 = kelvin (Tn);
     178                 :       6480 :   IsT = pnCurrent_T (T1, T2, Is, Eg, 1, Xti);
     179                 :       6480 :   setScaledProperty ("Is", IsT * A);
     180                 :            : 
     181                 :            :   // compute Vje, Vjc and Vjs temperature dependencies
     182                 :       6480 :   nr_double_t Vje = getPropertyDouble ("Vje");
     183                 :       6480 :   nr_double_t Vjc = getPropertyDouble ("Vjc");
     184                 :       6480 :   nr_double_t Vjs = getPropertyDouble ("Vjs");
     185                 :            :   nr_double_t VjeT, VjcT, VjsT;
     186                 :       6480 :   VjeT = pnPotential_T (T1,T2, Vje);
     187                 :       6480 :   VjcT = pnPotential_T (T1,T2, Vjc);
     188                 :       6480 :   VjsT = pnPotential_T (T1,T2, Vjs);
     189                 :       6480 :   setScaledProperty ("Vje", VjeT);
     190                 :       6480 :   setScaledProperty ("Vjc", VjcT);
     191                 :       6480 :   setScaledProperty ("Vjs", VjsT);
     192                 :            : 
     193                 :            :   // compute Bf and Br temperature dependencies
     194                 :       6480 :   nr_double_t Bf  = getPropertyDouble ("Bf");
     195                 :       6480 :   nr_double_t Br  = getPropertyDouble ("Br");
     196                 :       6480 :   nr_double_t Xtb = getPropertyDouble ("Xtb");
     197                 :       6480 :   nr_double_t F = qucs::exp (Xtb * qucs::log (T2 / T1));
     198                 :       6480 :   setScaledProperty ("Bf", Bf * F);
     199                 :       6480 :   setScaledProperty ("Br", Br * F);
     200                 :            : 
     201                 :            :   // compute Ise and Isc temperature and area dependencies
     202                 :       6480 :   nr_double_t Ise = getPropertyDouble ("Ise");
     203                 :       6480 :   nr_double_t Isc = getPropertyDouble ("Isc");
     204                 :       6480 :   nr_double_t Ne  = getPropertyDouble ("Ne");
     205                 :       6480 :   nr_double_t Nc  = getPropertyDouble ("Nc");
     206                 :       6480 :   nr_double_t G = qucs::log (IsT / Is);
     207                 :       6480 :   nr_double_t F1 = qucs::exp (G / Ne);
     208                 :       6480 :   nr_double_t F2 = qucs::exp (G / Nc);
     209                 :       6480 :   Ise = Ise / F * F1;
     210                 :       6480 :   Isc = Isc / F * F2;
     211                 :       6480 :   setScaledProperty ("Ise", Ise * A);
     212                 :       6480 :   setScaledProperty ("Isc", Isc * A);
     213                 :            : 
     214                 :            :   // check unphysical parameters
     215                 :       6480 :   nr_double_t Nf = getPropertyDouble ("Nf");
     216                 :       6480 :   nr_double_t Nr = getPropertyDouble ("Nr");
     217         [ -  + ]:       6480 :   if (Nf < 1.0) {
     218                 :            :     logprint (LOG_ERROR, "WARNING: Unphysical model parameter Nf = %g in "
     219                 :          0 :               "BJT `%s'\n", Nf, getName ());
     220                 :            :   }
     221         [ +  + ]:       6480 :   if (Nr < 1.0) {
     222                 :            :     logprint (LOG_ERROR, "WARNING: Unphysical model parameter Nr = %g in "
     223                 :        136 :               "BJT `%s'\n", Nr, getName ());
     224                 :            :   }
     225         [ -  + ]:       6480 :   if (Ne < 1.0) {
     226                 :            :     logprint (LOG_ERROR, "WARNING: Unphysical model parameter Ne = %g in "
     227                 :          0 :               "BJT `%s'\n", Ne, getName ());
     228                 :            :   }
     229         [ -  + ]:       6480 :   if (Nc < 1.0) {
     230                 :            :     logprint (LOG_ERROR, "WARNING: Unphysical model parameter Nc = %g in "
     231                 :          0 :               "BJT `%s'\n", Nc, getName ());
     232                 :            :   }
     233                 :            : 
     234                 :            :   /* Originally Vtf was expected to be PROP_POS_RANGE, but there are models
     235                 :            :    * which use negative values. Instead of failing, warn the user.
     236                 :            :    * \todo Provide a way to silece such warnings
     237                 :            :    */
     238                 :       6480 :   nr_double_t Vtf = getPropertyDouble ("Vtf");
     239         [ -  + ]:       6480 :   if (Vtf < 0.0) {
     240                 :            :     logprint (LOG_ERROR, "WARNING: Unphysical model parameter Vtf = %g in "
     241                 :          0 :               "BJT `%s'\n", Vtf, getName ());
     242                 :            :   }
     243                 :            : 
     244                 :            :   // compute Cje, Cjc and Cjs temperature and area dependencies
     245                 :       6480 :   nr_double_t Cje = getPropertyDouble ("Cje");
     246                 :       6480 :   nr_double_t Cjc = getPropertyDouble ("Cjc");
     247                 :       6480 :   nr_double_t Cjs = getPropertyDouble ("Cjs");
     248                 :       6480 :   nr_double_t Mje = getPropertyDouble ("Mje");
     249                 :       6480 :   nr_double_t Mjc = getPropertyDouble ("Mjc");
     250                 :       6480 :   nr_double_t Mjs = getPropertyDouble ("Mjs");
     251                 :       6480 :   Cje = pnCapacitance_T (T1, T2, Mje, VjeT / Vje, Cje);
     252                 :       6480 :   Cjc = pnCapacitance_T (T1, T2, Mjc, VjcT / Vjc, Cjc);
     253                 :       6480 :   Cjs = pnCapacitance_T (T1, T2, Mjs, VjsT / Vjs, Cjs);
     254                 :       6480 :   setScaledProperty ("Cje", Cje * A);
     255                 :       6480 :   setScaledProperty ("Cjc", Cjc * A);
     256                 :       6480 :   setScaledProperty ("Cjs", Cjs * A);
     257                 :            : 
     258                 :            :   // compute Rb, Rc, Re and Rbm area dependencies
     259                 :       6480 :   nr_double_t Rb  = getPropertyDouble ("Rb");
     260                 :       6480 :   nr_double_t Re  = getPropertyDouble ("Re");
     261                 :       6480 :   nr_double_t Rc  = getPropertyDouble ("Rc");
     262                 :       6480 :   nr_double_t Rbm = getPropertyDouble ("Rbm");
     263                 :       6480 :   setScaledProperty ("Rb", Rb / A);
     264                 :       6480 :   setScaledProperty ("Re", Re / A);
     265                 :       6480 :   setScaledProperty ("Rc", Rc / A);
     266                 :       6480 :   setScaledProperty ("Rbm", Rbm / A);
     267                 :            : 
     268                 :            :   // compute Ikf, Ikr, Irb and Itf area dependencies
     269                 :       6480 :   nr_double_t Ikf = getPropertyDouble ("Ikf");
     270                 :       6480 :   nr_double_t Ikr = getPropertyDouble ("Ikr");
     271                 :       6480 :   nr_double_t Irb = getPropertyDouble ("Irb");
     272                 :       6480 :   nr_double_t Itf = getPropertyDouble ("Itf");
     273                 :       6480 :   setScaledProperty ("Ikf", Ikf * A);
     274                 :       6480 :   setScaledProperty ("Ikr", Ikr * A);
     275                 :       6480 :   setScaledProperty ("Irb", Irb * A);
     276                 :       6480 :   setScaledProperty ("Itf", Itf * A);
     277                 :       6480 : }
     278                 :            : 
     279                 :       6480 : void bjt::initDC (void) {
     280                 :            : 
     281                 :            :   // no transient analysis
     282                 :       6480 :   doTR = false;
     283                 :            : 
     284                 :            :   // allocate MNA matrices
     285                 :       6480 :   allocMatrixMNA ();
     286                 :            : 
     287                 :            :   // initialize scalability
     288                 :       6480 :   initModel ();
     289                 :            : 
     290                 :            :   // apply polarity of BJT
     291                 :       6480 :   const char * const type = getPropertyString ("Type");
     292         [ +  + ]:       6480 :   pol = !strcmp (type, "pnp") ? -1 : 1;
     293                 :            : 
     294                 :            :   // get simulation temperature
     295                 :       6480 :   nr_double_t T = getPropertyDouble ("Temp");
     296                 :            : 
     297                 :            :   // initialize starting values
     298                 :       6480 :   restartDC ();
     299                 :            : 
     300                 :            :   // disable additional base-collector capacitance
     301         [ -  + ]:       6480 :   if (deviceEnabled (cbcx)) {
     302                 :          0 :     disableCapacitor (this, cbcx);
     303                 :            :   }
     304                 :            : 
     305                 :            :   // possibly insert series resistance at emitter
     306                 :       6480 :   nr_double_t Re = getScaledProperty ("Re");
     307         [ +  + ]:       6480 :   if (Re != 0.0) {
     308                 :            :     // create additional circuit if necessary and reassign nodes
     309                 :        542 :     re = splitResistor (this, re, "Re", "emitter", NODE_E);
     310                 :        542 :     re->setProperty ("R", Re);
     311                 :        542 :     re->setProperty ("Temp", T);
     312                 :        542 :     re->setProperty ("Controlled", getName ());
     313                 :        542 :     re->initDC ();
     314                 :            :   }
     315                 :            :   // no series resistance at emitter
     316                 :            :   else {
     317                 :       5938 :     disableResistor (this, re, NODE_E);
     318                 :            :   }
     319                 :            : 
     320                 :            :   // possibly insert series resistance at collector
     321                 :       6480 :   nr_double_t Rc = getScaledProperty ("Rc");
     322         [ +  + ]:       6480 :   if (Rc != 0.0) {
     323                 :            :     // create additional circuit if necessary and reassign nodes
     324                 :       3774 :     rc = splitResistor (this, rc, "Rc", "collector", NODE_C);
     325                 :       3774 :     rc->setProperty ("R", Rc);
     326                 :       3774 :     rc->setProperty ("Temp", T);
     327                 :       3774 :     rc->setProperty ("Controlled", getName ());
     328                 :       3774 :     rc->initDC ();
     329                 :            :   }
     330                 :            :   // no series resistance at collector
     331                 :            :   else {
     332                 :       2706 :     disableResistor (this, rc, NODE_C);
     333                 :            :   }
     334                 :            : 
     335                 :            :   // possibly insert base series resistance
     336                 :       6480 :   nr_double_t Rb  = getScaledProperty ("Rb");
     337                 :       6480 :   nr_double_t Rbm = getScaledProperty ("Rbm");
     338         [ +  + ]:       6480 :   if (Rbm <= 0.0) Rbm = Rb; // Rbm defaults to Rb if zero
     339         [ -  + ]:       6480 :   if (Rb < Rbm)   Rbm = Rb; // Rbm must be less or equal Rb
     340                 :       6480 :   setScaledProperty ("Rbm", Rbm);
     341         [ +  + ]:       6480 :   if (Rbm != 0.0) {
     342                 :            :     // create additional circuit and reassign nodes
     343                 :       3778 :     rb = splitResistor (this, rb, "Rbb", "base", NODE_B);
     344                 :       3778 :     rb->setProperty ("R", Rb);
     345                 :       3778 :     rb->setProperty ("Temp", T);
     346                 :       3778 :     rb->setProperty ("Controlled", getName ());
     347                 :       3778 :     rb->initDC ();
     348                 :            :   }
     349                 :            :   // no series resistance at base
     350                 :            :   else {
     351                 :       2702 :     disableResistor (this, rb, NODE_B);
     352                 :       2702 :     Rbb = 0.0;                 // set this operating point
     353                 :       2702 :     setProperty ("Xcjc", 1.0); // other than 1 is senseless here
     354                 :            :   }
     355                 :       6480 : }
     356                 :            : 
     357                 :       8377 : void bjt::restartDC (void) {
     358                 :            :   // apply starting values to previous iteration values
     359 [ +  - ][ +  - ]:       8377 :   UbePrev = real (getV (NODE_B) - getV (NODE_E)) * pol;
     360 [ +  - ][ +  - ]:       8377 :   UbcPrev = real (getV (NODE_B) - getV (NODE_C)) * pol;
     361                 :       8377 : }
     362                 :            : 
     363                 :            : #define cexState 6 // extra excess phase state
     364                 :            : 
     365                 :     145756 : void bjt::calcDC (void) {
     366                 :            : 
     367                 :            :   // fetch device model parameters
     368         [ +  - ]:     145756 :   nr_double_t Is   = getScaledProperty ("Is");
     369         [ +  - ]:     145756 :   nr_double_t Nf   = getPropertyDouble ("Nf");
     370         [ +  - ]:     145756 :   nr_double_t Nr   = getPropertyDouble ("Nr");
     371         [ +  - ]:     145756 :   nr_double_t Vaf  = getPropertyDouble ("Vaf");
     372         [ +  - ]:     145756 :   nr_double_t Var  = getPropertyDouble ("Var");
     373         [ +  - ]:     145756 :   nr_double_t Ikf  = getScaledProperty ("Ikf");
     374         [ +  - ]:     145756 :   nr_double_t Ikr  = getScaledProperty ("Ikr");
     375         [ +  - ]:     145756 :   nr_double_t Bf   = getScaledProperty ("Bf");
     376         [ +  - ]:     145756 :   nr_double_t Br   = getScaledProperty ("Br");
     377         [ +  - ]:     145756 :   nr_double_t Ise  = getScaledProperty ("Ise");
     378         [ +  - ]:     145756 :   nr_double_t Isc  = getScaledProperty ("Isc");
     379         [ +  - ]:     145756 :   nr_double_t Ne   = getPropertyDouble ("Ne");
     380         [ +  - ]:     145756 :   nr_double_t Nc   = getPropertyDouble ("Nc");
     381         [ +  - ]:     145756 :   nr_double_t Rb   = getScaledProperty ("Rb");
     382         [ +  - ]:     145756 :   nr_double_t Rbm  = getScaledProperty ("Rbm");
     383         [ +  - ]:     145756 :   nr_double_t Irb  = getScaledProperty ("Irb");
     384         [ +  - ]:     145756 :   nr_double_t T    = getPropertyDouble ("Temp");
     385                 :            : 
     386                 :            :   nr_double_t Ut, Q1, Q2;
     387                 :            :   nr_double_t Iben, Ibcn, Ibei, Ibci, Ibc, gbe, gbc, gtiny;
     388                 :            :   nr_double_t IeqB, IeqC, IeqE, IeqS, UbeCrit, UbcCrit;
     389                 :            :   nr_double_t gm, go;
     390                 :            : 
     391                 :            :   // interpret zero as infinity for these model parameters
     392         [ +  + ]:     145756 :   Ikf = Ikf > 0 ? 1.0 / Ikf : 0;
     393         [ +  + ]:     145756 :   Ikr = Ikr > 0 ? 1.0 / Ikr : 0;
     394         [ +  + ]:     145756 :   Vaf = Vaf > 0 ? 1.0 / Vaf : 0;
     395         [ +  + ]:     145756 :   Var = Var > 0 ? 1.0 / Var : 0;
     396                 :            : 
     397                 :     145756 :   T = kelvin (T);
     398                 :     145756 :   Ut = T * kBoverQ;
     399 [ +  - ][ +  - ]:     145756 :   Ube = real (getV (NODE_B) - getV (NODE_E)) * pol;
                 [ +  - ]
     400 [ +  - ][ +  - ]:     145756 :   Ubc = real (getV (NODE_B) - getV (NODE_C)) * pol;
                 [ +  - ]
     401                 :            : 
     402                 :            :   // critical voltage necessary for bad start values
     403         [ +  - ]:     145756 :   UbeCrit = pnCriticalVoltage (Is, Nf * Ut);
     404         [ +  - ]:     145756 :   UbcCrit = pnCriticalVoltage (Is, Nr * Ut);
     405         [ +  - ]:     145756 :   UbePrev = Ube = pnVoltage (Ube, UbePrev, Ut * Nf, UbeCrit);
     406         [ +  - ]:     145756 :   UbcPrev = Ubc = pnVoltage (Ubc, UbcPrev, Ut * Nr, UbcCrit);
     407                 :            : 
     408                 :     145756 :   Uce = Ube - Ubc;
     409                 :            : 
     410                 :            :   // base-emitter diodes
     411         [ +  + ]:     145756 :   gtiny = Ube < - 10 * Ut * Nf ? (Is + Ise) : 0;
     412                 :            : #if 0
     413                 :            :   If = pnCurrent (Ube, Is, Ut * Nf);
     414                 :            :   Ibei = If / Bf;
     415                 :            :   gif = pnConductance (Ube, Is, Ut * Nf);
     416                 :            :   gbei = gif / Bf;
     417                 :            :   Iben = pnCurrent (Ube, Ise, Ut * Ne);
     418                 :            :   gben = pnConductance (Ube, Ise, Ut * Ne);
     419                 :            :   Ibe = Ibei + Iben + gtiny * Ube;
     420                 :            :   gbe = gbei + gben + gtiny;
     421                 :            : #else
     422         [ +  - ]:     145756 :   pnJunctionBIP (Ube, Is, Ut * Nf, If, gif);
     423                 :     145756 :   Ibei = If / Bf;
     424                 :     145756 :   gbei = gif / Bf;
     425         [ +  - ]:     145756 :   pnJunctionBIP (Ube, Ise, Ut * Ne, Iben, gben);
     426                 :     145756 :   Iben += gtiny * Ube;
     427                 :     145756 :   gben += gtiny;
     428                 :     145756 :   Ibe = Ibei + Iben;
     429                 :     145756 :   gbe = gbei + gben;
     430                 :            : #endif
     431                 :            : 
     432                 :            :   // base-collector diodes
     433         [ +  + ]:     145756 :   gtiny = Ubc < - 10 * Ut * Nr ? (Is + Isc) : 0;
     434                 :            : #if 0
     435                 :            :   Ir = pnCurrent (Ubc, Is, Ut * Nr);
     436                 :            :   Ibci = Ir / Br;
     437                 :            :   gir = pnConductance (Ubc, Is, Ut * Nr);
     438                 :            :   gbci = gir / Br;
     439                 :            :   Ibcn = pnCurrent (Ubc, Isc, Ut * Nc);
     440                 :            :   gbcn = pnConductance (Ubc, Isc, Ut * Nc);
     441                 :            :   Ibc = Ibci + Ibcn + gtiny * Ubc;
     442                 :            :   gbc = gbci + gbcn + gtiny;
     443                 :            : #else
     444         [ +  - ]:     145756 :   pnJunctionBIP (Ubc, Is, Ut * Nr, Ir, gir);
     445                 :     145756 :   Ibci = Ir / Br;
     446                 :     145756 :   gbci = gir / Br;
     447         [ +  - ]:     145756 :   pnJunctionBIP (Ubc, Isc, Ut * Nc, Ibcn, gbcn);
     448                 :     145756 :   Ibcn += gtiny * Ubc;
     449                 :     145756 :   gbcn += gtiny;
     450                 :     145756 :   Ibc = Ibci + Ibcn;
     451                 :     145756 :   gbc = gbci + gbcn;
     452                 :            : #endif
     453                 :            : 
     454                 :            :   // compute base charge quantities
     455                 :     145756 :   Q1 = 1 / (1 - Ubc * Vaf - Ube * Var);
     456                 :     145756 :   Q2 = If * Ikf + Ir * Ikr;
     457                 :     145756 :   nr_double_t SArg = 1.0 + 4.0 * Q2;
     458 [ +  - ][ +  - ]:     145756 :   nr_double_t Sqrt = SArg > 0 ? qucs::sqrt (SArg) : 1;
     459                 :     145756 :   Qb = Q1 * (1 + Sqrt) / 2;
     460                 :     145756 :   dQbdUbe = Q1 * (Qb * Var + gif * Ikf / Sqrt);
     461                 :     145756 :   dQbdUbc = Q1 * (Qb * Vaf + gir * Ikr / Sqrt);
     462                 :            : 
     463                 :            :   // during transient analysis only
     464         [ +  + ]:     145756 :   if (doTR) {
     465                 :            :     // calculate excess phase influence
     466                 :      72850 :     If /= Qb;
     467         [ +  - ]:      72850 :     excessPhase (cexState, If, gif);
     468                 :      72850 :     If *= Qb;
     469                 :            :   }
     470                 :            : 
     471                 :            :   // compute transfer current
     472                 :     145756 :   It = (If - Ir) / Qb;
     473                 :            : 
     474                 :            :   // compute forward and backward transconductance
     475                 :     145756 :   gitf = (+gif - It * dQbdUbe) / Qb;
     476                 :     145756 :   gitr = (-gir - It * dQbdUbc) / Qb;
     477                 :            : 
     478                 :            :   // compute old SPICE values
     479                 :     145756 :   go = -gitr;
     480                 :     145756 :   gm = +gitf - go;
     481         [ +  - ]:     145756 :   setOperatingPoint ("gm", gm);
     482         [ +  - ]:     145756 :   setOperatingPoint ("go", go);
     483                 :            : 
     484                 :            :   // calculate current-dependent base resistance
     485         [ +  + ]:     145756 :   if (Rbm != 0.0) {
     486         [ +  + ]:      64901 :     if (Irb != 0.0) {
     487                 :            :       nr_double_t a, b, z;
     488                 :       9386 :       a = (Ibci + Ibcn + Ibei + Iben) / Irb;
     489         [ +  + ]:       9386 :       a = MAX (a, NR_TINY); // enforce positive values
     490 [ +  - ][ +  - ]:       9386 :       z = (qucs::sqrt (1 + 144 / sqr (M_PI) * a) - 1) / 24 * sqr (M_PI) / qucs::sqrt (a);
         [ +  - ][ +  - ]
     491         [ +  - ]:       9386 :       b = qucs::tan (z);
     492         [ +  - ]:       9386 :       Rbb = Rbm + 3 * (Rb - Rbm) * (b - z) / z / sqr (b);
     493                 :            :     }
     494                 :            :     else {
     495                 :      55515 :       Rbb = Rbm + (Rb - Rbm) / Qb;
     496                 :            :     }
     497         [ +  - ]:      64901 :     rb->setScaledProperty ("R", Rbb);
     498         [ +  - ]:      64901 :     rb->calcDC ();
     499                 :            :   }
     500                 :            : 
     501                 :            :   // compute autonomic current sources
     502                 :     145756 :   IeqB = Ibe - Ube * gbe;
     503                 :     145756 :   IeqC = Ibc - Ubc * gbc;
     504                 :            : #if NEWSGP
     505                 :            :   IeqE = It - Ube * gitf - Ubc * gitr;
     506                 :            : #else
     507                 :     145756 :   IeqE = It - Ube * gm - Uce * go;
     508                 :            : #endif
     509                 :     145756 :   IeqS = 0;
     510         [ +  - ]:     145756 :   setI (NODE_B, (-IeqB - IeqC) * pol);
     511         [ +  - ]:     145756 :   setI (NODE_C, (+IeqC - IeqE - IeqS) * pol);
     512         [ +  - ]:     145756 :   setI (NODE_E, (+IeqB + IeqE) * pol);
     513         [ +  - ]:     145756 :   setI (NODE_S, (+IeqS) * pol);
     514                 :            : 
     515                 :            :   // apply admittance matrix elements
     516                 :            : #if NEWSGP
     517                 :            :   setY (NODE_B, NODE_B, gbc + gbe);
     518                 :            :   setY (NODE_B, NODE_C, -gbc);
     519                 :            :   setY (NODE_B, NODE_E, -gbe);
     520                 :            :   setY (NODE_B, NODE_S, 0);
     521                 :            :   setY (NODE_C, NODE_B, -gbc + gitf + gitr);
     522                 :            :   setY (NODE_C, NODE_C, gbc - gitr);
     523                 :            :   setY (NODE_C, NODE_E, -gitf);
     524                 :            :   setY (NODE_C, NODE_S, 0);
     525                 :            :   setY (NODE_E, NODE_B, -gbe - gitf - gitr);
     526                 :            :   setY (NODE_E, NODE_C, gitr);
     527                 :            :   setY (NODE_E, NODE_E, gbe + gitf);
     528                 :            :   setY (NODE_E, NODE_S, 0);
     529                 :            :   setY (NODE_S, NODE_B, 0);
     530                 :            :   setY (NODE_S, NODE_C, 0);
     531                 :            :   setY (NODE_S, NODE_E, 0);
     532                 :            :   setY (NODE_S, NODE_S, 0);
     533                 :            : #else
     534         [ +  - ]:     145756 :   setY (NODE_B, NODE_B, gbc + gbe);
     535         [ +  - ]:     145756 :   setY (NODE_B, NODE_C, -gbc);
     536         [ +  - ]:     145756 :   setY (NODE_B, NODE_E, -gbe);
     537         [ +  - ]:     145756 :   setY (NODE_B, NODE_S, 0);
     538         [ +  - ]:     145756 :   setY (NODE_C, NODE_B, -gbc + gm);
     539         [ +  - ]:     145756 :   setY (NODE_C, NODE_C, go + gbc);
     540         [ +  - ]:     145756 :   setY (NODE_C, NODE_E, -go - gm);
     541         [ +  - ]:     145756 :   setY (NODE_C, NODE_S, 0);
     542         [ +  - ]:     145756 :   setY (NODE_E, NODE_B, -gbe - gm);
     543         [ +  - ]:     145756 :   setY (NODE_E, NODE_C, -go);
     544         [ +  - ]:     145756 :   setY (NODE_E, NODE_E, gbe + go + gm);
     545         [ +  - ]:     145756 :   setY (NODE_E, NODE_S, 0);
     546         [ +  - ]:     145756 :   setY (NODE_S, NODE_B, 0);
     547         [ +  - ]:     145756 :   setY (NODE_S, NODE_C, 0);
     548         [ +  - ]:     145756 :   setY (NODE_S, NODE_E, 0);
     549         [ +  - ]:     145756 :   setY (NODE_S, NODE_S, 0);
     550                 :            : #endif
     551                 :     145756 : }
     552                 :            : 
     553                 :      79278 : void bjt::saveOperatingPoints (void) {
     554                 :            :   nr_double_t Vbe, Vbc;
     555 [ +  - ][ +  - ]:      79278 :   Vbe = real (getV (NODE_B) - getV (NODE_E)) * pol;
     556 [ +  - ][ +  - ]:      79278 :   Vbc = real (getV (NODE_B) - getV (NODE_C)) * pol;
     557 [ +  - ][ +  - ]:      79278 :   Ucs = real (getV (NODE_S) - getV (NODE_C)) * pol;
     558                 :      79278 :   setOperatingPoint ("Vbe", Vbe);
     559                 :      79278 :   setOperatingPoint ("Vbc", Vbc);
     560                 :      79278 :   setOperatingPoint ("Vce", Vbe - Vbc);
     561                 :      79278 :   setOperatingPoint ("Vcs", Ucs);
     562         [ -  + ]:      79278 :   if (deviceEnabled (cbcx)) {
     563 [ #  # ][ #  # ]:          0 :     Ubx = real (cbcx->getV (NODE_1) - cbcx->getV (NODE_2)) * pol;
     564                 :          0 :     setOperatingPoint ("Vbx", Ubx);
     565                 :            :   }
     566                 :      79278 : }
     567                 :            : 
     568                 :      72850 : void bjt::loadOperatingPoints (void) {
     569                 :      72850 :   Ube = getOperatingPoint ("Vbe");
     570                 :      72850 :   Ubc = getOperatingPoint ("Vbc");
     571                 :      72850 :   Uce = getOperatingPoint ("Vce");
     572                 :      72850 :   Ucs = getOperatingPoint ("Vcs");
     573                 :      72850 : }
     574                 :            : 
     575                 :      72862 : void bjt::calcOperatingPoints (void) {
     576                 :            : 
     577                 :            :   // fetch device model parameters
     578                 :      72862 :   nr_double_t Cje0 = getScaledProperty ("Cje");
     579                 :      72862 :   nr_double_t Vje  = getScaledProperty ("Vje");
     580                 :      72862 :   nr_double_t Mje  = getPropertyDouble ("Mje");
     581                 :      72862 :   nr_double_t Cjc0 = getScaledProperty ("Cjc");
     582                 :      72862 :   nr_double_t Vjc  = getScaledProperty ("Vjc");
     583                 :      72862 :   nr_double_t Mjc  = getPropertyDouble ("Mjc");
     584                 :      72862 :   nr_double_t Xcjc = getPropertyDouble ("Xcjc");
     585                 :      72862 :   nr_double_t Cjs0 = getScaledProperty ("Cjs");
     586                 :      72862 :   nr_double_t Vjs  = getScaledProperty ("Vjs");
     587                 :      72862 :   nr_double_t Mjs  = getPropertyDouble ("Mjs");
     588                 :      72862 :   nr_double_t Fc   = getPropertyDouble ("Fc");
     589                 :      72862 :   nr_double_t Vtf  = getPropertyDouble ("Vtf");
     590                 :      72862 :   nr_double_t Tf   = getPropertyDouble ("Tf");
     591                 :      72862 :   nr_double_t Xtf  = getPropertyDouble ("Xtf");
     592                 :      72862 :   nr_double_t Itf  = getScaledProperty ("Itf");
     593                 :      72862 :   nr_double_t Tr   = getPropertyDouble ("Tr");
     594                 :            : 
     595                 :            :   nr_double_t Cbe, Cbci, Cbcx, Ccs;
     596                 :            : 
     597                 :            :   // interpret zero as infinity for that model parameter
     598         [ +  + ]:      72862 :   Vtf = Vtf > 0 ? 1.0 / Vtf : 0;
     599                 :            : 
     600                 :            :   // depletion capacitance of base-emitter diode
     601                 :      72862 :   Cbe = pnCapacitance (Ube, Cje0, Vje, Mje, Fc);
     602                 :      72862 :   Qbe = pnCharge (Ube, Cje0, Vje, Mje, Fc);
     603                 :            : 
     604                 :            :   // diffusion capacitance of base-emitter diode
     605         [ +  - ]:      72862 :   if (If != 0.0) {
     606                 :            :     nr_double_t e, Tff, dTffdUbe, dTffdUbc, a;
     607                 :      72862 :     a = 1 / (1 + Itf / If);
     608         [ +  - ]:      72862 :     e = 2 * qucs::exp (MIN (Ubc * Vtf, 709));
     609                 :      72862 :     Tff = Tf * (1 + Xtf * sqr (a) * e);
     610                 :      72862 :     dTffdUbe = Tf * Xtf * 2 * gif * Itf * cubic (a) / sqr (If) * e;
     611                 :      72862 :     Cbe += (If * dTffdUbe + Tff * (gif - If / Qb * dQbdUbe)) / Qb;
     612                 :      72862 :     Qbe += If * Tff / Qb;
     613                 :      72862 :     dTffdUbc = Tf * Xtf * Vtf * sqr (a) * e;
     614                 :      72862 :     dQbedUbc = If / Qb * (dTffdUbc - Tff / Qb * dQbdUbc);
     615                 :            :   }
     616                 :            : 
     617                 :            :   // depletion and diffusion capacitance of base-collector diode
     618                 :      72862 :   Cbci = pnCapacitance (Ubc, Cjc0 * Xcjc, Vjc, Mjc, Fc) + Tr * gir;
     619                 :      72862 :   Qbci = pnCharge (Ubc, Cjc0 * Xcjc, Vjc, Mjc, Fc) + Tr * Ir;
     620                 :            : 
     621                 :            :   // depletion and diffusion capacitance of external base-collector capacitor
     622                 :      72862 :   Cbcx = pnCapacitance (Ubx, Cjc0 * (1 - Xcjc), Vjc, Mjc, Fc);
     623                 :      72862 :   Qbcx = pnCharge (Ubx, Cjc0 * (1 - Xcjc), Vjc, Mjc, Fc);
     624                 :            : 
     625                 :            :   // depletion capacitance of collector-substrate diode
     626                 :      72862 :   Ccs = pnCapacitance (Ucs, Cjs0, Vjs, Mjs);
     627                 :      72862 :   Qcs = pnCharge (Ucs, Cjs0, Vjs, Mjs);
     628                 :            : 
     629                 :            :   // finally save the operating points
     630                 :      72862 :   setOperatingPoint ("Cbe", Cbe);
     631                 :      72862 :   setOperatingPoint ("Cbci", Cbci);
     632                 :      72862 :   setOperatingPoint ("Cbcx", Cbcx);
     633                 :      72862 :   setOperatingPoint ("Ccs", Ccs);
     634                 :      72862 :   setOperatingPoint ("gmf", gitf);
     635                 :      72862 :   setOperatingPoint ("gmr", gitr);
     636                 :      72862 :   setOperatingPoint ("gmu", gbci + gbcn);
     637                 :      72862 :   setOperatingPoint ("gpi", gbei + gben);
     638                 :      72862 :   setOperatingPoint ("Rbb", Rbb);
     639                 :      72862 :   setOperatingPoint ("Ibe", Ibe);
     640                 :      72862 :   setOperatingPoint ("Ice", It);
     641                 :      72862 : }
     642                 :            : 
     643                 :          2 : void bjt::initSP (void) {
     644                 :          2 :   allocMatrixS ();
     645                 :          2 :   processCbcx ();
     646         [ -  + ]:          2 :   if (deviceEnabled (cbcx)) {
     647                 :          0 :     cbcx->initSP ();
     648                 :          0 :     cbcx->initNoiseSP ();
     649                 :            :   }
     650                 :          2 : }
     651                 :            : 
     652                 :         38 : void bjt::processCbcx (void) {
     653                 :         38 :   nr_double_t Xcjc = getPropertyDouble ("Xcjc");
     654                 :         38 :   nr_double_t Rbm  = getScaledProperty ("Rbm");
     655                 :         38 :   nr_double_t Cjc0 = getScaledProperty ("Cjc");
     656                 :            : 
     657                 :            :   /* if necessary then insert external capacitance between internal
     658                 :            :      collector node and external base node */
     659 [ +  + ][ +  + ]:         38 :   if (Rbm != 0.0 && Cjc0 != 0.0 && Xcjc != 1.0) {
                 [ -  + ]
     660         [ #  # ]:          0 :     if (!deviceEnabled (cbcx)) {
     661                 :            :       cbcx = splitCapacitor (this, cbcx, "Cbcx", rb->getNode (NODE_1),
     662                 :          0 :                              getNode (NODE_C));
     663                 :            :     }
     664                 :          0 :     cbcx->setProperty ("C", getOperatingPoint ("Cbcx"));
     665                 :            :   }
     666                 :            :   else {
     667                 :         38 :     disableCapacitor (this, cbcx);
     668                 :            :   }
     669                 :         38 : }
     670                 :            : 
     671                 :         10 : void bjt::initAC (void) {
     672                 :         10 :   allocMatrixMNA ();
     673                 :         10 :   processCbcx ();
     674         [ -  + ]:         10 :   if (deviceEnabled (cbcx)) {
     675                 :          0 :     cbcx->initAC ();
     676                 :          0 :     cbcx->initNoiseAC ();
     677                 :            :   }
     678                 :         10 : }
     679                 :            : 
     680                 :       1000 : void bjt::calcAC (nr_double_t frequency) {
     681         [ +  - ]:       1000 :   setMatrixY (calcMatrixY (frequency));
     682                 :       1000 : }
     683                 :            : 
     684                 :          0 : void bjt::calcNoiseAC (nr_double_t frequency) {
     685         [ #  # ]:          0 :   setMatrixN (calcMatrixCy (frequency));
     686                 :          0 : }
     687                 :            : 
     688                 :            : #define qbeState 0 // base-emitter charge state
     689                 :            : #define cbeState 1 // base-emitter current state
     690                 :            : #define qbcState 2 // base-collector charge state
     691                 :            : #define cbcState 3 // base-collector current state
     692                 :            : #define qcsState 4 // collector-substrate charge state
     693                 :            : #define ccsState 5 // collector-substrate current state
     694                 :            : 
     695                 :            : #define qbxState 0 // external base-collector charge state
     696                 :            : #define cbxState 1 // external base-collector current state
     697                 :            : 
     698                 :         26 : void bjt::initTR (void) {
     699                 :         26 :   setStates (7);
     700                 :         26 :   initDC ();
     701                 :         26 :   doTR = true;
     702                 :            : 
     703                 :            :   // handle external base-collector capacitance appropriately
     704                 :         26 :   processCbcx ();
     705         [ -  + ]:         26 :   if (deviceEnabled (cbcx)) {
     706                 :          0 :     cbcx->initTR ();
     707                 :          0 :     cbcx->setProperty ("Controlled", getName ());
     708                 :            :   }
     709                 :         26 : }
     710                 :            : 
     711                 :      72850 : void bjt::calcTR (nr_double_t t) {
     712                 :      72850 :   calcDC ();
     713                 :      72850 :   saveOperatingPoints ();
     714                 :      72850 :   loadOperatingPoints ();
     715                 :      72850 :   calcOperatingPoints ();
     716                 :            : 
     717                 :      72850 :   nr_double_t Cbe  = getOperatingPoint ("Cbe");
     718                 :      72850 :   nr_double_t Ccs  = getOperatingPoint ("Ccs");
     719                 :      72850 :   nr_double_t Cbci = getOperatingPoint ("Cbci");
     720                 :      72850 :   nr_double_t Cbcx = getOperatingPoint ("Cbcx");
     721                 :            : 
     722                 :            :   // handle Rbb and Cbcx appropriately
     723         [ +  + ]:      72850 :   if (Rbb != 0.0) {
     724                 :      35628 :     rb->setScaledProperty ("R", Rbb);
     725                 :      35628 :     rb->calcTR (t);
     726         [ -  + ]:      35628 :     if (deviceEnabled (cbcx)) {
     727                 :          0 :       cbcx->clearI ();
     728                 :          0 :       cbcx->clearY ();
     729                 :          0 :       cbcx->transientCapacitance (qbxState, NODE_1, NODE_2, Cbcx, Ubx, Qbcx);
     730                 :            :     }
     731                 :            :   }
     732                 :            : 
     733                 :            :   // usual capacitances
     734                 :      72850 :   transientCapacitance (qbeState, NODE_B, NODE_E, Cbe, Ube, Qbe);
     735                 :      72850 :   transientCapacitance (qbcState, NODE_B, NODE_C, Cbci, Ubc, Qbci);
     736                 :      72850 :   transientCapacitance (qcsState, NODE_S, NODE_C, Ccs, Ucs, Qcs);
     737                 :            : 
     738                 :            :   // trans-capacitances
     739                 :      72850 :   transientCapacitanceC (NODE_B, NODE_E, NODE_B, NODE_C, dQbedUbc, Ubc);
     740                 :      72850 : }
     741                 :            : 
     742                 :      72850 : void bjt::excessPhase (int istate, nr_double_t& i, nr_double_t& g) {
     743                 :            : 
     744                 :            :   // fetch device properties
     745                 :      72850 :   nr_double_t Ptf = getPropertyDouble ("Ptf");
     746                 :      72850 :   nr_double_t Tf = getPropertyDouble ("Tf");
     747                 :      72850 :   nr_double_t td = rad (Ptf) * Tf;
     748                 :            : 
     749                 :            :   // return if nothing todo
     750         [ +  + ]:      79834 :   if (td == 0.0) return;
     751                 :            : 
     752                 :            :   // fill-in current history during initialization
     753         [ +  + ]:       6984 :   if (getMode () & MODE_INIT) fillState (istate, i);
     754                 :            : 
     755                 :            :   // calculate current coefficients C1, C2 and C3
     756                 :       6984 :   nr_double_t * delta = getDelta ();
     757                 :            :   nr_double_t c3, c2, c1, dn, ra;
     758                 :       6984 :   c1 = delta[0] / td;
     759                 :       6984 :   c2 = 3 * c1;
     760                 :       6984 :   c1 = c2 * c1;
     761                 :       6984 :   dn = 1 + c1 + c2;
     762                 :       6984 :   c1 = c1 / dn;
     763                 :       6984 :   ra = delta[0] / delta[1];
     764                 :       6984 :   c2 = (1 + ra + c2) / dn;
     765                 :       6984 :   c3 = ra / dn;
     766                 :            : 
     767                 :            :   // update and save current, update transconductance
     768                 :       6984 :   i = i * c1 + getState (istate, 1) * c2 - getState (istate, 2) * c3;
     769                 :       6984 :   setState (istate, i);
     770                 :       6984 :   g = g * c1;
     771                 :            : }
     772                 :            : 
     773                 :            : // properties
     774                 :            : PROP_REQ [] = {
     775                 :            :   { "Is", PROP_REAL, { 1e-16, PROP_NO_STR }, PROP_POS_RANGE },
     776                 :            :   { "Nf", PROP_REAL, { 1, PROP_NO_STR }, PROP_RNGII (0.1, 100) },
     777                 :            :   { "Nr", PROP_REAL, { 1, PROP_NO_STR }, PROP_RNGII (0.1, 100) },
     778                 :            :   { "Ikf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     779                 :            :   { "Ikr", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     780                 :            :   { "Vaf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     781                 :            :   { "Var", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     782                 :            :   { "Ise", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     783                 :            :   { "Ne", PROP_REAL, { 1.5, PROP_NO_STR }, PROP_RNGII (0.1, 100) },
     784                 :            :   { "Isc", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     785                 :            :   { "Nc", PROP_REAL, { 2, PROP_NO_STR }, PROP_RNGII (0.1, 100) },
     786                 :            :   { "Bf", PROP_REAL, { 100, PROP_NO_STR }, PROP_POS_RANGEX },
     787                 :            :   { "Br", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGEX },
     788                 :            :   { "Rbm", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     789                 :            :   { "Irb", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     790                 :            :   { "Cje", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     791                 :            :   { "Vje", PROP_REAL, { 0.75, PROP_NO_STR }, PROP_RNGXI (0, 10) },
     792                 :            :   { "Mje", PROP_REAL, { 0.33, PROP_NO_STR }, PROP_RNGII (0, 1) },
     793                 :            :   { "Cjc", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     794                 :            :   { "Vjc", PROP_REAL, { 0.75, PROP_NO_STR }, PROP_RNGXI (0, 10) },
     795                 :            :   { "Mjc", PROP_REAL, { 0.33, PROP_NO_STR }, PROP_RNGII (0, 1) },
     796                 :            :   { "Xcjc", PROP_REAL, { 1, PROP_NO_STR }, PROP_RNGII (0, 1) },
     797                 :            :   { "Cjs", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     798                 :            :   { "Vjs", PROP_REAL, { 0.75, PROP_NO_STR }, PROP_RNGXI (0, 10) },
     799                 :            :   { "Mjs", PROP_REAL, { 0, PROP_NO_STR }, PROP_RNGII (0, 1) },
     800                 :            :   { "Fc", PROP_REAL, { 0.5, PROP_NO_STR }, PROP_RNGII (0, 1) },
     801                 :            :   { "Vtf", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
     802                 :            :   { "Tf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     803                 :            :   { "Xtf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     804                 :            :   { "Itf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     805                 :            :   { "Tr", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     806                 :            :   PROP_NO_PROP };
     807                 :            : PROP_OPT [] = {
     808                 :            :   { "Rc", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     809                 :            :   { "Re", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     810                 :            :   { "Rb", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     811                 :            :   { "Kf", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     812                 :            :   { "Af", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
     813                 :            :   { "Ffe", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
     814                 :            :   { "Kb", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
     815                 :            :   { "Ab", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
     816                 :            :   { "Fb", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGE },
     817                 :            :   { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
     818                 :            :   { "Type", PROP_STR, { PROP_NO_VAL, "npn" }, PROP_RNG_BJT },
     819                 :            :   { "Ptf", PROP_REAL, { 0, PROP_NO_STR }, PROP_RNGII (-180, +180) },
     820                 :            :   { "Xtb", PROP_REAL, { 0, PROP_NO_STR }, PROP_NO_RANGE },
     821                 :            :   { "Xti", PROP_REAL, { 3, PROP_NO_STR }, PROP_POS_RANGE },
     822                 :            :   { "Eg", PROP_REAL, { EgSi, PROP_NO_STR }, PROP_POS_RANGE },
     823                 :            :   { "Tnom", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
     824                 :            :   { "Area", PROP_REAL, { 1, PROP_NO_STR }, PROP_POS_RANGEX },
     825                 :            :   PROP_NO_PROP };
     826                 :            : struct define_t bjt::cirdef =
     827                 :            :   { "BJT", 4, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_NONLINEAR, PROP_DEF };

Generated by: LCOV version 1.11