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 };
|