/* $Id: d_bjt.model 2014年11月23日 al$ -*- C++ -*- * Copyright (C) 2002 Albert Davis * Author: Albert Davis * * 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, 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 * model: .model mname NPN * or .model mname PNP * * known BUGs * 1. excess phase partially implemented, disabled, as if PTF == 0. */ /*--------------------------------------------------------------------------*/ h_headers { #include "d_diode.h" } cc_headers { #include "u_limit.h" } /*--------------------------------------------------------------------------*/ device BUILT_IN_BJT { parse_name bjt; model_type BUILT_IN_BJT; id_letter Q; circuit { sync; ports {c b e} {s short_to=e}; local_nodes { ic short_to=c short_if="!OPT::rstray || m->rc == 0."; ib short_to=b short_if="!OPT::rstray || (m->rb == 0. && m->rbm == 0.)"; ie short_to=e short_if="!OPT::rstray || m->re == 0."; } // basics cpoly_g Ice {ic,ie ib,ie} state=ccexxx; // cce, go, gm cpoly_g Ipi {ib ie} state=cpixxx; // cpi, gpi cpoly_g Imu {ib ic} state=cmuxxx; // cmu, gmu // junction charge effects fpoly_cap Cbx {b ic} state=qbx; // qbx, cqbx fpoly_cap Cbc {ib ic} state=qbc; // qbc, cqbc fpoly_cap Ccs {s ic} state=qcs // qcs, cqcs // omit="!(_n[n_s].n_())"; unreachable, removed ; fpoly_cap Cbe {ib ie ib ic} state=qbe; // qbe, cqbe, geqbc // parasitics resistor Rc {c ic} value="m->rc / c->area" omit="!OPT::rstray || m->rc == 0."; // gcpr resistor Re {e ie} value="m->re / c->area" omit="!OPT::rstray || m->re == 0."; // gepr cpoly_g Yb {b ib} state=ixxxx // gx. should be "eval" omit="!OPT::rstray || (m->rb == 0. && m->rbm == 0.)"; capacitor Cbcp {b c} value="m->cbcp * c->area" omit="!OPT::cstray || m->cbcp == 0."; capacitor Cbep {b e} value="m->cbep * c->area" omit="!OPT::cstray || m->cbep == 0."; capacitor Cbs {b s} value="(m->cbsp + m->ccsp) * c->area" omit="!OPT::cstray || ((m->cbsp + m->ccsp) == 0.)"; } tr_probe { v = "@n_c[V] - @n_e[V]"; "vbei{nt}" = "vbe"; "vbci{nt}" = "vbc"; "vbxi{nt}" = "vbx"; "vcsi{nt}" = "vcs"; vbs = "@n_b[V] - @n_s[V]"; vbe = "@n_b[V] - @n_e[V]"; vbc = "@n_b[V] - @n_c[V]"; vbx = "@n_b[V] - @n_ib[V]"; vcs = "@n_c[V] - @n_s[V]"; vcb = "@n_c[V] - @n_b[V]"; vce = "@n_c[V] - @n_e[V]"; ves = "@n_e[V] - @n_s[V]"; veb = "@n_e[V] - @n_b[V]"; vec = "@n_e[V] - @n_c[V]"; vb = "@n_b[V]"; vc = "@n_c[V]"; ve = "@n_e[V]"; vs = "@n_s[V]"; vbi = "@n_ib[V]"; vci = "@n_ic[V]"; vei = "@n_ie[V]"; "i" = "cce"; "ice" = "cce"; "iceo{ffset}" = "ccexxx"; hoe = "go"; "ro{e}" = "(go != 0.) ? 1/go : BIGBIG"; ipi = "cpi"; "ipio{ffset}" = "cpixxx"; rpi = "(gpi != 0.) ? 1/gpi : BIGBIG"; hie = "(gpi != 0.) ? 1/gpi : BIGBIG"; imu = "cmu"; "imuo{ffset}" = "cmuxxx"; rmu = "(gmu != 0.) ? 1/gmu : BIGBIG"; ib = "cpi + cmu"; rx = "(gx != NA) ? 1/gx : 0."; ic = "cce - cmu"; ie = "-cce -cpi"; cbx = "cqbx"; cbc = "cqbc"; cmu = "cqbc"; ccs = "cqcs"; cbe = "cqbe"; cpi = "cqbe"; p = "@Ice[P] + @Ipi[P] + @Imu[P] + @Rc[P] + @Re[P] + @Yb[P] + @Cbx[P] + @Cbc[P] + @Ccs[P] + @Cbe[P]"; pd = "@Ice[PD] + @Ipi[PD] + @Imu[PD] + @Rc[PD] + @Re[PD] + @Yb[PD] + @Cbx[PD] + @Cbc[PD] + @Ccs[PD] + @Cbe[PD]"; ps = "@Ice[PS] + @Ipi[PS] + @Imu[PS] + @Rc[PS] + @Re[PS] + @Yb[PS] + @Cbx[PS] + @Cbc[PS] + @Ccs[PS] + @Cbe[PS]"; status = "static_cast(converged() * 2)"; } device { calculated_parameters { double vbe "B-E voltage"; // gather double vbc "B-C voltage"; double vbx "B-C voltage (ext base)"; double vcs "C-S voltage"; double cce "collector-emitter current"; double ccexxx; double go "Small signal output conductance"; double gm "Small signal transconductance"; double cpi "emitter-base current"; double cpixxx; double gpi "Small signal input conductance - pi"; double cmu "collector-base current"; double cmuxxx; double gmu "Small signal conductance - mu"; double ixxxx "Current offset at base node, constant" default=0.; double gx "dix/dvbb Conductance from base to internal base"; double qbx "Charge storage B-X junction"; double cqbx "Cap. due to charge storage in B-X jct."; // cbx, capbx double qbc "Charge storage B-C junction"; double cqbc "Cap. due to charge storage in B-C jct."; // cmu, capbc double qcs "Charge storage C-S junction"; double cqcs "Cap. due to charge storage in C-S jct."; // ccs, capcs double qbe "Charge storage B-E junction"; double cqbe "Cap. due to charge storage in B-E jct."; // cpi, capbe double geqcb "d(Ieb)/d(Vcb)"; double cexbc_0 "Total Capacitance in B-X junction"; // ?? double cexbc_1 ""; double cexbc_2 ""; double _dt_0 "time step"; double _dt_1 ""; } } common { unnamed area; raw_parameters { double area "area factor" name=Area positive default=1.; bool off "device initially off" name=OFF default=false print_test=off; double icvbe "Initial B-E voltage" name="ICVBE" default=NA; double icvce "Initial C-E voltage" name="ICVCE" default=NA; double temp_c "instance temperature" name="TEMP" default=NA; } calculated_parameters { double oik "" calculate="m->invrollofff / c->area"; double oikr "" calculate="m->invrolloffr / c->area"; } } tr_eval { int foo=3; } } /*--------------------------------------------------------------------------*/ model BUILT_IN_BJT { level 1; dev_type BUILT_IN_BJT; hide_base; inherit BUILT_IN_DIODE; public_keys { npn polarity=pN; pnp polarity=pP; npn1 polarity=pN; pnp1 polarity=pP; } independent { override { double kf "Flicker Noise Coefficient" name=KF default=0.; double af "Flicker Noise Exponent" name=AF default=1.; } raw_parameters { int level "dummy" name=LEVEL default=1 print_test=false; // basic double bf "Ideal forward beta" name=BF alt_name=BFM default=100.; double br "Ideal reverse beta" name=BR alt_name=BRM default=1.; double ibc "bc Saturation Current" name=IBC default=NA print_test="ibe != ibc" final_default="((has_hard_value(i_s)) ? i_s : 1e-16)"; double ibe "be Saturation Current" name=IBE default=NA print_test="ibe != ibc" final_default="((has_hard_value(i_s)) ? i_s : 1e-16)"; double i_s "Saturation Current" name=IS default=NA print_test="ibe == ibc" final_default="((ibe == ibc) ? ibe : NA)"; //double iss "bulk to collector or base sat current (ignored)" //name=ISS default=0; //double expli "current explosion factor (ignored)" //name=EXPLI default=1e15; double nf "Forward emission coefficient" name=NF default=1.; double nr "Reverse emission coefficient" name=NR default=1.; //double ns "substrate leakage emission coefficient (ignored)" //name=NS default=1; //int subs "geometry, +1=vertical, -1=lateral (ignored)", name=SUBS //default="(polarity==pP) ? -1 : 1"; // base width modulation double vaf "Forward Early voltage" name=VAf alt_name=VA0円VBF default=NA; double var "Reverse Early voltage" name=VAR alt_name=VB default=NA; // low current beta degeneration double isc "B-C leakage saturation current" name=ISC default=NA final_default="(c4*ibc)"; double c4 "obsolete, don't use" name=C4 alt_name=JLC default=0.; double nc "B-C leakage emission coefficient" name=NC default=2.; double ise "B-E leakage saturation current" name=ISE default=NA final_default="(c2*ibe)"; double c2 "obsolete, don't use" name=C2 alt_name=JLE default=0.; double ne "B-E leakage emission coefficient" name=NE default=1.5; // high current beta degeneration double ikf "Forward beta roll-off corner current" name=IKf alt_name=IK0円JBF default=NA; double ikr "reverse beta roll-off corner current" name=IKR alt_name=JBR default=NA; // parasitic resistance double irb "Current for base resistance=(rb+rbm)/2" name=IRB alt_name=JRB0円IOB default=NA; double rb "Zero bias base resistance" name=RB default=0.; double rbm "Minimum base resistance" name=RBM default=NA final_default=rb; double re "Emitter resistance" name=RE default=0.; double rc "Collector resistance" name=RC default=0.; // parasitic capacitance double cbcp "external BC capacitance" name=CBCP print_test="cbcp!=0." default=0.; double cbep "external BE capacitance" name=CBEP print_test="cbep!=0." default=0.; double cbsp "external BS capacitance (lateral)" name=CBSP print_test="cbsp!=0." default=0.; double ccsp "external BS capacitance (vertical)" name=CCSP print_test="ccsp!=0." default=0.; // junction capacitance double cjc "Zero bias B-C depletion capacitance" name=CJC default=0.; double cje "Zero bias B-E depletion capacitance" name=CJE default=0.; double cjs "Zero bias C-S capacitance" name=CJS alt_name=CCS0円CSUB default=0.; double fc "Forward bias junction fit parameter" name=FC default=NA final_default=.5 quiet_max=.9999; double mjc "B-C junction grading coefficient" name=MJC alt_name=MC0円MJ default=.33; double mje "B-E junction grading coefficient" name=MJE alt_name=ME default=.33; double mjs "Substrate junction grading coefficient" name=MJS alt_name=MSub0円MS0円ESUB default=0.; // alt name ESUB?? double vjc "B-C built in potential" name=VJC alt_name=PC default=.75; double vje "B-E built in potential" name=VJE alt_name=PE default=.75; double vjs "Substrate junction built in potential" name=VJS alt_name=PSub0円PS default=.75; double xcjc "Fraction of B-C cap to internal base" name=XCJC alt_name=CDIS default=1.; // transit time double itf "High current dependence of TF" name=ITF alt_name=JTF default=0.; double ptf "Excess phase" name=PTf default=0.; double tf "Ideal forward transit time" name=TF default=0.; double tr "Ideal reverse transit time" name=TR default=0.; double vtf "Voltage giving VBC dependence of TF" name=VTF default=NA; double xtf "Coefficient for bias dependence of TF" name=XTF default=0.; // temperature effects double xtb "Forward and reverse beta temp. exp." name=XTB alt_name=TB default=0.; // alt name TCB double xti "Temp. exponent for IS" name=XTI default=3.; double eg "Energy gap for IS temp. dependency" name=EG default=1.11; } calculated_parameters { double tnom_k "nominal temperature, kelvin" calculate="_tnom_c + P_CELSIUS0"; polarity_t polarity "" default=pN; double invearlyvoltf "Inverse early voltage:forward" name=INVEARLYVOLTF calculate="(has_nz_value(vaf)) ? 1./vaf : 0."; double invearlyvoltr "Inverse early voltage:reverse" name=INVEARLYVOLTR calculate="(has_nz_value(var)) ? 1./var : 0."; double invrollofff "Inverse roll off - forward" name=INVROLLOFFF calculate="(has_nz_value(ikf)) ? 1./ikf : 0."; double invrolloffr "Inverse roll off - reverse" name=INVROLLOFFR calculate="(has_nz_value(ikr)) ? 1./ikr : 0."; double transtimevbcfact "Transit time VBC factor" name=TRANSTIMEVBCFACT calculate="(has_nz_value(vtf)) ? 1./(vtf*1.44) : 0."; double excessphasefactor "Excess phase fact." name=EXCESSPHASEFACTOR calculate="(ptf * DTOR) * tf"; double xfc "" calculate="log(1 - fc)"; double f2 "" calculate="exp((1 + mje) * xfc)"; double f3 "" calculate="1 - fc * (1 + mje)"; double f6 "" calculate="exp((1 + mjc) * xfc)"; double f7 "" calculate="1 - fc * (1 + mjc)"; } } temperature_dependent { calculated_parameters { double vt ""; //double is "BJTtSatCur" calculate = "m->is * factor"; double ibc "BJTtSatCur" calculate = "m->ibc * factor"; double ibe "BJTtSatCur" calculate = "m->ibe * factor"; double BetaF "BJTtBetaF" calculate = "m->bf * bfactor"; double BetaR "BJTtBetaR" calculate = "m->br * bfactor"; double BEleakCur "BJTtBEleakCur" calculate = "m->ise * exp(factlog/m->ne) / bfactor"; double BCleakCur "BJTtBCleakCur" calculate = "m->isc * exp(factlog/m->nc) / bfactor"; double BEpot "BJTtBEpot"; double BEcap "BJTtBEcap"; double DepCap ""; double f1 ""; double BCpot "BJTtBCpot"; double BCcap "BJTtBCcap"; double f4 ""; double f5 ""; double Vcrit "" calculate="vt * log(vt / (M_SQRT2 * m->ibe))"; } code_pre { const double reftemp = 300.15; double temp_k = ((has_hard_value(c->temp_c)) ? (c->temp_c + P_CELSIUS0) : c->temp_k()); double fact1 = m->tnom_k / reftemp; double fact2 = temp_k / reftemp; double tempratio = temp_k / m->tnom_k; // fact2/fact1 double kt = temp_k * P_K; vt = temp_k * P_K_Q; double egap = 1.16 - (7.02e-4*temp_k*temp_k) / (temp_k+1108.); // egfet // double arg = (m->eg*tempratio - egap) / (2*kt); double arg = -egap/(2 * kt) + 1.1150877 / (P_K * (reftemp+reftemp)); double pbfact = -2 * vt * (1.5 * log(fact2) + P_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); } code_post { { 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_k-reftemp)-gmaold))) * (1 + m->mje * (4e-4*(temp_k-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_k-reftemp)-gmaold))) * (1 + m->mjc * (4e-4*(temp_k-reftemp)-gmanew)); f4 = m->fc * BCpot; f5 = BCpot * (1 - exp((1 - m->mjc) * m->xfc)) / (1 - m->mjc); } } } tr_eval { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - trace0("--------------------------"); trace0(d->long_label().c_str()); trace4("", d->vbe, d->vbc, d->vbx, d->vcs); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - double cbe, gbe; { // d->cpi, d->gpi, d->cpixxx // 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->cpixxx = d->cpi - d->vbe * d->gpi; trace3("", t->BetaF, d->cpi, d->gpi); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - double cbc, gbc, cbcn; { // d->cmu, d->gmu, d->cmuxxx // 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->cmuxxx = 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 (_sim->is_initial_step()) { d->cexbc_2 = d->cexbc_1 = cbe / qb; }else{ } 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->ccexxx = 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 || (!has_nz_value(m->rb) && !has_nz_value(m->rbm))) { 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 (has_nz_value(m->irb)) {untested();//554 // 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{ 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 (has_nz_value(m->tf) && d->vbe> 0.) { double argtf = NA; double arg2 = NA; double arg3 = NA; if (has_nz_value(m->xtf)) {untested();//579 if (m->transtimevbcfact != 0.) { argtf = m->xtf * exp(d->vbc * m->transtimevbcfact); }else{untested(); argtf = m->xtf; } arg2 = argtf; if(has_nz_value(m->itf)) { double temp = cbe / (cbe + m->itf * c->area); argtf *= temp*temp; arg2 *= (3-temp-temp); }else{ } 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); } } } } } /*--------------------------------------------------------------------------*/ cc_direct { /*--------------------------------------------------------------------------*/ bool DEV_BUILT_IN_BJT::tr_needs_eval()const { if (is_q_for_eval()) { untested(); return false; }else if (!converged()) { return true; }else{ const COMMON_BUILT_IN_BJT* c = prechecked_cast(common()); assert(c); const MODEL_BUILT_IN_BJT* m=prechecked_cast(c->model()); assert(m); int polarity = int(m->polarity); return !(conchk(vbc, polarity*(n_(n_ib).v0()-n_(n_ic).v0()), OPT::vntol) && conchk(vbe, polarity*(n_(n_ib).v0()-n_(n_ie).v0()), OPT::vntol) && conchk(vcs, polarity*(n_(n_ic).v0()-n_(n_s).v0()), OPT::vntol)); } } /*--------------------------------------------------------------------------*/ bool DEV_BUILT_IN_BJT::do_tr() { const COMMON_BUILT_IN_BJT* c = prechecked_cast(common()); assert(c); const MODEL_BUILT_IN_BJT* m = prechecked_cast(c->model()); assert(m); const TDP_BUILT_IN_BJT T(this); const TDP_BUILT_IN_BJT* t = &T; if(_sim->is_initial_step()) { // initial guess if (c->off) { vbe = 0.; }else{ double vt = c->temp_k() * P_K_Q; vbe = vt * log(vt / (M_SQRT2 * m->ibe)); } vbc = 0.; /* ERROR: need to initialize VCS, VBX here */ vcs = vbx = 0.; }else{ // normal gather int polarity = int(m->polarity); vbe = pnj_limit((polarity * volts_limited(n_(n_ib), n_(n_ie))), vbe, t->vt, t->Vcrit); vbc = pnj_limit((polarity * volts_limited(n_(n_ib), n_(n_ic))), vbc, t->vt, t->Vcrit); vbx = polarity * volts_limited(n_(n_b), n_(n_ic)); vcs = polarity * volts_limited(n_(n_s), n_(n_ic)); } if (_sim->uic_now()) {untested();//736 int polarity = int(m->polarity); if (has_good_value(c->icvbe)) {untested();//737 vbe = polarity * c->icvbe; }else{untested();//739 } if (has_good_value(c->icvce)) {untested();//741 vbc = vbe - polarity * c->icvce; vbx = vbc; }else{untested();//744 } }else{ } m->tr_eval(this); switch (m->polarity) { case pP: cce = -cce; ccexxx = -ccexxx; cpi = -cpi; cpixxx = -cpixxx; cmu = -cmu; cmuxxx = -cmuxxx; assert(ixxxx == 0.); qbx = -qbx; qbc = -qbc; qcs = -qcs; qbe = -qbe; break; case pN: // leave it as is break; } assert(subckt()); set_converged(subckt()->do_tr()); return converged(); } } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/

AltStyle によって変換されたページ (->オリジナル) /