Logo Search packages:      
Sourcecode: gnucap version File versions  Download package

d_bjt.cc

/* $Id: d_bjt.model,v 24.23 2004/02/01 21:12:55 al Exp $ -*- C++ -*-
 * Copyright (C) 2002 Albert Davis
 * Author: Albert Davis <aldavis@ieee.org>
 *
 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *------------------------------------------------------------------
 * Berkeley BJT model
 * Derived from Spice code, both from 2g6 and 3f4
 * Recoded for Gnucap model compiler, Al Davis, 2002
 *------------------------------------------------------------------
 * data structures and defaults for bjt model.
 *
 * netlist syntax:
 * device:  qxxxx c b e s mname <device args>
 * model:   .model mname NPN <args>
 *    or  .model mname PNP <args>
 *
 * known BUGs
 * 1. excess phase partially implemented, disabled, as if PTF == 0.
 */
/* This file is automatically generated. DO NOT EDIT */

#include "d_admit.h"
#include "d_cap.h"
#include "d_res.h"
#include "ap.h"
#include "d_bjt.h"
/*--------------------------------------------------------------------------*/
const double NA(NOT_INPUT);
const double INF(BIGBIG);
/*--------------------------------------------------------------------------*/
int MODEL_BJT::_count = 0;
/*--------------------------------------------------------------------------*/
SDP_BJT::SDP_BJT(const COMMON_COMPONENT* cc)
  :SDP_DIODE(cc)
{
}
/*--------------------------------------------------------------------------*/
TDP_BJT::TDP_BJT(const DEV_BJT* d)
{
  assert(d);
  const COMMON_BJT* c = prechecked_cast<const COMMON_BJT*>(d->common());
  assert(c);
  const SDP_BJT* s = prechecked_cast<const SDP_BJT*>(c->sdp());
  assert(s);
  const MODEL_BJT* m = prechecked_cast<const MODEL_BJT*>(c->model());
  assert(m);

      const double reftemp = 300.15;
      double temp = (c->temp != NA) ? c->temp : SIM::temp;
      double fact1 = m->_tnom / reftemp;
      double fact2 = temp / reftemp;
      double tempratio  = temp / m->_tnom; // fact2/fact1
      double kt = temp * K;
      vt = kt / Q;
      double egap = 1.16 - (7.02e-4*temp*temp) / (temp+1108.); // egfet
      // double arg = (m->eg*tempratio - egap) / (2*kt);
      double arg = -egap/(2 * kt) + 1.1150877 / (K * (reftemp+reftemp));
      double pbfact = -2 * vt * (1.5 * log(fact2) + Q * arg);
      double ratlog = log(tempratio);
      double ratio1 = tempratio - 1;
      double factlog = ratio1 * m->eg / vt + m->xti * ratlog;
      double factor = exp(factlog);
      double bfactor = exp(ratlog * m->xtb);

  ibc = m->ibc * factor;
  ibe = m->ibe * factor;
  BetaF = m->bf * bfactor;
  BetaR = m->br * bfactor;
  BEleakCur = m->ise * exp(factlog/m->ne) / bfactor;
  BCleakCur = m->isc * exp(factlog/m->nc) / bfactor;
  Vcrit = vt * log(vt / (kRT2 * m->ibe));

      {
      double pbo = (m->vje - pbfact) / fact1;
      BEpot = fact2 * pbo + pbfact;
      double gmaold = (m->vje - pbo) / pbo;
      double gmanew = (BEpot - pbo) / pbo;
      BEcap = (m->cje / (1 + m->mje * (4e-4*(m->_tnom-reftemp)-gmaold)))
        * (1 + m->mje * (4e-4*(temp-reftemp)-gmanew));
      DepCap = m->fc * BEpot;
      f1 = BEpot * (1 - exp((1 - m->mje) * m->xfc)) / (1 - m->mje);
      }
      {
      double pbo = (m->vjc - pbfact) / fact1;
      BCpot = fact2 * pbo + pbfact;
      double gmaold = (m->vjc - pbo) / pbo;
      double gmanew = (BCpot - pbo) / pbo;
      BCcap = (m->cjc / (1 + m->mjc * (4e-4*(m->_tnom-reftemp)-gmaold)))
        * (1 + m->mjc * (4e-4*(temp-reftemp)-gmanew));
      f4 = m->fc * BCpot;
      f5 = BCpot * (1 - exp((1 - m->mjc) * m->xfc)) / (1 - m->mjc);
      }
}
/*--------------------------------------------------------------------------*/
MODEL_BJT::MODEL_BJT()
  :MODEL_DIODE(),
   bf(100),
   br(1),
   ibc(NA),
   ibe(NA),
   is(NA),
   nf(1),
   nr(1),
   vaf(NA),
   var(NA),
   isc(NA),
   c4(0),
   nc(2),
   ise(NA),
   c2(0),
   ne(1.5),
   ikf(NA),
   ikr(NA),
   irb(NA),
   rb(0),
   rbm(NA),
   re(0),
   rc(0),
   cbcp(0),
   cbep(0),
   cbsp(0),
   ccsp(0),
   cjc(0),
   cje(0),
   cjs(0),
   fc(NA),
   mjc(.33),
   mje(.33),
   mjs(0),
   vjc(.75),
   vje(.75),
   vjs(.75),
   xcjc(1),
   itf(0),
   ptf(0),
   tf(0),
   tr(0),
   vtf(NA),
   xtf(0),
   xtb(0),
   xti(3),
   eg(1.11),
   polarity(pN),
   invearlyvoltf(NA),
   invearlyvoltr(NA),
   invrollofff(NA),
   invrolloffr(NA),
   transtimevbcfact(NA),
   excessphasefactor(NA),
   xfc(NA),
   f2(NA),
   f3(NA),
   f6(NA),
   f7(NA)
{
  ++_count;
  kf = 0;
  af = 1;
}
/*--------------------------------------------------------------------------*/
bool MODEL_BJT::parse_front(CS& cmd)
{
  return ONE_OF
    || set(cmd, "NPN", &polarity, pN)
    || set(cmd, "PNP", &polarity, pP)
    ;
}
/*--------------------------------------------------------------------------*/
bool MODEL_BJT::parse_params(CS& cmd)
{
  return ONE_OF
    || get(cmd, "KF", &kf)
    || get(cmd, "AF", &af)
    || get(cmd, "BF", &bf)
    || get(cmd, "BFM", &bf)
    || get(cmd, "BR", &br)
    || get(cmd, "BRM", &br)
    || get(cmd, "IBC", &ibc)
    || get(cmd, "IBE", &ibe)
    || get(cmd, "IS", &is)
    || get(cmd, "NF", &nf)
    || get(cmd, "NR", &nr)
    || get(cmd, "VAf", &vaf)
    || get(cmd, "VBF", &vaf)
    || get(cmd, "VAR", &var)
    || get(cmd, "VB", &var)
    || get(cmd, "ISC", &isc)
    || get(cmd, "C4", &c4)
    || get(cmd, "JLC", &c4)
    || get(cmd, "NC", &nc)
    || get(cmd, "ISE", &ise)
    || get(cmd, "C2", &c2)
    || get(cmd, "JLE", &c2)
    || get(cmd, "NE", &ne)
    || get(cmd, "IKf", &ikf)
    || get(cmd, "JBF", &ikf)
    || get(cmd, "IKR", &ikr)
    || get(cmd, "JBR", &ikr)
    || get(cmd, "IRB", &irb)
    || get(cmd, "JRB", &irb)
    || get(cmd, "RB", &rb)
    || get(cmd, "RBM", &rbm)
    || get(cmd, "RE", &re)
    || get(cmd, "RC", &rc)
    || get(cmd, "CBCP", &cbcp)
    || get(cmd, "CBEP", &cbep)
    || get(cmd, "CBSP", &cbsp)
    || get(cmd, "CCSP", &ccsp)
    || get(cmd, "CJC", &cjc)
    || get(cmd, "CJE", &cje)
    || get(cmd, "CJS", &cjs)
    || get(cmd, "CCS", &cjs)
    || get(cmd, "FC", &fc)
    || get(cmd, "MJc", &mjc)
    || get(cmd, "MC", &mjc)
    || get(cmd, "MJE", &mje)
    || get(cmd, "ME", &mje)
    || get(cmd, "MJS", &mjs)
    || get(cmd, "MSub", &mjs)
    || get(cmd, "VJC", &vjc)
    || get(cmd, "PC", &vjc)
    || get(cmd, "VJE", &vje)
    || get(cmd, "PE", &vje)
    || get(cmd, "VJS", &vjs)
    || get(cmd, "PSub", &vjs)
    || get(cmd, "XCJC", &xcjc)
    || get(cmd, "CDIS", &xcjc)
    || get(cmd, "ITF", &itf)
    || get(cmd, "JTF", &itf)
    || get(cmd, "PTf", &ptf)
    || get(cmd, "TF", &tf)
    || get(cmd, "TR", &tr)
    || get(cmd, "VTF", &vtf)
    || get(cmd, "XTF", &xtf)
    || get(cmd, "XTB", &xtb)
    || get(cmd, "TB", &xtb)
    || get(cmd, "XTI", &xti)
    || get(cmd, "EG", &eg)
    ;
}
/*--------------------------------------------------------------------------*/
void MODEL_BJT::parse_finish()
{
  if (ibc == NA) {
    ibc = ((is!=NA) ? is : 1e-16);
  }
  if (ibe == NA) {
    ibe = ((is!=NA) ? is : 1e-16);
  }
  if (is == NA) {
    is = ((ibe == ibc) ? ibe : NA);
  }
  if (isc == NA) {
    isc = (c4*is);
  }
  if (ise == NA) {
    ise = (c2*is);
  }
  if (rbm == NA) {
    rbm = rb;
  }
  if (fc == NA) {
    fc = .5;
  }
  fc = std::min(fc, .9999);
  invearlyvoltf = (vaf != NA && vaf != 0.) ? 1./vaf : 0.;
  invearlyvoltr = (var != NA && var != 0.) ? 1./var : 0.;
  invrollofff = (ikf != NA && ikf != 0.) ? 1./ikf : 0.;
  invrolloffr = (ikr != NA && ikr != 0.) ? 1./ikr : 0.;
  transtimevbcfact = (vtf != NA && vtf != 0.) ? 1./(vtf*1.44) : 0.;
  excessphasefactor = (ptf * DTOR) * tf;
  xfc = log(1 - fc);
  f2 = exp((1 + mje) * xfc);
  f3 = 1 - fc * (1 + mje);
  f6 = exp((1 + mjc) * xfc);
  f7 = 1 - fc * (1 + mjc);
}
/*--------------------------------------------------------------------------*/
SDP_CARD* MODEL_BJT::new_sdp(const COMMON_COMPONENT* c)const
{
  assert(c);
  {if (dynamic_cast<const COMMON_BJT*>(c)) {
    return new SDP_BJT(c);
  }else{
    return MODEL_DIODE::new_sdp(c);
  }}
}
/*--------------------------------------------------------------------------*/
void MODEL_BJT::print_front(OMSTREAM& o)const
{
  {if (polarity == pN) {
    o << "  npn";
  }else if (polarity == pP) {
    o << "  pnp";
  }else{
    unreachable();
  }}
}
/*--------------------------------------------------------------------------*/
void MODEL_BJT::print_params(OMSTREAM& o)const
{
  o << "  kf=" << kf;
  o << "  af=" << af;
  o << "  bf=" << bf;
  o << "  br=" << br;
  if (ibe != ibc)
    o << "  ibc=" << ibc;
  if (ibe != ibc)
    o << "  ibe=" << ibe;
  if (ibe == ibc)
    o << "  is=" << is;
  o << "  nf=" << nf;
  o << "  nr=" << nr;
  if (vaf != NA)
    o << "  vaf=" << vaf;
  if (var != NA)
    o << "  var=" << var;
  if (isc != NA)
    o << "  isc=" << isc;
  o << "  c4=" << c4;
  o << "  nc=" << nc;
  if (ise != NA)
    o << "  ise=" << ise;
  o << "  c2=" << c2;
  o << "  ne=" << ne;
  if (ikf != NA)
    o << "  ikf=" << ikf;
  if (ikr != NA)
    o << "  ikr=" << ikr;
  if (irb != NA)
    o << "  irb=" << irb;
  o << "  rb=" << rb;
  if (rbm != NA)
    o << "  rbm=" << rbm;
  o << "  re=" << re;
  o << "  rc=" << rc;
  if (cbcp!=0)
    o << "  cbcp=" << cbcp;
  if (cbep!=0)
    o << "  cbep=" << cbep;
  if (cbsp!=0)
    o << "  cbsp=" << cbsp;
  if (ccsp!=0)
    o << "  ccsp=" << ccsp;
  o << "  cjc=" << cjc;
  o << "  cje=" << cje;
  o << "  cjs=" << cjs;
  if (fc != NA)
    o << "  fc=" << fc;
  o << "  mjc=" << mjc;
  o << "  mje=" << mje;
  o << "  mjs=" << mjs;
  o << "  vjc=" << vjc;
  o << "  vje=" << vje;
  o << "  vjs=" << vjs;
  o << "  xcjc=" << xcjc;
  o << "  itf=" << itf;
  o << "  ptf=" << ptf;
  o << "  tf=" << tf;
  o << "  tr=" << tr;
  if (vtf != NA)
    o << "  vtf=" << vtf;
  o << "  xtf=" << xtf;
  o << "  xtb=" << xtb;
  o << "  xti=" << xti;
  o << "  eg=" << eg;
}
/*--------------------------------------------------------------------------*/
void MODEL_BJT::print_calculated(OMSTREAM& o)const
{
  o << "";
}
/*--------------------------------------------------------------------------*/
bool MODEL_BJT::is_valid(const COMMON_COMPONENT* cc)const
{
  return MODEL_DIODE::is_valid(cc);
}
/*--------------------------------------------------------------------------*/
void MODEL_BJT::tr_eval(COMPONENT* brh)const
{
  DEV_BJT* d = prechecked_cast<DEV_BJT*>(brh);
  assert(d);
  const COMMON_BJT* c = prechecked_cast<const COMMON_BJT*>(d->common());
  assert(c);
  const SDP_BJT* s = prechecked_cast<const SDP_BJT*>(c->sdp());
  assert(s);
  const MODEL_BJT* m = this;
  const TDP_BJT T(d);
  const TDP_BJT* t = &T;

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    trace0("--------------------------");
    trace1(d->long_label().c_str(), d->evaliter());
    trace4("", d->vbe, d->vbc, d->vbx, d->vcs);
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    double cbe, gbe;
    { // d->cpi, d->gpi, d->cpi_cpoly
      // uses: d->vbe
      double cben, gben;
      double vtn = t->vt * m->nf;
      double csat = t->ibe * c->area;
      double c2 = t->BEleakCur * c->area;
      {if (d->vbe > -5 * vtn) {
      double evbe = exp(d->vbe / vtn);
      cbe = csat * (evbe-1) + OPT::gmin * d->vbe;
      gbe = csat * evbe/vtn + OPT::gmin;
      {if (c2 == 0) {
        cben = 0;
        gben = 0;
      }else{
        double vte = m->ne * t->vt;
        double evben = exp(d->vbe / vte);
        cben = c2 * (evben-1);
        gben = c2 * evben/vte;
      }}
      trace4("vbe on", cbe, gbe, cben, gben);
      }else{
      gbe = -csat/d->vbe + OPT::gmin;
      cbe = gbe * d->vbe;
      gben = -c2 / d->vbe;
      cben = gben * d->vbe;
      trace4("vbe off", cbe, gbe, cben, gben);
      }}
      d->cpi = cbe / t->BetaF + cben;
      d->gpi = gbe / t->BetaF + gben;
      d->cpi_cpoly = d->cpi - d->vbe * d->gpi;
      trace3("", t->BetaF, d->cpi, d->gpi);
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    double cbc, gbc, cbcn;
    { // d->cmu, d->gmu, d->cmu_cpoly
      // uses: d->vbc
      double gbcn;
      double vtn = t->vt * m->nr;
      double csat = t->ibc * c->area;
      double c4 = t->BCleakCur * c->area;
      {if (d->vbc > -5 * vtn) {
      double evbc = exp(d->vbc / vtn);
      cbc = csat * (evbc-1) + OPT::gmin * d->vbc;
      gbc = csat * evbc/vtn + OPT::gmin;
      {if (c4 == 0) {
        cbcn = 0;
        gbcn = 0;
      }else{
        double vtc = m->nc * t->vt;
        double evbcn = exp(d->vbc / vtc);
        cbcn = c4 * (evbcn-1);
        gbcn = c4 * evbcn/vtc;
      }}
      trace4("vbc on", cbc, gbc, cbcn, gbcn);
      }else{
      gbc = -csat/d->vbc + OPT::gmin;
      cbc = gbc * d->vbc;
      gbcn = -c4 / d->vbc;
      cbcn = gbcn * d->vbc;
      trace4("vbc off", cbc, gbc, cbcn, gbcn);
      }}
      d->cmu = cbc / t->BetaR + cbcn;
      d->gmu = gbc / t->BetaR + gbcn;
      d->cmu_cpoly = d->cmu - d->vbc * d->gmu;
      trace3("", t->BetaR, d->cmu, d->gmu);
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //   determine base charge terms
    double qb, dqbdve, dqbdvc;
    {
      double q1 = 1 / (1 - m->invearlyvoltf*d->vbc - m->invearlyvoltr*d->vbe);
      {if(c->oik == 0 && c->oikr == 0) {
      qb = q1;
      dqbdve = q1 * qb * m->invearlyvoltr;
      dqbdvc = q1 * qb * m->invearlyvoltf;
      trace4("!oik", q1, qb, dqbdve, dqbdvc);
      }else{
      double q2 = c->oik * cbe + c->oikr * cbc;
      double arg = std::max(0., 1+4*q2);
      double sqarg = (arg == 0) ? 1 : sqrt(arg);
      qb = q1 * (1+sqarg) / 2;
      dqbdve = q1 * (qb * m->invearlyvoltr + c->oik  * gbe / sqarg);
      dqbdvc = q1 * (qb * m->invearlyvoltf + c->oikr * gbc / sqarg);
      trace2("", c->oik, c->oikr);
      trace4("oik", q1, qb, dqbdve, dqbdvc);
      }}
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // weil's approx. for excess phase applied with backward-euler integration
    {
      double cc = 0;
      double cex = cbe;
      double gex = gbe;
      if (0 && m->excessphasefactor != 0) {
      unreachable();
      incomplete(); // doesn't save old values of cexbc, so disabled
      double arg1 = d->_dt_0 / m->excessphasefactor;
      double arg2 = 3 * arg1;
      arg1 *= arg2;
      double denom = 1 + arg1 + arg2;
      double arg3 = arg1 / denom;
      if (STATUS::iter[SIM::mode] <= 1) {
        d->cexbc_2 = d->cexbc_1 = cbe / qb;
      }
      cc = (d->cexbc_1 * (1 + d->_dt_0/d->_dt_1 + arg2)
            - d->cexbc_2 * d->_dt_0/d->_dt_1) / denom;
      cex *= arg3;
      gex *= arg3;
      }
      d->cexbc_0 = cc + cex / qb;

      d->cce = cc + (cex-cbc)/qb - cbc/t->BetaR - cbcn;
      d->go = (gbc + (cex-cbc)*dqbdvc / qb) / qb;
      d->gm = (gex - (cex-cbc)*dqbdve / qb) / qb - d->go;
      d->cce_cpoly = d->cce - ((d->vbe - d->vbc) * d->go + d->vbe * d->gm);
      trace4("", d->cce, d->go, d->gm, d->cce/t->vt);
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // d->gx
    // should be moved to a private eval
    // may use d->cpi, d->cmu, qb
    {
      {if (!OPT::rstray || (m->rb == 0. && m->rbm == 0.)) {
      trace3("", m->rb, m->irb, d->gx);
      assert(d->gx == NA);
      }else{
      double rx = NA;
      double rbpr = m->rbm / c->area;
      double rbpi = m->rb / c->area - rbpr;
      {if (m->irb != 0) { // base resistance lowering at high current
        double cb = d->cpi + d->cmu;
        double xjrb = m->irb * c->area;
        double arg1 = std::max(cb/xjrb, 1e-9);
        double arg2 = (-1 + sqrt(1+14.59025*arg1)) / 2.4317 / sqrt(arg1);
        arg1 = tan(arg2);
        rx = rbpr + 3 * rbpi * (arg1-arg2) / arg2 / arg1 / arg1;
      }else{
        untested();
        rx = rbpr + rbpi / qb;
      }}
      trace3("", m->rb, m->irb, rx);
      assert(rx != NA);
      assert(rx != 0);
      d->gx = 1 / rx;
      trace1("", d->gx);
      }}
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    const bool charge_computation_needed = OPT::cstray;
    if (charge_computation_needed) {
      {if (m->tf != 0 && d->vbe > 0) {
      double argtf = NA;
      double arg2  = NA;
      double arg3  = NA;
      {if (m->xtf != 0) {
        {if (m->transtimevbcfact != 0) {
          //untested();
          argtf = m->xtf * exp(d->vbc * m->transtimevbcfact);
        }else{
          untested();
          argtf = m->xtf;
        }}
        arg2 = argtf;
        {if(m->itf != 0) {
          //untested();
          double temp = cbe / (cbe + m->itf * c->area);
          argtf *= temp*temp;
          arg2  *= (3-temp-temp);
        }else{
          //untested();
        }}
        arg3 = cbe * argtf * m->transtimevbcfact;
      }else{
        arg3 = arg2 = argtf = 0;
      }}
      assert(argtf != NA);
      assert(arg2  != NA);
      assert(arg3  != NA);
      cbe *= (1+argtf) / qb;
      gbe = (gbe * (1+arg2) - cbe * dqbdve) / qb;
      d->geqcb=m->tf*(arg3-cbe*dqbdvc)/qb;
      }else{
      d->geqcb=0;
      }}
      { // d->qbe, d->cqbe
      // uses: d->vbe, cbe, gbe
      double czbe = t->BEcap * c->area;
      {if (d->vbe < t->DepCap) {
        double arg = 1 - d->vbe / t->BEpot;
        double sarg = pow(arg, -m->mje);
        d->qbe = m->tf * cbe + t->BEpot * czbe * (1-arg*sarg) / (1 - m->mje);
        d->cqbe = m->tf * gbe + czbe * sarg;
      }else{
        double czbef2 = czbe / m->f2;
        d->qbe = m->tf * cbe + czbe * t->f1 
          + czbef2 * (m->f3 * (d->vbe - t->DepCap)
                  + (m->mje / (2. * t->BEpot))
                  * (d->vbe * d->vbe - t->DepCap * t->DepCap));
        d->cqbe = m->tf * gbe + czbef2 * (m->f3 + m->mje*d->vbe / t->BEpot);
      }}
      }
      { // d->qbc, d->cqbc
      // uses: d->vbc, cbc, gbc
      double czbc = t->BCcap * c->area * m->xcjc;
      {if (d->vbc < t->f4) {
        double arg = 1 - d->vbc / t->BCpot;
        double sarg = pow(arg, -m->mjc);
        d->qbc = m->tr *cbc + t->BCpot *czbc * (1 - arg*sarg) / (1 - m->mjc);
        d->cqbc = m->tr * gbc + czbc * sarg;
      }else{
        double czbcf2 = czbc / m->f6;
        d->qbc = m->tr * cbc + czbc * t->f5
          + czbcf2 * (m->f7 * (d->vbc-t->f4) 
            + (m->mjc/(t->BCpot+t->BCpot)) * (d->vbc*d->vbc-t->f4*t->f4));
        d->cqbc = m->tr * gbc + czbcf2 * (m->f7 + m->mjc * d->vbc/t->BCpot);
      }}
      }
      { // d->qbx, d->cqbx
      // uses: d->vbx
      double czbx = t->BCcap * c->area * (1 - m->xcjc);
      {if (d->vbx < t->f4) {
        double arg = 1 - d->vbx / t->BCpot;
        double sarg = pow(arg, -m->mjc);
        d->qbx = t->BCpot * czbx * (1 - arg*sarg) / (1 - m->mjc);
        d->cqbx = czbx * sarg;
      }else{
        double czbxf2 = czbx / m->f6;
        d->qbx = czbx * t->f5 + czbxf2 
          * (m->f7 * (d->vbx-t->f4)
            + (m->mjc / (t->BCpot+t->BCpot)) * (d->vbx*d->vbx-t->f4*t->f4));
        d->cqbx = czbxf2 * (m->f7 + m->mjc * d->vbx / t->BCpot);
      }}
      }
      { // d->qcs, d->cqcs
      // uses: d->vcs
      double czcs = m->cjs * c->area;
      {if (d->vcs < 0) {
        double arg = 1 - d->vcs / m->vjs;
        double sarg = pow(arg, -m->mjs);
        d->qcs = m->vjs * czcs * (1 - arg*sarg) / (1 - m->mjs);
        d->cqcs = czcs * sarg;
      }else{
        d->qcs = d->vcs * czcs * (1 + m->mjs * d->vcs / (2 * m->vjs));
        d->cqcs = czcs * (1 + m->mjs * d->vcs / m->vjs);
      }}
      }
    }
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
int DEV_BJT::_count = 0;
int COMMON_BJT::_count = -1;
static COMMON_BJT Default_BJT(CC_STATIC);
/*--------------------------------------------------------------------------*/
COMMON_BJT::COMMON_BJT(int c)
  :COMMON_COMPONENT(c),
   m(1.0),
   area(1),
   off(false),
   icvbe(NA),
   icvce(NA),
   temp(NA),
   _sdp(0),
   oik(NA),
   oikr(NA)
{
  ++_count;
}
/*--------------------------------------------------------------------------*/
COMMON_BJT::COMMON_BJT(const COMMON_BJT& p)
  :COMMON_COMPONENT(p),
   m(p.m),
   area(p.area),
   off(p.off),
   icvbe(p.icvbe),
   icvce(p.icvce),
   temp(p.temp),
   _sdp(0),
   oik(p.oik),
   oikr(p.oikr)
{
  ++_count;
}
/*--------------------------------------------------------------------------*/
COMMON_BJT::~COMMON_BJT()
{
  --_count;
  delete _sdp;
}
/*--------------------------------------------------------------------------*/
bool COMMON_BJT::operator==(const COMMON_COMPONENT& x)const
{
  const COMMON_BJT* p = dynamic_cast<const COMMON_BJT*>(&x);
  return (p
    && m == p->m
    && area == p->area
    && off == p->off
    && icvbe == p->icvbe
    && icvce == p->icvce
    && temp == p->temp
    && is_equal(x));
}
/*--------------------------------------------------------------------------*/
void COMMON_BJT::parse(CS& cmd)
{
  assert(!has_model());
  parse_modelname(cmd);
  if (cmd.is_float()) {
    cmd >> area;
  }
  int here = cmd.cursor();
  do{
    0
    || get(cmd, "M", &m, mPOSITIVE)
    || get(cmd, "Area", &area, mPOSITIVE)
    || get(cmd, "OFF", &off)
    || get(cmd, "ICVBE", &icvbe)
    || get(cmd, "ICVCE", &icvce)
    || get(cmd, "TEMP", &temp)
    ;
  }while (cmd.more() && !cmd.stuck(&here));
  cmd.check(bWARNING, "what's this?");
}
/*--------------------------------------------------------------------------*/
void COMMON_BJT::print(OMSTREAM& o)const
{
  o << "  " << modelname();
  o.setfloatwidth(7);
  if (m != 1.)
    o << "  m=" << m;
  o << "  area=" << area;
  if (off)
    o << "  off=" << off;
  if (icvbe != NA)
    o << "  icvbe=" << icvbe;
  if (icvce != NA)
    o << "  icvce=" << icvce;
  if (temp != NA)
    o << "  temp=" << temp;
  o << '\n';
}
/*--------------------------------------------------------------------------*/
void COMMON_BJT::expand(const COMPONENT* d)
{
  const COMMON_BJT* c = this;
  const MODEL_BJT* m = dynamic_cast<const MODEL_BJT*>(attach_model(d));
  if (!m) {
    error(bERROR, d->long_label() + ": model " + modelname()
          + " is not a bjt\n");
  }
  delete _sdp;
  _sdp = m->new_sdp(this);
  assert(_sdp);
  const SDP_BJT* s = dynamic_cast<const SDP_BJT*>(_sdp);
  assert(s);
  oik = m->invrollofff / c->area;
  oikr = m->invrolloffr / c->area;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
DEV_BJT::DEV_BJT()
  :BASE_SUBCKT(),
   _net_nodes(0),
   vbe(NA),
   vbc(NA),
   vbx(NA),
   vcs(NA),
   cce(NA),
   cce_cpoly(NA),
   go(NA),
   gm(NA),
   cpi(NA),
   cpi_cpoly(NA),
   gpi(NA),
   cmu(NA),
   cmu_cpoly(NA),
   gmu(NA),
   ix_cpoly(0),
   gx(NA),
   qbx(NA),
   cqbx(NA),
   qbc(NA),
   cqbc(NA),
   qcs(NA),
   cqcs(NA),
   qbe(NA),
   cqbe(NA),
   geqcb(NA),
   cexbc_0(NA),
   cexbc_1(NA),
   cexbc_2(NA),
   _dt_0(NA),
   _dt_1(NA),
   _Ice(0),
   _Ipi(0),
   _Imu(0),
   _Cbx(0),
   _Cbc(0),
   _Ccs(0),
   _Cbe(0),
   _Rc(0),
   _Re(0),
   _Yb(0),
   _Cbcp(0),
   _Cbep(0),
   _Cbsp(0),
   _Ccsp(0)
{
  _n = _nodes + int_nodes();
  attach_common(&Default_BJT);
  ++_count;
}
/*--------------------------------------------------------------------------*/
DEV_BJT::DEV_BJT(const DEV_BJT& p)
  :BASE_SUBCKT(p),
   _net_nodes(p._net_nodes),
   vbe(p.vbe),
   vbc(p.vbc),
   vbx(p.vbx),
   vcs(p.vcs),
   cce(p.cce),
   cce_cpoly(p.cce_cpoly),
   go(p.go),
   gm(p.gm),
   cpi(p.cpi),
   cpi_cpoly(p.cpi_cpoly),
   gpi(p.gpi),
   cmu(p.cmu),
   cmu_cpoly(p.cmu_cpoly),
   gmu(p.gmu),
   ix_cpoly(p.ix_cpoly),
   gx(p.gx),
   qbx(p.qbx),
   cqbx(p.cqbx),
   qbc(p.qbc),
   cqbc(p.cqbc),
   qcs(p.qcs),
   cqcs(p.cqcs),
   qbe(p.qbe),
   cqbe(p.cqbe),
   geqcb(p.geqcb),
   cexbc_0(p.cexbc_0),
   cexbc_1(p.cexbc_1),
   cexbc_2(p.cexbc_2),
   _dt_0(p._dt_0),
   _dt_1(p._dt_1),
   _Ice(0),
   _Ipi(0),
   _Imu(0),
   _Cbx(0),
   _Cbc(0),
   _Ccs(0),
   _Cbe(0),
   _Rc(0),
   _Re(0),
   _Yb(0),
   _Cbcp(0),
   _Cbep(0),
   _Cbsp(0),
   _Ccsp(0)
{
  _n = _nodes + int_nodes();
  for (int ii = -int_nodes(); ii < max_nodes(); ++ii) {
    _n[ii] = p._n[ii];
  }
  ++_count;
}
/*--------------------------------------------------------------------------*/
void DEV_BJT::parse(CS& cmd)
{
  assert(has_common());
  COMMON_BJT* c = prechecked_cast<COMMON_BJT*>(common()->clone());
  assert(c);

  parse_Label(cmd);
  _net_nodes = parse_nodes(cmd, max_nodes(), min_nodes());
  _net_nodes = std::max(_net_nodes, min_nodes());
  c->parse(cmd);
  attach_common(c);
}
/*--------------------------------------------------------------------------*/
void DEV_BJT::print(OMSTREAM& o, int)const
{
  const COMMON_BJT* c = prechecked_cast<const COMMON_BJT*>(common());
  assert(c);

  o << short_label();
  printnodes(o);
  c->print(o);
}
/*--------------------------------------------------------------------------*/
void DEV_BJT::expand()
{
  COMMON_BJT* c = prechecked_cast<COMMON_BJT*>(mutable_common());
  assert(c);
  c->expand(this);
  const MODEL_BJT* m = prechecked_cast<const MODEL_BJT*>(c->model());
  assert(m);
  const SDP_BJT* s = prechecked_cast<const SDP_BJT*>(c->sdp());
  assert(s);

  {if (!OPT::rstray || m->rc == 0.) {
    _n[n_icol] = _n[n_col];
  }else{
    _n[n_icol].new_model_node();
  }}
  {if (!OPT::rstray || (m->rb == 0. && m->rbm == 0.)) {
    _n[n_ibase] = _n[n_base];
  }else{
    _n[n_ibase].new_model_node();
  }}
  {if (!OPT::rstray || m->re == 0.) {
    _n[n_iemit] = _n[n_emit];
  }else{
    _n[n_iemit].new_model_node();
  }}

  {{
    if (!_Ice) {
      _Ice = new DEV_CPOLY_G;
      subckt().push_front(_Ice);
    }
    {{
      node_t nodes[] = {_n[n_icol], _n[n_iemit], _n[n_ibase], _n[n_iemit]};
      _Ice->set_parameters("Ice", this, NULL, 0., 3, &cce_cpoly, 4, nodes);
    }}
  }}
  {{
    if (!_Ipi) {
      _Ipi = new DEV_CPOLY_G;
      subckt().push_front(_Ipi);
    }
    {{
      node_t nodes[] = {_n[n_ibase], _n[n_iemit]};
      _Ipi->set_parameters("Ipi", this, NULL, 0., 2, &cpi_cpoly, 2, nodes);
    }}
  }}
  {{
    if (!_Imu) {
      _Imu = new DEV_CPOLY_G;
      subckt().push_front(_Imu);
    }
    {{
      node_t nodes[] = {_n[n_ibase], _n[n_icol]};
      _Imu->set_parameters("Imu", this, NULL, 0., 2, &cmu_cpoly, 2, nodes);
    }}
  }}
  {{
    if (!_Cbx) {
      _Cbx = new DEV_FPOLY_CAP;
      subckt().push_front(_Cbx);
    }
    {{
      node_t nodes[] = {_n[n_base], _n[n_icol]};
      _Cbx->set_parameters("Cbx", this, NULL, 0., 2, &qbx, 2, nodes);
    }}
  }}
  {{
    if (!_Cbc) {
      _Cbc = new DEV_FPOLY_CAP;
      subckt().push_front(_Cbc);
    }
    {{
      node_t nodes[] = {_n[n_ibase], _n[n_icol]};
      _Cbc->set_parameters("Cbc", this, NULL, 0., 2, &qbc, 2, nodes);
    }}
  }}
  {if (_n[n_sub].is_unconnected()) {
    if (_Ccs) {
      subckt().erase(_Ccs);
      _Ccs = NULL;
    }
  }else{
    if (!_Ccs) {
      _Ccs = new DEV_FPOLY_CAP;
      subckt().push_front(_Ccs);
    }
    {{
      node_t nodes[] = {_n[n_sub], _n[n_icol]};
      _Ccs->set_parameters("Ccs", this, NULL, 0., 2, &qcs, 2, nodes);
    }}
  }}
  {{
    if (!_Cbe) {
      _Cbe = new DEV_FPOLY_CAP;
      subckt().push_front(_Cbe);
    }
    {{
      node_t nodes[] = {_n[n_ibase], _n[n_iemit], _n[n_ibase], _n[n_icol]};
      _Cbe->set_parameters("Cbe", this, NULL, 0., 3, &qbe, 4, nodes);
    }}
  }}
  {if (!OPT::rstray || m->rc == 0.) {
    if (_Rc) {
      subckt().erase(_Rc);
      _Rc = NULL;
    }
  }else{
    if (!_Rc) {
      _Rc = new DEV_RESISTANCE;
      subckt().push_front(_Rc);
    }
    {{
      node_t nodes[] = {_n[n_col], _n[n_icol]};
      _Rc->set_parameters("Rc", this, NULL, m->rc / (c->area * c->m), 0, 0, 2, nodes);
    }}
  }}
  {if (!OPT::rstray || m->re == 0.) {
    if (_Re) {
      subckt().erase(_Re);
      _Re = NULL;
    }
  }else{
    if (!_Re) {
      _Re = new DEV_RESISTANCE;
      subckt().push_front(_Re);
    }
    {{
      node_t nodes[] = {_n[n_emit], _n[n_iemit]};
      _Re->set_parameters("Re", this, NULL, m->re / (c->area * c->m), 0, 0, 2, nodes);
    }}
  }}
  {if (!OPT::rstray || (m->rb == 0. && m->rbm == 0.)) {
    if (_Yb) {
      subckt().erase(_Yb);
      _Yb = NULL;
    }
  }else{
    if (!_Yb) {
      _Yb = new DEV_CPOLY_G;
      subckt().push_front(_Yb);
    }
    {{
      node_t nodes[] = {_n[n_base], _n[n_ibase]};
      _Yb->set_parameters("Yb", this, NULL, 0., 2, &ix_cpoly, 2, nodes);
    }}
  }}
  {if (!OPT::cstray || m->cbcp == 0.) {
    if (_Cbcp) {
      subckt().erase(_Cbcp);
      _Cbcp = NULL;
    }
  }else{
    if (!_Cbcp) {
      _Cbcp = new DEV_CAPACITANCE;
      subckt().push_front(_Cbcp);
    }
    {{
      node_t nodes[] = {_n[n_base], _n[n_col]};
      _Cbcp->set_parameters("Cbcp", this, NULL, m->cbcp * c->area * c->m, 0, 0, 2, nodes);
    }}
  }}
  {if (!OPT::cstray || m->cbep == 0.) {
    if (_Cbep) {
      subckt().erase(_Cbep);
      _Cbep = NULL;
    }
  }else{
    if (!_Cbep) {
      _Cbep = new DEV_CAPACITANCE;
      subckt().push_front(_Cbep);
    }
    {{
      node_t nodes[] = {_n[n_base], _n[n_col]};
      _Cbep->set_parameters("Cbep", this, NULL, m->cbep * c->area * c->m, 0, 0, 2, nodes);
    }}
  }}
  {if (!OPT::cstray || m->cbsp == 0.) {
    if (_Cbsp) {
      subckt().erase(_Cbsp);
      _Cbsp = NULL;
    }
  }else{
    if (!_Cbsp) {
      _Cbsp = new DEV_CAPACITANCE;
      subckt().push_front(_Cbsp);
    }
    {{
      node_t nodes[] = {_n[n_base], _n[n_col]};
      _Cbsp->set_parameters("Cbsp", this, NULL, m->cbsp * c->area * c->m, 0, 0, 2, nodes);
    }}
  }}
  {if (!OPT::cstray || m->ccsp == 0.) {
    if (_Ccsp) {
      subckt().erase(_Ccsp);
      _Ccsp = NULL;
    }
  }else{
    if (!_Ccsp) {
      _Ccsp = new DEV_CAPACITANCE;
      subckt().push_front(_Ccsp);
    }
    {{
      node_t nodes[] = {_n[n_base], _n[n_col]};
      _Ccsp->set_parameters("Ccsp", this, NULL, m->ccsp * c->area * c->m, 0, 0, 2, nodes);
    }}
  }}
  assert(subckt().exists());
  subckt().expand();
  assert(!constant());
  subckt().set_slave();
}
/*--------------------------------------------------------------------------*/
double DEV_BJT::tr_probe_num(CS& cmd)const
{
  const COMMON_BJT* c = prechecked_cast<const COMMON_BJT*>(common());
  assert(c);
  const MODEL_BJT* m = prechecked_cast<const MODEL_BJT*>(c->model());
  assert(m);
  const SDP_BJT* s = prechecked_cast<const SDP_BJT*>(c->sdp());
  assert(s);

  {if (cmd.pmatch("VBEInt")) {
    return  vbe;
  }else if (cmd.pmatch("VBCInt")) {
    return  vbc;
  }else if (cmd.pmatch("VBXInt")) {
    return  vbx;
  }else if (cmd.pmatch("VCSInt")) {
    return  vcs;
  }else if (cmd.pmatch("VBS")) {
    return  _n[n_base].v0() - _n[n_sub].v0();
  }else if (cmd.pmatch("VBE")) {
    return  _n[n_base].v0() - _n[n_emit].v0();
  }else if (cmd.pmatch("VBC")) {
    return  _n[n_base].v0() - _n[n_col].v0();
  }else if (cmd.pmatch("VBX")) {
    return  _n[n_base].v0() - _n[n_ibase].v0();
  }else if (cmd.pmatch("VCS")) {
    return  _n[n_col].v0() - _n[n_sub].v0();
  }else if (cmd.pmatch("VCB")) {
    return  _n[n_col].v0() - _n[n_base].v0();
  }else if (cmd.pmatch("VCE")) {
    return  _n[n_col].v0() - _n[n_emit].v0();
  }else if (cmd.pmatch("VES")) {
    return  _n[n_emit].v0() - _n[n_sub].v0();
  }else if (cmd.pmatch("VEB")) {
    return  _n[n_emit].v0() - _n[n_base].v0();
  }else if (cmd.pmatch("VEC")) {
    return  _n[n_emit].v0() - _n[n_col].v0();
  }else if (cmd.pmatch("VB")) {
    return  _n[n_base].v0();
  }else if (cmd.pmatch("VC")) {
    return  _n[n_col].v0();
  }else if (cmd.pmatch("VE")) {
    return  _n[n_emit].v0();
  }else if (cmd.pmatch("VS")) {
    return  _n[n_sub].v0();
  }else if (cmd.pmatch("VBI")) {
    return  _n[n_ibase].v0();
  }else if (cmd.pmatch("VCI")) {
    return  _n[n_icol].v0();
  }else if (cmd.pmatch("VEI")) {
    return  _n[n_iemit].v0();
  }else if (cmd.pmatch("ICE")) {
    return  cce;
  }else if (cmd.pmatch("ICEOffset")) {
    return  cce_cpoly;
  }else if (cmd.pmatch("HOE")) {
    return  go;
  }else if (cmd.pmatch("GO")) {
    return  go;
  }else if (cmd.pmatch("ROe")) {
    return  (go != 0) ? 1/go : BIGBIG;
  }else if (cmd.pmatch("GM")) {
    return  gm;
  }else if (cmd.pmatch("IPI")) {
    return  cpi;
  }else if (cmd.pmatch("IPIOffset")) {
    return  cpi_cpoly;
  }else if (cmd.pmatch("GPI")) {
    return  gpi;
  }else if (cmd.pmatch("RPI")) {
    return  (gpi != 0) ? 1/gpi : BIGBIG;
  }else if (cmd.pmatch("HIE")) {
    return  (gpi != 0) ? 1/gpi : BIGBIG;
  }else if (cmd.pmatch("IMU")) {
    return  cmu;
  }else if (cmd.pmatch("IMUOffset")) {
    return  cmu_cpoly;
  }else if (cmd.pmatch("GMU")) {
    return  gmu;
  }else if (cmd.pmatch("RMU")) {
    return  (gmu != 0) ? 1/gmu : BIGBIG;
  }else if (cmd.pmatch("IB")) {
    return  cpi + cmu;
  }else if (cmd.pmatch("GX")) {
    return  gx;
  }else if (cmd.pmatch("RX")) {
    return  (gx != NA) ? 1/gx : 0.;
  }else if (cmd.pmatch("IC")) {
    return  cce + cmu;
  }else if (cmd.pmatch("IE")) {
    return  -cce -cpi;
  }else if (cmd.pmatch("QBX")) {
    return  qbx;
  }else if (cmd.pmatch("CQBX")) {
    return  cqbx;
  }else if (cmd.pmatch("CBX")) {
    return  cqbx;
  }else if (cmd.pmatch("QBC")) {
    return  qbc;
  }else if (cmd.pmatch("CQBC")) {
    return  cqbc;
  }else if (cmd.pmatch("CBC")) {
    return  cqbc;
  }else if (cmd.pmatch("CMU")) {
    return  cqbc;
  }else if (cmd.pmatch("QCS")) {
    return  qcs;
  }else if (cmd.pmatch("CQCS")) {
    return  cqcs;
  }else if (cmd.pmatch("CCS")) {
    return  cqcs;
  }else if (cmd.pmatch("QBE")) {
    return  qbe;
  }else if (cmd.pmatch("CQBE")) {
    return  cqbe;
  }else if (cmd.pmatch("CBE")) {
    return  cqbe;
  }else if (cmd.pmatch("CPI")) {
    return  cqbe;
  }else if (cmd.pmatch("GEQCB")) {
    return  geqcb;
  }else if (cmd.pmatch("P")) {
    return  CARD::probe(_Ice,"P") + CARD::probe(_Ipi,"P") + CARD::probe(_Imu,"P") + CARD::probe(_Rc,"P") + CARD::probe(_Re,"P") + CARD::probe(_Yb,"P") + CARD::probe(_Cbx,"P") + CARD::probe(_Cbc,"P") + CARD::probe(_Ccs,"P") + CARD::probe(_Cbe,"P");
  }else if (cmd.pmatch("PD")) {
    return  CARD::probe(_Ice,"PD") + CARD::probe(_Ipi,"PD") + CARD::probe(_Imu,"PD") + CARD::probe(_Rc,"PD") + CARD::probe(_Re,"PD") + CARD::probe(_Yb,"PD") + CARD::probe(_Cbx,"PD") + CARD::probe(_Cbc,"PD") + CARD::probe(_Ccs,"PD") + CARD::probe(_Cbe,"PD");
  }else if (cmd.pmatch("PS")) {
    return  CARD::probe(_Ice,"PS") + CARD::probe(_Ipi,"PS") + CARD::probe(_Imu,"PS") + CARD::probe(_Rc,"PS") + CARD::probe(_Re,"PS") + CARD::probe(_Yb,"PS") + CARD::probe(_Cbx,"PS") + CARD::probe(_Cbc,"PS") + CARD::probe(_Ccs,"PS") + CARD::probe(_Cbe,"PS");
  }else if (cmd.pmatch("Status")) {
    return  static_cast<double>(converged() * 2);
  }else {
    return BASE_SUBCKT::tr_probe_num(cmd);
  }}
}
/*--------------------------------------------------------------------------*/
void DEV_BJT::limit(double vnew, double *vold, double vt, double vcrit)
{

    /* Spice style limiting */
    trace4("limit-in", vnew, *vold, vt, vcrit);
    {if ((vnew > vcrit) && (std::abs(vnew - *vold) > (2 * vt))) {
      {if (*vold > 0) {
      double arg = 1 + (vnew - *vold) / vt;
      *vold = (arg > 0) ? (*vold + vt * log(arg)) : vcrit;
      trace3("limit-1", *vold, vt*log(arg), arg);
      }else{
      *vold = vt * log(vnew/vt);
      trace3("limit-2", *vold, vt*log(vnew/vt), vnew/vt);
      }}
    }else{
      *vold = vnew;
      trace1("limit-3", *vold);
    }}
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------*/
bool DEV_BJT::tr_needs_eval()
{
  {if (is_q_for_eval()) {
    untested();
    return false;
  }else if (!converged()) {
    return true;
  }else{
    const COMMON_BJT* c = prechecked_cast<const COMMON_BJT*>(common());
    assert(c);
    const MODEL_BJT* m=prechecked_cast<const MODEL_BJT*>(c->model());
    assert(m);
    polarity_t polarity = m->polarity;
    return !(conchk(vbc, polarity*(_n[n_ibase].v0()-_n[n_icol].v0()),
                OPT::vntol)
           && conchk(vbe, polarity*(_n[n_ibase].v0()-_n[n_iemit].v0()),
                   OPT::vntol)
           && conchk(vcs, polarity*(_n[n_icol].v0()-_n[n_sub].v0()),
                   OPT::vntol));
  }}
}
/*--------------------------------------------------------------------------*/
bool DEV_BJT::do_tr()
{
  const COMMON_BJT* c = prechecked_cast<const COMMON_BJT*>(common());
  assert(c);
  const MODEL_BJT* m = prechecked_cast<const MODEL_BJT*>(c->model());
  assert(m);
  assert(subckt().exists());
  const TDP_BJT T(this);
  const TDP_BJT* t = &T;

  {if(STATUS::iter[SIM::mode] <= 1) {     // initial guess
    {if (c->off) {
      vbe = 0;
    }else{
      double vt = SIM::temp * K / Q;
      vbe = vt * log(vt / (kRT2 * m->ibe));
    }}
    vbc = 0;
    /* ERROR:  need to initialize VCS, VBX here */
    vcs = vbx = 0;
  }else{                      // normal gather
    // vbe = m->polarity * volts_limited(_n[n_ibase], _n[n_iemit]);
    limit((m->polarity * volts_limited(_n[n_ibase], _n[n_iemit])),
        &vbe, t->vt, t->Vcrit);
    // vbc = m->polarity * volts_limited(_n[n_ibase], _n[n_icol]);
    limit((m->polarity * volts_limited(_n[n_ibase], _n[n_icol])),
        &vbc, t->vt, t->Vcrit);
    vbx = m->polarity * volts_limited(_n[n_base], _n[n_icol]);
    vcs = m->polarity * volts_limited(_n[n_sub], _n[n_icol]);
  }}

  if (SIM::uic_now()) {
    untested();
    {if (c->icvbe != NA) {
      untested();
      vbe = m->polarity * c->icvbe;
    }else{
      untested();
    }}
    {if (c->icvce != NA) {
      untested();
      vbc = vbe - m->polarity * c->icvce;
      vbx = vbc;
    }else{
      untested();
    }}
  }

  m->tr_eval(this);
  switch (m->polarity) {
  case pP:
    cce = -cce;
    cce_cpoly = -cce_cpoly;
    cpi = -cpi;
    cpi_cpoly = -cpi_cpoly;
    cmu = -cmu;
    cmu_cpoly = -cmu_cpoly;
    assert(ix_cpoly == 0.);
    qbx = -qbx;
    qbc = -qbc;
    qcs = -qcs;
    qbe = -qbe;
    break;
  case pN:
    // leave it as is
    break;
  }
  if (c->m != 1.) {
    cce *= c->m;
    cce_cpoly *= c->m;
    go *= c->m;
    gm *= c->m;
    
    cpi *= c->m;
    cpi_cpoly *= c->m;
    gpi *= c->m;
    
    cmu *= c->m;
    cmu_cpoly *= c->m;
    gmu *= c->m;
    
    ix_cpoly *= c->m;
    gx  *= c->m;
    
    qbx *= c->m;
    cqbx *= c->m;
    
    qbc  *= c->m;
    cqbc *= c->m;
    
    qcs  *= c->m;
    cqcs *= c->m;
    
    qbe  *= c->m;
    cqbe *= c->m;
    geqcb *= c->m;
  }
  set_converged(subckt().do_tr());
  return converged();
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

Generated by  Doxygen 1.6.0   Back to index