Examples / TI op amp handbook / Differential input
Balanced output amplifier
SBOA092B page 69, The Differential (Balanced) Output Amplifier: an op amp with two outputs. E1 goes through RI into the inverting input with RO to the top output; E2 goes through RI into the non-inverting input with RO to the bottom output. The handbook calls the bottom output EP and the top one EO + EP, so EO is the difference between the two.
E_O = (R_O / R_I)(E2 - E1)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/balanced_output_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 gives no values, so the program chooses them (values): R_I =
10 kΩ and R_O = 100 kΩ in both legs, a differential gain of 10. Three
constraints: the two R_I are equal, the two R_O are equal (the page’s
subtraction of the leg equations needs both), and a_d = R_O / R_I.
The page is careful to say that E_f and E_P, where the inputs and outputs sit
together, are not set by the loop. The op amp sets them. The bench’s model
(DifferentialOpAmp) holds the outputs’ common level at ground, so E_P comes
out as -E_O/2. That is the model’s choice, not the handbook’s, and the program
reports E_P without claiming it.
What the simulation found
Section titled “What the simulation found”out/simulation.txt, from the decks under
out/spice/:
| Run | Measured | Claimed |
|---|---|---|
difference, E1 = 0.2 V, E2 = 0.5 V: gain | 10 | 10 (a_d), holds |
difference: E_P | -1.5 V | not a claim |
floating, E1 = 2.2 V, E2 = 2.5 V: E_O | 3 V | 3 V, holds |
common_mode, E1 = E2 = 1 V: E_O | 1.7 fV | 0 V ± 100 µV, holds |
The floating run is the page’s “ground reference is not critical”: the same
0.3 V difference lifted by 2.2 V gives the same E_O.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/differential_input/balanced_output_amplifier/balanced_output_amplifier.pypython examples/regenerate.py ti_opamp_handbook/differential_input/balanced_output_amplifier # needs ngspiceThe whole program
Section titled “The whole program”"""The differential (balanced) output amplifier, SBOA092B page 69.Show 16 more lines
E_O = (R_O / R_I) (E2 - E1)
An op amp with two outputs. E1 reaches the inverting input through R_I, withR_O from there to the top output; E2 reaches the non-inverting input throughR_I, with R_O from there to the bottom output. The handbook calls the bottomoutput E_P and the top one E_O + E_P, so E_O is the difference between them.
The page says what the loop does not set: "the values of E_f and E_P are notuniquely determined". Where the two outputs sit together is the op amp's ownbusiness, and the bench's model holds that common level at ground. So E_P isreported and not claimed; only the difference is.
The figure names the resistors and gives no values, so `values` records thepair chosen here: 10 kOhm and 100 kOhm, a differential gain of 10."""
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, DifferentialOpAmp, Ground, Run, Terminal, equals, over, ratio,)
class BalancedOutputAmplifier(System): """Two inverting legs around one op amp with two outputs."""
figure = Cites( "E_O = (R_O/R_I)(E2 - E1). Note that the values of E_f and E_P are not " "uniquely determined by the above equations", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 69, The Differential (Balanced) Output Amplifier", )
values = Chooses( "What are R_I and R_O?", selected="10 kOhm and 100 kOhm in both legs, a differential gain of 10", alternatives=[ { "option": "leave them unknown", "reason": "a gain nobody can compute is not a claim anything can check", }, { "option": "different pairs in the two legs", "reason": ( "the page's subtraction of the two leg equations needs the " "same R_I and R_O in both; the figure labels them alike" ), }, ], rationale=( "the figure names the resistors and gives no values", "a gain of 10 keeps each output far inside the swing for the drives used", ), )
a_d = Parameter("1", default=10 * ratio, description="E_O / (E2 - E1)")
e1 = Terminal() e2 = Terminal() e_o = Terminal() e_p = Terminal() common = 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 = DifferentialOpAmp() ground = Ground()
def architecture(self): # The top leg: E1 into the - input, R_O to the output that falls when # that input rises. self.e1.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_o.probe
# The bottom leg: E2 into the + input, R_O to the other output. self.e2.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.amp.output_minus.signal self.amp.output_minus.signal >> self.e_p.probe
# Nothing in the figure touches ground but the grounded terminal # between E1 and E2: the op amp's common level is its own. self.common.probe >> self.ground.node
def constraints(self): require(equals(self.r_in_top.resistance, self.r_in_bottom.resistance)) require(equals(self.r_out_top.resistance, self.r_out_bottom.resistance)) require(equals(self.a_d, over(self.r_out_top.resistance, self.r_in_top.resistance)))
BENCH = Bench( page=69, title="The Differential (Balanced) Output Amplifier", runs=[ Run( "difference", OperatingPoint(), drive={"e1": "DC 0.2", "e2": "DC 0.5"}, measure={ "gain": "(v({e_o.1}) - v({e_p.1})) / (v({e2.1}) - v({e1.1}))", "e_p": "v({e_p.1})", }, claims=[Claim("gain", "a_d", within=0.001)], units={"e_p": "V"}, note=( "E_O is the top output less the bottom one. E_P, where the bottom " "output sits, is set inside the op amp; this model centres the " "pair on ground, so E_P is -E_O/2 here and not a handbook claim." ), ), Run( "floating", OperatingPoint(), drive={"e1": "DC 2.2", "e2": "DC 2.5"}, measure={"e_o": "v({e_o.1}) - v({e_p.1})"}, claims=[ Claim("e_o", 3.0, within=0.001, unit="V", note="the same 0.3 V difference riding on 2.2 V: still 10 x 0.3 V"), ], ), Run( "common_mode", OperatingPoint(), drive={"e1": "DC 1", "e2": "DC 1"}, measure={"e_o": "v({e_o.1}) - v({e_p.1})"}, claims=[Claim("e_o", 0, within=1e-4, absolute=True, unit="V", note="1 V on both inputs gives no difference out")], ), ],)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 -TP4 Terminal -TP5 Terminal -U1 DifferentialOpAmp -Net-(GND1-Pad1) GND1.1 TP1.1Net-(R1-Pad1) R1.1 TP3.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-(R3-Pad2) R3.2 TP5.1 U1.OUT-Net-(R4-Pad2) R4.2 TP4.1 U1.OUT+Every check that ran, and every one left undecided.
3 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 11 component 22 connection 3 constraint 1 decision 1 evidence 3 interface 18 pin 18 port 78 totalsnapshot sha256:5aa1f1efd122fcca2459562a5230e5e42c8bb7181b321814c1c1548d4abbfebcAll of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/differential_input/balanced_output_amplifier/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/differential_input/balanced_output_amplifier/balanced_output_amplifier.py