The workflow

Eight steps, in the order you actually do them.

FTT never talks to your ECU. It reads a datalog you already have, bins it into the breakpoints you already use, and gives you a correction you can argue with before any of it reaches your tune.

  1. 01

    Set the breakpoints to match the ECU

    You type in the axis values your ECU actually uses. Nothing is auto-binned, and that is deliberate: a bin edge sitting between two ECU breakpoints quietly averages two cells of your tune into one number, and nothing on screen would tell you it happened.

  2. 02

    Load the log

    Load the CSV your logging software exports. FTT reads the header row; you map its columns to channels once, and choose which channel positions each axis — RPM against MAP, TPS, or whatever the engine is logging. Load several logs and they append into one timeline.

  3. 03

    Set the filters

    A row filter is a condition you write against any logged channel — abs([delta_tps]) > 5 drops throttle transients, a temperature threshold in the log's own units drops a cold engine. Then two filters inside each cell: sigma rejection (K = 2.0 by default), so one bad sample can't drag an average, and a minimum sample count (5 by default), below which a cell reads empty rather than trusted.

  4. 04

    Read the grid

    Every row that survives lands in exactly one cell, and the grid updates the moment a filter changes — there is no recompute step. Each map is a layer of the same grid: the average lambda in a cell, the hits behind it, the error against your target, or any formula you define. Switch between them without losing your place.

  5. 05

    Shape the correction

    The correction is a map you define with a formula — the logged error turned into a change against your base fuel, written in terms you can read. With an inverse formula, editing the corrected map writes back through to the base map, so the two stay tied. Nothing has been written to your tune at this point. It is a table on your screen until you copy it out.

  6. 06

    Fill, interpolate and smooth

    Select a region. H and V interpolate a ramp across it. Smooth blends each cell with its neighbours at a strength you set, and can ignore empty cells so gaps don't drag good data down. Smart Fill estimates empty cells from nearby cells that have data, and leaves a hole with nothing near it empty rather than invent a number. Every tool writes to the map you choose, and one undo history covers all of it.

  7. 07

    Check the change against the data

    The Tune Quality Report compares the tune before and after your edits, load row by load row: how much you added against how much the data asked for, and where those disagree. Numbers only — the decision stays yours. Save it as text, CSV or PDF for the customer file.

  8. 08

    Get the numbers back into the tune

    Select the finished region and copy. It lands on the clipboard tab-separated, in the same shape as the grid, which is what a tuning table paste expects. The project itself — axes, maps, filters and channel mappings — saves as one XML file on your own disk.

Before and after

A log, a table, a map.

The same pull at three points in the workflow. The middle panel is the log binned into your breakpoints, and nothing in the last panel reaches your tune until you copy it out.

01

What the log looks like

Logged lambda against target, every row, unbinned. This is the shape of the problem: tens of thousands of points, a large share of them recorded while the throttle was still moving.

Screenshot pending

The scatter view — logged lambda against target, before any binning.

Awaiting a capture from a real FuelTech log, at 2× DPR.
02

What it becomes

Averaged into your breakpoints, with the hit count under every value. The %Change table is another layer of this same grid — same axes, same cells.

ACTUAL LAMBDA (FILTERED) · 15,518 rows · 4 filters active
1.0k
1.8k
2.5k
3.3k
4.0k
4.8k
5.5k
6.3k
7.0k
7.8k
8.5k
9.3k
220
—7
—10
—18
.74936
.76371
.763125
.744189
.745243
.765264
.763243
.751183
.764119
190
—9
—14
.79030
.79466
.806135
.791241
.777368
.792474
.803516
.790474
.790361
.811234
160
—18
.83732
.82858
.842106
.840190
.819317
.820469
.838597
.833648
.821593
.836459
.852300
130
.88577
.867134
.874197
.884253
.867303
.853361
.867436
.875506
.860528
.861477
.883368
.884240
100
.911231
.906400
.921562
.917645
.895616
.897515
.912413
.904346
.891302
.907254
.923191
.911125
70
.942337
.952584
.962815
.944916
.931832
.944621
.948396
.931234
.932145
.95499
.95469
.94045
45
.982230
.999397
.994552
.973617
.975555
.988404
.976242
.963125
.97961
.99333
—21
—14
25
.02875
.039127
.021175
.010195
.023175
.023128
.00477
.00540
—20
—11
—8
—7

Small figures are hit counts. Cells under the minimum sample threshold stay unshaded — no data is not the same as on target.

03

What you keep

After interpolation across the thin corners and a smoothing pass. Every changed cell is one you chose to change.

Screenshot pending

The working map after interpolation and smoothing.

Awaiting a capture from a real FuelTech log, at 2× DPR.

Which ECUs this works with.

Listed by model number, with what we read from each and what we haven't got to yet.

Supported hardware