Skip to content
copperhead.sh
Get started

Examples / TI op amp handbook / AC amplifiers

AC non inverting

SBOA092B page 77, Non-Inverting: EI through C2 1 µF onto the + input, R2 100 kΩ from there to ground; R0 90 kΩ from the output to the - input, and R1 10 kΩ in series with C1 100 µF from there to ground.

E_O = (R_O + R_I) / R_I x E_I = 10 E_I
f_-3dB = 1 / (2 pi R_I C_I) = 0.16 Hz
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/ac_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 gain is 1 + 90k/10k = 10 (a_v). There are two low-frequency corners. f_gain is the printed one, within 1% of 1/(2 pi R_1 C_1) = 0.159 Hz: the gain network’s, below which the gain falls toward 1. f_input is the input network’s, 1/(2 pi R_2 C_2) = 1.59 Hz, and a constraint says it is at least five times higher. f_low, where the whole circuit is 3 dB down, is set equal to f_input.

out/simulation.txt:

RunMeasuredClaimed
response, gain at 1 kHz1010 (a_v), holds
response, phase at 1 kHz0.0007 rad0, holds
response, circuit -3 dB point1.608 Hz1.6 Hz (f_low) ±1%, holds
response, E_O / E_+ at 0.159 Hz7.1067.106, holds
response, E_+ at 1.59 Hz0.707 V0.7071 V, holds
dc, E_O with E_I = 1 V d.c.0 V0 V, holds

At 0.159 Hz the gain network is 3 dB down from 10, which is the corner the page prints, but by then C_2 and R_2 have already cut E_I by 20 dB. The source sees the input network’s 1.59 Hz corner first.

The printed f_-3dB = 0.16 Hz is the gain network’s corner (and the formula names R_I and C_I where the figure has R_1 and C_1). The drawn circuit is 3 dB down at 1.6 Hz, set by C_2 R_2, ten times higher. To make 0.16 Hz the circuit’s corner, C_2 would need to be 10 µF or R_2 1 MΩ.

