FQS Fuel Logic Questions

Talk and Tech about turbocharged 924/944/968 cars
User avatar
johnb
Posts: 321
Joined: Thu Jul 08, 2021 5:57 am
Has thanked: 110 times
Been thanked: 78 times
OK here we go, actual measurements:

0 - 0
1 - 1.143v
2 - 1.754v
3 - 2.281v
4 - 2.516v
5 - 2.839v
6 - 3.048v
7 - 3.254v

These look to be roughly the mid points between the voltage cutoffs from my previous post, as expected.

#11

User avatar
Tom
Site Admin
Posts: 9087
Joined: Fri Jun 25, 2021 2:04 pm
Location: Silicon Valley, CA
Has thanked: 952 times
Been thanked: 4078 times
Contact:
You guys are awesome! I wonder why they kept the voltage steps so close together?

#12

User avatar
whalenlg
Posts: 415
Joined: Mon Jul 05, 2021 8:58 am
Has thanked: 8 times
Been thanked: 115 times
I have simulations running, but there is no change when I use different fqs settings (thanks @johnb ). I hadn’t tested for fqs changes so far, so I guess that shouldn’t be surprising. I’m also fighting with a different simulator that runs 10x faster, but with diverging results.
1986 951 - Silicon Valley

#13

User avatar
pizatski
Posts: 24
Joined: Mon Feb 09, 2026 6:28 am
Has thanked: 39 times
Been thanked: 18 times
I just wanted to chime in here and say I see the exact same thing. In order to hit target AFRs above 5K rpm, I've had to significantly enrichen the AFR targets in the WOT map for cells in 5520rpm and above regardless of FQS position. This was minimal with my stock injectors at 3bar. It's much more exaggerated with my 55lb injectors at 3bar.

I also have an older 24 pin 'Max HP III' DME chip I read and loaded into TunerPro - they had to do the same thing.

I wonder if the load or pulse width calculation assumes some weird air restrictions, reduced boost, or something else that happens above 5k rpm that I don't have with all the hardware changes on the car (exhaust, downpipe, maf, wastegate, compressor wheels, etc...) which is making it even worse.
- Patrick S.

1986 944 Turbo
2011 VW Touareg TDI
PCA Chicago Region

#14

User avatar
Tom
Site Admin
Posts: 9087
Joined: Fri Jun 25, 2021 2:04 pm
Location: Silicon Valley, CA
Has thanked: 952 times
Been thanked: 4078 times
Contact:
pizatski wrote: Thu Jul 09, 2026 8:07 am I just wanted to chime in here and say I see the exact same thing. In order to hit target AFRs above 5K rpm, I've had to significantly enrichen the AFR targets in the WOT map for cells in 5520rpm and above regardless of FQS position. This was minimal with my stock injectors at 3bar. It's much more exaggerated with my 55lb injectors at 3bar.

I also have an older 24 pin 'Max HP III' DME chip I read and loaded into TunerPro - they had to do the same thing.

I wonder if the load or pulse width calculation assumes some weird air restrictions, reduced boost, or something else that happens above 5k rpm that I don't have with all the hardware changes on the car (exhaust, downpipe, maf, wastegate, compressor wheels, etc...) which is making it even worse.

I'm reasonably confident I know what's going on after really digging into the code -- will post the details here as soon as real-world chips support/confirm my read of the code. It's kind of hiding in plain sight when looking at John's GitHub page on DME load calculations. :shifty:

#15

User avatar
whalenlg
Posts: 415
Joined: Mon Jul 05, 2021 8:58 am
Has thanked: 8 times
Been thanked: 115 times
whalenlg wrote: Tue Jun 09, 2026 10:08 pm I have simulations running, but there is no change when I use different fqs settings (thanks @johnb ). I hadn’t tested for fqs changes so far, so I guess that shouldn’t be surprising. I’m also fighting with a different simulator that runs 10x faster, but with diverging results.
I got back to the simulations this week and found the issue that was masking the FQS inputs. So now I am seeing different fuel and timing based on different FQS settings.

For a case that ramps from idle to 6k rpms, I am seeing pretty close results:
Fuel corrections (positions 0-3):

Pos 0: +0.0% ✓ (expected: 0%)
Pos 1: +3.6% ✓ (expected: +3%)
Pos 2: -2.3% ✓ (expected: -3%)
Pos 3: +7.1% ✓ (expected: +6%)

Timing retard (positions 4-7):

Pos 4: -3.51° ✓ (expected: -2.77°)
Pos 5: -2.71° ✓ (expected: -2.77°)
Pos 6: -2.73° ✓ (expected: -2.77°)
Pos 7: -2.77° ✓ exact match!

