|
nyet
|
 |
« on: October 24, 2024, 01:20:02 AM »
|
|
|
Similar to the FKVVS tuner, this is specifically made to tune KFKHFM based on fr/frm logs. https://github.com/nyetwurk/trim-heatmap/releasesIt is command line based, so you have to give it one or more log files on the command line. If you do not know what that means, this tool is not for you usage: heatmap.py [-h] [-w WINDOW] [-l LOAD_FILTER] [-r RPM_FILTER] [-m MIN_SAMPLES] [-f] [-u] [-v] [filename ...]
Create trim heatmap for KFKHFM based on fr/frm datalog
positional arguments: filename csv files(s) to parse (log.csv)
options: -h, --help show this help message and exit -w WINDOW, --window WINDOW number of sequential rows to detect constant rpm/load (5) -l LOAD_FILTER, --load-filter LOAD_FILTER change in load which is still "constant" load (10) -r RPM_FILTER, --rpm-filter RPM_FILTER change in RPM which is still "constant" RPM (100) -m MIN_SAMPLES, --min-samples MIN_SAMPLES minimum number of samples required to generate a cell (10) -f, --use-fr use "fr" instead of "frm" (the default) -u, --use-unweighted-mean use unweighted mean instead of weighted average (the default) -v, --verbose
|
|
|
|
« Last Edit: October 24, 2024, 01:22:52 AM by nyet »
|
Logged
|
ME7.1 tuning guideECUx PlotME7Sum checksumTrim heatmap toolPlease do not ask me for tunes. I'm here to help people make their own. Do not PM me technical questions! Please, ask all questions on the forums! Doing so will ensure the next person with the same issue gets the opportunity to learn from your ex
|
|
|
ratosluaf
Jr. Member

Karma: +1/-3
Offline
Posts: 39
|
 |
« Reply #1 on: January 06, 2025, 03:31:43 AM »
|
|
|
I've done something similar in the past for myself. Now I had some free time so I've rewritten it to streamlit and deployed it on the community cloud. Here's the link: https://fixhfm.streamlit.app/It does depend on nmot_w, rl_w and fr_w from me7logger, so idk if it will work with all logs. It does stick your data to nearest nmot_w and rl_w in kfkhfm table and calculate it depending on weighted mean. You can copy your table from tunerpro or import your table from csv file - example of log file and map csv file in github repo. github repo: https://github.com/rwalkuski/hfm_fixerAny feedback is welcome since now i have no possibility to test output myself, but had success with my own car in the past. Edit: for now, when you want to copy from site to tunerpro, please buffer the data in notepad or any other text editor Copying directly into tunerpro causes destroying of data table, but i don't know why for now. edit2: copying directly from site lacks of carriage return which tunerpro interprets as new line. At the moment, i do not know how to fix that, so please buffer your data.
|
|
|
|
« Last Edit: January 06, 2025, 05:09:25 AM by ratosluaf »
|
Logged
|
|
|
|
Crazy18T
Newbie
Karma: +0/-0
Offline
Posts: 17
|
 |
