Measuring with .meas
Turn a simulated waveform into numbers with meas: delays, rise times, extremes and energy, with the crossing named and the result checked.
- Lesson
- E1.5
- Time
- 25 min
- Runs on
- ngspice
- Check
- 5 questions
A characterization script measured an RC delay with TRIG v(in) VAL=0.5 RISE=1 TARG v(out) VAL=0.5 RISE=1. Before the input edge, a glitch pushed the output past 0.5 V, so the first rise of v(out) came first. The script wrote a delay of −17.71 µs into a spreadsheet that nobody checked.
- v(in)
- v(out)
- Time 2.293 µsv(in) = 0 V · v(out) = 499.3 mV
v(out) rises through 0.5 V at 2.293 µs, on the glitch. TARG with RISE=1 stops here, before the TRIG edge, so the delay comes out negative.
- Time 20 µsv(in) = 396.8 mV · v(out) = 216 µV
The input crosses 0.5 V at 20.0005 µs, halfway up its 1 ns edge. This is the TRIG point.
- Time 20.69 µsv(in) = 1 V · v(out) = 499.9 mV
v(out) crosses 0.5 V again at 20.69 µs. Counting from the TRIG point, that is a delay of 693.1 ns, which is ln 2 · τ for τ = 1 µs.
Read the plot as a table
| Time | v(in) | v(out) |
|---|---|---|
| 0 s | 0 V | 0 V |
| 2.293 µs | 0 V | 499.3 mV |
| 5 µs | 0 V | 64.91 mV |
| 10 µs | 0 V | 437.5 µV |
| 15 µs | 0 V | 2.948 µV |
| 20 µs | 297.7 mV | 49.62 µV |
| 20 µs | 396.8 mV | 216 µV |
| 20.69 µs | 1 V | 499.9 mV |
| 25 µs | 1 V | 993.3 mV |
| 30 µs | 1 V | 1 V |
Measured on ngspice 42 (500 of the run's points).
A meas line answers exactly the question you wrote, so write the question with care.
Turning a curve into a number
meas runs after an analysis has finished. It reads the saved vectors and prints one line per result, such as tdelay = 6.931367e-07. Inside a .control block the result also becomes a vector, so a later let or meas can use it.
| Form | The question it answers | In the lab |
|---|---|---|
FIND v(x) AT=t | What is v(x) at time t? | every E1.3 milestone |
WHEN v(x)=val | When does v(x) cross val? | the predict item below |
FIND v(y) WHEN v(x)=val | What is v(y) when v(x) crosses val? | the phase at −3 dB in E1.4 |
TRIG ... TARG ... | How long from one crossing to another? | tdelay, trise |
MIN MAX PP AVG RMS | Extreme, peak-to-peak, mean or RMS over a window | vglitch |
INTEG | The area under a curve over a window | esrc, eheat |
FROM= and TO= set the window; TD= starts the search later.
The crossing forms take a count. RISE=2 means the second time the signal rises through the value, FALL=1 the first time it falls, and CROSS=3 the third crossing in either direction. LAST picks the final one. TD=20u ignores everything before 20 µs.
Most forms also print where they found their answer. vglitch = 7.843741e-01 at= 2.507000e-06 says the glitch peaked at 0.7844 V at 2.507 µs, just as the current pulse ended. A TRIG ... TARG line prints both crossing times, trig= and targ=, which is the quickest way to see which edges a delay was measured between.
A meas line cannot compute an expression of vectors inside .control. Build the vector first with let, then measure it. The lab does that for the power the source delivers, let p = -v(in)*i(V1). The minus sign undoes the SPICE convention that a delivering source has a negative current.
Name the crossing
The hook's line asked for the first rise of v(out) past 0.5 V, and the glitch supplied it. Two small changes ask the question that was meant.
The first crossing
meas tran tbad TRIG v(in) VAL=0.5 RISE=1 TARG v(out) VAL=0.5 RISE=1
tbad = -1.770781e-05: the target is the glitch at 2.293 µs, 17.71 µs before the trigger.
The crossing after the edge
meas tran tdelay TRIG v(in) VAL=0.5 RISE=1 TARG v(out) VAL=0.5 RISE=1 TD=20u
tdelay = 6.931367e-07: 693.1 ns, which is ln 2 · τ.
Both lines are in the lab netlist, measured on ngspice 42.
The rise time in the lab uses the other fix. Its trigger, TRIG v(out) VAL=0.1 RISE=2, skips the glitch's rise by counting it. The result, trise = 2.197201e-06, is the 10 % to 90 % time of E1.3, ln 9 · τ.
Prefer TD= when you know when the event starts, and a count when you know how many edges come first. Never trust "the first one" on a waveform you have not looked at.
Check that it worked, and check it on a known answer
A meas that finds no crossing prints a line ending in failed! and creates no vector. A later let that uses it stops with an error, as below, and every line after it that needs the value fails too. Read the log for failed, and never let a script reuse an old number.
meas tran t15 WHEN v(out)=1.5
let x = t15*2
* the log:
* meas tran t15 when v(out)=1.5 failed!
* Error: RHS "t15*2" invalidA script usually turns a number into a verdict with if. Inside .control, comparisons are written gt, lt, ge and le. A condition on a vector that a failed meas never created counts as false, so the else branch runs. Write the test so that only a good number can reach PASS.
PASS unless proven bad
if tdelay lt 0.65u or tdelay gt 0.75u
echo FAIL tdelay
else
echo PASS tdelay
end
C1 typed as 1u: v(out) never reaches 0.5 V, tdelay fails, and the log still says PASS tdelay.
PASS only on a good number
if tdelay gt 0.65u and tdelay lt 0.75u
echo PASS tdelay
else
echo FAIL tdelay
end
The same broken bench prints FAIL tdelay. With C1 = 1n both print PASS tdelay.
Both follow the lab's tdelay line on the bench without the glitch, measured on ngspice 42.
Then test the measurement on a circuit whose answer you know. Charging a capacitor C to V through any resistor takes energy C·V2 from the source. Half is stored in the capacitor, and the other half is burned in the resistor, whatever its value.
- v(out)
- p = −v(in)·i(V1)
- Time 20 µsv(out) = 631 µV · p = −v(in)·i(V1) = 530 µW
Right after the edge the full 1 V sits across R1: the source delivers 1 mW.
- Time 20.69 µsv(out) = 499.9 mV · p = −v(in)·i(V1) = 500.1 µW
At the 50 % point the current has halved, and so has the power.
- Time 25 µsv(out) = 993.3 mV · p = −v(in)·i(V1) = 6.743 µW
Five time constants later the power is almost zero. The area under the whole pulse,
esrc, is 0.9998 nJ.
Read the plot as a table
| Time | v(out) | p = −v(in)·i(V1) |
|---|---|---|
| 0 s | 0 V | 0 W |
| 5 µs | 64.91 mV | 0 W |
| 10 µs | 437.5 µV | 0 W |
| 15 µs | 2.948 µV | 0 W |
| 20 µs | 49.62 µV | 89.28 µW |
| 20 µs | 631 µV | 530 µW |
| 20.69 µs | 499.9 mV | 500.1 µW |
| 25 µs | 993.3 mV | 6.743 µW |
| 30 µs | 1 V | 45.42 nW |
Measured on ngspice 42 (500 of the run's points).
The lab measures esrc = 9.99837e-10 from the source and eheat = 4.99841e-10 in R1: C·V2 = 1 nJ and half of it, to 0.02 %. Without the glitch source I2, change R1 to 2 kΩ: the charge takes twice as long, and esrc still reads 0.9999 nJ. The small shortfall is the 1 ns input edge: a ramp charges a little more gently than a step.
Asked in interviews
How do you measure propagation delay and rise time in SPICE?
With TRIG/TARG: delay from the input's 50 % crossing to the output's, rise time from the output's 10 % to its 90 % crossing. Name the edge with RISE/FALL counts or TD, and check the result is positive and plausible.
How do you measure the average power of a block?
Build the supply power with let, p = −v(vdd)·i(VDD), then use AVG over a whole number of periods, or INTEG for energy per event. Exclude the start-up transient from the window.
What do you do when a .meas fails?
Read why: usually the crossing never happens in the window, or a count is too high. Plot the signal, fix the value, window or count, and make the script stop on "failed" rather than reuse an old result.
Try it
Run it and read the seven lines. tbad is negative, tdelay and trise match the RC milestones of E1.3, vglitch shows how high the glitch went, and e5 shows what a short window misses.
Now delete the I2 line and rerun. tbad turns into the same number as tdelay, and trise fails: with no glitch there is no second rise. Change its count to RISE=1. Then change R1 to 2k and predict tdelay, esrc and eheat before you run.
Run the netlist to draw its plots here.
tbad = -1.770781e-05 targ= 2.292689e-06 trig= 2.000050e-05 tdelay = 6.931367e-07 targ= 2.069364e-05 trig= 2.000050e-05 trise = 2.197201e-06 targ= 2.230306e-05 trig= 2.010586e-05 vglitch = 7.843741e-01 at= 2.507000e-06 esrc = 9.99837e-10 from= 2.00000e-05 to= 7.00000e-05 eheat = 4.99841e-10 from= 2.00000e-05 to= 7.00000e-05 e5 = 9.93096e-10 from= 2.00000e-05 to= 2.50000e-05Check yourself
Remember
measturns saved vectors into numbers after the run: FIND AT, WHEN, FIND WHEN, TRIG/TARG, MIN/MAX/PP/AVG/RMS and INTEG over a FROM/TO window.- Name the crossing with RISE, FALL or CROSS counts, or start the search later with TD; never trust the first crossing on an unseen waveform.
- A failed meas prints "failed!" and creates no vector; anything that uses it fails, so stop on it instead of reusing an old value.
- Inside .control, build expressions with let and measure the new vector.
- Check a bench on a known answer: charging C to V costs C·V2 from the source, half of it heat in R, for any R.