Automating Hondata AFM Curve Correction with Pandas and Numpy
In the previous article, “What is Air-Fuel Ratio, Fuel Trim, and AFM Curve—How to Use Hondata Log Data to Understand if Your Intake Components are Working Properly”, we learned that if you replace the intake kit or filter, you can correct the AFM curve using Hondata.
For example, if you record a Datalog and plot AFM.v and S.Trim using Hondata’s XY plot, and you see something like the figure below, you will know that there is a dip around 1.1v (down to -8%), indicating that the intake volume corresponding to the voltage value in the calibration is too high (the computer injects fuel based on the calibration, then finds that it is 8% too rich, so it reduces the fuel injection by 8% through S.Trim).
At this point, we need to find the AFM table and modify the data in the corresponding range, reducing it by about 8% to correct this situation:
Then, through more Datalogs under different conditions, we perform repeated road tests and corrections to obtain the smoothest AFM.v - S.Trim curve. This process is known as AFM correction, which is also a very important foundation in program adjustment.
If the AFM correction is not done correctly, the vehicle’s response will be quite strange, and at WOT (Wide Open Throttle), because it does not use S.Trim, the AF (actual air-fuel ratio) will not be able to stably follow the AFCMD (computer requested air-fuel ratio).
If you do not quite understand the above content, I suggest you review my article “What is Air-Fuel Ratio, Fuel Trim, and AFM Curve—How to Use Hondata Log Data to Understand if Your Intake Components are Working Properly”.
Alright, now we know the whole process, but manually correcting the AFM curve sounds too “artisan”. Let’s think carefully about the AFM.v - S.Trim plot, which is actually just putting the AFM.v and S.Trim of each frame in the Datalog on a scatter plot, and:
- The more data, the better, because if the amount of data is too small, it may just be occasional fluctuations, which we should ignore.
- The time variable is meaningless here because it is just the relationship between AFM.v and S.Trim.
Understanding the above points, we realize that if we want to manually correct the AFM curve using Hondata, we need multiple different Datalogs, or a single Datalog covering a large number of scenarios. Considering that we are not conducting experiments on a test bench, the more realistic situation is to have multiple Datalogs recorded at different times. We then need to manually look at the XY plot of each corresponding Datalog, try to find common patterns, and make corrections.
This is too slow!
Automated Calibration
We need a capability to automatically analyze Datalogs and correct the AFM. The process is divided into the following steps:
- Obtain structured Datalog data and overlay them together.
- Obtain the deviation amount from 0 for each voltage value through the mean of a large amount of data.
- Reverse correct the AFM table.
Export to CSV
Fortunately, Hondata provides the function to export as CSV:
The exported CSV has some junk rows at the beginning, but each row is the data of all sensors for each frame:
Thus, we can export multiple Datalog CSVs and merge them together to obtain a large amount of Datalog data recorded at different times and under different conditions.
CSV to Dataframe
In the previous step, we have a large amount of data. Now we can try to import it into a Dataframe for analysis:
Fuel Status of 2 indicates closed-loop status. We only want to correct the closed-loop (non-WOT) part.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
df = pd.read_csv('exported.csv')
# Only reserve the rows with 'Fuel Status' = 2
df = df[df['Fuel Status'] == 2]
x = df['AFM.v']
y = df['S.TRIM']
plt.scatter(x, y, label='Data Points', color='blue', alpha=0.5)
bins = np.linspace(x.min(), x.max(), 100)
bin_centers = 0.5 * (bins[:-1] + bins[1:])
mean_values = [y[(x >= bins[i]) & (x < bins[i + 1])].mean() for i in range(len(bins) - 1)]
plt.plot(bin_centers, mean_values, label='Mean Curve', color='red', linewidth=2)
plt.xlabel('AFM.v')
plt.ylabel('S.TRIM')
plt.legend()
plt.title('Scatter Plot and Mean Curve of AFM.v vs S.TRIM')
plt.show()
Here we use
np.linspace
to divide the data into 100 bins and calculate the average value, then plot the mean curve.
Doesn’t it look like Hondata’s XY plot?
Import AFM and adjust
With the above Dataframe and corresponding mean values, we can import the existing AFM table’s voltage-airflow relationship. In Hondata, the AFM table has 64 columns. Below, k_values
are the voltage values, and v_values
are the calibrated airflow (g/s):
k_values = [
0.00, 0.00, 0.35, 0.43, 0.51, 0.59, 0.66, 0.74, 0.82, 0.90, 0.98, 1.05, 1.13, 1.21, 1.29, 1.33, 1.37, 1.41, 1.45, 1.52,
1.56, 1.60, 1.68, 1.72, 1.76, 1.84, 1.88, 1.91, 1.99, 2.03, 2.07, 2.15, 2.19, 2.23, 2.30, 2.34, 2.38, 2.46, 2.50, 2.54,
2.62, 2.70, 2.77, 2.85, 2.93, 3.01, 3.09, 3.16, 3.24, 3.32, 3.40, 3.48, 3.55, 3.63, 3.71, 3.79, 3.87, 4.02, 4.18, 4.34,
4.49, 4.65, 4.84, 5.00
]
v_values = [
0.00, 0.00, 0.00, 0.00, 0.03, 0.08, 0.17, 0.28, 0.43, 0.62, 0.87, 1.16, 1.48, 1.93, 2.34, 2.60, 2.88, 3.25, 3.58, 4.31,
4.70, 5.10, 5.98, 6.46, 6.97, 8.11, 8.55, 9.19, 10.54, 11.25, 12.00, 13.18, 14.00, 15.15, 17.04, 18.05, 19.44, 21.63,
23.24, 24.45, 27.06, 29.89, 32.82, 35.89, 39.23, 42.77, 45.62, 49.55, 53.67, 57.47, 61.44, 66.23, 71.30, 76.67, 80.70,
86.52, 92.63, 105.67, 119.80, 135.13, 151.92, 170.44, 196.45, 220.14
]
df_kv = pd.DataFrame({'AFM.v': k_values, 'AFM Intake': v_values})
Then we use linear interpolation to interpolate the mean curve mentioned above onto the k_values
and find the difference with the corresponding v_values
:
expected_values = np.interp(df_kv['AFM.v'], bin_centers, mean_values)
expected_values = np.nan_to_num(expected_values, nan=0.0)
Next, we calculate the adjustment amount based on the percentage difference:
df_kv['AFM Intake Adjusted'] = df_kv['AFM Intake'] * (expected_values/100 + 1)
print(df_kv.to_string())
See, it’s done like this!
AFM.v AFM Intake AFM Intake Adjusted
0 0.00 0.00 0.000000
1 0.00 0.00 0.000000
2 0.35 0.00 0.000000
3 0.43 0.00 0.000000
4 0.51 0.03 0.029600
5 0.59 0.08 0.078933
6 0.66 0.17 0.167733
7 0.74 0.28 0.276267
8 0.82 0.43 0.424267
...
43 2.85 35.89 35.015254
44 2.93 39.23 38.783246
45 3.01 42.77 41.663699
46 3.09 45.62 44.038772
47 3.16 49.55 48.285323
48 3.24 53.67 53.670000
49 3.32 57.47 55.442512
...
We can also overlay the adjusted and original curves for comparison:
plt.plot(df_kv['AFM.v'], df_kv['AFM Intake'], label='Original', color='blue')
plt.plot(df_kv['AFM.v'], df_kv['AFM Intake Adjusted'], label='Adjusted', color='red')
Hondata Auto AFM Correction Website
With this idea in mind, I thought of creating a simple website where users can upload the Datalog CSV file and the current AFM table to automatically calculate the corrections. I continued to collaborate with WebP Cloud Services and our dedicated frontend developer Tuki Deng to create the Hondata Auto AFM Correction website. The domain is: https://hondata.nova.moe
Feel free to give it a try!