« Reply #2 on: April 29, 2025, 11:20:31 PM »
|
|
|
Finally have my car back together (in a slightly temporary fashion), so I was eager to try this.  After struggling to get the output to not cause issues with the tune (tried every setting and many iterations), I decided to take a closer look at the code. It seems the bucket creation code is quite broken. Applying this patch, we can see both RPM and load bucket calculation are way off: diff -ur trim-heatmap-0.0.5/src/heatmap.py trim-heatmap-0.0.5-testing/src/heatmap.py --- trim-heatmap-0.0.5/src/heatmap.py 2024-11-06 02:39:02.000000000 -0700 +++ trim-heatmap-0.0.5-testing/src/heatmap.py 2025-04-29 23:49:57.097326680 -0600 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # internal modules import os @@ -78,6 +78,7 @@ frdata[lk]={} for rk,rv in rpms.items(): query = f"{rv[0]} <= @lc.rpm <= {rv[1]} & {lv[0]} <= @lc.load <= {lv[1]}" + print(query) res = lc.query(query).copy() if len(res.index) >= (args.min_samples, 1)[args.no_filter]: # ternary is (false, true) # size of cell, center to corner
A few rounds of output with patch applied (example log.csv): $ ./heatmap.py 0 <= @lc.rpm <= 859.0 & 0 <= @lc.load <= 14.0 860.0 <= @lc.rpm <= 1119.0 & 0 <= @lc.load <= 14.0 1120.0 <= @lc.rpm <= 1379.0 & 0 <= @lc.load <= 14.0 1380.0 <= @lc.rpm <= 1759.0 & 0 <= @lc.load <= 14.0 1760.0 <= @lc.rpm <= 2259.0 & 0 <= @lc.load <= 14.0 2260.0 <= @lc.rpm <= 2759.0 & 0 <= @lc.load <= 14.0 2760.0 <= @lc.rpm <= 3259.0 & 0 <= @lc.load <= 14.0 3260.0 <= @lc.rpm <= 3759.0 & 0 <= @lc.load <= 14.0 3760.0 <= @lc.rpm <= 4259.0 & 0 <= @lc.load <= 14.0 4260.0 <= @lc.rpm <= 4759.0 & 0 <= @lc.load <= 14.0 4760.0 <= @lc.rpm <= 5259.0 & 0 <= @lc.load <= 14.0 5260.0 <= @lc.rpm <= 5759.0 & 0 <= @lc.load <= 14.0 5760.0 <= @lc.rpm <= 6259.0 & 0 <= @lc.load <= 14.0 6260.0 <= @lc.rpm <= 10000 & 0 <= @lc.load <= 14.0 0 <= @lc.rpm <= 859.0 & 15.0 <= @lc.load <= 24.125 860.0 <= @lc.rpm <= 1119.0 & 15.0 <= @lc.load <= 24.125 1120.0 <= @lc.rpm <= 1379.0 & 15.0 <= @lc.load <= 24.125 1380.0 <= @lc.rpm <= 1759.0 & 15.0 <= @lc.load <= 24.125 1760.0 <= @lc.rpm <= 2259.0 & 15.0 <= @lc.load <= 24.125 2260.0 <= @lc.rpm <= 2759.0 & 15.0 <= @lc.load <= 24.125 2760.0 <= @lc.rpm <= 3259.0 & 15.0 <= @lc.load <= 24.125 3260.0 <= @lc.rpm <= 3759.0 & 15.0 <= @lc.load <= 24.125 3760.0 <= @lc.rpm <= 4259.0 & 15.0 <= @lc.load <= 24.125 4260.0 <= @lc.rpm <= 4759.0 & 15.0 <= @lc.load <= 24.125 4760.0 <= @lc.rpm <= 5259.0 & 15.0 <= @lc.load <= 24.125 5260.0 <= @lc.rpm <= 5759.0 & 15.0 <= @lc.load <= 24.125 5760.0 <= @lc.rpm <= 6259.0 & 15.0 <= @lc.load <= 24.125 6260.0 <= @lc.rpm <= 10000 & 15.0 <= @lc.load <= 24.125 0 <= @lc.rpm <= 859.0 & 25.125 <= @lc.load <= 33.875 860.0 <= @lc.rpm <= 1119.0 & 25.125 <= @lc.load <= 33.875 1120.0 <= @lc.rpm <= 1379.0 & 25.125 <= @lc.load <= 33.875 1380.0 <= @lc.rpm <= 1759.0 & 25.125 <= @lc.load <= 33.875 1760.0 <= @lc.rpm <= 2259.0 & 25.125 <= @lc.load <= 33.875 2260.0 <= @lc.rpm <= 2759.0 & 25.125 <= @lc.load <= 33.875 2760.0 <= @lc.rpm <= 3259.0 & 25.125 <= @lc.load <= 33.875 3260.0 <= @lc.rpm <= 3759.0 & 25.125 <= @lc.load <= 33.875 3760.0 <= @lc.rpm <= 4259.0 & 25.125 <= @lc.load <= 33.875 4260.0 <= @lc.rpm <= 4759.0 & 25.125 <= @lc.load <= 33.875 4760.0 <= @lc.rpm <= 5259.0 & 25.125 <= @lc.load <= 33.875 5260.0 <= @lc.rpm <= 5759.0 & 25.125 <= @lc.load <= 33.875 5760.0 <= @lc.rpm <= 6259.0 & 25.125 <= @lc.load <= 33.875 6260.0 <= @lc.rpm <= 10000 & 25.125 <= @lc.load <= 33.875 0 <= @lc.rpm <= 859.0 & 34.875 <= @lc.load <= 44.0 860.0 <= @lc.rpm <= 1119.0 & 34.875 <= @lc.load <= 44.0 1120.0 <= @lc.rpm <= 1379.0 & 34.875 <= @lc.load <= 44.0 1380.0 <= @lc.rpm <= 1759.0 & 34.875 <= @lc.load <= 44.0 1760.0 <= @lc.rpm <= 2259.0 & 34.875 <= @lc.load <= 44.0 2260.0 <= @lc.rpm <= 2759.0 & 34.875 <= @lc.load <= 44.0 2760.0 <= @lc.rpm <= 3259.0 & 34.875 <= @lc.load <= 44.0 3260.0 <= @lc.rpm <= 3759.0 & 34.875 <= @lc.load <= 44.0 3760.0 <= @lc.rpm <= 4259.0 & 34.875 <= @lc.load <= 44.0 4260.0 <= @lc.rpm <= 4759.0 & 34.875 <= @lc.load <= 44.0 4760.0 <= @lc.rpm <= 5259.0 & 34.875 <= @lc.load <= 44.0 5260.0 <= @lc.rpm <= 5759.0 & 34.875 <= @lc.load <= 44.0 5760.0 <= @lc.rpm <= 6259.0 & 34.875 <= @lc.load <= 44.0 6260.0 <= @lc.rpm <= 10000 & 34.875 <= @lc.load <= 44.0
|
|
|
|
|
Logged
|
|
|
|
|
nyet
|
 |
