Files
samplez/tunie/research/reference-maps/TABLES.md
uhryniuk f830f8937d Log real-world road test results and correct/extend the CO-trim theory
New research/ROAD_TEST_LOG.md: the 2026-09-15 flash of
20262-arrow-delete-lowthrottle-composed.hex was a major real-world
success (stalling fully resolved, decel backfire much reduced but not
eliminated). Captures the live diagnostic reasoning that followed:
correcting an overly-lean-leaning framing mid-session (residual decel pop
is more likely a rich-unburned-mixture-with-no-SAI-assist problem, not a
lean one), a structural hypothesis that the Idle Fuel Trim (CO) curve
likely applies whenever the throttle is closed at any RPM rather than
only at a literal stop (only 2 of its 32 points are currently corrected,
and the untouched middle range lines up with the residual pop's RPM
window), and the reasoning for rejecting airbox-baffle removal as a fix
for decel popping specifically (wrong mechanism -- closed throttle isn't
airbox-limited -- and risks worsening the separately-flagged, still
unaddressed main-VE-table leanness gap).

Also updates TABLES.md with the CO-trim applicability open question, and
brings TUNING_GUIDE.md's "local research assets" section up to date (it
still said maps were gitignored/unflashable, both stale).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FP2GaxS9HkUdL5sLBnjKje
2026-09-16 09:07:35 -05:00

