Examples / TI op amp handbook / DC amplifiers
Differential output
SBOA092B page 73, Differential Output: EI between two input terminals, one through RI 10 kΩ to the - input with RO 100 kΩ back from the output, the other through RI 10 kΩ to the + input with RO 100 kΩ from there to ground. EO is taken from the output to ground.
E_O = R_O / R_I x E_I = 10 E_I "For driving floating load."The 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/differential_output.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”Two readings are recorded as decisions. reading: the drawing is a
difference amplifier whose input floats; its output is single-ended, so the
program follows the drawing and not the title or caption. polarity: the
figure marks none, and E_O = +10 E_I holds with E_I positive at the bottom
terminal, the one that reaches the + input. Two constraints hold the gain
and the match of the two pairs that makes it a difference gain:
require(equals(self.a_v, over(self.r_out_top.resistance, self.r_in_top.resistance)))require(equals(over(self.r_out_bottom.resistance, self.r_in_bottom.resistance), over(self.r_out_top.resistance, self.r_in_top.resistance)))What the simulation found
Section titled “What the simulation found”out/simulation.txt, operating points:
| Run | Drive (top, bottom) | Measured | Claimed |
|---|---|---|---|
floating | -0.5 V, +0.5 V | gain 10 | 10 (a_v), holds |
offset_source | 3 V, 4 V | gain 10 | 10 (a_v), holds |
common_mode | 1 V, 1 V | E_O ≈ 0 V | 0 V, holds |
Where the handbook is off
Section titled “Where the handbook is off”The title and “for driving floating load” describe a circuit with a floating output. The figure has one op amp and one output referred to ground; what floats is the input. The formula is right for the drawn circuit, with E_I taken positive at the terminal that feeds the + input.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/dc_amplifiers/differential_output/differential_output.pypython examples/regenerate.py ti_opamp_handbook/dc_amplifiers/differential_output # needs ngspiceThe whole program
Section titled “The whole program”"""The "differential output" amplifier, SBOA092B page 73.Show 17 more lines
E_O = R_O / R_I x E_I = 10 E_I "For driving floating load."
What the figure draws is a difference amplifier: E_I arrives between twoinput terminals, neither of them ground. The top one reaches the - inputthrough R_I, with R_O from the output back to it; the bottom one reaches the+ input through the other R_I, with the other R_O from there to ground. Theoutput is one terminal against ground. So the input floats and the outputdoes not, which is the reverse of the title and of the caption; `reading`records that the program follows the drawing.
The figure marks no polarity on E_I. For E_O = +10 E_I to hold, E_I has tobe positive at the bottom terminal, the one that reaches the + input, and`polarity` records that. Because the matched pairs make the stage rejectwhat the two terminals share, the bench also drives them together and findsnothing at the output."""
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 OperatingPoint
from handbook import ( Bench, Claim, Ground, OpAmp, Run, Terminal, equals, over, ratio,)
class DifferentialOutput(System): """A difference amplifier: E_I between two terminals, E_O against ground."""
figure = Cites( "E_O = R_O / R_I E_I = 10 E_I. For driving floating load.", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 73, Differential Output", )
reading = Chooses( "Which side of the circuit floats?", selected=( "the input: E_I is applied between the two left-hand terminals, " "and E_O is taken from the output to ground" ), alternatives=[ { "reading": "a floating load driven between two outputs", "reason": ( "the figure has one op amp with one output, and the lower " "right terminal is on the ground symbol; there is no " "second output for a floating load to sit between" ), }, ], rationale=( "the lower left terminal goes to the + input through R_I, not to ground", "the drawing is the source of truth; the caption does not match it", ), )
polarity = Chooses( "Which input terminal is E_I positive at?", selected="the bottom one, which reaches the + input, so E_O = +10 E_I as printed", alternatives=[ { "option": "the top one", "reason": "E_O would be -10 E_I, and the page prints a positive gain", }, ], rationale=("the figure marks no polarity",), )
a_v = Parameter("1", default=10 * ratio, description="E_O / E_I, E_I positive at the bottom terminal")
e_in_top = Terminal() e_in_bottom = Terminal() e_out = Terminal() r_in_top = Resistor(resistance=10 * kOhm) r_out_top = Resistor(resistance=100 * kOhm) r_in_bottom = Resistor(resistance=10 * kOhm) r_out_bottom = Resistor(resistance=100 * kOhm) amp = OpAmp() ground = Ground()
def architecture(self): self.e_in_top.probe >> self.r_in_top.p1 self.r_in_top.p2 >> self.amp.inverting.signal self.amp.inverting.signal >> self.r_out_top.p1 self.r_out_top.p2 >> self.amp.output.signal self.amp.output.signal >> self.e_out.probe
self.e_in_bottom.probe >> self.r_in_bottom.p1 self.r_in_bottom.p2 >> self.amp.non_inverting.signal self.amp.non_inverting.signal >> self.r_out_bottom.p1 self.r_out_bottom.p2 >> self.ground.node
def constraints(self): # The printed gain is R_O / R_I, and it is the difference gain only # while the two pairs are matched, which is also what rejects the # common mode. require(equals(self.a_v, over(self.r_out_top.resistance, self.r_in_top.resistance))) require( equals( over(self.r_out_bottom.resistance, self.r_in_bottom.resistance), over(self.r_out_top.resistance, self.r_in_top.resistance), ) )
BENCH = Bench( page=73, title="Differential Output", runs=[ Run( "floating", OperatingPoint(), drive={"e_in_top": "DC -0.5", "e_in_bottom": "DC 0.5"}, measure={"gain": "v({e_out.1}) / (v({e_in_bottom.1}) - v({e_in_top.1}))"}, claims=[Claim("gain", "a_v", within=0.001)], note="E_I = 1 V split symmetrically about ground: -0.5 V on the top terminal, +0.5 V on the bottom.", ), Run( "offset_source", OperatingPoint(), drive={"e_in_top": "DC 3", "e_in_bottom": "DC 4"}, measure={"gain": "v({e_out.1}) / (v({e_in_bottom.1}) - v({e_in_top.1}))"}, claims=[Claim("gain", "a_v", within=0.001)], note="The same 1 V of E_I, riding 3 V above ground: only the difference reaches E_O.", ), Run( "common_mode", OperatingPoint(), drive={"e_in_top": "DC 1", "e_in_bottom": "DC 1"}, measure={"e_out": "v({e_out.1})"}, claims=[ Claim( "e_out", 0, within=1e-4, absolute=True, unit="V", note="both terminals at 1 V, E_I = 0: the matched pairs reject it", ) ], ), ],)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 10 kOhm -R3 100 kOhm -R4 100 kOhm -TP1 Terminal -TP2 Terminal -TP3 Terminal -U1 OpAmp -Net-(GND1-Pad1) GND1.1 R3.2Net-(R1-Pad1) R1.1 TP1.1Net-(R1-Pad2) R1.2 R3.1 U1.IN+Net-(R2-Pad1) R2.1 TP2.1Net-(R2-Pad2) R2.2 R4.1 U1.IN-Net-(R4-Pad2) R4.2 TP3.1 U1.OUTEvery check that ran, and every one left undecided.
2 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 9 component 18 connection 2 constraint 2 decision 1 evidence 3 interface 15 pin 15 port 66 totalsnapshot sha256:a34321c425312c392be865f080810aa8f371e6c8f3deeabf14792bec560324caAll of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/dc_amplifiers/differential_output/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/dc_amplifiers/differential_output/differential_output.py