Sweeps, Corners, and Monte Carlo

After a single simulation is stable, use Monata to run structured exploration: parameter sweeps, PVT corners, and statistical variation.

Parameter Sweeps

ParameterSweep creates one SimTask per parameter value.

from monata.sim.core import ParameterSweep, TranSpec

sweep = ParameterSweep(
    circuit,
    TranSpec(stop=10e-9),
    output_names=["out"],
)
sweep.sweep("w_p", [0.5e-6, 1e-6, 2e-6, 4e-6])
results = sweep.run()

values = results.values()
delays = results.extract(propagation_delay)

Use one-dimensional sweeps for early sensitivity checks. Use two-dimensional sweeps when you need an interaction map between two variables.

sweep.sweep("w_p", [0.5e-6, 1e-6], param2="w_n", values2=[0.25e-6, 0.5e-6])
results = sweep.run()
result = results.result_at(1e-6, 0.5e-6)

ParameterSweep is a mutable builder. Calling sweep() again replaces the previous sweep definition, including clearing a previous second axis when the new sweep is one-dimensional.

Corners

CornerMatrix expands temperatures, voltages, and model corners into a list of simulation tasks.

from monata.sim.core import CornerMatrix, TranSpec

corners = CornerMatrix(circuit, TranSpec(stop=10e-9), output_names=["out"])
corners.add_temperatures(-40, 27, 125)
corners.add_model_corners(
    tt="models/tt.lib",
    ss="models/ss.lib",
    ff="models/ff.lib",
)

corner_results = corners.run()

For the native ngspice backend, temperature corners emit .temp, model corners emit .include for the selected model file, and voltage corners mutate matching voltage sources through source.V overrides. Process/model-deck corners need a concrete model file or techlib projection; otherwise the backend fails explicitly with metadata["reason"] == "unsupported_corner".

Use specs to summarize corners instead of manually inspecting every waveform.

table = specs.evaluate_all(corner_results)
worst_corner, worst_delay = specs.worst_corner("tpd", corner_results)

Monte Carlo

Monte Carlo analysis is for statistical variation. Use it after nominal and corner behavior are understood.

Typical Monte Carlo flow:

  1. Define variations for device or process parameters.

  2. Generate repeated simulation tasks.

  3. Evaluate the same metric for every result.

  4. Summarize yield, histogram, and worst-case behavior.

MonteCarlo.run() builds one SimTask per sample and submits the batch through the executor. Seeded Monte Carlo runs are reproducible. add_mismatch() is not implemented in the current milestone and raises NotImplementedError instead of silently ignoring mismatch input.

Execution Guidance

Sweeps and corners can create many independent tasks. Use LocalExecutor with an explicit worker count when running locally:

from monata.sim.core import LocalExecutor

executor = LocalExecutor(max_workers=8)
corner_results = corners.run(executor=executor)

Keep the first run small. Expand the matrix only after the metric functions and backend configuration are proven.