Skip to content
copperhead.sh
Get started

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 schematic, drawn by copperhead from the circuit's netlist
The schematic, drawn by copperhead from the circuit's netlist

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, fang's own projection
The interconnect view, fang's own projection

The interconnect view is fang’s own projection. It names the parts as the program does, so it reads against the code below.

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.

out/simulation.txt, a 1 V step at t = 0:

RunMeasuredClaimed
dc_gain-1-1 (a_v), holds
step, 50% point589 µ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% point275 µsnot a claim
step, overshoot-1.022 Vnot 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%.

Terminal window
fang check examples/ti_opamp_handbook/lead_lag/time_delay/time_delay.py
python examples/regenerate.py ti_opamp_handbook/lead_lag/time_delay # needs ngspice
examples/ti_opamp_handbook/lead_lag/time_delay/time_delay.py
"""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; the
feedback is R in parallel with a T of 0.8 C, 0.8 C with R/4 to ground from
their junction. At DC the capacitors are open: R/6 + 2R/3 + R/6 = R in, R
across, 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 chosen
here: R = 60 kOhm, so each fraction of it is a round number, and
C = 10 nF, so RC = 600 us.
"""
import sys
from decimal import Decimal
from 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, us
from fang.parts import Capacitor, Resistor
from fang.rationale import Chooses, Cites
from 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 parts, then the nets and the pads on them.

out/netlist.txt
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.1
Net-(C2-Pad2) C2.2 R1.2 TP2.1 U1.OUT
Net-(C3-Pad1) C3.1 R2.2 R3.1
Net-(C3-Pad2) C3.2 C4.2 GND1.1 R5.2 U1.IN+
Net-(C4-Pad1) C4.1 R3.2 R4.1
Net-(R2-Pad1) R2.1 TP1.1

Every check that ran, and every one left undecided.

out/checks.txt
12 checks, 0 failed, 0 undecided

What the elaborated graph contains, by entity kind.

out/graph.txt
1 block
13 component
34 connection
12 constraint
1 decision
1 evidence
3 interface
24 pin
24 port
113 total
snapshot sha256:deae09cdcd73047907f46b680f850ac0e3c89b1a27ef6896b862bbfb89e50ad9

All of it, including the KiCad netlist, is in examples/ti_opamp_handbook/lead_lag/time_delay/out/. Rebuild it with:

Terminal window
fang build examples/ti_opamp_handbook/lead_lag/time_delay/time_delay.py