Examples / TI op amp handbook / Basic amplifiers
Inverting amplifier
SBOA092B page 54, The Inverting Amplifier: EI through RI into the summing point, RO from the output back to it, and the non-inverting input on ground.
E_O / E_I = -R_O / R_IThe 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/inverting_amplifier.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 the two resistors and gives them no values, so the program
chooses them and records the choice as a decision (values): 10 kΩ in and
100 kΩ across, for a gain of -10. The claim is a parameter, a_v = -10, and
one constraint holds it to the parts:
require(equals(self.a_v, negative(over(self.r_out.resistance, self.r_in.resistance))))Change either resistor and the check fails until a_v agrees.
What the simulation found
Section titled “What the simulation found”out/simulation.txt, from the two decks under
out/spice/:
| Run | Measured | Claimed |
|---|---|---|
gain, operating point, E_I = 1 V | -10 | -10 (a_v), holds |
bandwidth, gain at 1 kHz | 10 | 10, holds |
bandwidth, -3 dB point | 906.9 kHz | not a claim |
The handbook’s algebra lets the open-loop gain go to infinity. The bench’s op amp has 120 dB of it and 10 MHz of gain-bandwidth, so the DC gain lands within a part in 10^5 of -10, and the closed loop runs out near 10 MHz / 11, the noise gain. That corner is the op amp’s, not a claim of the handbook.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/basic_amplifiers/inverting_amplifier/inverting_amplifier.pypython examples/regenerate.py ti_opamp_handbook/basic_amplifiers/inverting_amplifier # needs ngspiceThe whole program
Section titled “The whole program”"""The inverting amplifier, SBOA092B page 54.Show 13 more lines
E_O / E_I = -R_O / R_I
The handbook derives it by letting the open-loop gain go to infinity, so theinverting input sits at ground and the current through R_I is the currentthrough R_O. The figure names the two resistors and gives them no values, so`values` records the pair chosen here: 10 kOhm in and 100 kOhm across, a gainof -10.
The bench drives E_I with 1 V and reads E_O, then sweeps the frequency to showwhere the claim stops holding: a 10 MHz op amp closed for a noise gain of 11has a bandwidth near 900 kHz, which the ideal algebra does not see."""
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, kOhm, requirefrom fang.parts import Resistorfrom fang.rationale import Chooses, Citesfrom fang.simulation import ACSweep, OperatingPoint
from handbook import ( Bench, Claim, Ground, OpAmp, Run, Terminal, equals, negative, over, ratio,)
class InvertingAmplifier(System): """E_I through R_I into the summing point, R_O back from the output."""
figure = Cites( "E_O / E_I = -R_O / R_I", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 54, The Inverting Amplifier", )
values = Chooses( "What are R_I and R_O?", selected="10 kOhm and 100 kOhm, for a gain of -10", alternatives=[ { "option": "leave them unknown", "reason": "a gain nobody can compute is not a claim anything can check", }, ], rationale=( "the figure names the resistors and gives no values", "a decade of gain keeps E_O far inside the swing for a 1 V drive", ), )
a_v = Parameter("1", default=-10 * ratio, description="E_O / E_I")
e_in = Terminal() e_out = Terminal() r_in = Resistor(resistance=10 * kOhm) r_out = Resistor(resistance=100 * kOhm) 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.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.a_v, negative(over(self.r_out.resistance, self.r_in.resistance))))
BENCH = Bench( page=54, title="The Inverting Amplifier", runs=[ Run( "gain", OperatingPoint(), drive={"e_in": "DC 1"}, measure={"gain": "v({e_out.1}) / v({e_in.1})"}, claims=[Claim("gain", "a_v", within=0.001)], ), Run( "bandwidth", ACSweep(points=20, start="10", stop="10meg"), drive={"e_in": "DC 0 AC 1"}, measure={ "gain_1k": "find vm({e_out.1}) at=1k", "f_3db": "when vdb({e_out.1})=17 fall=1", }, claims=[Claim("gain_1k", 10, within=0.001)], units={"f_3db": "Hz"}, note=( "The magnitude, so 10 rather than -10. The -3 dB point is " "not a handbook claim: it is the op amp's, 10 MHz over a noise " "gain of 11." ), ), ],)The files it writes
Section titled “The files it writes”The parts, then the nets and the pads on them.
GND1 Ground -R1 10 kOhm -R2 100 kOhm -TP1 Terminal -TP2 Terminal -U1 OpAmp -Net-(GND1-Pad1) GND1.1 U1.IN+Net-(R1-Pad1) R1.1 TP1.1Net-(R1-Pad2) R1.2 R2.1 U1.IN-Net-(R2-Pad2) R2.2 TP2.1 U1.OUTEvery check that ran, and every one left undecided.
1 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 6 component 12 connection 1 constraint 1 decision 1 evidence 3 interface 10 pin 10 port 45 totalsnapshot sha256:90fdbdd5e6dfc85266d9af0ab54257f27fb9e62b51c0542cb49361ecaeab75afAll of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/basic_amplifiers/inverting_amplifier/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/basic_amplifiers/inverting_amplifier/inverting_amplifier.py