Examples / TI op amp handbook / Basic amplifiers
Noninverting amplifier
SBOA092B page 53, The Non-Inverting Amplifier: EI on the non-inverting input, RO from the output to the inverting input and RI from there to ground.
E_O / E_I = (R_O + R_I) / R_I = 1 + 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/noninverting_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 (values): 10 kΩ and 90 kΩ, 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, total(1 * ratio, over(self.r_out.resistance, self.r_in.resistance))))What the simulation found
Section titled “What the simulation found”| Run | Measured | Claimed |
|---|---|---|
gain, operating point, E_I = 1 V | 10 | 10 (a_v), holds |
bandwidth, gain at 1 kHz | 10 | 10 (a_v), holds |
bandwidth, -3 dB point | 997.6 kHz | not a claim |
Here the noise gain is the signal gain, 10, so the 10 MHz op amp closes near 1 MHz. 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/noninverting_amplifier/noninverting_amplifier.pypython examples/regenerate.py ti_opamp_handbook/basic_amplifiers/noninverting_amplifier # needs ngspiceThe whole program
Section titled “The whole program”"""The non-inverting amplifier, SBOA092B page 53.Show 13 more lines
E_O / E_I = (R_O + R_I) / R_I = 1 + R_O / R_I
E_I goes in at the + input. R_O and R_I divide the output down to the -input, and the loop holds the - input at E_I, so the current E_I / R_I in R_Iis the current in R_O and the output stands E_I R_O / R_I above E_I. Thehandbook derives it by letting the open-loop gain go to infinity.
The figure names the two resistors and gives them no values, so `values`records the pair chosen here: 10 kOhm and 90 kOhm, a gain of +10. The benchdrives E_I with 1 V and reads E_O, then sweeps the frequency: the noise gainis the signal gain here, 10, so a 10 MHz op amp closes near 1 MHz."""
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, over, ratio, total,)
class NoninvertingAmplifier(System): """E_I on the + input; R_O from the output to the - input, R_I from there to ground."""
figure = Cites( "E_O / E_I = (R_O + R_I) / R_I = 1 + R_O / R_I", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 53, The Non-Inverting Amplifier", )
values = Chooses( "What are R_I and R_O?", selected="10 kOhm and 90 kOhm, for a gain of +10", alternatives=[ { "option": "10 kOhm and 100 kOhm, as in the inverting example", "reason": "gives 11, a gain nobody reads off at a glance", }, { "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() e_in_return = Terminal() e_out_return = Terminal() r_in = Resistor(resistance=10 * kOhm) r_out = Resistor(resistance=90 * kOhm) amp = OpAmp() ground = Ground()
def architecture(self): self.e_in.probe >> self.amp.non_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.inverting.signal >> self.r_in.p1 self.r_in.p2 >> self.ground.node self.e_in_return.probe >> self.ground.node self.e_out_return.probe >> self.ground.node
def constraints(self): require( equals(self.a_v, total(1 * ratio, over(self.r_out.resistance, self.r_in.resistance))) )
BENCH = Bench( page=53, title="The Non-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", "a_v", within=0.001)], units={"f_3db": "Hz"}, note=( "The -3 dB point is not a handbook claim: it is the op amp's, " "10 MHz over a noise gain of 10." ), ), ],)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 90 kOhm -TP1 Terminal -TP2 Terminal -TP3 Terminal -TP4 Terminal -U1 OpAmp -Net-(GND1-Pad1) GND1.1 R1.2 TP2.1 TP4.1Net-(R1-Pad1) R1.1 R2.1 U1.IN-Net-(R2-Pad2) R2.2 TP3.1 U1.OUTNet-(TP1-Pad1) TP1.1 U1.IN+Every check that ran, and every one left undecided.
1 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 8 component 16 connection 1 constraint 1 decision 1 evidence 3 interface 12 pin 12 port 55 totalsnapshot sha256:711a679e7230d16e189c92026cff39c5a9cc64137f4a00248d48baa3054fbfa9All of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/basic_amplifiers/noninverting_amplifier/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/basic_amplifiers/noninverting_amplifier/noninverting_amplifier.py