Examples / TI op amp handbook / References
Reference voltage supply
SBOA092B page 52, Reference Voltage Supply: the cell Eref through R1 (10 kΩ) into an inverter with R0 (100 kΩ) across it, whose output is -EO; R3 and R2 (10 kΩ each) make a second, unity-gain inverter whose output is +EO; and R4 (90 kΩ) runs from +EO back to the cell's + terminal.
The handbook prints no formula. The drawing’s:
-E_O = -(R_0 / R_1) Eref = -10 Eref, +E_O = +10 ErefThe 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/reference_voltage_supply.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”R_4 is the point of the figure. It carries (10 Eref - Eref) / 90 kΩ =
Eref / 10 kΩ into the cell’s node, exactly the current R_1 draws out of it, so
the cell supplies no net current. The program holds that as a constraint on
i_cell, with the arithmetic in bootstrap. The cell has no value in the
figure, so cell records a Weston cell, 1.0183 V, for ±10.183 V out.
What the simulation found
Section titled “What the simulation found”| Run | Measured | Claimed |
|---|---|---|
outputs, -E_O | -10.183 V | -10.183 V (e_out_minus), holds |
outputs, +E_O | 10.183 V | 10.183 V (e_out_plus), holds |
outputs, cell current | 453.5 pA | 0 (i_cell) ± 1 nA, holds |
outputs, current in R_1 | 101.8 µA | not a claim |
The cell’s current is not zero in the simulation because the outputs carry the op amps’ ppm-level loop-gain error, and R_4’s current with them. It is 453 pA against the 101.8 µA R_1 draws, a cancellation to 4.5 ppm.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/references/reference_voltage_supply/reference_voltage_supply.pypython examples/regenerate.py ti_opamp_handbook/references/reference_voltage_supply # needs ngspiceThe whole program
Section titled “The whole program”"""The reference voltage supply, SBOA092B page 52.Show 18 more lines
-E_O = -(R_0 / R_1) Eref = -10 Eref, +E_O = -(R_2 / R_3)(-E_O) = +10 Eref
The first amplifier inverts the cell with a gain of -10, and the secondinverts that with a gain of -1, so the pair gives both polarities of tentimes the cell. The handbook prints no formula for this figure; the twoabove are what its drawing does.
R_4 is the part worth reading. It runs from +E_O back to the cell's +terminal, so it carries (10 Eref - Eref) / 90 kOhm = Eref / 10 kOhm into thatnode, which is exactly the current R_1 draws out of it into the firstamplifier's summing point. The cell's net current is zero: the circuitsupplies its own reference's load. `bootstrap` below writes that down, andthe bench measures the cell's current to check it.
The figure gives every resistor and no cell value, so `cell` records aWeston cell, 1.0183 V, for outputs of +/-10.183 V."""
import sysfrom decimal import Decimalfrom 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 A, Parameter, System, V, kOhm, requirefrom fang.parts import Resistorfrom fang.rationale import Calculates, Chooses, Citesfrom fang.simulation import OperatingPoint
from handbook import ( Bench, Cell, Claim, Ground, OpAmp, Run, Terminal, equals, minus, negative, over, product,)
class ReferenceVoltageSupply(System): """Eref through R_1 into an inverter of -10, then an inverter of -1; R_4 back to the cell."""
figure = Cites( "Reference Voltage Supply: Eref; R1 10 kOhm, R0 100 kOhm, R3 10 kOhm, " "R2 10 kOhm, R4 90 kOhm; outputs -E_O and +E_O", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 52, Reference Voltage Supply", )
cell = Chooses( "What is Eref?", selected="a saturated Weston cell, 1.0183 V, for outputs of +/-10.183 V", alternatives=[ { "option": "a 1.000 V reference, for round +/-10 V outputs", "reason": ( "the page's circuits are standard-cell circuits, and the " "point of R_4 is protecting a cell" ), }, ], rationale=("the figure labels the cell Eref and gives no value",), )
bootstrap = Calculates( "i_cell = Eref / R_1 - (+E_O - Eref) / R_4", inputs=("e_ref", "r_1", "r_4", "r_0", "r_2", "r_3"), result=( "Eref / 10 kOhm - 9 Eref / 90 kOhm = 0: R_4 returns to the cell's " "node exactly the 101.8 uA that R_1 takes from it" ), )
e_out_minus = Parameter("V", default=Decimal("-10.183") * V, description="-E_O") e_out_plus = Parameter("V", default=Decimal("10.183") * V, description="+E_O") i_cell = Parameter("A", default=0 * A, description="what the cell supplies")
e_ref = Cell(voltage=Decimal("1.0183") * V) r_1 = Resistor(resistance=10 * kOhm) r_0 = Resistor(resistance=100 * kOhm) r_3 = Resistor(resistance=10 * kOhm) r_2 = Resistor(resistance=10 * kOhm) r_4 = Resistor(resistance=90 * kOhm) amp_1 = OpAmp() amp_2 = OpAmp() out_minus = Terminal() out_plus = Terminal() out_return = Terminal() ground = Ground()
def architecture(self): # The cell's + node: R_1 leaves it, R_4 returns to it. self.e_ref.p1 >> self.r_1.p1 self.r_1.p1 >> self.r_4.p1 # The first inverter, gain -R_0 / R_1. self.r_1.p2 >> self.amp_1.inverting.signal self.amp_1.inverting.signal >> self.r_0.p1 self.r_0.p2 >> self.amp_1.output.signal self.amp_1.output.signal >> self.out_minus.probe # The second, gain -R_2 / R_3. self.amp_1.output.signal >> self.r_3.p1 self.r_3.p2 >> self.amp_2.inverting.signal self.amp_2.inverting.signal >> self.r_2.p1 self.r_2.p2 >> self.amp_2.output.signal self.amp_2.output.signal >> self.out_plus.probe self.amp_2.output.signal >> self.r_4.p2 # The bottom wire. self.e_ref.p2 >> self.ground.node self.amp_1.non_inverting.signal >> self.ground.node self.amp_2.non_inverting.signal >> self.ground.node self.out_return.probe >> self.ground.node
def constraints(self): require( equals( self.e_out_minus, negative(product(over(self.r_0.resistance, self.r_1.resistance), self.e_ref.voltage)), ) ) require( equals( self.e_out_plus, negative(product(over(self.r_2.resistance, self.r_3.resistance), self.e_out_minus)), ) ) require( equals( self.i_cell, minus( over(self.e_ref.voltage, self.r_1.resistance), over(minus(self.e_out_plus, self.e_ref.voltage), self.r_4.resistance), ), ) )
BENCH = Bench( page=52, title="Reference Voltage Supply", runs=[ Run( "outputs", OperatingPoint(), measure={ "e_out_minus": "v({out_minus.1})", "e_out_plus": "v({out_plus.1})", "i_r1": "(v({r_1.1}) - v({r_1.2})) / 10e3", "i_cell": "-i(v1)", }, claims=[ Claim( "e_out_minus", "e_out_minus", within=1e-4, unit="V", note="Held to 100 ppm: a noise gain of 11 costs 11 ppm of loop-gain error.", ), Claim("e_out_plus", "e_out_plus", within=1e-4, unit="V"), Claim( "i_cell", "i_cell", within=1e-9, absolute=True, unit="A", note=( "Held to 1 nA, absolute, against the 101.8 uA R_1 " "draws (i_r1): the two currents at the cell's node " "cancel to within the outputs' ppm-level error." ), ), ], units={"e_out_minus": "V", "e_out_plus": "V", "i_r1": "A", "i_cell": "A"}, ), ],)The files it writes
Section titled “The files it writes”The parts, then the nets and the pads on them.
GND1 Ground -R1 100 kOhm -R2 10 kOhm -R3 10 kOhm -R4 10 kOhm -R5 90 kOhm -TP1 Terminal -TP2 Terminal -TP3 Terminal -U1 OpAmp -U2 OpAmp -V1 1.0183 V -Net-(GND1-Pad1) GND1.1 TP3.1 U1.IN+ U2.IN+ V1.-Net-(R1-Pad1) R1.1 R2.2 U1.IN-Net-(R1-Pad2) R1.2 R4.1 TP1.1 U1.OUTNet-(R2-Pad1) R2.1 R5.1 V1.+Net-(R3-Pad1) R3.1 R4.2 U2.IN-Net-(R3-Pad2) R3.2 R5.2 TP2.1 U2.OUTEvery check that ran, and every one left undecided.
3 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 1 calculation 12 component 32 connection 3 constraint 1 decision 1 evidence 3 interface 22 pin 22 port 98 totalsnapshot sha256:3981944e7f74f9894b31bfb9a1f432faf96f00c292d1e3daacbca8694e72ce39All of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/references/reference_voltage_supply/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/references/reference_voltage_supply/reference_voltage_supply.py