Terminal window
fang check examples/ti_opamp_handbook/ac_amplifiers/ac_non_inverting/ac_non_inverting.py
python examples/regenerate.py ti_opamp_handbook/ac_amplifiers/ac_non_inverting # needs ngspice
examples/ti_opamp_handbook/ac_amplifiers/ac_non_inverting/ac_non_inverting.py
"""The a.c. non-inverting amplifier, SBOA092B page 77.
Show 17 more lines
E_O = (R_O + R_I) / R_I x E_I = 10 E_I
f_-3dB = 1 / (2 pi R_I C_I) = 0.16 Hz
E_I reaches the + input through C_2, and R_2 returns that input to ground.
R_0 (90 kOhm) from the output and R_1 (10 kOhm) in series with C_1 (100 uF)
to ground set the gain: 1 + 90k/10k = 10 in the midband, falling to 1 at
d.c., where C_1 is open and the output offset is not multiplied.
There are two low-frequency corners, not one. The printed 0.16 Hz is the
gain network's, 1/(2 pi R_1 C_1) = 0.159 Hz (the formula calls them R_I and
C_I; the figure labels them R_1 and C_1). The input network C_2 R_2 turns at
1/(2 pi 100k 1u) = 1.59 Hz, ten times higher, and it is that one the source
sees first: the circuit is 3 dB down at 1.6 Hz, not 0.16. The program encodes
what the drawn circuit does (`f_low`, from C_2 and R_2), cites what the page
prints, and the bench measures both corners.
"""
import sys
from decimal import Decimal
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 Hz, Parameter, System, kOhm, require, uF
from fang.parts import Capacitor, Resistor
from fang.rationale import Cites
from fang.simulation import ACSweep, OperatingPoint
from handbook import (
Bench,
Claim,
Ground,
OpAmp,
Run,
Terminal,
at_least,
corner,
equals,
over,
product,
ratio,
total,
within,
)
class AcNonInverting(System):
"""E_I through C_2 onto the + input, R_0 over R_1 and C_1 setting the gain."""
figure = Cites(
"E_O in phase with E_I. E_O = (R_O + R_I) / R_I = 10 E_I. "
"Low frequency rolloff f_-3dB = 1 / (2 pi R_I C_I) = 0.16 Hz",
document="SBOA092B, Handbook of Operational Amplifier Applications",
locator="page 77, Non-Inverting",
)
a_v = Parameter("1", default=10 * ratio, description="E_O / E_I in the midband")
f_gain = Parameter("Hz", default=Decimal("0.16") * Hz, description="the gain network's corner, as printed")
f_input = Parameter("Hz", default=Decimal("1.6") * Hz, description="the input network's corner")
f_low = Parameter("Hz", default=Decimal("1.6") * Hz, description="where the circuit is 3 dB down")
e_in = Terminal()
e_out = Terminal()
c_2 = Capacitor(capacitance=1 * uF)
r_2 = Resistor(resistance=100 * kOhm)
r_1 = Resistor(resistance=10 * kOhm)
c_1 = Capacitor(capacitance=100 * uF)
r_0 = Resistor(resistance=90 * kOhm)
amp = OpAmp()
ground = Ground()
def architecture(self):
self.e_in.probe >> self.c_2.p1
self.c_2.p2 >> self.amp.non_inverting.signal
self.amp.non_inverting.signal >> self.r_2.p1
self.amp.inverting.signal >> self.r_1.p1
self.r_1.p2 >> self.c_1.p1
self.amp.inverting.signal >> self.r_0.p1
self.r_0.p2 >> self.amp.output.signal
self.amp.output.signal >> self.e_out.probe
self.r_2.p2 >> self.ground.node
self.c_1.p2 >> self.ground.node
def constraints(self):
require(
equals(
self.a_v,
over(total(self.r_0.resistance, self.r_1.resistance), self.r_1.resistance),
)
)
# The printed corner is the gain network's, rounded from 0.159 Hz.
require(within(self.f_gain, corner(self.r_1.resistance, self.c_1.capacitance), 0.01))
# The input network's is ten times higher, 1.59 Hz, and it is the one
# that sets the circuit's -3 dB point.
require(within(self.f_input, corner(self.r_2.resistance, self.c_2.capacitance), 0.01))
require(at_least(self.f_input, product(self.f_gain, 5 * ratio)))
require(equals(self.f_low, self.f_input))
BENCH = Bench(
page=77,
title="Non-Inverting",
runs=[
Run(
"response",
ACSweep(points=40, start="0.001", stop="10meg"),
drive={"e_in": "DC 0 AC 1"},
measure={
"gain_1k": "find vm({e_out.1}) at=1k",
"phase_1k": "find vp({e_out.1}) at=1k",
"f_3db": "when vdb({e_out.1})=16.9897 cross=1",
"out_at_gain_corner": "find vm({e_out.1}) at=0.159155",
"plus_at_gain_corner": "find vm({amp.IN+}) at=0.159155",
"gain_network": "out_at_gain_corner / plus_at_gain_corner",
"plus_at_input_corner": "find vm({amp.IN+}) at=1.59155",
},
claims=[
Claim("gain_1k", "a_v", within=0.001),
Claim(
"phase_1k",
0,
within=0.01,
absolute=True,
note="in radians: E_O in phase with E_I, as the page says",
),
Claim(
"f_3db",
"f_low",
within=0.01,
unit="Hz",
note=(
"the handbook prints 0.16 Hz; the drawn circuit is 3 dB "
"down at 1.61 Hz, set by C_2 R_2 (1.59 Hz) with a "
"little from the gain network"
),
),
Claim(
"gain_network",
7.106,
within=0.001,
note=(
"E_O over the + input at 1/(2 pi R_1 C_1) = 0.159 Hz: "
"sqrt(1 + 10^2) / sqrt(2), the gain network 3 dB down "
"from 10. This is the corner the page prints"
),
),
Claim(
"plus_at_input_corner",
0.7071,
within=0.001,
unit="V",
note="the + input 3 dB down at 1/(2 pi R_2 C_2) = 1.59 Hz: the corner that comes first",
),
],
units={"out_at_gain_corner": "V", "plus_at_gain_corner": "V"},
),
Run(
"dc",
OperatingPoint(),
drive={"e_in": "DC 1"},
measure={"e_out": "v({e_out.1})"},
claims=[
Claim(
"e_out",
0,
within=1e-6,
absolute=True,
unit="V",
note="C_2 blocks the 1 V; R_2 holds the + input at ground",
)
],
),
],
)

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

out/netlist.txt
C1 100 uF -
C2 1 uF -
GND1 Ground -
R1 90 kOhm -
R2 10 kOhm -
R3 100 kOhm -
TP1 Terminal -
TP2 Terminal -
U1 OpAmp -
Net-(C1-Pad1) C1.1 R2.2
Net-(C1-Pad2) C1.2 GND1.1 R3.2
Net-(C2-Pad1) C2.1 TP1.1
Net-(C2-Pad2) C2.2 R3.1 U1.IN+
Net-(R1-Pad1) R1.1 R2.1 U1.IN-
Net-(R1-Pad2) R1.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
9 component
20 connection
5 constraint
1 evidence
3 interface
16 pin
16 port
71 total
snapshot sha256:a8b6b7c6d2a4824ee3d88ed7b18504daf9f5c949d4d9c226d6bf30adca2e6167

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

Terminal window
fang build examples/ti_opamp_handbook/ac_amplifiers/ac_non_inverting/ac_non_inverting.py