Simulating opamps by hand


Sometimes you need to simulate an opamp by hand to figure why is it doing some thing or the other. So you start from the definition: V_out = A * (V+ - V-) and use it for our particular case: V_out = A * (V+ - V_out) if you solve it algebraically, it gives you the correct answer: V_out = A / (A + 1) * V+ The bad news is that the same method gives you the answer for buffer with a _positive_ feedback, which in reality wouldn't work: V_out = A / (A - 1) * V- Something is missing.
falstad circuit simulator has the same problem
If you decide to solve this equation iterativelly instead of algebraically, it will diverge quickly (but it will probably hit the rails before reaching the petavolts shown below): >>> Vout = 4 >>> Vplus = 4.3 >>> A = 100 >>> for _ in range(10): ... Vout = A * (Vplus - Vout) ... print(Vout) ... 29.999999999999982 -2569.999999999998 257429.99999999983 -25742569.999999985 2574257429.9999986 -257425742569.99985 25742574257429.984 -2574257425742568.5 2.574257425742573e+17 -2.574257425742573e+19 It seems that the high amplification factor will amplify every error on input beyond any reasonable value. Only if the reaction of the amplifier to errors could be a little "tamer". Say limit the change per iteration (simulation step) to something significantly smaller than the amplification factor! For example, let's limit the reaction to error of "1" to "0.5" after amplification: >>> def limit(old, new, max_diff): ... if new < old: ... return max(new, old - max_diff) ... else: ... return min(new, old + max_diff) ... >>> limit(5, 6, 0.2) 5.2 >>> limit(5, 4, 0.2) 4.8 >>> ... Vout = 4 >>> Vplus = 4.3 >>> A = 100 >>> for _ in range(100): ... Vout = limit(Vout, A * (Vplus - Vout), 1 / (A * 2)) ... print(Vout) ... 4.005 4.01 4.015 4.02 4.0249999999999995 4.029999999999999 4.034999999999999 4.039999999999999 ... 4.254999999999995 4.2599999999999945 4.254999999999995 4.2599999999999945 That's almost the algebraical solution (100/101*4.3 = 4.257...). With the new simulation the example with positive feedback will slowly but relentlessly fuck off towards the rail. >>> Vout = 4 >>> Vplus = 4.3 >>> A = 100 >>> for _ in range(100): ... Vout = limit(Vout, A * (Vout - Vplus), 1 / (A * 2)) ... print(Vout) ... 3.995 3.99 3.9850000000000003 3.9800000000000004 ... 3.5050000000000106 ... -1.4199999999999287 -1.4249999999999285 So real op-amps have a thing called "slew rate" which is usually specified in V per us, which is the maximal rate of change they are willing to output in given time. This is not as much technological constrain as the core of how they operate: op-amp works by slowly changing its output in the direction of the error and waiting for the feedback to signal whether it had reached its desired goal.
pink is amp input, yellow amp output
This of course has several problems. One of it is that the feedback function has to be quick enough, so that the op-amp has a change to settle. If we introduce just enough delay in the feedback loop, we will get this:
delay in feedback, circuit at the end
The good thing is that the opamp "algorithm" works very well with all sorts of feedback functions, provided that the feedback does increase/decrease the difference in the correct direction.
falstad
This circuit sets whatever voltage drop on transistor R1 (in this case 1V, thus we want 5-1=4 V at point X). You get 1V over that transistor no matter the R2 transistor (up to a limit) and no matter the diode drop the transistor requires, all through the magic of feedback. Also note: this op-amp configuration has feedback via the "plus" pin, because the higher the opamp sets its output, the lower goes the voltage in point "X" (and if you are like me, you might have had associated the "+" and "-" inputs of opamp with "positive" and "negative" feedback, with which they have nothing in common). [TODO: put here some interesting feedback circuits] General-purpose opamps has slew rate around 1V/us, which limits how many "analog operations" per second you can do, or the limit on signal frequency it can amplify (ie. you want the buffered sine signal to go 0...5V...0, you can do this only 100_000 times per second, which means max. 100 KHz signals). Also: the op-amp with which I'm testing this (MCP6002) has a slight delay before it changes its output:
how did it get there?
I'm not sure why, it's likely that this is for noise reduction. If you feed it with PWM fast enought (and with low duty cycle), you will get nothing on output:
mcp6002
It's also quite useful for simulating delay - I connected four op-amps like this to produce the image with opamp trying to catch up:
Anyway, that's all I wanted to say.