Tuning a parameter against measured data

August 28, 2026

"Recovering structure from data" and its follow-up covered a model you don't know the shape of yet, letting a CSV propose the nodes and equations themselves. This page is the opposite situation: you already know the equations, you're just not sure about a couple of constants in them. That's a much more common gap in practice, and Konjugate has a dedicated feature for closing it: mark a parameter "Tunable," import measured data, and let a real optimizer search for the values that fit, on an edge's own parameters and a node's own source-term parameters alike, together in one pass.

The example reuses "Getting started"'s hot plate and room air, hand-built the same way, except this time the cooling relationship is written as a genuine Newton's-law-of-cooling term, rate × (plate − room), Room air also gets its own constant heat-gain source term, and both get a deliberately wrong starting guess.

Marking a parameter tunable

Every edge parameter already has a Mode of Constant or Live. A second, independent checkbox sits below it in the same relationship editor:

The Cooling relationship's parameter row, with a wrong initial guess and Tunable unchecked
k starts at 0.02. The equation itself, k · (sourcePlateTemperature − targetRoomTemperature), is a real cooling law, not a placeholder.

Checking Tunable (fitting target) reveals fitting bounds, a minimum and maximum the optimizer is allowed to search between:

The same parameter row with Tunable checked and fitting bounds set
Bounds of [0, 0.2] give the optimizer plenty of room to move away from the wrong 0.02 guess.

Tunable is unrelated to Live: a live parameter is meant to be dragged on a slider mid-run, so it has no fixed baseline worth calibrating beforehand, and the editor disables Tunable while Mode is Live for exactly that reason. A parameter can be tunable, live, both or neither.

Source-term parameters can be tunable too

Tunable isn't limited to a relationship's own parameters. A node's own source term, the same place a self-contained physics term lives, independent of any edge, gets an identical Parameters section in its own editor, with the identical Tunable checkbox:

Room air's own source term, with a wrong initial guess and Tunable unchecked
Ambient gain starts at 0: no assumed background heating at all, inside a source term whose equation is just ambientGain, a constant contribution to Room air's own temperature.
The same source-term parameter row with Tunable checked and fitting bounds set
Bounds of [-1, 1] cover both a heat gain and a heat loss, since the wrong 0 guess gives no hint which direction the real value lies in.

Room air's Cooling edge already pulls heat from the hot plate; this source term adds a second, independent effect: a constant ambient gain unrelated to the plate at all, the kind of background term real measured data often needs to account for. Nothing about marking it tunable differs from an edge parameter: same checkbox, same fitting-bounds fields, same underlying mechanism.

What the wrong guesses predict

Before touching the tuning feature at all, it's worth seeing what the wrong guesses actually produce. Running the model for 40 seconds:

The 40-second run with both wrong guesses: Room air reaches only 58.5
Room air: 58.5495. With ambientGain still at its wrong guess of 0, this run is identical to a Cooling-only model: the source term contributes nothing yet.

The Tuning panel

Parameter tuning, its own button in the toolbar, opens the tuning card. It starts with a choice of goal: Match measured data, which is what the rest of this page does, or Optimise an objective, covered near the end. Choosing a CSV of measured data shows what it found:

The Parameter tuning card after loading a CSV: column mapping and both tunable parameters, each ticked with its range
roomTemperature matched Room air's Temperature state by exact name. Both Cooling · Rate and Room air · source term · Ambient gain are listed under Parameters to tune, each with its current value and its range.

Mapping here is existing-states-only: unlike causal inference, there's no "create a new node" option, since fitting a parameter requires a model that already exists to fit it against. A CSV column with no matching state by that exact name simply isn't usable, rather than prompting to create something new. Parameters to tune lists every parameter in the model that can be tuned, on a relationship or a source term alike, each with a Tune tick and a minimum and maximum; the optimizer fits the ticked ones together against the same measured signal. The Optimizer dropdown offers nine real backends, five derivative-free (BOBYQA, COBYLA, Nelder-Mead, PRAXIS, Subplex, plus the global ISRES) and three gradient-based (SLSQP, MMA, CCSAQ), all running through NLopt against the actual simulator, not a surrogate model. Simulations (at most) and an optional Time limit keep a first attempt from running away.

