Tests run in interactive mode - each test executes its own analysis separately. Write simple, direct measurement commands.
Test(
name="test_name",
environment=[], # Optional: temperature, supply voltage, etc.
spice_code="""
.ac dec 100 1 1G
meas ac my_metric_val FIND vdb(vout) AT=10
print my_metric_val
""",
description="What this test measures"
)Metrics MUST be named {metric.lower()}_val:
- Target:
metric="DC_GAIN"→ Variable:dc_gain_val - Target:
metric="POWER"→ Variable:power_val
Use netlist format (with dot prefix):
.ac dec 100 1 1G- AC analysis.dc Vin 0 1.8 0.01- DC sweep.tran 1n 100n- Transient.op- Operating point
These are automatically converted to interactive commands (ac, dc, tran, op).
❌ DON'T use if/else/end - they don't work in interactive mode.
✅ DO use simple measurements and calculations:
meas ac dc_gain_val FIND vdb(vout) AT=10
let power_val = v(vdd) * (-i(V2))
Don't include .control/.endc or run - they're handled automatically.
Test(
name="dc_gain_measurement",
environment=[],
spice_code="""
.ac dec 100 1 1G
meas ac dc_gain_val FIND vdb(vout) AT=10
print dc_gain_val
""",
description="Measure DC gain at 10 Hz"
)Test(
name="power_measurement",
environment=[],
spice_code="""
.op
let power_val = v(vdd) * (-i(V2))
print power_val
""",
description="Measure DC power"
)Test(
name="gbw_measurement",
environment=[],
spice_code="""
.ac dec 100 1 1G
meas ac dc_gain_for_gbw FIND vdb(vout) AT=10
let gbw_val = 10 * 10^((dc_gain_for_gbw - 0) / 20)
print gbw_val
""",
description="Estimate GBW from DC gain"
)Test(
name="phase_margin_measurement",
environment=[],
spice_code="""
.ac dec 100 1 1G
meas ac phase_rad FIND vp(vout) AT=1e6
let phase_margin_val = (180 + phase_rad * 180 / pi)
print phase_margin_val
""",
description="Phase at 1MHz converted to degrees"
)meas ac gain FIND vdb(vout) AT=1e6
meas dc current FIND i(R1) AT=0.9
meas tran max_v FIND v(out) AT=50n
meas ac ugf WHEN vdb(vout)=0 CROSS=1
meas dc threshold WHEN v(out)=0.9 CROSS=1
let power_val = v(vdd) * abs(i(V2))
let phase_deg = vp(vout) * 180 / pi
let gain_linear = 10^(vdb(vout) / 20)
Each test runs independently with its own analysis:
tests = [
Test(name="gain", spice_code=".ac dec 100 1 1G\nmeas ac dc_gain_val ..."),
Test(name="phase", spice_code=".ac dec 100 1 1G\nmeas ac phase_val ..."),
Test(name="power", spice_code=".op\nlet power_val ..."),
]All tests execute in sequence for each optimization iteration.
Cause: Measurement failed (threshold not crossed, frequency out of range)
Solution: Use simpler measurements or adjust frequency/threshold:
# Instead of:
meas ac ugf WHEN vdb(vout)=0 CROSS=1 # Might fail
# Try:
meas ac phase_val FIND vp(vout) AT=1e6 # Always succeeds if simulation runs
Cause: Variable name doesn't match {metric}_val pattern
Solution: Check naming:
Target(metric="DC_GAIN", ...) # Target name
# Variable must be:
meas ac dc_gain_val ... # Lowercase + _val✅ DO:
- Use
.ac/.dc/.tran/.opanalysis directives - Name variables
{metric.lower()}_val - Use simple
measandletstatements - Include
printstatements for debugging
❌ DON'T:
- Use
if/else/endcontrol flow - Include
.control/.endcblocks - Use
runcommand - Forget the
_valsuffix
Test(
name="my_test",
environment=[],
spice_code="""
.ac dec 100 1 1G
meas ac my_metric_val FIND vdb(vout) AT=10
print my_metric_val
""",
description="Brief description"
)