Results & Data Export
Every run's results are written to disk as a self-describing NumPy `.npy` file you can read from Python, MATLAB, or any tool that speaks NumPy — no re-running the simulation. This chapter covers where results live, how to export them in other formats, and how to read the `.npy` in a few lines of Python.
The result model: DataSet & DataCube
Every analysis returns a DataSet — a named collection of DataCubes. A DataCube is an
N-dimensional array of one kind (Real or Complex) with named, labelled axes. For example, a
harmonic-balance voltage cube V has axes [node, harmonic, sweep]: the node axis carries
string labels like X1.drain, the harmonic axis carries integer orders, and the sweep axis
carries the swept values and their unit. This self-describing structure is exactly what the .npy
file preserves — so a trace, a marker, or a Python script all address the same data the same way.
Measurements (figures of merit) are added to the DataSet as named cubes too.
Where results live
A run writes one file holding every analysis it produced, plus a measurements group. It goes to
the workspace's shared results folder:
<workspace>/results/<name>.npy
You choose <name>, in the Analyses panel. Above the analyses list there is a single
Results file field — one field for the whole run, not one per analysis card, because a run produces
one file.
| Results file field | What happens |
|---|---|
| Left blank (the default) | The run writes <schematicKey>.npy, where the key is the cell or schematic name. Every run under that schematic overwrites it. |
| A name you type | The run writes that file instead. This is how you keep a baseline: name one run before-tuning.npy, clear the field, and subsequent runs go back to the default file while the baseline stays put. |
The name is sanitised to a plain file name — .npy is appended if you leave it off, and path
separators are stripped, so the field names a file, not a folder. Every result of every schematic
in the workspace lands side by side in that one results/ directory, which is what lets the Data
Display offer them all in one picker.
Naming a file preserves it only until you run again under the same name. There is no automatic run history and no numbered suffixes: the named file is overwritten silently on every subsequent run under that name. Clear the field once you have the baseline you want.
A scratch schematic — one you have not saved into a workspace — still writes its
results, into the scratch recovery session's own results/ folder, so a quick experiment is
plottable without saving anything first.
See Grouped results below for what is inside the file. The Data Display reads these files directly; nothing is recomputed to plot a result you already ran.
Exporting in other formats
Open the exporter from File → Export… or the Export button on the Data Display toolbar. Pick a
run (any results file in the workspace's results/ folder), choose what to include, and pick a
format:
| Format | Extension | What it's for |
|---|---|---|
| NumPy | .npy | The full grouped DataSet, lossless — the format this chapter documents. |
| MATLAB | .mat | The same cubes as MATLAB struct fields. |
| Tab-delimited text | .txt | Columns of numbers for spreadsheets / quick inspection. |
| Touchstone | .sNp | S-parameters for a single group — renormalized to one real reference impedance (you set Z0); choose magnitude-angle, dB, or real-imag. |
| Loadpull SPL | .spl | A loadpull-shaped result as an SPL dataset (offered only for loadpull runs). |
| Loadpull LP-CWave | .lpcwave | A loadpull-shaped result as an LP-CWave dataset (offered only for loadpull runs). |
You can include or exclude the measurements group, and Touchstone/loadpull exports let you pin
or iterate sweep axes to slice out the block you want. Multi-frequency loadpull results export
across all their frequency blocks.
The same formats come out of a headless run. Every run verb takes -o <path>, and the
extension picks the format — hb, lp and lpp write .mat, .npy or .txt; lp also writes
.spl and .lpcwave; sparam always writes Touchstone; em writes both a Touchstone and a grouped
.npy carrying its diagnostics. See The Command Line.
Grouped results
A run that has several analyses produces one grouped DataSet: a group per analysis (named for
the analysis — HB1, SP1, DC1, …) plus a measurements group for your figures of merit. In
the .npy file:
The metadata lists the groups in order, and every cube records which group and cube it is.
A cube is addressed by its qualified name (
HB1.V) or, when unambiguous, its bare name (V) — the same way a measurement references it.
A single-analysis run (e.g. a CLI S-parameter export) typically has just one group plus possibly
measurements.
Reading a .npy in Python
The file is a single NumPy structured array. The __meta__ field is a JSON blob describing every
cube — its group, kind, and axes (names, units, values, labels). Read the metadata, then index the
cube field:
import json, numpy as np
arr = np.load('run.npy', allow_pickle=False)
meta = json.loads(arr['__meta__'][0]) # bytes → dict
assert meta['format_version'] == 2
print('groups:', meta['groups']) # e.g. ['HB1', 'measurements']
# Map (group, cube) → the numpy field name. Read group/cube from __meta__;
# the field name itself is opaque — never parse it.
field_of = { (e['group'], e['cube']): f
for f, e in meta.items()
if isinstance(e, dict) and 'cube' in e }
# Pull the HB voltage cube and its axes
vf = field_of[('HB1', 'V')]
V = arr[vf][0] # shape [node, harmonic, sweep], complex128
axes = meta[vf]['axes']
# Find a node by its label, plot its fundamental vs the sweep
nodes = axes[0]['labels'] # ['X1.gate', 'X1.drain', ...]
drain = nodes.index('X1.drain')
sweep = axes[2]['values'] # e.g. Pin in dBm
fund = V[drain, 1, :] # harmonic order 1, all sweep points
for pin, v in zip(sweep, fund):
print(f'Pin={pin} dBm |V_drain|={abs(v):.4f} V')
An export can optionally carry the run's linear network (the MNA matrices and source
vectors), which lets a consumer reconstruct any linear-interior node voltage or branch current
that wasn't stored as a cube — by solving the linear system rather than re-running the simulation. The full
math, field-by-field layout, and a worked Python example are in the developer guide
docs/design/npy-data-consumer-guide.md.
Format stability
The on-disk .npy layout is not stable during the alpha. The current
format_version is 2; always check it before reading and reject a mismatch.
Backward compatibility is explicitly declined — if the exporter changes, regenerate your files. Don't build
persistent archives or third-party tooling on this format until it is declared stable (post-v1.0).
See also: Measurements · Plot
types · Simulations. Full developer-facing format spec (groups, the
__meta__ schema, and linear-network reconstruction):
docs/design/npy-data-consumer-guide.md.