The idea behind depth-based derating can be tested directly: draw a delay for each stage from a normal distribution, add them up, and measure the spread of the totals. This is a model of independent random variation only; it says nothing about systematic effects.
import random, statistics
rng = random.Random(2024) # fixed seed: deterministic
def rel_sigma(n, samples=4000):
totals = [sum(rng.gauss(0.10, 0.005) for _ in range(n)) for _ in range(samples)]
return statistics.pstdev(totals) / statistics.fmean(totals)
r = {n: rel_sigma(n) for n in (1, 4, 16)}
assert 0.045 < r[1] < 0.056 # expected 0.05 for one stage
assert 3.7 < r[1] / r[16] < 4.4 # expected 4 = sqrt(16)
assert 1.8 < r[1] / r[4] < 2.2 # expected 2 = sqrt(4)
print("PASS: relative sigma by stages", {n: round(v, 4) for n, v in r.items()}, "; ratio 1 to 16:", round(r[1] / r[16], 2))Stages | Relative sigma (theory) | Relative sigma (simulation, approx.) |
|---|---|---|
1 | 0.0500 | 0.050 |
4 | 0.0250 | 0.025 |
16 | 0.0125 | 0.012 |
Each stage has a mean of 0.10 ns and a sigma of 0.005 ns, so a single stage has 5% relative spread. Four stages give about half of that and sixteen stages a quarter, matching 1 over the square root of n. The simulation confirms the formula behind the depth-based table. It also marks the limit of the method: if stage variations are correlated (a common supply or temperature effect), the spread does not shrink this way.
The depth-based tables reflect independent random variation; systematic effects are carried by corners and other margins.
Stage counting matches the way the tables were built.
Any use of depth credit on a path dominated by a few cells (long wires, a macro) is questioned.
One eighth (1/sqrt(64)), so 0.05 / 8 = 0.00625 in this model.