Model calibration
A model here predicts something measurable about a design — how many cycles a firing takes, how many LUTs a module costs — and says how much to believe the answer. Those numbers are properties of the synthesized hardware, so they are recovered from measurement rather than asserted: run the kernel through synthesis or RTL cosim, record what happened, fit a model, and the fast Python estimate tracks the slow truth without anyone transcribing report numbers by hand.
This section is the machinery, not either axis. Timing and resource models are the same class: they differ in what they predict and where their numbers come from, but not in shape. What follows is that shape, once — the two axes then apply it in Timing Models and Resource Models.
Start here
- What a
CalibModelis —get_params→transform→predict_feat, plus confidence, fit, and where a model’s data lives. - The corpus — the measured data every
fitreads, and its one canonical shape. CalibDataFrame— the object implementing that format.- Confidence — the four levels, and why a composed estimate reports the weakest.
- The model kinds — the concrete models you construct, and how to choose between them.
Two quantities, one set of machinery
This section covers timing and resources, and they share more than they differ:
| timing | resources | |
|---|---|---|
| where a number comes from | a run — cosim or an XSI trace | a report — csynth.xml |
| what is recovered | a fit (latency, ii, a residual) |
a measurement, attributed per module |
| keyed by | platform = FPGA part + synthesis clock | the same |
| stored in | the same record store | the same |
| published by | the same work → publish flow | the same |
The asymmetry worth remembering is in the middle row. A timing number is fit — a model form with coefficients recovered from a sweep. A resource number is measured — the report says 32 DSPs and that is what it is. Predicting resources at an unmeasured point is a separate problem, and one the module keys are designed to make cheap: two designs that induce the same module reuse one measurement rather than paying for a second synthesis.
Where the fit lives: custom vs shared infra
A fit is stored in one of two places, chosen by one knob:
- Custom components — your accelerator’s own kernels. The fit is specific to your design, so it goes
in a project-local directory you pick (
calib_dir). - Shared-infra components — reusable framework kernels (
MemRStream/MemWStream, …). Their fit is a(component, platform)property, so it goes in a git-tracked platform library (platform_dir) and ships with the repo — reuse the component on a calibrated platform and inherit its timing with no re-calibration. The library is keyed by an FPGA-part identity (see Platforms) and populated through a two-tier work → publish flow.
Why a platform is keyed by part and clock
Both axes depend on the synthesis clock (create_clock -period), not just the part: HLS schedules
to meet it, so a different target period changes the schedule — and therefore both the cycle counts
and the logic that had to be replicated to hit it. A number measured at one period does not describe
the same hardware at another, which is why the platform identity carries
both.
The simulation frequency is a different thing and changes nothing. Timing artifacts are stored in cycles rather than seconds precisely so a re-deploy at a different sim frequency needs no refit.
In this section
- What a
CalibModelis — the shape:get_params→transform→predict_feat, plusconfidence,fit, and where a model’s data lives. - The corpus —
corpus.csv: one row per measurement, derived from each axis’s raw tier rather than maintained. CalibDataFrame— the object implementing that format.- Confidence —
EXACT/INTERPOLATED/EXTRAPOLATED/UNCALIBRATED, and why a composed estimate reports the weakest link. - The model kinds — lookup, prior, concat and the two regressions, and how to choose.
- A worked example — the fit mechanics end to end: fit a
LinCalibModel, score it, hold a point out; then a saturating curve withInterpCalibModel. - Module keys and the record store — addressing a measurement by the module’s structure rather than its parameter dict, and the one record envelope both axes use.
The two axes
Everything above is shared. What differs is where a number comes from, and each axis documents its own half:
- Timing Models — declaring a model’s form, then calibrating it: the direct sweep fit, the RTL-vs-pysim residual, the once-per-platform bus model.
- Resource Models — predicting utilization: the model kinds a design attaches,
composeover a hierarchy, and attributing acsynthreport to the modules that caused it.
Pages that moved (2026-08-04). Fitting a timing model, Component residuals, The bus-transfer model and The mem-stream residual are now under Timing Models; Resource measurements is under Resource Models. They were written when this was the timing calibration section; now that the base is genuinely shared, only the axis-agnostic pages belong here.
Everything here is stored on a platform — the identity it is keyed by, the directory layout, and the commands that create and publish one are in Platforms.
See also
- Platforms — the target these fits are valid for, and where they live.
- Timing Analysis Tools — the measurement side: extracting cycle counts and bus spans from a VCD / cosim run (where the datapoints come from).
BuildConfig— theplatform/part/clk_freqselector that names the platform a build synthesizes and calibrates for.
Table of contents
- What a CalibModel is - The base every calibrated model shares, on both the timing and resource axes: get_params extracts what the corpus records, transform derives features from it, then a prediction, a confidence and a fit. Plus where a model's data lives, derived from its name and platform rather than passed.
- The corpus — measured data - One canonical shape for measured data on both axes: corpus.csv, one row per measurement, a column per parameter and per target plus a timestamp. Derived on demand from each axis's raw tier — RTL runs for timing, synthesis reports for resources — so it can never go stale, and read by fit() as the default source.
- CalibDataFrame — the corpus API - CalibDataFrame is the calibration corpus: a thin wrapper composing a pandas.DataFrame, one row per synth/cosim measurement. It adds only what a raw frame lacks — a per-row measured_at timestamp and a save/load storage path — and otherwise exposes the underlying frame as .df for native pandas filter/select.
- Confidence - Every prediction carries a level and the facts behind it: EXACT, INTERPOLATED, EXTRAPOLATED or UNCALIBRATED. What each means, how a model earns one, and why a composed estimate reports the weakest link rather than an average.
- The model kinds - The concrete kinds implementing the CalibModel shape, all axis-agnostic: LookupCalibModel memorizes and refuses to interpolate, PriorCalibModel is a zero-parameter formula, LinCalibModel an sklearn regression, InterpCalibModel a 1-D calibrated table, and ConcatCalibModel composes them across targets so each comes from whichever is honest for it.
- A worked example - A minimal end-to-end calibration: build a CalibDataFrame from a few (size, cycles) measurements, fit a LinCalibModel, read its coefficients, score it, hold a point out, and plot it; then calibrate a saturating curve with InterpCalibModel.
- Module keys and the record store - Every measurement — a cycle count from cosim, a DSP count from csynth — is a fact about one module in one configuration, and has to be filed where a different design can find it again. The address is the module's STRUCTURE, not its parameter dict, which makes the projection from system parameters onto per-module subsets mechanical rather than hand-declared. Records share one envelope {key, target, source, cost_seconds, payload, provenance} for both timing and resources, and a read verifies provenance rather than trusting the directory name.