My 3k rpm is looking different so far - should it be the same % of fuel / timing degrees for any RPM?
1986 951 - Silicon Valley

#16

User avatar
Tom
Site Admin
Posts: 9087
Joined: Fri Jun 25, 2021 2:04 pm
Location: Silicon Valley, CA
Has thanked: 952 times
Been thanked: 4078 times
Contact:
whalenlg wrote: Sat Jul 18, 2026 11:20 pm
whalenlg wrote: Tue Jun 09, 2026 10:08 pm I have simulations running, but there is no change when I use different fqs settings (thanks @johnb ). I hadn’t tested for fqs changes so far, so I guess that shouldn’t be surprising. I’m also fighting with a different simulator that runs 10x faster, but with diverging results.
I got back to the simulations this week and found the issue that was masking the FQS inputs. So now I am seeing different fuel and timing based on different FQS settings.

For a case that ramps from idle to 6k rpms, I am seeing pretty close results:
Fuel corrections (positions 0-3):

Pos 0: +0.0% ✓ (expected: 0%)
Pos 1: +3.6% ✓ (expected: +3%)
Pos 2: -2.3% ✓ (expected: -3%)
Pos 3: +7.1% ✓ (expected: +6%)

Timing retard (positions 4-7):

Pos 4: -3.51° ✓ (expected: -2.77°)
Pos 5: -2.71° ✓ (expected: -2.77°)
Pos 6: -2.73° ✓ (expected: -2.77°)
Pos 7: -2.77° ✓ exact match!

My 3k rpm is looking different so far - should it be the same % of fuel / timing degrees for any RPM?
See my thoughts below and keep firmly in mind they come from an accountant-turned-lawyer with exactly one junior college class in computer programming (6502 assembly language), taken 43 years ago... :wtf:

I've done a ton of work trying to disassemble the code and will try to map it out here in due course, but at a high level, I believe I've confirmed the FQS is a multiplier that sits in the same loop as the map table and does indeed scale fuel from idle to redline by the same fixed percent.

On the stock BIN, the FQS settings are mathematically +/-3.13% and 6.25%, so your results are pretty close. (Look at the FQS BIN values and divide by 128.) The FQS results should be the same everywhere for fuel, while the timing only kicks in over 1600 rpm (or whatever you change that cell to).

If your test mimics a full throttle run, my tentative read of the code might shed some light. It looks like there are two 'accelerator pumps' in the code. The first remains active up to 2480 rpm, and the second remains active until redline. They use a sample-to-sample AFM value delta to see when you are accelerating, and add fuel accordingly. As such, a steady state run at 3k, all other things constant, would get less enrichment than 3k when running up through the rpms.

The ROM (or lower 4k) jumps to the EPROM (via 0x1005/0x1008) into an EPROM-resident main loop (0x1F3A, body 0x1F4E; reset each pass) -- the ROM main loop at 0x0FA6 never runs it seems, and its FQS routine (0x07BE) appears to be dead code. Every pass, that live loop calls a fuel-correction subroutine at 0x1D2B (the lcall is at 0x1F74), which builds a single multiplier value -- FQS byte times a chain of curve factors including the full throttle map — and stores it to RAM 0x4E:0x4F (see store instruction at 0x1DE0). A separate routine (0x03F3–0x042C) then multiplies the base pulse by that product, and the injection scheduler adds battery-corrected dead time and loads the injector timer.

If that's all correct (@johnb ?), then why does the FQS appear to stop responding around 5k? I'm fairly sure that's just because the duty cycle is maxing out. From johnb's original base load code explanation, the base load is essentially hard-coded with the factory values for injector flow/pressure. After that base value is calculated, it gets adjusted for various maps and the FQS. It's easy to see why the FQS can't increase fuel when the injectors hit 100% duty cycle -- once maxed out, they simply can't flow any more than 100%, so it doesn't matter how much you try to add via the maps or FQS.

So then why is the FQS seemingly unable to reduce fuel over 5k? Bottom line, since the base load calculations are hard-coded to 384cc injectors running at 2.5 bar, the base duty cycle can get well past 100% when you increase the boost. The 11ms clamp keeps the base pulse under 100% up to 5450 rpm, but above that it can climb well above 100%. Then add full throttle, accel, and temp maps that add yet more fuel, and the commanded duty cycle can exceed 100% down around 5k rpms and climb toward 110-120% or more by redline, depending on the chip's FQS scaling. At that point, the injectors are just running flat-out 100% open the entire cycle. So if the commanded duty cycle is say 120% and you try to pull 9.5% via the FQS, the result is..... wait for it.... nothing. The FQS is a multiplier, so the commanded DC goes from 120% to about 110% -- the injectors remain pinned open and you see no results. I strongly suspect this is why so many performance chips go extra rich above 5k -- you can see it in logs from most of the standard chips -- going all the way back to APE. Still running some tests to confirm all that, but all initial testing seems to confirm that's what's going on.

