Examples / TI op amp handbook / Integrators
Simple integrator
SBOA092B page 56, Simple Integrators (the first figure): EI through RI (100 kΩ) into the summing point, CO (1 µF) from the output back to it, and a switch across CO. "Close switch to reset to zero."
E_O = -1/(R_I C_O) ∫ E_I dt = -10 ∫ 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/simple_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”The claim is a parameter, rate = -10 /s (volts of output per second, per
volt of input), held to the parts by one constraint:
require(equals(self.rate, negative(over(1 * ratio, product(self.r_in.resistance, self.c_out.capacitance)))))The figure gives no drive and no timing for the switch, so the program records
the bench as a decision (bench): the switch is closed at t = 0 and opens at
10 ms, with a steady 0.1 V already on E_I. That makes a ramp of -1 V/s, which
stays inside the swing for the whole run.
What the simulation found
Section titled “What the simulation found”out/simulation.txt, from the deck under out/spice/:
| Run | Measured | Claimed |
|---|---|---|
ramp, output with the switch closed | -1 µV | 0 V ± 1 mV, holds |
ramp, slope from 0.1 s to 1.1 s over E_I | -10 /s | -10 /s (rate), holds |
While the switch is closed the 1 Ω across C_O holds the output at zero even with the input applied. Once it opens the output falls 1 V/s for 0.1 V in.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/integrators/simple_integrator/simple_integrator.pypython examples/regenerate.py ti_opamp_handbook/integrators/simple_integrator # needs ngspiceThe whole program
Section titled “The whole program”"""The simple integrator, SBOA092B page 56 (top).Show 13 more lines
E_O = -1/(R_I C_O) integral E_I dt = -10 integral E_I dt
R_I is 100 kOhm and C_O is 1 uF, so R_I C_O is 0.1 s and the output ramps at-10 V/s for every volt at the input. The switch across C_O is the reset: thehandbook says to close it to reset to zero.
The figure says nothing about when the switch opens or what E_I is, so theprogram had to decide the bench: the switch is closed at t = 0, which holds theoutput at zero while the input is already applied, and opens at 10 ms; E_I is asteady 0.1 V, so the ramp runs at -1 V/s and stays inside the swing for thewhole second the run lasts."""
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 Chooses, Citesfrom fang.simulation import Transient
from handbook import ( Bench, Claim, Ground, OpAmp, Run, Switch, Terminal, equals, negative, over, product, ratio,)
#: A rate: volts of output per second, for each volt of input.per_second = UnitLiteral("1/s")
class SimpleIntegrator(System): """E_I through R_I into the summing point, C_O back from the output, a switch across C_O."""
figure = Cites( "E_O = -(1/(R_I C_O)) integral E_I dt = -10 integral E_I dt. " "Close switch to reset to zero.", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 56, Simple Integrators", )
bench = Chooses( "How is the integrator reset and started?", selected=( "the switch closed at t = 0 and opened at 10 ms, with a steady 0.1 V " "already on E_I, so the ramp starts from zero when the switch opens" ), alternatives=[ { "option": "no switch, an initial condition on C_O", "reason": "the figure draws the switch, and the reset is what it is for", }, { "option": "a 1 V input", "reason": "at -10 V/s the output would reach the -13.5 V swing in 1.35 s", }, ], rationale=( "the handbook says only to close the switch to reset to zero", "0.1 V gives -1 V/s, a ramp that stays well inside the swing for the run", ), )
rate = Parameter( "1/s", default=-10 * per_second, description="dE_O/dt for each volt of E_I: -1/(R_I C_O)", )
e_in = Terminal() e_out = Terminal() r_in = Resistor(resistance=100 * kOhm) c_out = Capacitor(capacitance=1 * uF) reset = Switch() 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.c_out.p1 self.c_out.p1 >> self.reset.p1 self.c_out.p2 >> self.amp.output.signal self.reset.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.rate, negative(over(1 * ratio, product(self.r_in.resistance, self.c_out.capacitance))), ) )
BENCH = Bench( page=56, title="Simple Integrators", runs=[ Run( "ramp", Transient(stop="1.1", step="1m"), drive={"e_in": "DC 0.1"}, switches={"reset": "PWL(0 1 10m 1 10.001m 0)"}, measure={ "held": "find v({e_out.1}) at=5m", "e_early": "find v({e_out.1}) at=0.1", "e_late": "find v({e_out.1}) at=1.1", "rate_per_volt": "(e_late - e_early) / 1.0 / 0.1", }, claims=[ Claim("held", 0, within=1e-3, absolute=True, unit="V", note="the switch is closed: the output sits at zero with the input applied"), Claim("rate_per_volt", "rate", within=0.001, unit="/s"), ], units={"e_early": "V", "e_late": "V"}, note=( "E_I is 0.1 V throughout; the reset switch opens at 10 ms. The slope " "is taken between 0.1 s and 1.1 s and divided by E_I." ), ), ],)The files it writes
Section titled “The files it writes”The parts, then the nets and the pads on them.
C1 1 uF -GND1 Ground -R1 100 kOhm -SW1 Switch -TP1 Terminal -TP2 Terminal -U1 OpAmp -Net-(C1-Pad1) C1.1 R1.2 SW1.1 U1.IN-Net-(C1-Pad2) C1.2 SW1.2 TP2.1 U1.OUTNet-(GND1-Pad1) GND1.1 U1.IN+Net-(R1-Pad1) R1.1 TP1.1Every check that ran, and every one left undecided.
1 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 7 component 16 connection 1 constraint 1 decision 1 evidence 3 interface 12 pin 12 port 54 totalsnapshot sha256:0e350f79f4cf2033caa90ee98cfebf0327cc9af403a56d79b96ccf0dc0e558edAll of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/integrators/simple_integrator/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/integrators/simple_integrator/simple_integrator.py