Version: ngspice-47 (macOS arm64). The same code is on pre-master-48 at 7b048c03.
Summary. A Gummel-Poon BJT with the Kull quasi-saturation parameters (RCO, VO, GAMMA)
simulates correctly with QCO = 0. With any QCO > 0, even 1e-12, the transient stops at the
first switching edge with "Timestep too small ... trouble with q-instance". Solver options
(method=gear, reltol, gmin, slower edges) do not help. Vendor models that set QCO cannot be
simulated in transient. We found it with ST's BD140 model (QCO = 0.214 nC).
Cause. In src/spicelib/devices/bjt/bjtload.c, the epi charges Qbci and Qbcx are
computed only inside if (vrci > 0.). The else branch sets them, and their derivatives,
to 0. When vrci crosses zero, the charge steps by about QCO·sqrt(1+GAMMA) ≈ QCO, so dQ/dt
is unbounded and the time step collapses. In Kull's model, PSpice and HSPICE, and in the
VBIC code in ngspice (vbicload.c), the epi charge depends on vbc and vbcx only, not on
the sign of the current through RCO.
Reproduction (qco_repro.cir, attached):
V5 vcc 0 5
Re vcc e 4.7
Q1 c b e QP
Rbe b e 10k
Rb b drv 330
Vdrv drv 0 PULSE(5 0 10u 1u 1u 100u 200u)
Rl c 0 47
.model QP PNP(Is=1e-14 Bf=150 Rco=1.7 Vo=10 Gamma=1e-10 Qco=1e-10)
.tran 0.1u 300u
.control
run
meas tran vhigh MAX v(c)
.endc
.end
Expected: the transient completes, with vhigh close to the QCO = 0 value (4.406 V).
Actual: Timestep too small; time = 0.000111888, timestep = 1.25e-19: trouble with
qp-instance q1.
Proposed fix (patch attached):
vrci test. The twoqbc and qbcx. VBIC in ngspice uses QCO·KQ0 term. The capacitances aretests/regression/model/bjt-qco-1.cir, which fails without theI checked the other users of the epi charge. bjtacld.c and bjtpzld.c read the
capacitance that bjtload.c stores at MODEINITSMSIG, and the sensitivity code gets
qbc by reloading the device. bjttrunc.c and bjtconv.c do not depend on the sign of
vrci. So the change in bjtload.c is enough.
Verification (pre-master-48 @ 7b048c03, macOS arm64, bison 3.8.2):
| Circuit | unpatched | patched |
|---|---|---|
qco_repro.cir |
Timestep too small at 111.9 µs | completes, vhigh = 4.411 V |
| same, QCO = 0 | vhigh = 4.406 V | vhigh = 4.406 V |
| ST BD140 model (QCO = 0.214 nC) in the same circuit | Timestep too small at 10.0 µs | completes, vhigh = 4.424 V |
| AC, NPN with QCO, forward-active / saturated / cut off | reference | identical (OP, gain at 10 kHz and 10 MHz, phase) |
| DC sweep of Vce through quasi-saturation | reference | identical |
make check |
58 PASS + new bjt-qco-1.cir PASS, 0 FAIL |
Not changed by this patch. For vrci <= 0 the code models RCO as a plain resistor,
while PSpice uses the Kull current expression for both signs. That is a separate model
difference and does not cause this failure.
The patch is contributed under the ngspice modified BSD license.
Thanks for the detailed report and for the patch.
Confirmed on pre-master-48. Your repro deck stops at about 112 µs without the patch and runs to the end with it, giving vhigh = 4.4115 V here, matching your number. With the real ST BD140 model (QCO = 0.214 nC) the unpatched run dies at the first switching edge; depending on the options it either aborts or completes with a several-hundred-volt artefact on a 5 V supply, which is worse than the abort.
What I checked against the patch:
DC results unchanged, the sweep output is identical byte for byte.
AC changes only at operating points with vrci <= 0, where the epi capacitance was missing altogether. At Vbe = 0.9 V, Vce = -0.2 V the base current used to be flat over frequency and now rises as it should.
ctest passes including your new test.
On the charge form: the offset you chose, Q = QCO*(K - 1 - GAMMA/2), is what both the PSpice and the Spectre manuals document, so I would keep it rather than the VBIC-style QCOK. It is also the faster of the two here: with the ST BD140 the patched run needs 257k timepoints for 4 µs against 373k for the plain QCOK form, at identical results.
Two follow-ups that came out of reviewing this, which I will handle separately:
The epi charge and the epi resistance carry no area factor in ngspice, while PSpice (areaQCO, areaIepi). A device with area=2 did not match the same device with m=2 once RCO was given.
ngspice divides by VO without a guard, so a model card carrying VO=0 cannot reach an usable operating point at all.
On the difference you left open, the plain ohmic branch for vrci <= 0. That is a model change rather than a bug fix, so it deserves its own discussion.
BTW, unrelated to this report, just for information: the ST BD139/BD140 subcircuits wrap the transistor in 1 µΩ terminal resistors, which is less than a bond wire and an order of magnitude below the 57 mΩ RB of the model itself. In a transient that starts from the quiescent state this drives the timestep into the sub-picosecond range. For a 4 µs run I get 257k timepoints, 99.9 % of them in the idle window before the first switching edge, median step 0.39 ps. Raising those resistors to 1e-5 Ω gives 432 timepoints and the same result to six digits.
A 1 µΩ resistor in a passive network is fine, and the same transistor is fine once the circuit has been excited, so it takes the combination of a BJT, a near-zero terminal resistance and a transient starting at rest. I have not chased it further.