« Reply #3 on: April 29, 2025, 11:57:17 PM »
|
|
|
post the log ill take a look
what are you expecting to see?
|
|
|
|
« Last Edit: April 29, 2025, 11:59:11 PM by nyet »
|
Logged
|
ME7.1 tuning guideECUx PlotME7Sum checksumTrim heatmap toolPlease do not ask me for tunes. I'm here to help people make their own. Do not PM me technical questions! Please, ask all questions on the forums! Doing so will ensure the next person with the same issue gets the opportunity to learn from your ex
|
|
|
Crazy18T
Newbie
Karma: +0/-0
Offline
Posts: 17
|
 |
« Reply #4 on: April 30, 2025, 12:03:42 AM »
|
|
|
This is the example log.csv as stated. I assume the bucket code is AI generated? Why do you not see the issue here?
|
|
|
|
|
Logged
|
|
|
|
Crazy18T
Newbie
Karma: +0/-0
Offline
Posts: 17
|
 |
« Reply #5 on: April 30, 2025, 12:34:06 AM »
|
|
|
I expect to see the RPM and load buckets populated as you provided (rpms loads) for the 2.7T. In my case they are adjusted for my setup, but that's beyond the scope of this thread. Sorry! I didn't mean to come across as rude.
|
|
|
|
|
Logged
|
|
|
|
|
nyet
|
 |
« Reply #6 on: April 30, 2025, 10:39:27 AM »
|
|
|
I expect to see the RPM and load buckets populated as you provided (rpms loads) for the 2.7T. In my case they are adjusted for my setup, but that's beyond the scope of this thread. Sorry! I didn't mean to come across as rude.
You're not printing the output. You're printing a query that happens in the core code, before anything else happens, including all processing. What is the input you are giving it? What command line parameters?
|
|
|
|
« Last Edit: April 30, 2025, 10:41:11 AM by nyet »
|
Logged
|
ME7.1 tuning guideECUx PlotME7Sum checksumTrim heatmap toolPlease do not ask me for tunes. I'm here to help people make their own. Do not PM me technical questions! Please, ask all questions on the forums! Doing so will ensure the next person with the same issue gets the opportunity to learn from your ex
|
|
|
Crazy18T
Newbie
Karma: +0/-0
Offline
Posts: 17
|
 |
« Reply #7 on: April 30, 2025, 03:31:55 PM »
|
|
|
I'm aware I'm not printing the output, but the output can't be correct if the buckets/cells aren't populated using the proper values. The command line is included with my post. It's just showing what buckets are created using your example log.csv.
|
|
|
|
|
Logged
|
|
|
|
Crazy18T
Newbie
Karma: +0/-0
Offline
Posts: 17
|
 |
« Reply #8 on: April 30, 2025, 03:58:17 PM »
|
|
|
calc_ranges() seems to be completely broken. I don't understand how you aren't seeing this? It creates rpms as 14 buckets/cells as expected, but for example the first bucket shouldn't be 0-859. It should be 720-999. And it continues on with both bucket ranges in this confusing way.
|
|
|
|
|
Logged
|
|
|
|
|
nyet
|
 |
« Reply #9 on: April 30, 2025, 10:08:57 PM »
|
|
|
the map numbers are the *centers* of the cells. We either do a linear average or a weighted average by distance from the center of the cell (which is the map axis data)
|
|
|
|
« Last Edit: April 30, 2025, 10:11:22 PM by nyet »
|
Logged
|
ME7.1 tuning guideECUx PlotME7Sum checksumTrim heatmap toolPlease do not ask me for tunes. I'm here to help people make their own. Do not PM me technical questions! Please, ask all questions on the forums! Doing so will ensure the next person with the same issue gets the opportunity to learn from your ex
|
|
|
Crazy18T
Newbie
Karma: +0/-0
Offline
Posts: 17
|
 |
