Skip to content
copperhead.sh
Get started

Examples / TI op amp handbook / DC amplifiers

Simple inverting

SBOA092B page 70, Simple Inverting sign changing amplifier: the inverting amplifier with values. RI = 1 kΩ in, RO = 100 kΩ across, the + input on ground.

E_O = -(R_O / R_I) E_I = -100 E_I
resistor = R_O R_I / (R_I + R_O) = 1 kΩ
Z_in = R_I = 1 kΩ
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_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 resistors are the figure’s, so the gain and input impedance need no choice: a_v = -R_O/R_I = -100 and z_in = R_I = 1 kΩ.

The page’s third line, “resistor”, names a part the figure does not draw. It is the bias-compensation resistor that normally goes from the + input to ground, sized to R_O ∥ R_I so both input bias currents drop the same voltage. The program builds the figure as drawn, with the + input straight to ground, and keeps the value as a parameter, r_compensation, held to R_O ∥ R_I = 990.1 Ω and within 1% of the printed 1 kΩ.

The bench’s op amp has no bias current. To show what the undrawn resistor is for, one run adds 100 nA out of the - input with a card (bias records the value and why it is a card): with nothing on the + input to cancel it, the whole I_B R_O = 10 mV appears at the output.

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

RunMeasuredClaimed
gain, E_I = 0.1 V: E_O / E_I-99.99-100 (a_v) ± 0.1%, holds
gain: input impedance1 kΩ1 kΩ (z_in), holds
bias_error, E_I = 0, 100 nA on the - input9.999 mV10 mV (e_bias), holds

The gain misses -100 by 1 part in 10^4, the model’s 10^6 open-loop gain against a noise gain of 101.

Only in drawing: the “resistor” the page sizes is not in the figure, and its value is 990 Ω, which the page rounds to 1 kΩ.

Terminal window
fang check examples/ti_opamp_handbook/dc_amplifiers/simple_inverting/simple_inverting.py
python examples/regenerate.py ti_opamp_handbook/dc_amplifiers/simple_inverting # needs ngspice
examples/ti_opamp_handbook/dc_amplifiers/simple_inverting/simple_inverting.py
"""The simple inverting (sign changing) amplifier, SBOA092B page 70.
Show 19 more lines
E_O = -(R_O / R_I) E_I = -100 E_I
resistor = R_O R_I / (R_I + R_O) = 1 kOhm
Z_in = R_I = 1 kOhm
The inverting amplifier of page 54 with values: R_I = 1 kOhm, R_O = 100 kOhm.
The page also gives a third resistance, R_O R_I / (R_I + R_O), and does not
draw it. It is the usual bias-compensation resistor, from the non-inverting
input to ground, sized to the resistance the inverting input sees so the two
input bias currents drop the same voltage. In the figure the + input goes
straight to ground, and the program builds what is drawn. The value is kept
as a parameter, `r_compensation`, held to the two resistors; it is 990 Ohm,
which the page rounds to 1 kOhm.
The bench's op amp has no input bias current, so its gain and input impedance
are the page's algebra. One more run puts a bias current on the inverting
input with a card, to show the output error the undrawn resistor is there to
cancel; `bias` records the value used.
"""
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, Ohm, nA, mV, require
from fang.parts import Resistor
from fang.rationale import Chooses, Cites
from fang.simulation import OperatingPoint
from handbook import (
Bench,
Claim,
Ground,
OpAmp,
Run,
Terminal,
equals,
negative,
over,
parallel,
product,
ratio,
within,
)
class SimpleInverting(System):
"""E_I through R_I into the summing point, R_O back from E_O, + on ground."""
figure = Cites(
"E_O = -(R_O/R_I) E_I = -100 E_I; resistor = R_O R_I/(R_I + R_O) = 1 kOhm; "
"Z_in = R_I = 1 kOhm",
document="SBOA092B, Handbook of Operational Amplifier Applications",
locator="page 70, Simple Inverting sign changing amplifier",
)
bias = Chooses(
"What input bias current does the bias-error run apply?",
selected="100 nA into the inverting input, applied by a card, in one run only",
alternatives=[
{
"option": "none, and say nothing about the undrawn resistor",
"reason": (
"the page prints its value, so a program that ignores it "
"leaves a line of the page unexplained"
),
},
{
"option": "a bias-current parameter on the op amp",
"reason": (
"the shared model has an input offset voltage and no bias "
"current, and the harness is not this program's to change"
),
},
],
rationale=(
"100 nA is the order of a general-purpose bipolar input; it is an "
"illustration, not a part's datasheet value",
"the + input is on ground as drawn, so there is no resistor there "
"for the matching current to cross, and the error is the whole I_B R_O",
),
)
a_v = Parameter("1", default=-100 * ratio, description="E_O / E_I")
z_in = Parameter("Ohm", default=1 * kOhm, description="what E_I sees: R_I, into a virtual ground")
r_compensation = Parameter(
"Ohm",
default=990 * Ohm,
description="R_O || R_I, the undrawn resistor from the + input to ground",
)
r_compensation_printed = Parameter(
"Ohm", default=1 * kOhm, description="the value the page prints for it"
)
i_bias = Parameter("A", default=100 * nA, description="the bias current the bias run applies")
e_bias = Parameter(
"V", default=10 * mV, description="E_O with E_I = 0 and I_B on the - input: I_B R_O"
)
e_in = Terminal()
e_out = Terminal()
r_in = Resistor(resistance=1 * 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))))
require(equals(self.z_in, self.r_in.resistance))
# The undrawn compensation resistor: R_O in parallel with R_I is
# 990.1 Ohm, which the page rounds to 1 kOhm.
require(
within(
parallel(self.r_out.resistance, self.r_in.resistance),
self.r_compensation,
0.001,
)
)
require(within(self.r_compensation, self.r_compensation_printed, 0.01))
# With the + input on ground, the bias current has only R_O to flow in.
require(equals(self.e_bias, product(self.i_bias, self.r_out.resistance)))
BENCH = Bench(
page=70,
title="Simple Inverting sign changing amplifier",
runs=[
Run(
"gain",
OperatingPoint(),
drive={"e_in": "DC 0.1"},
measure={
"gain": "v({e_out.1}) / v({e_in.1})",
"z_in": "-v({e_in.1}) / i(vdrive_e_in)",
},
claims=[
Claim("gain", "a_v", within=0.001),
Claim("z_in", "z_in", within=0.001, unit="Ohm"),
],
note=(
"E_I = 0.1 V, so E_O = -10 V stays inside the swing. The drive's "
"current is taken positive into its + terminal, hence the sign."
),
),
Run(
"bias_error",
OperatingPoint(),
drive={"e_in": "DC 0"},
cards=["IBIAS_MINUS {amp.IN-} 0 DC 100n"],
measure={"e_o": "v({e_out.1})"},
claims=[
Claim(
"e_o", "e_bias", within=0.001, unit="V",
note=(
"100 nA drawn out of the - input (see `bias`), E_I at 0 V. "
"The same current into the + input through the page's 990 "
"Ohm would put it at -99 uV, which times the noise gain of "
"101 cancels this; the figure does not draw that resistor, "
"so the run does not either"
),
)
],
),
],
)

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

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

Every check that ran, and every one left undecided.

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

What the elaborated graph contains, by entity kind.

out/graph.txt
1 block
6 component
12 connection
5 constraint
1 decision
1 evidence
3 interface
10 pin
10 port
49 total
snapshot sha256:575c49c667b8614156490bcd298ca3256d9418a2812d3226773d032b88689142

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

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