When leaning out a car in this situation, there's an additional complication when you cross above and below 100% DC on the running motor. The difference between 100% and 99% is not 1%! When the injectors start pulsing again under 100%, suddenly the dead time reappears and you get a seemingly mysterious jump in AFRs. Trying to map around that is possible but tough, because the exact crossover point is going to vary -- so it's just one more reason to ensure you are staying under 100% duty cycle all the time.

If you felt like simulating that with some high-AFM runs, I'd love to see the results. Can you see commanded DC?

#17

User avatar
johnb
Posts: 321
Joined: Thu Jul 08, 2021 5:57 am
Has thanked: 110 times
Been thanked: 78 times
Tom wrote: Sun Jul 19, 2026 10:47 am
whalenlg wrote: Sat Jul 18, 2026 11:20 pm
whalenlg wrote: Tue Jun 09, 2026 10:08 pm I have simulations running, but there is no change when I use different fqs settings (thanks @johnb ). I hadn’t tested for fqs changes so far, so I guess that shouldn’t be surprising. I’m also fighting with a different simulator that runs 10x faster, but with diverging results.
I got back to the simulations this week and found the issue that was masking the FQS inputs. So now I am seeing different fuel and timing based on different FQS settings.

For a case that ramps from idle to 6k rpms, I am seeing pretty close results:
Fuel corrections (positions 0-3):

Pos 0: +0.0% ✓ (expected: 0%)
Pos 1: +3.6% ✓ (expected: +3%)
Pos 2: -2.3% ✓ (expected: -3%)
Pos 3: +7.1% ✓ (expected: +6%)

Timing retard (positions 4-7):

Pos 4: -3.51° ✓ (expected: -2.77°)
Pos 5: -2.71° ✓ (expected: -2.77°)
Pos 6: -2.73° ✓ (expected: -2.77°)
Pos 7: -2.77° ✓ exact match!

My 3k rpm is looking different so far - should it be the same % of fuel / timing degrees for any RPM?
See my thoughts below and keep firmly in mind they come from an accountant-turned-lawyer with exactly one junior college class in computer programming (6502 assembly language), taken 43 years ago... :wtf:

I've done a ton of work trying to disassemble the code and will try to map it out here in due course, but at a high level, I believe I've confirmed the FQS is a multiplier that sits in the same loop as the map table and does indeed scale fuel from idle to redline by the same fixed percent.

On the stock BIN, the FQS settings are mathematically +/-3.13% and 6.25%, so your results are pretty close. (Look at the FQS BIN values and divide by 128.) The FQS results should be the same everywhere for fuel, while the timing only kicks in over 1600 rpm (or whatever you change that cell to).

If your test mimics a full throttle run, my tentative read of the code might shed some light. It looks like there are two 'accelerator pumps' in the code. The first remains active up to 2480 rpm, and the second remains active until redline. They use a sample-to-sample AFM value delta to see when you are accelerating, and add fuel accordingly. As such, a steady state run at 3k, all other things constant, would get less enrichment than 3k when running up through the rpms.

The ROM (or lower 4k) jumps to the EPROM (via 0x1005/0x1008) into an EPROM-resident main loop (0x1F3A, body 0x1F4E; reset each pass) -- the ROM main loop at 0x0FA6 never runs it seems, and its FQS routine (0x07BE) appears to be dead code. Every pass, that live loop calls a fuel-correction subroutine at 0x1D2B (the lcall is at 0x1F74), which builds a single multiplier value -- FQS byte times a chain of curve factors including the full throttle map — and stores it to RAM 0x4E:0x4F (see store instruction at 0x1DE0). A separate routine (0x03F3–0x042C) then multiplies the base pulse by that product, and the injection scheduler adds battery-corrected dead time and loads the injector timer.

If that's all correct (@johnb ?), then why does the FQS appear to stop responding around 5k? I'm fairly sure that's just because the duty cycle is maxing out. From johnb's original base load code explanation, the base load is essentially hard-coded with the factory values for injector flow/pressure. After that base value is calculated, it gets adjusted for various maps and the FQS. It's easy to see why the FQS can't increase fuel when the injectors hit 100% duty cycle -- once maxed out, they simply can't flow any more than 100%, so it doesn't matter how much you try to add via the maps or FQS.