« Reply #10 on: June 26, 2025, 10:04:27 PM »
|
|
|
Appreciate the clarification. As you probably figured out, my issues actually stemmed from minor hardware issues. I would like to continue on in helping to develop open source tools to help dial in air/fuel on ME7. I was able to create a KFLF version for ME7.5 1.8T no problem. The reason being, we have additional ranges on this load/air correction map that could help smooth things out. The obvious next step is to create the inverse map using the same logic, so we can try and determine when we have an air/load correction situation vs just a non-linearity issue with injector pulse. My first attempt to do this works in continuous mode, but it provides no output in other modes. Do you think this is because calc_ranges() doesn't tolerate the small floating points used in IOT of FKKVS? It's the best guess I have at this point. Appreciate the code! $ trim-heatmap-fkkvs/src/heatmap.py log.csv --text -s1 Empty DataFrame Columns: [] Index: [] $ trim-heatmap-fkkvs/src/heatmap.py log.csv -s1 Traceback (most recent call last): File "/home/tuning/trim-heatmap-fkkvs/src/heatmap.py", line 255, in <module> main() File "/home/tuning/trim-heatmap-fkkvs/src/heatmap.py", line 246, in main sbs.heatmap(heatmap, annot=(not args.continuous), center=0, cmap='PiYG', cbar_kws={'label': '% trim'}).invert_yaxis() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/seaborn/matrix.py", line 446, in heatmap plotter = _HeatMapper(data, vmin, vmax, cmap, center, robust, annot, fmt, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/seaborn/matrix.py", line 163, in __init__ self._determine_cmap_params(plot_data, vmin, vmax, File "/usr/lib/python3/dist-packages/seaborn/matrix.py", line 202, in _determine_cmap_params vmin = np.nanmin(calc_data) ^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/numpy/lib/nanfunctions.py", line 343, in nanmin res = np.fmin.reduce(a, axis=axis, out=out, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ValueError: zero-size array to reduction operation fmin which has no identity
|
|
|
|
« Last Edit: June 26, 2025, 10:34:58 PM by Crazy18T »
|
Logged
|
|
|
|
Crazy18T
Newbie
Karma: +0/-0
Offline
Posts: 17
|
 |
« Reply #11 on: June 27, 2025, 11:54:33 PM »
|
|
|
Changes for the FKKVS variation are quite simple, but I'm still not sure exactly the logic of calc_ranges(). I have no reason to think it's anything else given it works in continuous mode. Maybe I'm missing something? diff -ur trim-heatmap-0.0.5/src/heatmap.py trim-heatmap-fkkvs-mod/src/heatmap.py --- trim-heatmap-0.0.5/src/heatmap.py 2024-11-06 02:39:02.000000000 -0700 +++ trim-heatmap-fkkvs-mod/src/heatmap.py 2025-06-28 00:39:48.101375975 -0600 @@ -58,9 +58,9 @@ return buckets def continuous_heatmap(lc): - lc['load'] = lc['load'].round(0) + lc['iot'] = lc['iot'].round(0) lc['rpm'] = (lc['rpm']/10).round(0) * 10 - heatmap = lc.pivot_table(index='load', columns='rpm', values='fr') + heatmap = lc.pivot_table(index='iot', columns='rpm', values='fr') return heatmap.dropna(how='all', axis=0).dropna(how='all', axis=1) def distance(x0, y0, x1, y1): @@ -68,23 +68,22 @@ def quantized_heatmap(lc, args): # create bucket ranges - rpms = calc_ranges([720, 1000, 1240, 1520, 2000, 2520, 3000, 3520, 4000, 4520, 5000, 5520, 6000, 6520], 10000) - loads = calc_ranges([9.75, 20.25, 30, 39.75, 50.25, 60, 69.75, 80.25, 90, 99.75, 110.25, 120, 140.25, 159.75], 300) - #loads = calc_ranges([9.75, 20.25, 30, 39.75, 50.25, 60, 69.75, 80.25, 90, 99.75, 110.25, 140.25, 150, 168]) + rpms = calc_ranges([600, 800, 1000, 1240, 1520, 1720, 2000, 2520, 3000, 3520, 4000, 4520, 5000, 5520, 6000, 6520], 10000) + iots = calc_ranges([0.997, 1.299, 1.6, 2, 2.499, 3.003, 4, 5.003, 6.001, 7.004, 8.001, 9.004, 10.001, 13.004, 16.002, 19.005], 30) # sort lambda control (fr/frm) into buckets frdata={} - for lk,lv in loads.items(): + for lk,lv in iots.items(): frdata[lk]={} for rk,rv in rpms.items(): - query = f"{rv[0]} <= @lc.rpm <= {rv[1]} & {lv[0]} <= @lc.load <= {lv[1]}" + query = f"{rv[0]} <= @lc.rpm <= {rv[1]} & {lv[0]} <= @lc.iot <= {lv[1]}" res = lc.query(query).copy() if len(res.index) >= (args.min_samples, 1)[args.no_filter]: # ternary is (false, true) # size of cell, center to corner cellradius = distance(lv[0], rv[0], lv[1], rv[1])/2 # find distance to cell center # FIXME: this is not right for cells at edges of map, but we have to weight data off the map somehow - res['distance'] = res.apply(lambda row: distance(row.load, row.rpm, lk, rk), axis=1) + res['distance'] = res.apply(lambda row: distance(row.iot, row.rpm, lk, rk), axis=1) # Weight is proportional to closeness to center: distance = 0 has highest weight # Don't let weights get negative due to weird radius calcs res['weight'] = np.maximum((cellradius-res.distance)/cellradius, 0.1) @@ -109,9 +108,9 @@ def main(): parser = argparse.ArgumentParser(description='Create trim heatmap for KFKHFM based on fr/frm datalog') parser.add_argument('filename', default=['log.csv'], nargs='*', help='csv files(s) to parse (log.csv)') - parser.add_argument('-w', '--window', type=int, default=10, help='number of sequential rows to detect constant rpm/load (10)') + parser.add_argument('-w', '--window', type=int, default=10, help='number of sequential rows to detect constant rpm/iot (10)') - parser.add_argument('-l', '--load-filter', type=float, default=10, help='change in load which is still "constant" load (10)') + parser.add_argument('-i', '--iot-filter', type=float, default=0.001, help='change in iot which is still "constant" iot (0.001)') parser.add_argument('-r', '--rpm-filter', type=int, default=100, help='change in RPM which is still "constant" RPM (100)') parser.add_argument('-m', '--maf-filter', type=float, default=10, help='change in MAF which is still "constant" MAF (10)') @@ -171,13 +170,13 @@ df.rename(str.strip, axis='columns', inplace=True) # pick rl or frm_w - whichrl = ('rl', 'rl_w')['rl_w' in df] + whichrl = ('FIXME', 'ti_b1')['ti_b1' in df] # pick nmot or nmot_w whichnmot = ('nmot', 'nmot_w')['nmot_w' in df] # pick frm or fr whichfr = ('frm', 'fr')[args.use_fr or 'frm_w' not in df] - rows = [whichnmot, whichrl, whichfr + '_w', 'mshfm_w'] + rows = [whichnmot, whichrl, whichfr + '_w'] if whichfr + '2_w' in df: rows.append(whichfr + '2_w') @@ -185,11 +184,10 @@ if args.verbose: print(f"using {rows} from log") - # grab only the things we need, rename rl/nmot/mshfm to load/rpm/maf + # grab only the things we need, rename rl/nmot to iot/rpm lc = df[rows]. \ - rename(columns={whichrl:'load'}). \ - rename(columns={whichnmot:'rpm'}). \ - rename(columns={'mshfm_w':'maf'}) + rename(columns={whichrl:'iot'}). \ + rename(columns={whichnmot:'rpm'}) # flatten index lc.columns = lc.columns.get_level_values(0) @@ -204,15 +202,12 @@ # set up filter source data lc['rpm_delta'] = lc.rpm.rolling(window=args.window).apply(lambda x: x.max() - x.min()) - lc['load_delta'] = lc.load.rolling(window=args.window).apply(lambda x: x.max() - x.min()) - lc['maf_delta'] = lc.maf.rolling(window=args.window).apply(lambda x: x.max() - x.min()) + lc['iot_delta'] = lc.iot.rolling(window=args.window).apply(lambda x: x.max() - x.min()) if not args.no_filter: # tag rows we want to use based on source data lc['use'] = \ - lc.rpm_delta.notnull() & (lc.rpm_delta <= args.rpm_filter) & \ - lc.load_delta.notnull() & (lc.load_delta <= args.load_filter) & \ - lc.maf_delta.notnull() & (lc.maf_delta <= args.maf_filter) + lc.rpm_delta.notnull() & (lc.rpm_delta <= args.rpm_filter) #print(lc[(abs(lc.fr)>5) & (lc.rpm_delta > 0)].to_string()) @@ -245,7 +240,7 @@ sbs.heatmap(heatmap, annot=(not args.continuous), center=0, cmap='PiYG', cbar_kws={'label': '% trim'}).invert_yaxis() plt.xlabel('RPM') - plt.ylabel('Load') + plt.ylabel('IOT') signal.signal(signal.SIGINT, signal_handler) plt.show()
|
|
|
|
|
Logged
|
|
|
|
Crazy18T
Newbie
Karma: +0/-0
Offline
Posts: 17
|
 |
« Reply #12 on: June 29, 2025, 08:13:39 PM »
|
|
|
After confirming my suspicions and studying calc_ranges(), I now understand how it works and have created a working patch for FKKVS. It could still use a bit of work, but I don't have a lot of time to work on this stuff right now, so it's a bit quick and dirty. Hope someone else finds this useful!  diff -ur trim-heatmap-0.0.5/src/heatmap.py trim-heatmap-fkkvs-mod/src/heatmap.py --- trim-heatmap-0.0.5/src/heatmap.py 2024-11-06 02:39:02.000000000 -0700 +++ trim-heatmap-fkkvs-mod/src/heatmap.py 2025-06-29 21:06:28.834621188 -0600 @@ -44,23 +44,34 @@ except subprocess.CalledProcessError: return True +def calc_median(num1, num2): + median_value = (num1 + num2) / 2 + return median_value + def calc_ranges(ary, max): - buckets = {} - for i,v in enumerate(ary): - if i == 0: - # very start - buckets[v] = [0, (ary[i]+ary[i+1])/2-1] - elif i != len(ary)-1: - buckets[v] = [(ary[i-1]+ary[i])/2, (ary[i]+ary[i+1])/2-1] - else: - # very end - buckets[v] = [(ary[i-1]+ary[i])/2, max] - return buckets + buckets = {} + for i,v in enumerate(ary): + if i == 0: + # very start + #buckets[v] = [0, (ary[i]+ary[i+1])/2-1] + if i > 30: + buckets[v] = [0, calc_median(ary[i],ary[i+1])-1] + else: + buckets[v] = [0, calc_median(ary[i],ary[i+1])-0.001] + elif i != len(ary)-1: + if i > 30: + buckets[v] = [calc_median(ary[i-1],ary[i]), calc_median(ary[i],ary[i+1])-1] + else: + buckets[v] = [calc_median(ary[i-1],ary[i]), calc_median(ary[i],ary[i+1])-0.001] + else: + # very end + buckets[v] = [(ary[i-1]+ary[i])/2, max] + return buckets def continuous_heatmap(lc): - lc['load'] = lc['load'].round(0) + lc['iot'] = lc['iot'].round(0) lc['rpm'] = (lc['rpm']/10).round(0) * 10 - heatmap = lc.pivot_table(index='load', columns='rpm', values='fr') + heatmap = lc.pivot_table(index='iot', columns='rpm', values='fr') return heatmap.dropna(how='all', axis=0).dropna(how='all', axis=1) def distance(x0, y0, x1, y1): @@ -68,23 +79,23 @@ def quantized_heatmap(lc, args): # create bucket ranges - rpms = calc_ranges([720, 1000, 1240, 1520, 2000, 2520, 3000, 3520, 4000, 4520, 5000, 5520, 6000, 6520], 10000) - loads = calc_ranges([9.75, 20.25, 30, 39.75, 50.25, 60, 69.75, 80.25, 90, 99.75, 110.25, 120, 140.25, 159.75], 300) - #loads = calc_ranges([9.75, 20.25, 30, 39.75, 50.25, 60, 69.75, 80.25, 90, 99.75, 110.25, 140.25, 150, 168]) + # 1.8T + rpms = calc_ranges([600, 800, 1000, 1240, 1520, 1720, 2000, 2520, 3000, 3520, 4000, 4520, 5000, 5520, 6000, 6520], 10000) + iots = calc_ranges([0.997, 1.299, 1.6, 2, 2.499, 3.003, 4, 5.003, 6.001, 7.004, 8.001, 9.004, 10.001, 13.004, 16.002, 19.005], 30) # sort lambda control (fr/frm) into buckets frdata={} - for lk,lv in loads.items(): + for lk,lv in iots.items(): frdata[lk]={} for rk,rv in rpms.items(): - query = f"{rv[0]} <= @lc.rpm <= {rv[1]} & {lv[0]} <= @lc.load <= {lv[1]}" + query = f"{rv[0]} <= @lc.rpm <= {rv[1]} & {lv[0]} <= @lc.iot <= {lv[1]}" res = lc.query(query).copy() if len(res.index) >= (args.min_samples, 1)[args.no_filter]: # ternary is (false, true) # size of cell, center to corner cellradius = distance(lv[0], rv[0], lv[1], rv[1])/2 # find distance to cell center # FIXME: this is not right for cells at edges of map, but we have to weight data off the map somehow - res['distance'] = res.apply(lambda row: distance(row.load, row.rpm, lk, rk), axis=1) + res['distance'] = res.apply(lambda row: distance(row.iot, row.rpm, lk, rk), axis=1) # Weight is proportional to closeness to center: distance = 0 has highest weight # Don't let weights get negative due to weird radius calcs res['weight'] = np.maximum((cellradius-res.distance)/cellradius, 0.1) @@ -109,11 +120,10 @@ def main(): parser = argparse.ArgumentParser(description='Create trim heatmap for KFKHFM based on fr/frm datalog') parser.add_argument('filename', default=['log.csv'], nargs='*', help='csv files(s) to parse (log.csv)') - parser.add_argument('-w', '--window', type=int, default=10, help='number of sequential rows to detect constant rpm/load (10)') + parser.add_argument('-w', '--window', type=int, default=10, help='number of sequential rows to detect constant rpm/iot (10)') - parser.add_argument('-l', '--load-filter', type=float, default=10, help='change in load which is still "constant" load (10)') + parser.add_argument('-i', '--iot-filter', type=float, default=0.001, help='change in iot which is still "constant" iot (0.001)') parser.add_argument('-r', '--rpm-filter', type=int, default=100, help='change in RPM which is still "constant" RPM (100)') - parser.add_argument('-m', '--maf-filter', type=float, default=10, help='change in MAF which is still "constant" MAF (10)') parser.add_argument('-n', '--no-filter', action='store_true', help='disable filter (default is enabled)') @@ -171,13 +181,13 @@ df.rename(str.strip, axis='columns', inplace=True) # pick rl or frm_w - whichrl = ('rl', 'rl_w')['rl_w' in df] + whichrl = ('FIXME', 'ti_b1')['ti_b1' in df] # pick nmot or nmot_w whichnmot = ('nmot', 'nmot_w')['nmot_w' in df] # pick frm or fr whichfr = ('frm', 'fr')[args.use_fr or 'frm_w' not in df] - rows = [whichnmot, whichrl, whichfr + '_w', 'mshfm_w'] + rows = [whichnmot, whichrl, whichfr + '_w'] if whichfr + '2_w' in df: rows.append(whichfr + '2_w') @@ -185,11 +195,10 @@ if args.verbose: print(f"using {rows} from log") - # grab only the things we need, rename rl/nmot/mshfm to load/rpm/maf + # grab only the things we need, rename rl/nmot to iot/rpm lc = df[rows]. \ - rename(columns={whichrl:'load'}). \ - rename(columns={whichnmot:'rpm'}). \ - rename(columns={'mshfm_w':'maf'}) + rename(columns={whichrl:'iot'}). \ + rename(columns={whichnmot:'rpm'}) # flatten index lc.columns = lc.columns.get_level_values(0) @@ -204,15 +213,12 @@ # set up filter source data lc['rpm_delta'] = lc.rpm.rolling(window=args.window).apply(lambda x: x.max() - x.min()) - lc['load_delta'] = lc.load.rolling(window=args.window).apply(lambda x: x.max() - x.min()) - lc['maf_delta'] = lc.maf.rolling(window=args.window).apply(lambda x: x.max() - x.min()) + lc['iot_delta'] = lc.iot.rolling(window=args.window).apply(lambda x: x.max() - x.min()) if not args.no_filter: # tag rows we want to use based on source data lc['use'] = \ - lc.rpm_delta.notnull() & (lc.rpm_delta <= args.rpm_filter) & \ - lc.load_delta.notnull() & (lc.load_delta <= args.load_filter) & \ - lc.maf_delta.notnull() & (lc.maf_delta <= args.maf_filter) + lc.rpm_delta.notnull() & (lc.rpm_delta <= args.rpm_filter) #print(lc[(abs(lc.fr)>5) & (lc.rpm_delta > 0)].to_string()) @@ -245,7 +251,7 @@ sbs.heatmap(heatmap, annot=(not args.continuous), center=0, cmap='PiYG', cbar_kws={'label': '% trim'}).invert_yaxis() plt.xlabel('RPM') - plt.ylabel('Load') + plt.ylabel('IOT') signal.signal(signal.SIGINT, signal_handler) plt.show()
|
|
|
|
|
Logged
|
|
|
|
Crazy18T
Newbie
Karma: +0/-0
Offline
Posts: 17
|
 |
« Reply #13 on: July 01, 2025, 07:35:34 PM »
|
|
|
Not sure why nyet seems to be butthurt that I haven't posted logs. I never asked for help with my tune (only logic questions), and I'm writing open source code. I won't be posting details of my build or any raw logs, but I will demonstrate with today's test that my logic is sound. It is possible to discern where adjustments should be made when certain reference points are lost. This is a bit of a Top Chef level proof, as I'm providing fueling 3 ways!  In this case, a sample size of 6 seemed to be ideal for this smallish 14 MB log at 30s/sec. Again, I hope someone else finds this useful. If you'd like I can provide a patch for 1.8T KFLF as well, but it's pretty straightforward to implement that. If you want it to line up better c/p into a window with a fixed width font. The forum code seems to lose the concept of this with a quote for some odd reason. $ hm /mnt/win7/ME7L/logs/pro_20250701_181512.csv --text -s6 600 800 1000 1240 1520 1720 2000 2520 3000 3520 4000 4520 5000 9.004 NaN NaN NaN NaN NaN NaN NaN NaN 3.227 NaN NaN NaN NaN 8.001 NaN NaN NaN NaN NaN NaN NaN NaN 2.420 NaN NaN NaN NaN 7.004 NaN NaN NaN NaN NaN NaN NaN 4.178 2.463 NaN NaN NaN NaN 6.001 NaN NaN NaN NaN NaN NaN NaN 5.612 5.282 4.641 NaN NaN NaN 5.003 NaN NaN NaN NaN 12.723 12.397 9.112 8.143 7.082 5.859 9.056 10.788 NaN 4.000 0.322 3.446 2.194 7.356 10.733 7.245 7.886 9.283 8.467 9.043 9.769 10.905 12.344 3.003 3.323 -0.489 7.611 5.273 3.701 0.021 2.266 5.367 4.682 7.583 8.830 NaN NaN 2.499 -3.556 -0.727 5.134 5.487 -0.666 2.313 1.712 3.180 2.952 6.275 1.927 NaN NaN 2.000 -20.017 -1.064 1.841 8.106 4.447 0.352 3.206 3.007 4.685 4.710 6.505 NaN NaN 1.600 NaN -3.323 7.188 10.081 6.467 0.030 0.429 1.962 5.093 1.300 5.939 NaN NaN 1.299 NaN NaN NaN 0.000 0.000 0.000 NaN 0.001 0.007 0.000 NaN NaN NaN 600 800 1000 1240 1520 2000 2520 3000 3520 4000 4520 5000 100.50 NaN NaN NaN NaN NaN NaN NaN 2.036 NaN NaN NaN NaN 80.25 NaN NaN NaN NaN NaN NaN 5.515 NaN 5.076 NaN NaN NaN 70.50 NaN NaN NaN NaN NaN NaN 7.461 4.075 2.964 NaN NaN NaN 60.00 NaN NaN NaN 6.291 11.940 8.644 7.638 8.831 9.017 10.119 10.705 NaN 50.25 NaN 4.823 2.511 4.705 10.077 7.814 10.083 9.166 9.293 9.571 10.905 12.344 40.50 NaN -0.224 2.092 3.996 -0.365 0.718 5.134 6.141 8.550 9.886 NaN NaN 30.00 3.643 -1.541 4.673 5.338 -1.181 2.250 3.228 2.799 6.395 NaN NaN NaN 20.25 -13.443 -2.136 2.233 7.484 5.303 3.061 2.855 4.409 7.379 6.243 NaN NaN 15.00 NaN 1.045 13.099 10.523 7.182 0.592 2.223 5.868 1.695 7.593 NaN NaN 10.50 NaN NaN NaN 0.000 0.000 NaN 0.000 0.005 0.006 NaN NaN NaN 1000 1480 1720 1840 1920 2000 2520 3000 3520 4520 5520 102.75 NaN NaN NaN NaN NaN NaN NaN 2.040 NaN NaN NaN 78.00 NaN NaN NaN NaN NaN NaN 5.007 4.441 6.014 NaN NaN 63.75 NaN 11.580 12.536 NaN NaN 8.706 8.482 8.708 7.759 10.499 NaN 49.50 4.102 11.496 7.491 6.704 8.029 7.488 9.174 9.138 9.604 10.847 13.145 37.50 2.531 -1.527 1.807 1.932 2.330 1.961 3.986 2.136 7.876 NaN NaN 15.00 -1.347 6.553 0.161 -0.007 0.000 0.798 2.479 4.896 2.555 NaN NaN 9.75 NaN 0.000 NaN NaN NaN NaN 0.000 0.000 0.000 NaN NaN
|
|
|
|
|
Logged
|
|
|
|
|
nyet
|
 |
« Reply #14 on: July 01, 2025, 09:50:22 PM »
|
|
|
code uses fixed width, quote does not.
|
|
|
|
|
Logged
|
ME7.1 tuning guideECUx PlotME7Sum checksumTrim heatmap toolPlease do not ask me for tunes. I'm here to help people make their own. Do not PM me technical questions! Please, ask all questions on the forums! Doing so will ensure the next person with the same issue gets the opportunity to learn from your ex
|
|
|
|