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