Skip to content
TwinProcessAI

Technology

Physics first, machine learning second.

This page is for the reader who wants to check us. It covers how the models were chosen, how they were validated, where they fail, and what the system deliberately does not attempt.

The engineering basis

Every output carries its formula, assumptions, units, reference, valid range and validation check.

The twin resolves 41 outputs, and each one is documented as data rather than prose: the equation it comes from, what was assumed, the units, the standard or textbook it follows, the range over which it holds, and the check that proves it. Species enthalpies come from NIST Shomate coefficients. The radiant section uses Lobo-Evans. The convection bank is rated with fin efficiency and a fouling allowance. Efficiency is computed twice, directly and through a full ASME PTC 4 loss ledger, and the two have to agree.

Stack temperature, the radiant and convection split, tube metal temperature and efficiency are outcomes of the geometry and the balance. They are not correlations fitted to a known answer, which is the usual shortcut and the reason most digital twins cannot be extrapolated past the data they were built on.

Source: thermotwin/ENGINEERING_BASIS.md, generated from the model rather than written by hand. Ask us for a copy at contact@twinprocessai.com.

Model selection

Twelve targets. A physics-hybrid wins on nine of them, and 9 clear an R2 of 0.99.

TargetModel chosenBlocked-CV R2MAPE
Thermal efficiency, LHV (%)PhysicsHybrid0.99340.04 %
Fuel fired (GJ/h)PhysicsHybrid0.99970.08 %
CO2 emitted (t/h)PhysicsHybrid0.99360.30 %
Specific energy (GJ/t feed)PhysicsHybrid0.99680.11 %
CO (ppm dry)PhysicsHybrid + log0.78043.55 %
Peak tube metal (C)Ridge0.99970.05 %
Stack temperature (C)PhysicsHybrid0.99570.29 %
Acid dew point (C)RandomForest0.91920.11 %
NOx at 3% O2 (ppm)MLP0.91990.57 %
Stack O2 (% dry)PhysicsHybrid0.99710.38 %
Net draught (mm H2O)PhysicsHybrid0.99440.70 %
Average radiant flux (kW/m2)PhysicsHybrid0.99980.05 %

CO is the weakest model at 0.78, and it is also the constraint that stops most recommendations. That is why the optimiser holds a margin against the 200 ppm limit rather than driving to it, and why a combustion anomaly blocks the move outright.

Source: ml_metrics.json. The R2 column is the mean of the blocked cross-validation folds, not the selection-split score, which runs optimistic. Thermal efficiency scores 0.9975 on the selection split against 0.9934 blocked.

Why blocked folds and not a random split

A random split on a time series will tell you almost anything you want to hear.

Plant data is autocorrelated. Two adjacent hours are nearly the same operating state, so a random train and test split puts near-copies of the test rows into training. The model then scores brilliantly and fails the moment it meets a week it has not seen.

The size of that effect is easy to show. On thermal efficiency, a random split gives R2 0.9999. Blocked folds on contiguous time give 0.9934. On CO the gap is far worse: 0.9998 random against 0.7804 blocked. The random figure is not a result, it is a measurement of how much the model was allowed to cheat.

Every accuracy number published on this site is the blocked one.

Source: ml_metrics.json, key split_leakage_check.

Soft sensors, including the one that failed

Three latent states were tested. Two ship. One does not, and it stays off.

Fouling indexShips0.971
True excess airShips0.981
Fuel hydrogenGated off0.050

Fuel hydrogen cannot be inferred from the available tags, so it is switched off and nothing downstream reads it. A refinery that wants it online needs a Wobbe meter or a fast GC on the fuel header. More modelling will not recover a signal the tags do not carry.

The safety interlock

It deliberately does not rest on the fault classifier, and the reason is worth reading.

A fault classifier trained on this history scores 0.95 balanced accuracy on a stratified split and 0.26 out of time. That gap is not a modelling failure. Each fault class occupies one contiguous window in the data, so there is no second occurrence to hold out, and out-of-time generalisation to a class is simply untestable. Publishing the 0.95 would be dishonest and publishing the 0.26 as a deployment estimate would be misleading.

So the interlock does not use the classifier. It compares the CO analyser against what a heater in good condition would produce at the same duty and air rate, and flags the gap. No fault labels are involved in building it.

Scored against the labels afterwards, it catches 81.5 % of burner degradation and register imbalance hours, the two faults a stack O2 analyser cannot see, with zero false alarms across 2,499 healthy hours. It stays correctly silent on fouling and on air deficiency, because neither is a burner problem and air deficiency is already caught by the CO constraint itself.

Source: ml_metrics.json, keys fault_classifier and interlock_performance.

What this does not do.

Published because you will find out anyway, and it is cheaper for both of us if you find out now.

  • It does not control your heater. It reads history and recommends. A person moves the setpoint.
  • It does not predict when equipment will fail. Fouling trend is not a failure model, and we will not dress it up as one.
  • It does not work without a reasonable tag set. If you have no stack O2 and no fuel flow, there is nothing to infer from.
  • It has not been calibrated against a real heater yet. Every number on this site comes from simulation, and the first pilot is what changes that.
  • It cannot infer fuel hydrogen from the tags. We tried, it scored 0.05, and it is switched off.