166 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Keihin SH7054 (Triumph 865 twin, mechanical odo) — table map
Reversed from `Nc()`/`Lb()` in `l.java` and validated against the stock reference
maps. All offsets are in the reconstructed **flat ROM** (0x60000). Compute per map:
```
fe = c.a[Qd*48] # Qd from the s.a directory lookup on the map signature
base = (fe[0] & 0x2F0) << 12 # = 0x50000 for the 865 twin family
offset(table) = base + fe[<field>]
```
Main tables are **32 rows (RPM) × 20 cols (throttle), 16-bit big-endian**.
## Axes
| Axis | fe field | Entries | Values (20187) | Meaning |
|---|---|---|---|---|
| RPM (rows) | `fe[8]` | 32 | 0, 500, 900, 1000 … 10000 | engine speed, direct RPM |
| Throttle (cols) | `fe[27]` | 20 | 0, 10, 20 … 780, 1000 | throttle %, ÷10 (0–100.0%) |
## Tables (validated by production 20187 vs aftermarket 20188 diff)
| Table | fe | Offset (20187) | Value range | Notes |
|---|---|---|---|---|
| Main fuel — cyl 1 | 11 | 0x56990 | 951–10480 | **strong**: 75% diff, smooth VE, aftermarket richer |
| Main fuel — cyl 2 | 12 | 0x56E90 | 951–10680 | **strong**: 67% diff |
| Low-throttle fuel — cyl 1 | 15 | 0x55590 | 0–10760 | 70% diff; starts at 0 (closed throttle) |
| Low-throttle fuel — cyl 2 | 16 | 0x55A90 | 0–10810 | 68% diff; cyl-1 pair |
| Fuel — base/idle | 9 | 0x55500 | 0–10760 | 61% diff; lower values |
| Ignition advance — gear 1 | 19 | 0x587D0 | 13–600 | 4 evenly-spaced (0x500) 20×32 tables |
| Ignition advance — gears 2–5 | 20 | 0x58CD0 | 13–600 | main operating map |
| Ignition advance — gear 6 | 21 | 0x591D0 | 13–600 | overdrive |
| Ignition advance — neutral | 22 | 0x596D0 | 60–600 | idle/free-rev |
## AFR / target lambda
`fe[2]` @ 0x52260 is an interleaved (value, breakpoint) curve where **128 = λ1.00
(stoich, 14.7 AFR)** — e.g. `… 128, 500, 128, 400, 128, 300 …`. The `128` cells are
the closed-loop lambda targets; disabling closed loop (O2 delete) lets you set
these richer. Exact dimensions still being confirmed.
## Scaling (confidence varies)
- **Fuel** values are VE/fuel-mass in the ECU's internal units (≈ 0–10800). Real
units (injector µs / VE %) need the ECU's fuel constant; relative changes are
exact, absolute scaling TBD.
- **Ignition** 13–600 is advance in an internal unit (candidate: value ÷ 10 = °BTDC,
giving ~1.3–60°; the low-RPM row 90→14→20 fits a retard-then-advance curve). TBD.
- **AFR** 128 = λ1.00 is solid (standard Keihin convention).
## Fuel/ignition trim array — RPM-indexed, 32 entries, `0x53690`-`0x536AF`
**Located and axis-mapped (Aug 2026).** A 32-byte array sitting just before
the device-flags region (`0x53801`, `TABLES.md` above / `DEVICES.md`), one
byte per **RPM breakpoint on the same 32-point RPM axis** as the main
tables (`fe[8]`: 0, 500, 900, 1000, ..., 10000). Not addressed via a `fe[]`
pointer for the maps checked (no `fe` field in `c.a[Qd*48]` equals `0x3690`
for `20187`'s `Qd=32`) — likely a fixed offset relative to the device-flags
struct rather than an independently relocatable table, unconfirmed.
Evidence for the RPM-axis mapping: diffing `20188Map2009AIRBOXBONNY.hex`
(the Bonneville SAI/O2 delete map) against stock `20188` shows **exactly 2
of the 32 cells changed — at RPM=2400 and RPM=7000** — with all 30 other
RPM-indexed cells byte-identical. That's `0x5369C` (index 12, RPM 2400) and
`0x536AB` (index 27, RPM 7000) from earlier sessions, now understood as two
specific points on this curve rather than free-floating bytes.
Cross-checked against `20184dynoTuneSteveO2-Disable.hex` (America,
open-pipe + airbox-snorkel-removed + O2-disable, real dyno tune) vs. stock
`20186`: **nearly every one of the 32 cells changed**, by large,
non-monotonic swings (e.g. RPM=1000: 231→63, RPM=4400: 235→5, RPM=5200:
25→204). Not a smooth curve shift — looks like cell-by-cell dyno-session
adjustment (consistent with a human tuner nudging individual RPM points
after successive pulls) rather than a single global correction. Confirms
this is a real, independently-tunable-per-cell array, not a scalar.
**Identity: confirmed as "Idle Fuel Trim (CO)".** Crawled tuneecu.net's full
docs site (`../tuneecu_site_mirror/`) and found the exact match in
`TuneECU_En/tests.html`, TuneECU's live-diagnostics parameter list:
> "Idle Fuel Trim (CO): lets you adjust the fuel richness at idle."
> Available for "**Triumph without O²-Sensor only**."
> (Counterpart: "Long Term Fuel Trim... Triumph models **with** O²-Sensor
> only" — the closed-loop equivalent for bikes that still have the sensor.)
This is a direct, official match to what we observed empirically: the table
is specifically the O2-delete-relevant trim, exactly why it's what the real
delete/dyno maps touch and the stock maps don't need to. `co_trim`/`ift_co`
string resources (`strings.xml`: "CO Trim" / "Idle Fuel Trim (CO)") back
this — "CO" = idle mixture richness, the classic idle-adjustment convention
carried over from carbureted-era tuning terminology.
**Encoding, upgraded confidence (Aug 2026):** found TuneECU's actual "CO
Trim" edit dialog (`MainActivity.java`'s `La()`) and its value-scaling
logic. Two independent code paths converge on the same answer:
1. The dialog's clamp/display logic (`j8()`) treats the value as a plain
signed range: `if (v < -128) v = -128; else if (v > 127) v = 127;`,
displayed as `Integer.toString(v)` — no fractional scaling.
2. A separate live-value dispatcher (`n.java`, a large switch handling
various PID-style codes) has a case doing manual two's-complement
conversion — `if (raw > 127) raw -= 256;` — immediately before storing
into the same field (`MainActivity.Mc`) the CO Trim dialog reads.
**Conclusion: the raw byte is signed two's-complement (-128 to 127), used
directly with no multiply/divide scaling factor** — not the unsigned 0-255
interpretation this project used everywhere earlier. **This retroactively
resolves the "255 looks like a sentinel" puzzle** from the exhaust-family
composability analysis (`COMMUNITY_TUNING.md`/`PERMUTATIONS.md`): unsigned
`255` is simply signed `-1` — an entirely ordinary, near-neutral value, not
a special case. Re-reading the earlier data with correct signs: the stock
aftermarket-silencer family sits near `-1` (neutral), production/Arrow
sits around `+69` to `+125` (already noticeably rich), and the real
SAI/O2 delete map pushes to `+117` — a large, deliberate enrichment,
exactly the physically-sensible story this parameter's name would predict.
The composability conclusion (can't cleanly merge Arrow's delta with the
delete map's delta) still holds — redone with correct signs, the combined
correction still saturates past the `+127` clamp — but now for an
intuitive reason (the needed correction is genuinely large) instead of an
unexplained sentinel.
**Not fully closed:** the *encoding* (signed int8, no scaling) is now
well-supported by two independent sites; the exact real-world *unit* (is
`+1` precisely "+1% CO", or a nearby-but-not-identical ECU-internal unit)
isn't separately confirmed by either site. Raised from low to medium-high
confidence — upgraded, not fully resolved.
**Practical implication for composing tunes:** don't treat this array as
"2 conflicting bytes" the way `compose_arrow_delete.py` originally did —
it's a full 32-cell curve. A conservative mod (mufflers only) may touch 2
cells; a more aggressive one (open pipes + airbox) touches nearly all 32.
Composing two independent tunes' curves here needs the same per-cell
arithmetic treatment as the main VE tables (`PERMUTATIONS.md`), not a
handful of spot fixes.
**Open question, raised from real-world testing (2026-09-15/16, see
`../ROAD_TEST_LOG.md`): does "idle" in this table's name mean literal
engine-stopped idle, or does it apply whenever the throttle is
closed/near-closed regardless of RPM?** TuneECU's own docs say "at idle,"
but the table has real, non-trivial entries all the way out to 10,000 RPM
— hard to explain if it only ever applied near a stop. Circumstantial
support for "applies whenever throttle is closed": a real-world decel
sweep through the *uncorrected* middle of this curve (RPM 2600-6500,
composed only touched points 2400 and 7000) produced residual popping in
exactly that RPM range, while the low-throttle table fix (a genuinely
different, confirmed-idle-adjacent table) independently and completely
fixed literal stopped-idle stalling. That's consistent with this curve
being live during the whole closed-throttle deceleration, not just at a
stop — but it's inference from one road test, not confirmed in the
decompile. Worth designing a deliberate test for if this gets revisited:
does the CO Trim value visibly change on TuneECU's live-diagnostics screen
while decelerating at 4000 RPM with the throttle shut, or only once RPM
actually reaches idle?
## SAI / O2 / lambda flags
Now findable via the localised flat-ROM diff (20187 vs 20188), which isolates small
single-byte changes (e.g. 0x50C13, 0x534AD, 0x59759) as prime toggle candidates.
Confirming which is SAI vs O2 needs either bench testing or the finer `Nc` device
logic — a follow-up.
## Status
Fuel and ignition table **locations** are validated end-to-end. Remaining: exact
scaling constants, AFR dimensions, and confirming the individual device flags.