Running the fit

Run fit simulates the model over and over, each time with different values for k and ambientGain together, scoring each attempt against the measured CSV until it converges. While it runs, a chart plots the score of every simulation with the best so far, along with the number of simulations, the time elapsed, the rate and how far the score has fallen from where it started. Stop and use best so far ends the search early and keeps what it found, and Apply best so far ends it and applies those values at once. A simulation that fails is scored as the worst possible, so one bad trial does not stop the search. When it finishes, the review looks like this:

The review step after a completed fit: k moved from 0.02 to 0.0498876, ambientGain from 0 to 0.299326
Converged (parameterToleranceReached), final loss 3.240e-11. The CSV was generated from true values of 0.05 and 0.3, so both recovered values are a genuine joint recovery, not a coincidence.

Both parameters get their own row with their own before/after values, checked independently. An unchecked row (which happens automatically when a fit diverges to a non-finite value for that specific parameter) is left out of the apply step rather than blocking the others. The comparison plot underneath shows measured against simulated for the fitted run, with a residual sub-plot beneath it: consistent blue for simulated and orange for measured throughout, so the two are easy to tell apart even when they nearly overlap.

Apply fitted values commits the checked rows through the same validate-then-apply pipeline every other model edit in this series has used, as one undoable step: both parameters land together, not one edit each. Konjugate is explicit about what that does and doesn't touch: "Fitted parameters applied. Use Save As to keep this as a new project -- the original is untouched until you do."

The result, with the real constants

Running the identical 40-second simulation again, changed only by those two parameters:

The 40-second run with the fitted values: Room air now reaches 85.7
Room air: 85.6733, matching the measured data this was fitted against far more closely than the original guesses ever did.

Tuning toward a goal instead of data

Not every question starts with measurements. Sometimes the question is "which value makes my model do the best it can at something?" For that, choose Optimise an objective at the top of the card. The data file becomes optional, and a new Objective section appears.

The Parameter tuning card with the two goals side by side
Match measured data is the flow above. Optimise an objective needs no CSV.

An objective is one number that the search makes as small or as large as it can, chosen with the Goal switch (Minimise or Maximise). It is written in the same equation editor used for relationships, in Visual or LaTeX. A state changes over the whole run, so it has to sit inside a summary, and the buttons under the editor add them: final (the value at the end), max, min, mean and ∫ over the run (the value added up over time). Chips below insert the model's states and parameters by name. The diagnostics line under the editor says Valid objective or explains what is wrong, such as a state used without a summary.

This example keeps the room near 60 for the whole 40 seconds. The objective is the total over the run of the squared distance from 60:

The objective written as an integral of the squared difference between Room air's temperature and 60
The integral button wrote the shape and the Room air · Temperature chip filled in the state. Each simulation runs for 40 seconds.

Room air's Ambient gain is the only parameter ticked, with a range of -1 to 1, so that is what the search may change. The objective has to be written in terms of the states and parameters the model actually has, and the card says so if it is not.

Run fit works exactly as before. Each trial is a full 40-second simulation scored by the objective, and the chart shows the best so far falling:

The progress of the search, with the best objective falling from 11480 to 9824
Seventeen simulations, a fall of 14%, and the ambient gain moving from 0 to -0.5215.

The review shows the value it chose and what that did to the objective, with the run before and after tuning drawn together:

The review of the objective tuning, with the room's temperature before and after tuning
The objective fell from 11480 at the starting value to 9824 with the tuned one. The tuned room (solid) stays closer to 60 than the starting room (dashed).

A note on what a result like this means. The search found the best value of one constant for this objective, not a room that sits at 60. A single constant gain cannot lift the room quickly at the start and also stop it overshooting later, so the search balances the two. To ask for more, add a limit with the plus button beside Limits, which keeps a number from the run within a bound, and breaking one is penalised so the search settles inside it when it can.

The whole setup is saved with the project, so reopening the card restores the goal, the objective and the limits.

Where to go from here

"Getting started" covers building this same hot plate and room air model from nothing. "Recovering structure from data" covers the other end of working with measured data: not knowing the equation at all, rather than knowing it and needing a few numbers inside it.

Follow Konjugate on LinkedIn for updates, or subscribe via RSS.

Comments