Examples / TI op amp handbook / Integrators
Augmenting integrator
SBOA092B pages 59 and 60, Augmenting Integrator: EI through RI (10 kΩ) into the summing point, with RO (100 kΩ) in series with CO (10 µF) as the feedback. "Sums the input signal and its time integral."
E_O = -(R_O/R_I) E_I - 1/(C_O R_I) ∫ E_I dtThe circuit
Section titled “The circuit”The schematic is drawn by copperhead’s
drafting engine from this circuit’s netlist, with KiCad’s own library symbols,
and it opens in KiCad as figure/augmenting_integrator.kicad_sch.
The op amp is KiCad’s generic one, since the handbook’s are ideal, and each
terminal is a test point named as the program names it. KiCad reads back from
the sheet exactly the connections the circuit has; draw_figures.py refuses to write
one that does not.
The interconnect view is fang’s own projection. It names the parts as the program does, so it reads against the code below.
What the program says
Section titled “What the program says”Two parameters, gain = -10 (-R_O/R_I) and rate = -10 /s
(-1/(C_O R_I)), each held to the parts. The bench uses a 0.1 V step at
10 ms, starting from rest (bench). The proportional term shows up as a
jump and the integral as the ramp after it, so one waveform carries both.
What the simulation found
Section titled “What the simulation found”out/simulation.txt, from the deck under out/spice/:
| Run | Measured | Claimed |
|---|---|---|
step, the jump (ramp extrapolated back to the step) over E_I | -10 | -10 (gain), holds |
step, the slope after it over E_I | -10 /s | -10 /s (rate), holds |
The output is -1.1 V at 0.11 s and -2.0 V at 1.01 s: a jump to -1 V, then a fall of 1 V/s.
Where the handbook is off
Section titled “Where the handbook is off”The handbook evaluates the formula as “-10 E_I - ∫ E_I dt”. The first term is right. The second is not: C_O R_I is 10 µF × 10 kΩ = 0.1 s, so the integral has a coefficient of 10, not 1. To get 1 it would need C_O = 100 µF. The program claims the rate the parts give, and the simulation measures that rate.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/integrators/augmenting_integrator/augmenting_integrator.pypython examples/regenerate.py ti_opamp_handbook/integrators/augmenting_integrator # needs ngspiceThe whole program
Section titled “The whole program”"""The augmenting integrator, SBOA092B pages 59 and 60.Show 17 more lines
E_O = -(R_O/R_I) E_I - 1/(C_O R_I) integral E_I dt
R_I is 10 kOhm; the feedback is R_O (100 kOhm) in series with C_O (10 uF).The current E_I/R_I flows through both, so the output is the drop across R_O,-(R_O/R_I) E_I, plus the charge on C_O, -1/(C_O R_I) integral E_I dt: the inputand its integral, summed.
The handbook evaluates this as "-10 E_I - integral E_I dt". The first term isright, R_O/R_I = 10. The second is not: C_O R_I is 10 uF times 10 kOhm, 0.1 s,so the integral is multiplied by 10, not 1. The program holds the rate to theparts, -10 per second, and the simulation agrees with it.
The bench applies a 0.1 V step at 10 ms to an integrator at rest, so bothterms can be read off one waveform: the jump is the proportional part, theslope after it the integral."""
import sysfrom pathlib import Path
# The handbook's shared parts and bench live in the folder above the sections.sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from fang.lang import Parameter, System, UnitLiteral, kOhm, require, uFfrom fang.parts import Capacitor, Resistorfrom fang.rationale import Calculates, Chooses, Citesfrom fang.simulation import Transient
from handbook import ( Bench, Claim, Ground, OpAmp, Run, Terminal, equals, negative, over, product, ratio,)
#: A rate: volts of output per second, for each volt of input.per_second = UnitLiteral("1/s")
class AugmentingIntegrator(System): """E_I through R_I into the summing point; R_O and C_O in series back from the output."""
figure = Cites( "E_O = -(R_O E_I)/R_I - 1/(C_O R_I) integral E_I dt = -10 E_I - integral E_I dt. " "Sums the input signal and its time integral.", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="pages 59-60, Augmenting Integrator", )
integral_term = Calculates( "1/(C_O R_I) = 1/(10 uF x 10 kOhm)", inputs=("c_out", "r_in"), result=( "10 per second. The handbook's second line prints the integral with " "a coefficient of 1, which would need C_O R_I = 1 s (100 uF, or R_I " "= 100 kOhm, which would also change the first term to -1)" ), )
bench = Chooses( "What input shows both terms?", selected="a 0.1 V step at 10 ms, from rest", alternatives=[ { "option": "a sine", "reason": "the two terms add in quadrature and have to be separated again", }, ], rationale=( "a step makes the proportional term a jump and the integral a ramp, " "each read directly", ), )
gain = Parameter("1", default=-10 * ratio, description="-R_O/R_I, the proportional term") rate = Parameter("1/s", default=-10 * per_second, description="-1/(C_O R_I), the integral term")
e_in = Terminal() e_out = Terminal() r_in = Resistor(resistance=10 * kOhm) r_out = Resistor(resistance=100 * kOhm) c_out = Capacitor(capacitance=10 * uF) amp = OpAmp() ground = Ground()
def architecture(self): self.e_in.probe >> self.r_in.p1 self.r_in.p2 >> self.amp.inverting.signal self.amp.inverting.signal >> self.r_out.p1 self.r_out.p2 >> self.c_out.p1 self.c_out.p2 >> self.amp.output.signal self.amp.output.signal >> self.e_out.probe self.amp.non_inverting.signal >> self.ground.node
def constraints(self): require(equals(self.gain, negative(over(self.r_out.resistance, self.r_in.resistance)))) require( equals( self.rate, negative(over(1 * ratio, product(self.c_out.capacitance, self.r_in.resistance))), ) )
BENCH = Bench( page=60, title="Augmenting Integrator", runs=[ Run( "step", Transient(stop="1.01", step="1m"), drive={"e_in": "PWL(0 0 10m 0 10.001m 0.1)"}, measure={ "e_early": "find v({e_out.1}) at=0.11", "e_late": "find v({e_out.1}) at=1.01", "rate_per_volt": "(e_late - e_early) / 0.9 / 0.1", "gain_step": "(e_early - rate_per_volt * 0.1 * 0.1) / 0.1", }, claims=[ Claim("gain_step", "gain", within=0.001, note="the jump at the step: the ramp extrapolated back to 10 ms, over E_I"), Claim("rate_per_volt", "rate", within=0.001, unit="/s", note=( "the handbook prints the integral term as -integral E_I dt, a " "rate of -1/s; 1/(C_O R_I) = 1/(10 uF x 10 kOhm) is 10/s, and " "that is what the circuit does" )), ], units={"e_early": "V", "e_late": "V"}, note=( "E_I steps from 0 to 0.1 V at 10 ms. The output should jump to " "-1 V and fall 1 V/s after it: -10 E_I - 10 integral E_I dt." ), ), ],)The files it writes
Section titled “The files it writes”The parts, then the nets and the pads on them.
C1 10 uF -GND1 Ground -R1 10 kOhm -R2 100 kOhm -TP1 Terminal -TP2 Terminal -U1 OpAmp -Net-(C1-Pad1) C1.1 R2.2Net-(C1-Pad2) C1.2 TP2.1 U1.OUTNet-(GND1-Pad1) GND1.1 U1.IN+Net-(R1-Pad1) R1.1 TP1.1Net-(R1-Pad2) R1.2 R2.1 U1.IN-Every check that ran, and every one left undecided.
2 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 1 calculation 7 component 14 connection 2 constraint 1 decision 1 evidence 3 interface 12 pin 12 port 54 totalsnapshot sha256:772cb918c912ddea56586ad60ed8897da6e1ff6795cbd6983bb6f04bbec8eca5All of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/integrators/augmenting_integrator/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/integrators/augmenting_integrator/augmenting_integrator.py