Examples / TI op amp handbook / Lead and lag
Adjustable lead
SBOA092B page 85, Adjustable Lead: R = 10 kΩ in, and a 10 kΩ pot from the summing point to the output with its wiper through C = 10 µF to ground. It is the adjustable lag's input network moved into the feedback path.
E_O = -[(D - D²) R C P] E_I (as printed)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/adjustable_lead.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 feedback is a T whose transfer impedance is R [1 + (D - D²) R C P], so the drawn circuit is
E_O = -[1 + (D - D²) R C P] E_Ia DC gain of a_v = -1 with a zero at 1/((D - D²) R C). The claims are held
at D = 1/2 (setting), where the zero is lowest: 40 rad/s, f_z = 6.37 Hz.
Where the handbook is off
Section titled “Where the handbook is off”The printed form drops the 1. Without it the stage would be a pure differentiator with no gain at DC; the drawn circuit passes DC at -1 and the bench measures it. At the zero the gain is |1 + j| = 1.414, where the printed form would give 1.
What the simulation found
Section titled “What the simulation found”| Run | Measured | Claimed |
|---|---|---|
dc_gain | -1 | -1 (a_v), holds |
lead, +3 dB point | 6.366 Hz | 6.366 Hz (f_z), holds |
lead, gain at the zero | 1.414 | 1.414, holds |
lead, phase at the zero | -2.356 rad (-135°) | -135°, holds |
lead, gain a decade above | 10.05 | 10.05, holds |
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/lead_lag/adjustable_lead/adjustable_lead.pypython examples/regenerate.py ti_opamp_handbook/lead_lag/adjustable_lead # needs ngspiceThe whole program
Section titled “The whole program”"""The adjustable lead, SBOA092B page 85.Show 16 more lines
printed: E_O = -[(D - D^2) R C P] E_I drawn: E_O = -[1 + (D - D^2) R C P] E_I
The adjustable lag's input network moved into the feedback path: R = 10 kOhmin, and a 10 kOhm potentiometer from the summing point to the output with itswiper through C = 10 uF to ground. Solving the wiper node, the feedback is aT whose transfer impedance is R [1 + (D - D^2) R C P], so the stage is azero at 1/((D - D^2) R C) on top of a DC gain of -1.
The printed form drops the 1. Without it the circuit would be a puredifferentiator with no DC gain at all, and the drawing plainly passes DC: Cis open there and the whole pot is in the loop, 10 kOhm against 10 kOhm.`setting` records that the claims are held at D = 1/2, where the lead islargest, the zero at 40 rad/s."""
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 Hz, Parameter, System, kOhm, require, uFfrom fang.parts import Capacitor, Resistorfrom fang.rationale import Chooses, Citesfrom fang.simulation import ACSweep, OperatingPoint
from handbook import ( Bench, Claim, Ground, OpAmp, Potentiometer, Run, Terminal, corner, equals, minus, negative, over, product, ratio, within,)
class AdjustableLead(System): """E_I through R into the summing point, the pot back from the output with its wiper to ground through C."""
figure = Cites( "E_O = -[(D - D^2) R C P] E_I; putting input network from adjustable " "lag circuit in feedback path gives lead element", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 85, Adjustable Lead", )
setting = Chooses( "Where is the wiper when the claims are held?", selected="D = 1/2, where D - D^2 is largest: a zero at 40 rad/s, 6.37 Hz", alternatives=[ { "option": "D = 0.1", "reason": "less lead, the zero at 111 rad/s; the page's companion lag is quoted at D = 1/2", }, ], rationale=( "the page gives no setting for the lead; the lag beside it is quoted at D = 1/2", "at the center the zero sits lowest, so the lead is widest", ), )
a_v = Parameter("1", default=-1 * ratio, description="E_O / E_I at DC, the 1 the printed form drops") f_z = Parameter("Hz", default=6.3662 * Hz, description="the zero at D = 1/2")
e_in = Terminal() e_out = Terminal() r_in = Resistor(resistance=10 * kOhm) pot = Potentiometer(resistance=10 * kOhm, setting=Decimal("0.5") * ratio) c = Capacitor(capacitance=10 * uF) amp = OpAmp() ground = Ground()
def architecture(self): self.e_in.probe >> self.r_in.p1 self.r_in.p2 >> self.amp.inverting.signal self.amp.inverting.signal >> self.pot.end_a self.pot.end_b >> self.amp.output.signal self.pot.wiper >> self.c.p1 self.c.p2 >> self.ground.node self.amp.output.signal >> self.e_out.probe self.amp.non_inverting.signal >> self.ground.node
def constraints(self): # At DC C is open and the whole pot is the feedback resistor. require(equals(self.a_v, negative(over(self.pot.resistance, self.r_in.resistance)))) # The zero: (D - D^2) R C. lead = product(minus(self.pot.setting, product(self.pot.setting, self.pot.setting)), self.pot.resistance) require(within(self.f_z, corner(lead, self.c.capacitance), 0.0001))
BENCH = Bench( page=85, title="Adjustable Lead", runs=[ Run( "dc_gain", OperatingPoint(), drive={"e_in": "DC 1"}, measure={"gain": "v({e_out.1}) / v({e_in.1})"}, claims=[ Claim( "gain", "a_v", within=0.001, note="the printed -[(D - D^2) R C P] E_I would give 0 here; the drawn circuit gives -1", ) ], ), Run( "lead", ACSweep(points=200, start="100m", stop="1k"), drive={"e_in": "DC 0 AC 1"}, measure={ "f_3db": "when vdb({e_out.1})=3.0103 rise=1", "gain_z": "find vm({e_out.1}) at=6.3662", "phase_z": "find vp({e_out.1}) at=6.3662", "gain_10z": "find vm({e_out.1}) at=63.662", }, claims=[ Claim("f_3db", "f_z", within=0.005, unit="Hz", note="where the gain has risen 3 dB above unity"), Claim("gain_z", 1.41421, within=0.005, note="|1 + j| at the zero; without the 1 it would be 1"), Claim( "phase_z", -2.35619, within=0.005, note="radians: -135 degrees, the inversion less the zero's 45", ), Claim( "gain_10z", 10.0499, within=0.005, note="|1 + 10 j| a decade above the zero; the op amp's 10 MHz is far off", ), ], note="D = 1/2. The rise flattens only where the op amp runs out of loop gain, far above this sweep.", ), ],)The files it writes
Section titled “The files it writes”The parts, then the nets and the pads on them.
C1 10 uF -GND1 Ground -R1 10 kOhm -RV1 Potentiometer -TP1 Terminal -TP2 Terminal -U1 OpAmp -Net-(C1-Pad1) C1.1 RV1.2Net-(C1-Pad2) C1.2 GND1.1 U1.IN+Net-(R1-Pad1) R1.1 TP1.1Net-(R1-Pad2) R1.2 RV1.1 U1.IN-Net-(RV1-Pad3) RV1.3 TP2.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 7 component 16 connection 2 constraint 1 decision 1 evidence 3 interface 13 pin 13 port 57 totalsnapshot sha256:3c70aa708871d7221fad1eb5ad8bef0245285c1de2791e590e701978dd37953bAll of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/lead_lag/adjustable_lead/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/lead_lag/adjustable_lead/adjustable_lead.py