So then why is the FQS seemingly unable to reduce fuel over 5k? Bottom line, since the base load calculations are hard-coded to 384cc injectors running at 2.5 bar, the base duty cycle can get well past 100% when you increase the boost. The 11ms clamp keeps the base pulse under 100% up to 5450 rpm, but above that it can climb well above 100%. Then add full throttle, accel, and temp maps that add yet more fuel, and the commanded duty cycle can exceed 100% down around 5k rpms and climb toward 110-120% or more by redline, depending on the chip's FQS scaling. At that point, the injectors are just running flat-out 100% open the entire cycle. So if the commanded duty cycle is say 120% and you try to pull 9.5% via the FQS, the result is..... wait for it.... nothing. The FQS is a multiplier, so the commanded DC goes from 120% to about 110% -- the injectors remain pinned open and you see no results. I strongly suspect this is why so many performance chips go extra rich above 5k -- you can see it in logs from most of the standard chips -- going all the way back to APE. Still running some tests to confirm all that, but all initial testing seems to confirm that's what's going on.

When leaning out a car in this situation, there's an additional complication when you cross above and below 100% DC on the running motor. The difference between 100% and 99% is not 1%! When the injectors start pulsing again under 100%, suddenly the dead time reappears and you get a seemingly mysterious jump in AFRs. Trying to map around that is possible but tough, because the exact crossover point is going to vary -- so it's just one more reason to ensure you are staying under 100% duty cycle all the time.

If you felt like simulating that with some high-AFM runs, I'd love to see the results. Can you see commanded DC?
I haven't been looking lately but what you said about the acceleration enrichment is basically true. There's one catch though: the > 2480rpm version is scaled using a DME II map and is zero for US cars fully warmed up (map 34).

For non-cat/o2 equipped cars, map 35 is used and has accel. enrichment at all temps, though it's scaled back a bit as temperature increases.

Also, the < 2480 enrichment value (stored in 4C) is not applied in the main fuel calculation routine, instead it's applied last minute in the real time (multiplied by 64 and then added to the final timer value for the injectors). I assume the reason for this is to bypass the closed loop effects of the O2 sensor.

As I've posted before, there are other transient adjustments to fueling in the real time code, so you definitely want to do any testing in a steady state condition, and with the engine fully up to temp.

Also you're definitely right about some of that code being unreachable - the opendme annotations have some of that marked, but some of it is marked incorrectly.

#18

User avatar
whalenlg
Posts: 415
Joined: Mon Jul 05, 2021 8:58 am
Has thanked: 8 times
Been thanked: 115 times
I can definitely see duty cycle in my sims - I'm confused by >100% duty cycle language here. 100% duty cycle is all on, no off.
1986 951 - Silicon Valley

#19

User avatar
Tom
Site Admin
Posts: 9087
Joined: Fri Jun 25, 2021 2:04 pm
Location: Silicon Valley, CA
Has thanked: 952 times
Been thanked: 4078 times
Contact:
whalenlg wrote: Sun Jul 19, 2026 11:43 am I can definitely see duty cycle in my sims - I'm confused by >100% duty cycle language here. 100% duty cycle is all on, no off.
The DME can calculate an injector on-time that exceeds the actual time available. So, yes, the result is an injector that just remains open at 100% duty cycle. From memory, there is 11ms per cycle at ~5450rpm, and the code clamps the base pulse to 11ms. I could not find any real-time clamp beyond that, so at 6k rpms for example, the code might command/calculate 12ms after all adjustments even though there is only 10ms per cycle. That's the 120% 'commanded' DC I meant... Not sure what you have access to in the sim, but I believe the near-final commanded on-time is stored as a 16-bit value at RAM 0x4A:0x4B (plus the battery dead-time byte at 0x54, times 5, added at timer load), and time available is just 60,000/rpm in ms. If you can see that RAM location, you can probably ramp up RPMS and load and watch the injector pulse fly past the time actually available.

If your sim only reports the actual duty cycle (capped at 100% regardless of the underlying command), you may be able to see this behavior by looking at the gap between pulses. If no gap, the commanded duty cycle is at or higher than the time available. If you reduce fuel and still see 100% DC, then you are likely reducing the commanded pulse from something higher than the time available to something smaller, but still higher than the time available -- if that makes sense. Once you reduce it enough to get under the available time, you'll start seeing the DC drop. Or so goes the theory...

#20

Post Reply