Examples / TI op amp handbook / Integrators
Integrator
SBOA092B page 55, Integrators: the inverting amplifier with a capacitor in place of its feedback resistor. EI through RI into the summing point, CO from the output back to it.
E_O = -Z_O/Z_I E_I = -E_I/(R_I C_O p) = -1/(R_I C_O) ∫ 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/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 figure names R_I and C_O and gives no values. The program chooses 10 kΩ
and 0.1 µF (values): R_I C_O = 1 ms, a rate of -1000 V/s per volt, and a
gain of 1 at 159 Hz. Two parameters carry the claims, rate = -1000 /s and
f_unity = 159.15 Hz, each held to the parts by a constraint.
The figure has no reset, so the transient run starts the output at zero with
an initial condition (start). Without one, an integrator starts wherever the
solver puts it.
What the simulation found
Section titled “What the simulation found”out/simulation.txt, from the decks under out/spice/:
| Run | Measured | Claimed |
|---|---|---|
ramp, 10 mV DC step, slope over E_I | -1000 /s | -1000 /s (rate), holds |
sine, gain at 159.155 Hz | 1 | 1, holds |
sine, gain at 15.9155 Hz | 10 | 10, holds |
sine, phase at 159 Hz | 90° | 90°, holds |
The gain is 1/(2π f R_I C_O): it falls a decade per decade of frequency. The phase is +90°, not -90°. The integral lags the input by 90° and the inversion adds 180°, so the output leads the input by 90°.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/integrators/integrator/integrator.pypython examples/regenerate.py ti_opamp_handbook/integrators/integrator # needs ngspiceThe whole program
Section titled “The whole program”"""The integrator, SBOA092B page 55.Show 14 more lines
E_O = -Z_O/Z_I E_I = -E_I/(R_I C_O p) = -1/(R_I C_O) integral E_I dt
The handbook gets it from the inverting amplifier by putting a capacitor whereR_O was: Z_O = 1/(C_O p), with p the operator d/dt, or j 2 pi f for a sine.The figure names R_I and C_O and gives them no values, so `values` records thepair chosen here: 10 kOhm and 0.1 uF, R_I C_O = 1 ms, a rate of -1000 V/s pervolt and a gain of 1 at 159 Hz.
The figure has no reset, and an integrator with nothing across its capacitorkeeps whatever it starts with, so the transient run starts it at zero with aninitial condition (`.ic`) on the output and the summing point. That is thebench's, not the circuit's."""
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 Hz, Parameter, System, UnitLiteral, kOhm, require, uFfrom fang.parts import Capacitor, Resistorfrom fang.rationale import Chooses, Citesfrom fang.simulation import ACSweep, Transient
from handbook import ( Bench, Claim, Ground, OpAmp, Run, Terminal, corner, equals, negative, over, product, ratio, within,)
#: A rate: volts of output per second, for each volt of input.per_second = UnitLiteral("1/s")
class Integrator(System): """E_I through R_I into the summing point, C_O back from the output."""
figure = Cites( "E_O = -Z_O/Z_I E_I = -E_I/(R_I C_O p) = -1/(R_I C_O) integral E_I dt", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 55, Integrators", )
values = Chooses( "What are R_I and C_O?", selected="10 kOhm and 0.1 uF: R_I C_O = 1 ms, -1000 V/s per volt, unity gain at 159 Hz", alternatives=[ { "option": "100 kOhm and 1 uF, as on page 56", "reason": "page 56 is its own program; a different pair shows the formula is general", }, { "option": "leave them unknown", "reason": "a rate nobody can compute is not a claim anything can check", }, ], rationale=( "the figure names the parts and gives no values", "a unity-gain frequency in the audio band is far below the op amp's " "10 MHz, so the ideal algebra is what the bench should measure", ), )
start = Chooses( "Where does the output start?", selected="at zero, from an initial condition the transient run sets", alternatives=[ { "option": "a reset switch", "reason": "the page 55 figure draws none; pages 56 onward add one", }, ], rationale=( "with nothing across C_O the op amp integrates any offset, so the " "starting point has to be said rather than left to the solver", ), )
rate = Parameter("1/s", default=-1000 * per_second, description="-1/(R_I C_O)") f_unity = Parameter( "Hz", default=159.15 * Hz, description="where |E_O/E_I| = 1/(2 pi f R_I C_O) comes to 1", )
e_in = Terminal() e_out = Terminal() r_in = Resistor(resistance=10 * kOhm) c_out = Capacitor(capacitance=0.1 * 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.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): rc = product(self.r_in.resistance, self.c_out.capacitance) require(equals(self.rate, negative(over(1 * ratio, rc)))) # 1/(2 pi 1 ms) is 159.155 Hz; the parameter is written to five figures. require(within(self.f_unity, corner(self.r_in.resistance, self.c_out.capacitance), 0.0001))
BENCH = Bench( page=55, title="Integrators", runs=[ Run( "ramp", Transient(stop="10m", step="10u"), drive={"e_in": "DC 0.01"}, cards=[".ic v({amp.OUT})=0 v({amp.IN-})=0"], measure={ "e_1ms": "find v({e_out.1}) at=1m", "e_9ms": "find v({e_out.1}) at=9m", "rate_per_volt": "(e_9ms - e_1ms) / 8m / 0.01", }, claims=[Claim("rate_per_volt", "rate", within=0.001, unit="/s")], units={"e_1ms": "V", "e_9ms": "V"}, note=( "A DC step of 10 mV, the output started at zero by `.ic`. It " "ramps at -10 V/s; the slope over 1 ms to 9 ms, divided by E_I, " "is the rate." ), ), Run( "sine", ACSweep(points=20, start="1", stop="100k"), drive={"e_in": "DC 0 AC 1"}, measure={ "gain_unity": "find vm({e_out.1}) at=159.155", "gain_15hz9": "find vm({e_out.1}) at=15.9155", "phase_rad": "find vp({e_out.1}) at=159.155", "phase_deg": "phase_rad * 180 / pi", }, claims=[ Claim("gain_unity", 1, within=0.001, note="at f_unity, 1/(2 pi f R_I C_O) is 1"), Claim("gain_15hz9", 10, within=0.001, note="a decade lower the gain is ten times higher"), Claim("phase_deg", 90, within=0.1, absolute=True, note=( "E_O/E_I = -1/(j 2 pi f R_I C_O) = +j/(2 pi f R_I C_O): the " "integral lags the input by 90 degrees and the inversion " "adds 180, so the output leads by 90" )), ], units={"phase_rad": ""}, ), ],)The files it writes
Section titled “The files it writes”The parts, then the nets and the pads on them.
C1 0.1 uF -GND1 Ground -R1 10 kOhm -TP1 Terminal -TP2 Terminal -U1 OpAmp -Net-(C1-Pad1) C1.1 R1.2 U1.IN-Net-(C1-Pad2) C1.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.
2 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 6 component 12 connection 2 constraint 2 decision 1 evidence 3 interface 10 pin 10 port 47 totalsnapshot sha256:16000664b7de374db6c6857d6d547d2ff5f6e0fe7381d12bf60a339f567eb096All of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/integrators/integrator/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/integrators/integrator/integrator.py