Skip to content
copperhead.sh
Get started

Examples / TI op amp handbook / DC amplifiers

Simple non inverting

SBOA092B page 71, Simple Non-Inverting: EI on the + input, RO 90 kΩ from the output to the - input and RI 10 kΩ from there to ground.

E_O = (R_O + R_I) / R_I x E_I = 10 E_I
the schematic, drawn by copperhead from the circuit's netlist
The schematic, drawn by copperhead from the circuit's netlist

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_non_inverting.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, fang's own projection
The interconnect view, fang's own projection

The interconnect view is fang’s own projection. It names the parts as the program does, so it reads against the code below.

The figure gives both values, so nothing is chosen. The claim is a parameter, a_v = 10, held to the parts by one constraint:

require(equals(self.a_v, over(total(self.r_out.resistance, self.r_in.resistance), self.r_in.resistance)))

out/simulation.txt, from the decks under out/spice/:

RunMeasuredClaimed
gain, operating point, E_I = 1 V1010 (a_v), holds
gain, the - input1 V1 V, holds
swing, E_O at E_I = 1 V in a sweep10 V10 (a_v), holds
swing, highest E_O13.51 V13.5 V, holds
swing, lowest E_O-13.51 V-13.5 V, holds

Both inputs sit at E_I, which is why the page warns about the common-mode limit. The bench’s op amp has no such limit, so the sweep shows the limit it does have: the output stops at its ±13.5 V swing once E_I passes 1.35 V.

Terminal window
fang check examples/ti_opamp_handbook/dc_amplifiers/simple_non_inverting/simple_non_inverting.py
python examples/regenerate.py ti_opamp_handbook/dc_amplifiers/simple_non_inverting # needs ngspice
examples/ti_opamp_handbook/dc_amplifiers/simple_non_inverting/simple_non_inverting.py
"""The simple non-inverting amplifier, SBOA092B page 71.
Show 12 more lines
E_O = (R_O + R_I) / R_I x E_I = 10 E_I
E_I goes straight to the + input, and R_O and R_I divide the output back to
the - input. The figure gives the values, 90 kOhm and 10 kOhm, so there is
nothing to choose: the gain is 100k / 10k = 10.
The page warns that the input common-mode limit must be observed, because
both inputs follow E_I. The macro-model has no common-mode limit, so the
bench shows the other limit it does have: the output swing, which a 1.35 V
input already reaches.
"""
import sys
from 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, require
from fang.parts import Resistor
from fang.rationale import Cites
from fang.simulation import DCSweep, OperatingPoint
from handbook import (
Bench,
Claim,
Ground,
OpAmp,
Run,
Terminal,
equals,
over,
ratio,
total,
)
class SimpleNonInverting(System):
"""E_I on the + input, R_O and R_I dividing the output back to the - input."""
figure = Cites(
"E_O = (R_O + R_I) / R_I E_I = 10 E_I; input common mode voltage limit must be observed",
document="SBOA092B, Handbook of Operational Amplifier Applications",
locator="page 71, Simple Non-Inverting",
)
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=90 * kOhm)
amp = OpAmp()
ground = Ground()
def architecture(self):
self.e_in.probe >> self.amp.non_inverting.signal
self.amp.inverting.signal >> self.r_in.p1
self.r_in.p2 >> self.ground.node
self.amp.inverting.signal >> self.r_out.p1
self.r_out.p2 >> self.amp.output.signal
self.amp.output.signal >> self.e_out.probe
def constraints(self):
require(
equals(
self.a_v,
over(total(self.r_out.resistance, self.r_in.resistance), self.r_in.resistance),
)
)
BENCH = Bench(
page=71,
title="Simple Non-Inverting",
runs=[
Run(
"gain",
OperatingPoint(),
drive={"e_in": "DC 1"},
measure={
"gain": "v({e_out.1}) / v({e_in.1})",
"e_minus": "v({amp.IN-})",
},
claims=[
Claim("gain", "a_v", within=0.001),
Claim(
"e_minus",
1,
within=0.001,
unit="V",
note="the - input follows E_I: both inputs sit at the input voltage, which is the common-mode limit the page warns of",
),
],
),
Run(
"swing",
DCSweep(source="VDRIVE_e_in", start="-2", stop="2", step="0.01"),
drive={"e_in": "DC 0"},
measure={
"e_out_top": "max v({e_out.1})",
"e_out_bottom": "min v({e_out.1})",
"gain_at_1v": "find v({e_out.1}) at=1",
},
claims=[
Claim("gain_at_1v", "a_v", within=0.001, note="E_O at E_I = 1 V, so the gain"),
Claim("e_out_top", 13.5, within=0.01, unit="V", note="the macro-model's swing, reached at E_I = 1.35 V; its clamp diode lets it pass by a few mV, hence 1%"),
Claim("e_out_bottom", -13.5, within=0.01, unit="V"),
],
note="A sweep of E_I from -2 V to 2 V. The output is linear at 10 E_I until it meets the +/-13.5 V swing.",
),
],
)

The parts, then the nets and the pads on them.

out/netlist.txt
GND1 Ground -
R1 10 kOhm -
R2 90 kOhm -
TP1 Terminal -
TP2 Terminal -
U1 OpAmp -
Net-(GND1-Pad1) GND1.1 R1.2
Net-(R1-Pad1) R1.1 R2.1 U1.IN-
Net-(R2-Pad2) R2.2 TP2.1 U1.OUT
Net-(TP1-Pad1) TP1.1 U1.IN+

Every check that ran, and every one left undecided.

out/checks.txt
1 checks, 0 failed, 0 undecided

What the elaborated graph contains, by entity kind.

out/graph.txt
1 block
6 component
12 connection
1 constraint
1 evidence
3 interface
10 pin
10 port
44 total
snapshot sha256:40d61acb4945d07baebb05221009f5568432848799e5d6e394e66ae650c196f7

All of it, including the KiCad netlist, is in examples/ti_opamp_handbook/dc_amplifiers/simple_non_inverting/out/. Rebuild it with:

Terminal window
fang build examples/ti_opamp_handbook/dc_amplifiers/simple_non_inverting/simple_non_inverting.py