Datasets¶
A campaign writes a folder that stands on its own:
| File | Content |
|---|---|
samples.parquet |
One row per simulation: what was injected, its status, the realised component values, the measurements |
waveforms.npy |
float32 [stored samples, points] (if a waveform was declared): one row per sample of the conditions that store one, in sample order; NaN for a failed simulation. Dataset.waveforms reads it aligned with the table, with NaN for the conditions that store none |
metadata.json |
The definition of the experiment: faults, variations, conditions, analyses, measurements, seed |
circuit.cir |
The source netlist |
manifest.json |
The record of the run: versions, platform, workers, counts by status, the git commit of the project that ran it (source), and the size and SHA-256 of every file |
from spicefault import Dataset
dataset = Dataset("data/rc_lowpass")
dataset.verify() # [] if the files match the manifest and each other
dataset.provenance(1234) # fault, seed key, realised values, versions of one sample
dataset.netlist(1234) # the netlist that was simulated for it
dataset.reproduce(n=50) # simulate samples again and compare with what is stored
X, y = dataset.to_ml(target="fault_location") # for any ML or statistical tool
analysis = dataset.analysis() # a ReliabilityAnalysis
netlistrebuilds a sample from the values stored in the table, so it needs nothing but the folder.reproducerebuilds the experiment frommetadata.jsonand reports, per sample, whether the definition, the drawn values and the status are the same, and the largest difference in the measurements and the waveform. On the machine and simulator version that wrote the dataset the differences are expected to be zero.- Functions cannot be stored. If the experiment used custom or joint variations, or
custom measurements, pass it again:
dataset.reproduce(experiment=experiment). - The library has no ML dependency:
to_mlreturns NumPy arrays.
split_by_replica(samples, test_fraction, seed) returns train/test row positions while
keeping all conditions of each replica together and stratifying by fault_id.
split_by_magnitude(samples, test_magnitudes) holds out every row at the selected fault
magnitudes. Both return NumPy index arrays. Derived labels can be added with
dataset.update_columns(frame, note=...); it updates the sample fingerprint and appends
the operation to manifest history, while definitions, parameters and measurements remain
protected.
Specifications¶
Whether a fault was injected and whether the circuit still meets its specifications
are two different questions. Dataset.label answers the second from limits that stay
with the dataset:
from spicefault import Specification
limits = [
Specification("spec_cmrr_db", minimum=89.0),
Specification("spec_noise_uvpp", maximum=30.0),
]
dataset.label(limits, note="IEC 60601-2-25 limits")
dataset.samples[["ok_spec_cmrr_db", "compliant", "violated"]]
dataset.specifications # the limits, read back from the manifest
It writes ok_<name> for each specification, compliant and violated (the names of
those that are not met), stores the limits in the manifest and appends to its history.
Calling it again with other limits relabels the dataset without simulating anything.
A value that could not be computed, also because the simulation failed, counts as a
violation. A specification belongs to the drawn circuit: with several operating
conditions, the rows of one circuit get the same labels, read in the conditions that
measure each quantity.
The instrument¶
The stored measurements are those of the simulator: noise-free. What an instrument would read is computed from them afterwards, so its noise, resolution and range are parameters of a study that need no new simulation.
from spicefault import Instrument, Reading
instrument = Instrument({"gain_db": Reading(noise=0.02, resolution=0.01, limits=(0, 40))})
observed = dataset.observe(instrument, seed=7) # a table; the dataset is not modified
dataset.statistics(instrument=instrument)
dataset.yield_report(limits, instrument=instrument) # the yield a test with it would find
dataset.analysis(instrument=instrument) # detection on what it reads
A Reading adds Gaussian noise, rounds to the resolution and clips to the limits, in
that order; each is optional. The noise of a value depends only on the seed, the
measurement and the sample, so the observed table is the same for any order or subset
of the rows. The instrument is recorded with each result (attrs["instrument"],
analysis.instrument), and in a reliability analysis the uncertainty of its readings is
the noise floor. One dataset then gives, for instance, the detectability of a fault
against the noise of the instrument.
One row per drawn circuit¶
When operating conditions have their own measurements, the table has one row per
circuit and condition, and each row holds only the measurements of its condition.
Dataset.cases joins them:
cases, waveforms = dataset.cases(waveform_from="service")
cases.attrs["features"] # the measurement columns, of every condition
X, y = dataset.to_ml(by_case=True)
analysis = dataset.analysis(by_case=True, compliant="compliant")
There is one row per fault and replica: the definition, the labels and the realised
parameters once, and the measurements of every condition side by side. A measurement
that several conditions make gets one column per condition, <name>_<condition>.
sim_ok is true only if every condition succeeded. waveform_from may be omitted
when a single condition stores the waveform.
Columns of the samples table¶
| Columns | Content |
|---|---|
sample_id |
The row number, and the position of the sample in the plan of the experiment |
fault_index, fault_id, fault_type, fault_location, fault_magnitude, fault_severity |
What was injected; healthy for the fault-free circuits |
replica, condition, seed_key |
Which draw, under which operating condition, from which random stream |
status, message, sim_ok |
The outcome of the simulation |
elapsed_s |
Time of the simulation; the only column that is not reproducible |
| labels | Quantities recorded by joint and catalogue variations, fault tags, and derived labels such as compliant |
p_<component>_<parameter> |
The value each varied parameter was drawn with, before the fault |
| measurements | One column per measurement; empty for a failed simulation and for a condition that does not make it |