Examples / TI op amp handbook / Integrators
Summing integrator
SBOA092B page 58, Summing Integrator: E1, E2 and E3 each through 100 kΩ into one summing point, CO (1 µF) across the op amp, and a reset switch across CO.
E_O = -1/(RC) ∫ (E1 + E2 + E3) dt = -10 ∫ (E1 + E2 + E3) 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/summing_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”One parameter, rate = -10 /s. There are three constraints, one for each
input resistor, and each says its own -1/(R C_O) is that same rate. The
figure gives no drive, so the program chooses two (bench). The first puts
0.1, 0.2 and 0.3 V on the inputs. The second uses 0.5, -0.2 and 0.1 V, so
one input has the opposite sign. The reset switch opens at 10 ms in both.
What the simulation found
Section titled “What the simulation found”out/simulation.txt, from the decks under out/spice/:
| Run | Sum | Output slope | Slope over sum | Claimed |
|---|---|---|---|---|
sum | 0.6 V | -6 V/s | -10 /s | -10 /s (rate), holds |
mixed_signs | 0.4 V | -4 V/s | -10 /s | -10 /s (rate), holds |
The output follows the algebraic sum of the inputs, whatever their signs.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/integrators/summing_integrator/summing_integrator.pypython examples/regenerate.py ti_opamp_handbook/integrators/summing_integrator # needs ngspiceThe whole program
Section titled “The whole program”"""The summing integrator, SBOA092B page 58 (top).Show 13 more lines
E_O = -1/(RC) integral (E1 + E2 + E3) dt = -10 integral (E1 + E2 + E3) dt
Three 100 kOhm inputs meet at the summing point, C_O is 1 uF, and a switchacross C_O resets it. Each input puts E_n/100k into the summing point and C_Ointegrates the sum, so the output ramps at -10 V/s for every volt ofE1 + E2 + E3.
The bench is the program's to choose: the reset switch closed at t = 0 andopened at 10 ms, and the inputs steady from the start. One run puts 0.1, 0.2and 0.3 V on the three inputs; a second mixes the signs, 0.5, -0.2 and 0.1 V,so the claim is about the sum and not about each input on its own."""
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")
#: The reset: closed at t = 0, open from 10 ms.RESET = "PWL(0 1 10m 1 10.001m 0)"
class SummingIntegrator(System): """Three inputs through 100 kOhm each into one summing point, C_O across the op amp."""
figure = Cites( "E_O = -1/(RC) integral (E1 + E2 + E3) dt = -10 integral (E1 + E2 + E3) dt. " "One amplifier replaces separate summer and integrator circuits.", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 58, Summing Integrator", )
bench = Chooses( "What goes on the three inputs, and when does the integrator start?", selected=( "steady inputs whose sum is 0.6 V in one run and 0.4 V (with one " "negative input) in another; the reset switch opens at 10 ms" ), alternatives=[ { "option": "one input at a time", "reason": "that checks three integrators, not that the inputs are summed", }, ], rationale=( "the figure gives the parts and no drive", "a mixed-sign run shows the output follows the algebraic sum", ), )
rate = Parameter( "1/s", default=-10 * per_second, description="dE_O/dt for each volt of E1 + E2 + E3: -1/(R C_O), the three R equal", )
e1 = Terminal() e2 = Terminal() e3 = Terminal() e_out = Terminal() r1 = Resistor(resistance=100 * kOhm) r2 = Resistor(resistance=100 * kOhm) r3 = Resistor(resistance=100 * kOhm) c_out = Capacitor(capacitance=1 * uF) reset = Switch() amp = OpAmp() ground = Ground()
def architecture(self): self.e1.probe >> self.r1.p1 self.e2.probe >> self.r2.p1 self.e3.probe >> self.r3.p1 self.r1.p2 >> self.amp.inverting.signal self.r2.p2 >> self.amp.inverting.signal self.r3.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): # Each input has its own rate; the claim is that they are the same one. for r in (self.r1, self.r2, self.r3): require( equals( self.rate, negative(over(1 * ratio, product(r.resistance, self.c_out.capacitance))), ) )
def _ramp(name: str, e1: float, e2: float, e3: float, note: str) -> Run: total = e1 + e2 + e3 return Run( name, Transient(stop="1.1", step="1m"), drive={"e1": f"DC {e1}", "e2": f"DC {e2}", "e3": f"DC {e3}"}, switches={"reset": RESET}, measure={ "e_early": "find v({e_out.1}) at=0.1", "e_late": "find v({e_out.1}) at=1.1", "rate_per_volt": f"(e_late - e_early) / 1.0 / {total:g}", }, claims=[Claim("rate_per_volt", "rate", within=0.001, unit="/s")], units={"e_early": "V", "e_late": "V"}, note=note, )
BENCH = Bench( page=58, title="Summing Integrator", runs=[ _ramp( "sum", 0.1, 0.2, 0.3, "E1 + E2 + E3 = 0.6 V, so the output falls 6 V/s once the switch " "opens at 10 ms. The slope over 0.1 s to 1.1 s, divided by 0.6 V, is the rate.", ), _ramp( "mixed_signs", 0.5, -0.2, 0.1, "E1 + E2 + E3 = 0.4 V with E2 negative: the output falls 4 V/s, " "the rate of the algebraic sum.", ), ],)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 -R2 100 kOhm -R3 100 kOhm -SW1 Switch -TP1 Terminal -TP2 Terminal -TP3 Terminal -TP4 Terminal -U1 OpAmp -Net-(C1-Pad1) C1.1 R1.2 R2.2 R3.2 SW1.1 U1.IN-Net-(C1-Pad2) C1.2 SW1.2 TP4.1 U1.OUTNet-(GND1-Pad1) GND1.1 U1.IN+Net-(R1-Pad1) R1.1 TP1.1Net-(R2-Pad1) R2.1 TP2.1Net-(R3-Pad1) R3.1 TP3.1Every check that ran, and every one left undecided.
3 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 11 component 24 connection 3 constraint 1 decision 1 evidence 3 interface 18 pin 18 port 80 totalsnapshot sha256:97f7698c80f1e592121f4a2e134ae41a8733ffe425f12f489e840256170583cfAll of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/integrators/summing_integrator/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/integrators/summing_integrator/summing_integrator.py