PREFACE: Make sure to always set .options plotwinsize=0
when analyzing quirky things like these.
The LTC6268 model has some internal signals coupled to ground.
However, other op amps exhibit the same issue, to varying degrees.
Even a single BJT configured as a common collector (voltage follower)
amplifier demonstrates the effect.
I think there are two mechanisms that are being conflated here. First, your instinct is correct when considering the LTC6268. Here is the subcircuit which ships with LTspice (found in LTC2.lib
).
.subckt LTC6268 1 2 3 4 5 6
A1 2 REF 0 0 0 0 0 0 OTA g=0 in=1p*uplim((freq/20Meg)**.9,3,.2)*dnlim((freq/60Meg)**1.5,1,.2)
B1 0 N004 I=10u*dnlim(uplim(V(1),V(4)-.4,.1), V(5)-.2, .1)+1n*V(1)-7.501009n
B2 N004 0 I=10u*dnlim(uplim(V(2),V(4)-.39,.1), V(5)-.21, .1)+1n*V(2)
C10 N004 0 .1f Rpar=100K noiseless
M1 3 N010 5 5 NI temp=27
C2 4 3 10f
M2 3 N005 4 4 PI temp=27
C3 4 N005 10f Rser=5Meg noiseless
C11 3 5 10f
C12 N010 5 10f Rser=5Meg noiseless
D6 N010 5 DLIMN
A4 0 N004 0 0 0 0 N006 0 OTA g=1m linear en=4n*dnlim((120k/freq)**.342,1,.1)*dnlim((2Meg/freq)**.1,1,.1)*dnlim((freq/40Meg)**.35,1,.1) Vhigh=1e308 Vlow=-1e308
C16 N008 3 .9p
G1 5 N010 N008 REF 100n
C7 4 1 225f
C17 0 N006 120f Rpar=1k noiseless
G4 0 N007 N006 0 1m
D14 4 N005 DLIMP
C4 2 1 100f
A6 N007 0 N009 REF REF REF N008 REF OTA g=2.5m asym isource=256u isink=-410u Rout=40k Vlow=-1e308 Vhigh=1e308
D9 4 6 DSHUT
A5 REF N008 N013 REF REF REF N005 REF OTA g=100n ref=-150m linear Vlow=-1e308 Vhigh=1e308
C14 4 5 20p Rpar=12.8k noiseless
S4 4 5 N013 REF SWP
C13 4 5 10p
A3 6 5 REF REF REF REF N013 REF SCHMITT vt=1.2 vh=.2 trise=900n tfall=800n
G2 0 REF 4 0 50m
G3 0 REF 5 0 50m
C19 REF 0 100p Rpar=10 noiseless
GESD1 2 4 2 4 1 vto=600m dir=1
GESD2 5 2 5 2 1 vto=600m dir=1
GESD3 1 4 1 4 1 vto=600m dir=1
GESD4 5 1 5 1 1 vto=600m dir=1
D1 3 4 DESD
D2 5 3 DESD
C1 4 2 225f
C5 1 5 225f
C6 2 5 225f
C8 0 N007 120f Rpar=1k noiseless
A2 1 REF 0 0 0 0 0 0 OTA g=0 in=1p*uplim((freq/20Meg)**.9,3,.2)*dnlim((freq/60Meg)**1.5,1,.2)
A7 N013 REF REF REF REF REF N009 REF BUF trise=100n
.model NI VDMOS(Vto=300m kp=100m lambda=.01)
.model PI VDMOS(Vto=-300m kp=100m lambda=.01 pchan is=0)
.model DSHUT D(Ron=1k Roff=1g Vfwd=.6 epsilon=100m ilimit=2u noiseless)
.model DIN D(Ron=300 Roff=100g Vfwd=.8 Vrev=.8 epsilon=100m revepsilon=100m noiseless)
.model DLIMP D(Ron=100k Roff=100Meg Vfwd=1.4 Vrev=340m epsilon=200m revepsilon=100m noiseless)
.model DLIMN D(Ron=1Meg Roff=100Meg Vfwd=800m Vrev=340m epsilon=200m revepsilon=100m noiseless)
.model SWP SW(Roff=1G Ron=500 vt=.5 vh=-.1 ilimit=5.6m noiseless)
.model DESD D(Ron=100 Roff=100T Vfwd=1 epsilon=50m noiseless)
.ends LTC6268
Notice all the explicit references to the zero node? Just as you called it. Also, harder to see are the B-source expressions containing voltages of single nodes, such as V(5)
, which always assume the zero node as the 2nd node. Unfortunately, if you peruse through some of the other subcircuits in the same file you'll find a lot of the same stuff.
So let's move onto your BJT voltage follower. You didn't show an explicit example, so here's my recreation of one. The discrepancy here is much less severe than with the LTC6268 and also oddly symmetric. Another important clue is that as you reduce the maximum timestep the output swing shrinks dramatically.
Weird symmetric oscillations like these can sometimes be due to the numerical integration method so I thought to try .options method=gear
. Sure enough, the oscillations go away regardless of maximum timestep.
One would think that the integration method shouldn't have any effect, since there are no capacitors or inductors to integrate (default NPN
model has these all set to zero). However, it's important to understand that LTspice's default method of "modified trap" is really a post-processing step applied to any transient simulation. Also, according to the built-in LTspice Help page titled "Integration Methods" modified trap can introduce:
...a small error in the saved value, which increases with increasing
time step. If this error is unacceptable, use trap integration
instead. In the majority of cases, the elimination of trap ringing far
outweighs the small loss of accuracy.
This explains why the larger timestep accumulates more error.
With this sorted out, let's go back to your LTC6268 circuit to confirm this is a separate mechanism than the internally referenced zero nodes.
OK. The Gear integration method didn't change anything, so this checks out. But what do you do if you wanna use an actual opamp that's immune to this? You have a couple options that I know of. First, you can use a transistor-based model. For example, there is an educational example that ships with LTspice named LM741.asc
. You can export this schematic's netlist and turn it into a subcircuit like so:
.subckt LM741 IN+ IN- VCC VEE OUT
Q1 N001 IN+ N007 0 NP
Q2 N001 IN- N008 0 NP
Q5 N010 N009 N008 0 PN
Q6 N012 N009 N007 0 PN
Q7 N012 N015 N017 0 NP
Q8 N010 N015 N018 0 NP
Q3 VCC N012 N015 0 NP
Q4 N001 N001 VCC 0 PN
R1 N017 VEE 1K
R2 N015 VEE 50K
R3 N018 VEE 1K
Q9 N009 N001 VCC 0 PN
Q10 N002 N002 VCC 0 PN
Q11 N003 N002 VCC 0 PN
Q12 N013 N013 VEE 0 NP
Q13 N009 N013 N019 0 NP
R4 N019 VEE 5K
Q14 N003 N004 N006 0 NP
Q15 N006 N014 N016 0 NP
Q16 N006 N010 N014 0 NP
R5 N014 VEE 50K
R6 N016 VEE 50
Q17 N010 N016 VEE 0 NP
C1 N003 N010 30p
R7 N006 N004 7.5K
R8 N003 N004 4.5K
Q18 VCC N003 N005 0 NP
Q19 VEE N006 N011 0 PN
R9 N005 OUT 25
R10 OUT N011 50
Q20 N003 N005 OUT 0 NP
R13 N002 N013 39K
.model NP NPN(BF=125 Cje=.5p Cjc=.5p Rb=500)
.model PN LPNP(BF=25 Cje=.3p Cjc=1.5p Rb=250)
.ends
You can then use the opamp2
symbol to use this subcircuit in your simulation. If we do that, the discrepancy that was there when using the LTC6268 is gone and you're left with only a teeny bit of numerical noise from the solver. We still need the .options method=gear
or need to set a super tiny maximum timestep since this model is built from BJTs (as discussed above).
There is another more versatile option I know of, and it doesn't appear to rely on the integration method or the maximum timestep. A few years ago, I wrote a generic opamp subcircuit which tries to match LTspice's built-in "UniversalOpamp2". I wrote it for the KiCad/ngspice project to give users a universal opamp to use in their simulations. One of the main goals of the subcircuit was to make sure it's completely floating from the zero node such that you can add noise sources to your VCC/VEE pins if needed. You can import this subcircuit into LTspice since I made sure it was also LTspice compatible. Doing so also results in what you would expect: