Examples / TI op amp handbook / Lead and lag
Time delay
SBOA092B page 86, Time Delay: an inverting stage built to approximate a pure delay. The input is a ladder, R/6, 3.6C to ground, 2R/3, 3.6C to ground, R/6; the feedback is R beside a T of 0.8C, 0.8C with R/4 to ground. The page prints no formula, only "Unity gain phase or time shift" and a sketch: the step comes out inverted after RC and completes its edge over 1.1 RC.
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/time_delay.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 only symbols, so the program chooses R = 60 kΩ and C = 10 nF
(values), RC = 600 µs, which makes R/6, 2R/3 and R/4 10k, 40k and 15k. Each
part is held to its fraction of the parameters r and c. At DC the three
input resistors add to R, so a_v = -1: it inverts, as the sketch draws. The
delay claims are rc for the 50% point and rise = 1.1 RC for the 10% to 90%
time, each held to 5% because the page gives a sketch, not a formula.
What the simulation found
Section titled “What the simulation found”out/simulation.txt, a 1 V step at t = 0:
| Run | Measured | Claimed |
|---|---|---|
dc_gain | -1 | -1 (a_v), holds |
step, 50% point | 589 µs (0.98 RC) | 600 µs (rc), holds |
step, 10% to 90% | 671 µs (1.12 RC) | 660 µs (rise), holds |
step, settled | -1 V | -1 V, holds |
step, 10% point | 275 µs | not a claim |
step, overshoot | -1.022 V | not a claim |
The sketch draws the output flat until RC. The simulated edge is smoother: already 10% of the way at 0.46 RC, centered on RC, and it overshoots by 2%.
Running it
Section titled “Running it”fang check examples/ti_opamp_handbook/lead_lag/time_delay/time_delay.pypython examples/regenerate.py ti_opamp_handbook/lead_lag/time_delay # needs ngspiceThe whole program
Section titled “The whole program”"""The time delay, SBOA092B page 86.Show 14 more lines
"Unity gain phase or time shift"
An inverting stage built to approximate a pure delay. The input is a ladder,R/6, 3.6 C to ground, 2R/3, 3.6 C to ground, R/6 into the summing point; thefeedback is R in parallel with a T of 0.8 C, 0.8 C with R/4 to ground fromtheir junction. At DC the capacitors are open: R/6 + 2R/3 + R/6 = R in, Racross, a gain of -1. The page's sketch shows a step coming out inverted,starting after about RC and completing its rise over about 1.1 RC.
The figure gives R and C only as symbols. `values` records the pair chosenhere: R = 60 kOhm, so each fraction of it is a round number, andC = 10 nF, so RC = 600 us."""
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 Parameter, System, kOhm, nF, require, usfrom fang.parts import Capacitor, Resistorfrom fang.rationale import Chooses, Citesfrom fang.simulation import OperatingPoint, Transient
from handbook import ( Bench, Claim, Ground, OpAmp, Run, Terminal, equals, negative, over, product, ratio, total,)
class TimeDelay(System): """An RC ladder in, R across with a capacitor T beside it."""
figure = Cites( "Unity gain phase or time shift; E_O follows the E_I step, delayed by RC, " "rising over 1.1 RC", document="SBOA092B, Handbook of Operational Amplifier Applications", locator="page 86, Time Delay", )
values = Chooses( "What are R and C?", selected="R = 60 kOhm and C = 10 nF, RC = 600 us", alternatives=[ { "option": "R = 10 kOhm", "reason": "R/6 and 2R/3 would be 1.667 k and 6.667 k, values nobody stocks", }, { "option": "leave them symbolic", "reason": "a delay nobody can compute is not a claim anything can check", }, ], rationale=( "the figure gives every part as a multiple of R or C and no values", "60 kOhm makes R/6, 2R/3 and R/4 10k, 40k and 15k", ), )
r = Parameter("Ohm", default=60 * kOhm, description="the page's R") c = Parameter("F", default=10 * nF, description="the page's C") rc = Parameter("s", default=600 * us, description="R C, the delay the sketch marks") rise = Parameter("s", default=660 * us, description="1.1 R C, the rise the sketch marks") a_v = Parameter("1", default=-1 * ratio, description="E_O / E_I at DC")
e_in = Terminal() e_out = Terminal() r_in1 = Resistor(resistance=10 * kOhm) c_in1 = Capacitor(capacitance=36 * nF) r_in2 = Resistor(resistance=40 * kOhm) c_in2 = Capacitor(capacitance=36 * nF) r_in3 = Resistor(resistance=10 * kOhm) r_fb = Resistor(resistance=60 * kOhm) c_fb1 = Capacitor(capacitance=8 * nF) c_fb2 = Capacitor(capacitance=8 * nF) r_tee = Resistor(resistance=15 * kOhm) amp = OpAmp() ground = Ground()
def architecture(self): # The input ladder. self.e_in.probe >> self.r_in1.p1 self.r_in1.p2 >> self.c_in1.p1 self.r_in1.p2 >> self.r_in2.p1 self.r_in2.p2 >> self.c_in2.p1 self.r_in2.p2 >> self.r_in3.p1 self.r_in3.p2 >> self.amp.inverting.signal self.c_in1.p2 >> self.ground.node self.c_in2.p2 >> self.ground.node # The feedback: R, and the capacitor T beside it. self.amp.inverting.signal >> self.r_fb.p1 self.r_fb.p2 >> self.amp.output.signal self.amp.inverting.signal >> self.c_fb1.p1 self.c_fb1.p2 >> self.c_fb2.p1 self.c_fb2.p2 >> self.amp.output.signal self.c_fb1.p2 >> self.r_tee.p1 self.r_tee.p2 >> self.ground.node self.amp.output.signal >> self.e_out.probe self.amp.non_inverting.signal >> self.ground.node
def constraints(self): # Every part is the fraction of R or C the figure labels it with. require(equals(self.r_in1.resistance, over(self.r, 6 * ratio))) require(equals(self.r_in2.resistance, over(product(2 * ratio, self.r), 3 * ratio))) require(equals(self.r_in3.resistance, over(self.r, 6 * ratio))) require(equals(self.r_fb.resistance, self.r)) require(equals(self.r_tee.resistance, over(self.r, 4 * ratio))) for part in (self.c_in1, self.c_in2): require(equals(part.capacitance, product(Decimal("3.6") * ratio, self.c))) for part in (self.c_fb1, self.c_fb2): require(equals(part.capacitance, product(Decimal("0.8") * ratio, self.c))) require(equals(self.rc, product(self.r, self.c))) require(equals(self.rise, product(Decimal("1.1") * ratio, self.rc))) # At DC: the ladder's three resistors in, R across. require( equals( self.a_v, negative( over( self.r_fb.resistance, total(self.r_in1.resistance, self.r_in2.resistance, self.r_in3.resistance), ) ), ) )
BENCH = Bench( page=86, title="Time Delay", 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)], ), Run( "step", Transient(stop="5m", step="1u"), drive={"e_in": "PULSE(0 1 0 1n 1n 1 2)"}, measure={ "t10": "when v({e_out.1})=-0.1 fall=1", "t50": "when v({e_out.1})=-0.5 fall=1", "t90": "when v({e_out.1})=-0.9 fall=1", "rise": "t90 - t10", "final": "find v({e_out.1}) at=4.9m", "overshoot": "min v({e_out.1}) from=0 to=5m", }, claims=[ Claim( "t50", "rc", within=0.05, unit="s", note=( "the 50% point of the inverted step, against the RC the " "sketch marks; the page draws the delay and prints no formula, " "so the claim is held to 5%" ), ), Claim( "rise", "rise", within=0.05, unit="s", note="10% to 90%, against the sketch's 1.1 RC, held to 5% for the same reason", ), Claim("final", "a_v", within=0.001, unit="V", note="a 1 V step settles at -1 V"), ], units={"t10": "s", "t90": "s", "overshoot": "V"}, note=( "A 1 V step at t = 0. The sketch has the output still until RC " "and then moving; the simulated edge is smoother than that, " "already 10% of the way at 0.46 RC, but its middle sits at RC " "and it takes 1.1 RC from 10% to 90%." ), ), ],)The files it writes
Section titled “The files it writes”The parts, then the nets and the pads on them.
C1 8 nF -C2 8 nF -C3 36 nF -C4 36 nF -GND1 Ground -R1 60 kOhm -R2 10 kOhm -R3 40 kOhm -R4 10 kOhm -R5 15 kOhm -TP1 Terminal -TP2 Terminal -U1 OpAmp -Net-(C1-Pad1) C1.1 R1.1 R4.2 U1.IN-Net-(C1-Pad2) C1.2 C2.1 R5.1Net-(C2-Pad2) C2.2 R1.2 TP2.1 U1.OUTNet-(C3-Pad1) C3.1 R2.2 R3.1Net-(C3-Pad2) C3.2 C4.2 GND1.1 R5.2 U1.IN+Net-(C4-Pad1) C4.1 R3.2 R4.1Net-(R2-Pad1) R2.1 TP1.1Every check that ran, and every one left undecided.
12 checks, 0 failed, 0 undecidedWhat the elaborated graph contains, by entity kind.
1 block 13 component 34 connection 12 constraint 1 decision 1 evidence 3 interface 24 pin 24 port 113 totalsnapshot sha256:deae09cdcd73047907f46b680f850ac0e3c89b1a27ef6896b862bbfb89e50ad9All of it, including the KiCad netlist, is in
examples/ti_opamp_handbook/lead_lag/time_delay/out/. Rebuild it with:
fang build examples/ti_opamp_handbook/lead_lag/time_delay/time_delay.py