Examples / TI op amp handbook / Summers
Adder
SBOA092B page 64, Adder: E1, E2 and E3 each through 10 kΩ into the summing point, 10 kΩ from the output back to it, and the non-inverting input on ground.
E_O = -(E1 + E2 + E3)Z_in = 10 kΩ for each inputThe 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/adder.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”Each input is an inverting amplifier of gain a_v = -1, and because the
summing point is a virtual ground each source sees only its own resistor,
z_in = 10 kΩ. Both hold for every input:
for r_n in (self.r_1, self.r_2, self.r_3): require(equals(self.a_v, negative(over(r_o, r_n.resistance)))) require(equals(self.z_in, r_n.resistance))The figure gives every value, so nothing was chosen.
What the simulation found
Section titled “What the simulation found”out/simulation.txt, from the deck under
out/spice/. One run drives E1..E3 with 1, 2 and -0.5 V:
Measured in sum | Measured | Claimed |
|---|---|---|
| E_O | -2.5 V | -2.5 V, holds |
| E_O / (E1 + E2 + E3) | -1 | -1 (a_v), holds |
| E1 / I1 | 10 kΩ | 10 kΩ (z_in), holds |
| E2 / I2 | 10 kΩ | 10 kΩ (z_in), holds |
| E3 / I3 | 10 kΩ | 10 kΩ (z_in), holds |
The impedances hold with all three inputs driven at once, which is what “the inputs are effectively isolated from each other” means.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/summers/adder/adder.pypython examples/regenerate.py ti_opamp_handbook/summers/adder # needs ngspiceThe whole program
Section titled “The whole program”"""The adder, SBOA092B page 64.Show 13 more lines
E_O = -(E1 + E2 + E3), Z_in = 10 kOhm for each input
Three 10 kOhm resistors bring E1, E2 and E3 to the summing point, and a fourth10 kOhm runs from the output back to it. Each input is an inverting amplifierof gain -1 on its own, and because the summing point sits at ground, eachsource sees only its own resistor: that is the 10 kOhm the page gives as theinput impedance, and why the inputs do not load one another.
The figure gives every value, so nothing was chosen. The bench drives thethree inputs with distinct voltages at once, reads E_O against their sum, andreads each input's impedance from the current its source delivers."""
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 Citesfrom fang.simulation import OperatingPoint
from handbook import ( Bench, Claim, Ground, OpAmp, Run, Terminal, equals, negative, over, ratio,)
class Adder(System): """E1, E2, E3 each through 10 kOhm into the summing point, 10 kOhm back."""
figure = Cites( "E_O = -(E1 + E2 + E3). Z_in = 10 kOhm for each input", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 64, Adder", )
a_v = Parameter("1", default=-1 * ratio, description="E_O / E_n, for each input") z_in = Parameter("Ohm", default=10 * kOhm, description="what each source sees")
e1 = Terminal() e2 = Terminal() e3 = Terminal() common = Terminal() e_out = Terminal()
r_1 = Resistor(resistance=10 * kOhm) r_2 = Resistor(resistance=10 * kOhm) r_3 = Resistor(resistance=10 * kOhm) r_feedback = Resistor(resistance=10 * kOhm) amp = OpAmp() ground = Ground()
def architecture(self): self.e1.probe >> self.r_1.p1 self.e2.probe >> self.r_2.p1 self.e3.probe >> self.r_3.p1 self.r_1.p2 >> self.amp.inverting.signal self.r_2.p2 >> self.amp.inverting.signal self.r_3.p2 >> self.amp.inverting.signal self.amp.inverting.signal >> self.r_feedback.p1 self.r_feedback.p2 >> self.amp.output.signal self.amp.output.signal >> self.e_out.probe self.amp.non_inverting.signal >> self.ground.node self.common.probe >> self.ground.node
def constraints(self): r_o = self.r_feedback.resistance # Each input is an inverting amplifier of its own, all of the same gain. for r_n in (self.r_1, self.r_2, self.r_3): require(equals(self.a_v, negative(over(r_o, r_n.resistance)))) # The summing point is a virtual ground, so a source sees its resistor. require(equals(self.z_in, r_n.resistance))
BENCH = Bench( page=64, title="Adder", runs=[ Run( "sum", OperatingPoint(), drive={"e1": "DC 1", "e2": "DC 2", "e3": "DC -0.5"}, measure={ "e_o": "v({e_out.1})", "sum_gain": "v({e_out.1}) / (v({e1.1}) + v({e2.1}) + v({e3.1}))", "z_in_e1": "-v({e1.1}) / i(vdrive_e1)", "z_in_e2": "-v({e2.1}) / i(vdrive_e2)", "z_in_e3": "-v({e3.1}) / i(vdrive_e3)", }, claims=[ Claim("e_o", -2.5, within=0.001, unit="V", note="-(1 + 2 - 0.5) = -2.5 V"), Claim("sum_gain", "a_v", within=0.001), Claim("z_in_e1", "z_in", within=0.001, unit="Ohm"), Claim("z_in_e2", "z_in", within=0.001, unit="Ohm"), Claim("z_in_e3", "z_in", within=0.001, unit="Ohm"), ], note=( "Each input's impedance is its drive voltage over the current its " "source delivers, which flows out of the source's + terminal and so " "reads negative in SPICE." ), ), ],)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 10 kOhm -R4 10 kOhm -TP1 Terminal -TP2 Terminal -TP3 Terminal -TP4 Terminal -TP5 Terminal -U1 OpAmp -Net-(GND1-Pad1) GND1.1 TP1.1 U1.IN+Net-(R1-Pad1) R1.1 TP2.1Net-(R1-Pad2) R1.2 R2.2 R3.2 R4.1 U1.IN-Net-(R2-Pad1) R2.1 TP3.1Net-(R3-Pad1) R3.1 TP4.1Net-(R4-Pad2) R4.2 TP5.1 U1.OUTEvery check that ran, and every one left undecided.
6 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 11 component 22 connection 6 constraint 1 evidence 3 interface 17 pin 17 port 78 totalsnapshot sha256:415d4b23c1033a4299b2789cea9ad7184c14ebbf53f9e59aa580b9f457dbb862All of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/summers/adder/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/summers/adder/adder.py