├── .classpath
├── .project
├── .settings
├── org.eclipse.jdt.core.prefs
└── org.eclipse.jdt.launching.prefs
├── LICENSE
├── MafScaling.jar
├── README.md
├── build.xml
├── config.xml
├── lib
├── CheckBoxTree_1.0.0.jar
├── JTattoo-1.6.11.jar
├── commons-math3-3.6.1.jar
├── jcommon-1.0.21.jar
├── jfreechart-1.5.3.jar
├── jmathio.jar
├── jmathplot.jar
├── log4j-1.2.14.jar
└── quicktable-3.0.jar
├── log4j.properties
├── resources
├── arrow.jpg
├── arrowr.jpg
├── chart.jpg
├── down.gif
├── ffw.png
├── find.png
├── open.png
├── pause.png
├── play.png
├── player.png
├── print.png
├── print_preview.png
├── redo.png
├── replace.png
├── rew.png
├── stop.png
├── table.jpg
└── undo.png
├── run.bat
├── run.sh
├── src
├── com
│ └── vgi
│ │ └── mafscaling
│ │ ├── ACompCalc.java
│ │ ├── AMafScaling.java
│ │ ├── BgColorFormatRenderer.java
│ │ ├── CLColumnsFiltersSelection.java
│ │ ├── ClosedLoop.java
│ │ ├── ColumnsFiltersSelection.java
│ │ ├── Config.java
│ │ ├── DBTFindFrame.java
│ │ ├── ExcelAdapter.java
│ │ ├── FCTabbedPane.java
│ │ ├── IMafChartHolder.java
│ │ ├── JMultiSelectionBox.java
│ │ ├── LCColumnsFiltersSelection.java
│ │ ├── LoadComp.java
│ │ ├── LogPlay.java
│ │ ├── LogPlayTable.java
│ │ ├── LogStats.java
│ │ ├── LogStatsFilters.java
│ │ ├── LogStatsFixedAxis.java
│ │ ├── LogView.java
│ │ ├── MafChartPanel.java
│ │ ├── MafCompare.java
│ │ ├── MafIatColumnsFiltersSelection.java
│ │ ├── MafIatComp.java
│ │ ├── MafOLCLMerge.java
│ │ ├── MafRescale.java
│ │ ├── MafScaling.java
│ │ ├── MafTablePane.java
│ │ ├── NumberFormatRenderer.java
│ │ ├── OLColumnsFiltersSelection.java
│ │ ├── OpenLoop.java
│ │ ├── PrimaryOpenLoopFuelingTable.java
│ │ ├── RestrictedFileSystemView.java
│ │ ├── TableCellListener.java
│ │ ├── TableRescale.java
│ │ ├── ThrottleMaps.java
│ │ ├── Utils.java
│ │ ├── VECalc.java
│ │ ├── VEColumnsFiltersSelection.java
│ │ ├── VVTCalc.java
│ │ ├── VVTColumnsFiltersSelection.java
│ │ ├── WotPullsGroups.java
│ │ ├── XYDomainMutilineAnnotation.java
│ │ ├── closedloop.properties
│ │ ├── loadcomp.properties
│ │ ├── logstats.properties
│ │ ├── logview.properties
│ │ ├── mafiatcomp.properties
│ │ ├── mafolclmerge.properties
│ │ ├── mafrescale.properties
│ │ ├── openloop.properties
│ │ ├── tablerescale.properties
│ │ ├── thrtlmaps.properties
│ │ ├── vecalc.properties
│ │ └── vvtcalc.properties
└── ij
│ └── measure
│ ├── CurveFitter.java
│ ├── IJMath.java
│ └── Minimizer.java
└── testfiles
├── ProECU-OL-CL-LC-LS-LV.log.csv
├── ThrottleMaps.xlsx
├── mafscaling_table.csv
└── polf_table.csv
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | MafScaling
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.builder.cleanOutputFolder=clean
3 | org.eclipse.jdt.core.builder.duplicateResourceTask=warning
4 | org.eclipse.jdt.core.builder.invalidClasspath=abort
5 | org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
6 | org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=
7 | org.eclipse.jdt.core.circularClasspath=error
8 | org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
9 | org.eclipse.jdt.core.classpath.mainOnlyProjectHasTestOnlyDependency=error
10 | org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
11 | org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error
12 | org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
13 | org.eclipse.jdt.core.incompatibleJDKLevel=ignore
14 | org.eclipse.jdt.core.incompleteClasspath=error
15 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.launching.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.launching.PREF_COMPILER_COMPLIANCE_DOES_NOT_MATCH_JRE=warning
3 | org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=warning
4 |
--------------------------------------------------------------------------------
/MafScaling.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/MafScaling.jar
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | A small utility for processing ECU log files to help tuning for Subaru owners (some tools will work for other cars)
2 |
3 | Sorry for the confusing name, it started as mafscaler but then evolved into a bit more than that.
4 |
5 | Currently these tools are implemented:
6 |
7 | MAF Open Loop Scaling
8 |
9 | MAF Closed Loop Scaling
10 |
11 | MAF Closed Loop and Open Loop Scalings merging and fitting
12 |
13 | MAF Rescaling
14 |
15 | Table Rescaling
16 |
17 | Throttle Maps
18 |
19 | Load Compensation / Injector Pulse Width Compensation
20 |
21 | IAT Compensation
22 |
23 | MAF VE Calculation
24 |
25 | WOT best VVT
26 |
27 | Log Statistics (learning)
28 |
29 | Log view, WOT comparison, and map tracing (replay)
30 |
31 |
32 |
33 | WIKI page - https://github.com/vimsh/mafscaling/wiki
34 |
35 | Thread on RomRaider - http://www.romraider.com/forum/viewtopic.php?t=10481
36 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | settings
5 |
6 |
--------------------------------------------------------------------------------
/lib/CheckBoxTree_1.0.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/lib/CheckBoxTree_1.0.0.jar
--------------------------------------------------------------------------------
/lib/JTattoo-1.6.11.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/lib/JTattoo-1.6.11.jar
--------------------------------------------------------------------------------
/lib/commons-math3-3.6.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/lib/commons-math3-3.6.1.jar
--------------------------------------------------------------------------------
/lib/jcommon-1.0.21.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/lib/jcommon-1.0.21.jar
--------------------------------------------------------------------------------
/lib/jfreechart-1.5.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/lib/jfreechart-1.5.3.jar
--------------------------------------------------------------------------------
/lib/jmathio.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/lib/jmathio.jar
--------------------------------------------------------------------------------
/lib/jmathplot.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/lib/jmathplot.jar
--------------------------------------------------------------------------------
/lib/log4j-1.2.14.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/lib/log4j-1.2.14.jar
--------------------------------------------------------------------------------
/lib/quicktable-3.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/lib/quicktable-3.0.jar
--------------------------------------------------------------------------------
/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=info, stdout, file
2 |
3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
5 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %F:%L - %m%n
6 |
7 | log4j.appender.file=org.apache.log4j.RollingFileAppender
8 | log4j.appender.file.File=./maf_scaling.log
9 | log4j.appender.file.MaxBackupIndex=1
10 | log4j.appender.file.layout=org.apache.log4j.PatternLayout
11 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %F:%L - %m%n
12 |
--------------------------------------------------------------------------------
/resources/arrow.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/arrow.jpg
--------------------------------------------------------------------------------
/resources/arrowr.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/arrowr.jpg
--------------------------------------------------------------------------------
/resources/chart.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/chart.jpg
--------------------------------------------------------------------------------
/resources/down.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/down.gif
--------------------------------------------------------------------------------
/resources/ffw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/ffw.png
--------------------------------------------------------------------------------
/resources/find.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/find.png
--------------------------------------------------------------------------------
/resources/open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/open.png
--------------------------------------------------------------------------------
/resources/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/pause.png
--------------------------------------------------------------------------------
/resources/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/play.png
--------------------------------------------------------------------------------
/resources/player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/player.png
--------------------------------------------------------------------------------
/resources/print.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/print.png
--------------------------------------------------------------------------------
/resources/print_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/print_preview.png
--------------------------------------------------------------------------------
/resources/redo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/redo.png
--------------------------------------------------------------------------------
/resources/replace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/replace.png
--------------------------------------------------------------------------------
/resources/rew.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/rew.png
--------------------------------------------------------------------------------
/resources/stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/stop.png
--------------------------------------------------------------------------------
/resources/table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/table.jpg
--------------------------------------------------------------------------------
/resources/undo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/resources/undo.png
--------------------------------------------------------------------------------
/run.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM *** Set/Change path to javaw.exe if you have multiple Java installations or if has not been added to the PATH ***
4 | REM set PATH=C:\Program Files\Java\jre17u3\bin;%PATH%
5 |
6 |
7 | REM *** Windows system skin ***
8 | start javaw -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
9 |
10 |
11 | REM *** Windows Classic system skin ***
12 | REM start javaw -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
13 |
14 |
15 | REM *** Java Default ***
16 | REM start javaw -Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
17 |
18 |
19 | REM *** Nimbus - New Java Swing . REQUIRES JAVA 7 OR GREATER ***
20 | REM start javaw -Dswing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
21 |
22 | REM *** Linux Motif ***
23 | REM start javaw -Dswing.defaultlaf=com.sun.java.swing.plaf.motif.MotifLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
24 |
25 |
26 | REM *** Variations of skinned default Java Swing look and feel ***
27 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.aero.AeroLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
28 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.smart.SmartLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
29 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.mint.MintLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
30 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.fast.FastLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
31 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.luna.LunaLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
32 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.texture.TextureLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
33 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.mcwin.McWinLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
34 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.aluminium.AluminiumLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
35 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.acryl.AcrylLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
36 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.graphite.GraphiteLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
37 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.hifi.HiFiLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
38 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.noire.NoireLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
39 | REM start javaw -Dswing.defaultlaf=com.jtattoo.plaf.bernstein.BernsteinLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
40 |
--------------------------------------------------------------------------------
/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # *** GTK ***
3 | #java -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
4 |
5 |
6 | # *** Java Default ***
7 | # start javaw -Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar
8 |
9 | # *** New Java Swing ***
10 | java -Dswing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
11 |
12 | # *** Linux Motif ***
13 | #java -Dswing.defaultlaf=com.sun.java.swing.plaf.motif.MotifLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
14 |
15 | # *** Variations of skinned default Java Swing look and feel ***
16 | #java -Dswing.defaultlaf=com.jtattoo.plaf.aero.AeroLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
17 | #java -Dswing.defaultlaf=com.jtattoo.plaf.smart.SmartLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
18 | #java -Dswing.defaultlaf=com.jtattoo.plaf.mint.MintLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
19 | #java -Dswing.defaultlaf=com.jtattoo.plaf.fast.FastLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
20 | #java -Dswing.defaultlaf=com.jtattoo.plaf.luna.LunaLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
21 | #java -Dswing.defaultlaf=com.jtattoo.plaf.texture.TextureLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
22 | #java -Dswing.defaultlaf=com.jtattoo.plaf.mcwin.McWinLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
23 | #java -Dswing.defaultlaf=com.jtattoo.plaf.aluminium.AluminiumLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
24 | #java -Dswing.defaultlaf=com.jtattoo.plaf.acryl.AcrylLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
25 | #java -Dswing.defaultlaf=com.jtattoo.plaf.graphite.GraphiteLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
26 | #java -Dswing.defaultlaf=com.jtattoo.plaf.hifi.HiFiLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
27 | #java -Dswing.defaultlaf=com.jtattoo.plaf.noire.NoireLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
28 | #java -Dswing.defaultlaf=com.jtattoo.plaf.bernstein.BernsteinLookAndFeel -Xms64M -Xmx512M -jar MafScaling.jar &
29 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/BgColorFormatRenderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.Color;
22 | import java.awt.Component;
23 | import javax.swing.JTable;
24 | import javax.swing.table.DefaultTableCellRenderer;
25 |
26 | public class BgColorFormatRenderer extends DefaultTableCellRenderer {
27 | private static final long serialVersionUID = -2283383526525346419L;
28 | private Color bgColor = getBackground();
29 | private Color[][] colors = null;
30 |
31 | /**
32 | * Method sets background color matrix for cells
33 | * @param colorMatrix
34 | */
35 | public void setColors(Color[][] colorMatrix) {
36 | colors = colorMatrix;
37 | }
38 |
39 | /**
40 | * Method returns background color matrix for cells
41 | * @return colorMatrix
42 | */
43 | public Color[][] getColors() {
44 | return colors;
45 | }
46 |
47 | /**
48 | * Method sets background color for a specific cell
49 | * @param color, background color
50 | * @param row, cell row index
51 | * @param column, cell column index
52 | */
53 | public void setColorAt(Color color, int row, int column) {
54 | if (colors != null && row < colors.length && column < colors[0].length)
55 | colors[row][column] = color;
56 | }
57 |
58 | /**
59 | * Method returns background color for a specific cell
60 | * @param row, cell row index
61 | * @param column, cell column index
62 | * @return Color
63 | */
64 | public Color getColorAt(int row, int column) {
65 | if (colors != null && row < colors.length && column < colors[0].length)
66 | return colors[row][column];
67 | return bgColor;
68 | }
69 |
70 | @Override
71 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
72 | if (colors != null) {
73 | if (row < colors.length && column < colors[0].length)
74 | setBackground(colors[row][column]);
75 | else
76 | setBackground(bgColor);
77 | }
78 | else
79 | setBackground(bgColor);
80 | return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column );
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/CLColumnsFiltersSelection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.event.ActionEvent;
22 |
23 | public class CLColumnsFiltersSelection extends ColumnsFiltersSelection {
24 | private boolean isPolfTableMap = false;
25 |
26 | public CLColumnsFiltersSelection(boolean isPolfTableMap) {
27 | this.isPolfTableMap = isPolfTableMap;
28 | }
29 |
30 | protected void addColSelection() {
31 | addRPMColSelection();
32 | addLoadColSelection();
33 | addAFLearningColSelection();
34 | addAFCorrectionColSelection();
35 | addMAFVoltageColSelection();
36 | addStockAFRColSelection();
37 | addClOlStatusColSelection();
38 | addTimeColSelection();
39 | addIATColSelection();
40 | if (isPolfTableMap)
41 | addManifoldAbsolutePressureColSelection();
42 | }
43 |
44 | protected void addFilterSelection() {
45 | addCLOLStatusFilter();
46 | clolStatusFilter.setValue(Config.getClOlStatusValue());
47 | addMAFVoltageMaximumFilter();
48 | maxMafVFilter.setText(String.valueOf(Config.getMafVMaximumValue()));
49 | addEngineLoadMinimumFilter();
50 | minEngineLoadFilter.setText(String.valueOf(Config.getLoadMinimumValue()));
51 | addIATMaximumFilter();
52 | maxIatFilter.setText(String.valueOf(Config.getIatMaximumValue()));
53 | addAFRMaximumFilter();
54 | maxAfrFilter.setText(String.valueOf(Config.getAfrMaximumValue()));
55 | addAFRMinimumFilter();
56 | minAfrFilter.setText(String.valueOf(Config.getAfrMinimumValue()));
57 | addDvDtMaximumFilter();
58 | maxDvdtFilter.setText(String.valueOf(Config.getDvDtMaximumValue()));
59 | addCellHitCountMinimumFilter();
60 | minCellHitCountFilter.setText(String.valueOf(Config.getCLMinCellHitCount()));
61 | }
62 |
63 | protected boolean validate(StringBuffer error) {
64 | boolean ret = true;
65 | String value;
66 | String colName;
67 |
68 | // Engine Speed
69 | value = rpmName.getText().trim();
70 | colName = rpmLabelText;
71 | if (value.isEmpty()) {
72 | ret = false;
73 | error.append("\"").append(colName).append("\" column must be specified\n");
74 | }
75 | else
76 | Config.setRpmColumnName(value);
77 |
78 | // Engine Load
79 | value = loadName.getText().trim();
80 | colName = loadLabelText;
81 | if (value.isEmpty()) {
82 | ret = false;
83 | error.append("\"").append(colName).append("\" column must be specified\n");
84 | }
85 | else
86 | Config.setLoadColumnName(value);
87 |
88 | // AFR Learning
89 | value = afLearningName.getText().trim();
90 | colName = afLearningLabelText;
91 | if (value.isEmpty()) {
92 | ret = false;
93 | error.append("\"").append(colName).append("\" column must be specified\n");
94 | }
95 | else
96 | Config.setAfLearningColumnName(value);
97 |
98 | // AFR Correction
99 | value = afCorrectionName.getText().trim();
100 | colName = afCorrectionLabelText;
101 | if (value.isEmpty()) {
102 | ret = false;
103 | error.append("\"").append(colName).append("\" column must be specified\n");
104 | }
105 | else
106 | Config.setAfCorrectionColumnName(value);
107 |
108 | // Maf Voltage
109 | value = mafVName.getText().trim();
110 | colName = mafVLabelText;
111 | if (value.isEmpty()) {
112 | ret = false;
113 | error.append("\"").append(colName).append("\" column must be specified\n");
114 | }
115 | else
116 | Config.setMafVoltageColumnName(value);
117 |
118 | // CL/OL Status
119 | value = clolStatusName.getText().trim();
120 | colName = clolStatusLabelText;
121 | if (value.isEmpty()) {
122 | ret = false;
123 | error.append("\"").append(colName).append("\" column must be specified\n");
124 | }
125 | else
126 | Config.setClOlStatusColumnName(value);
127 |
128 | // Stock AFR
129 | value = stockAfrName.getText().trim();
130 | colName = stockAfrLabelText;
131 | if (value.isEmpty()) {
132 | ret = false;
133 | error.append("\"").append(colName).append("\" column must be specified\n");
134 | }
135 | else
136 | Config.setAfrColumnName(value);
137 |
138 | // Time
139 | value = timeName.getText().trim();
140 | colName = timeLabelText;
141 | if (value.isEmpty()) {
142 | ret = false;
143 | error.append("\"").append(colName).append("\" column must be specified\n");
144 | }
145 | else
146 | Config.setTimeColumnName(value);
147 |
148 | // Intake Air Temperature
149 | value = iatName.getText().trim();
150 | colName = iatLabelText;
151 | if (value.isEmpty()) {
152 | ret = false;
153 | error.append("\"").append(colName).append("\" column must be specified\n");
154 | }
155 | else
156 | Config.setIatColumnName(value);
157 |
158 | // CL/OL Status
159 | value = clolStatusFilter.getValue().toString();
160 | colName = clolStatusLabelText;
161 | if (value.isEmpty() || value.equals("-1")) {
162 | ret = false;
163 | error.append("\"").append(colName).append("\" value must be specified\n");
164 | }
165 | else
166 | Config.setClOlStatusValue(Integer.valueOf(value));
167 |
168 | if (isPolfTableMap) {
169 | // Manifold Absolute Pressure
170 | value = mapName.getText().trim();
171 | colName = mapLabelText;
172 | if (value.isEmpty()) {
173 | ret = false;
174 | error.append("\"").append(colName).append("\" column must be specified\n");
175 | }
176 | else
177 | Config.setMapColumnName(value);
178 | }
179 |
180 | // Max MAF Voltage filter
181 | Config.setMafVMaximumValue(Double.valueOf(maxMafVFilter.getText()));
182 |
183 | // Engine Load filter
184 | Config.setLoadMinimumValue(Double.valueOf(minEngineLoadFilter.getText()));
185 |
186 | // Minimum Cell Hit Count Filter
187 | Config.setCLMinCellHitCount(Integer.valueOf(minCellHitCountFilter.getText()));
188 |
189 | // IAT filter
190 | Config.setIatMaximumValue(Double.valueOf(maxIatFilter.getText()));
191 |
192 | // AFR filters
193 | Config.setAfrMaximumValue(Double.valueOf(maxAfrFilter.getText()));
194 | Config.setAfrMinimumValue(Double.valueOf(minAfrFilter.getText()));
195 |
196 | // dV/dt filter
197 | Config.setDvDtMaximumValue(Double.valueOf(maxDvdtFilter.getText()));
198 |
199 | return ret;
200 | }
201 |
202 | protected boolean processDefaultButton(ActionEvent e) {
203 | if ("maxmafv".equals(e.getActionCommand()))
204 | maxMafVFilter.setText(Config.DefaultMafVMaximum);
205 | else if ("clolstatus".equals(e.getActionCommand()))
206 | clolStatusFilter.setValue(Integer.valueOf(Config.DefaultClOlStatusValue));
207 | else if ("minengload".equals(e.getActionCommand()))
208 | minEngineLoadFilter.setText(Config.DefaultLoadMinimum);
209 | else if ("maxiat".equals(e.getActionCommand()))
210 | maxIatFilter.setText(Config.DefaultIATMaximum);
211 | else if ("maxafr".equals(e.getActionCommand()))
212 | maxAfrFilter.setText(Config.DefaultAfrMaximum);
213 | else if ("minafr".equals(e.getActionCommand()))
214 | minAfrFilter.setText(Config.DefaultAfrMinimum);
215 | else if ("maxdvdt".equals(e.getActionCommand()))
216 | maxDvdtFilter.setText(Config.DefaultDvDtMaximum);
217 | else if ("minhitcnt".equals(e.getActionCommand()))
218 | minCellHitCountFilter.setText(Config.DefaultCLMinCellHitCount);
219 | else
220 | return false;
221 | return true;
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/DBTFindFrame.java:
--------------------------------------------------------------------------------
1 | package com.vgi.mafscaling;
2 |
3 | import java.awt.GridBagConstraints;
4 | import java.awt.GridBagLayout;
5 | import java.awt.Insets;
6 | import java.awt.Point;
7 | import java.awt.Window;
8 | import java.awt.event.ActionEvent;
9 | import java.awt.event.ActionListener;
10 | import java.awt.event.ItemEvent;
11 | import java.awt.event.ItemListener;
12 | import java.util.Vector;
13 | import javax.swing.JButton;
14 | import javax.swing.JCheckBox;
15 | import javax.swing.JComboBox;
16 | import javax.swing.JDialog;
17 | import javax.swing.JFrame;
18 | import javax.swing.JLabel;
19 | import javax.swing.JOptionPane;
20 | import javax.swing.JPanel;
21 |
22 | import org.apache.log4j.Logger;
23 |
24 | import quick.dbtable.DBTable;
25 |
26 | class DBTFindFrame extends JDialog implements ActionListener {
27 | private static final long serialVersionUID = 1513208156777653811L;
28 | private static final Logger logger = Logger.getLogger(DBTFindFrame.class);
29 |
30 | class ChangeListener implements ItemListener{
31 | public void itemStateChanged(ItemEvent e)
32 | {
33 | @SuppressWarnings("unchecked")
34 | JComboBox cb = (JComboBox) e.getSource();
35 | String text = (String)cb.getSelectedItem();
36 | if (text == null || "".equals(text))
37 | return;
38 | boolean exists= false;
39 | for (int i = 0; i < cb.getItemCount(); ++i)
40 | {
41 | if (text.equals(cb.getItemAt(i)))
42 | {
43 | exists=true;
44 | break;
45 | }
46 | }
47 | if (!exists)
48 | cb.addItem(text);
49 | }
50 | }
51 |
52 | private Window parent = null;
53 | private JPanel mainPanel = null;
54 | private JComboBox findCombo = null;
55 | private JComboBox replaceCombo = null;
56 | private JCheckBox searchRow = null;
57 | private JCheckBox searchColumn = null;
58 | private JButton nextButton = null;
59 | private JButton previousButton = null;
60 | private JButton replaceAllButton = null;
61 | private JButton closeButton = null;
62 | private DBTable dbTable = null;
63 | private Vector columnVector = null;
64 | private boolean find = true;
65 | private Point lastLoc = new Point(0, 0);
66 | private Insets insetsLabel = new Insets(3, 3, 3, 0);
67 | private Insets insets3 = new Insets(3, 3, 3, 3);
68 |
69 | DBTFindFrame(Window owner, DBTable table, boolean isFind) {
70 | super(owner, (isFind ? "Find Dialog" : "Replace Dialog"));
71 | parent = owner;
72 | dbTable = table;
73 | find = isFind;
74 | initialize();
75 | }
76 |
77 | private void initialize() {
78 | try {
79 | mainPanel = new JPanel();
80 | GridBagLayout gbl_dataPanel = new GridBagLayout();
81 | gbl_dataPanel.columnWidths = new int[] {0, 0, 0, 0};
82 | gbl_dataPanel.rowHeights = new int[] {0, 0, 0, 0, 0};
83 | gbl_dataPanel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0};
84 | gbl_dataPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0};
85 | mainPanel.setLayout(gbl_dataPanel);
86 | getContentPane().add(mainPanel);
87 |
88 | ChangeListener cl = new ChangeListener();
89 | addLabel(0, "Text to find");
90 | findCombo = addComboBox(0);
91 | findCombo.addItemListener(cl);
92 | if (!find) {
93 | addLabel(1, "Replace with");
94 | replaceCombo = addComboBox(1);
95 | replaceCombo.addItemListener(cl);
96 | }
97 | searchRow = addCheckBox(2, "From current row");
98 | searchColumn = addCheckBox(3, "From current column");
99 | if (!find) {
100 | replaceAllButton = addButton(0, "Replace All");
101 | nextButton = addButton(1, "Replace Next");
102 | previousButton = addButton(2, "Replace Previous");
103 | }
104 | else {
105 | nextButton = addButton(1, "Find Next");
106 | previousButton = addButton(2, "Find Previous");
107 | }
108 | closeButton = addButton(3, "Close");
109 | getRootPane().setDefaultButton(nextButton);
110 | pack();
111 | setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
112 | setIconImage(null);
113 | setResizable(false);
114 | setLocationRelativeTo(parent);
115 | setVisible(true);
116 | }
117 | catch (Exception e) {
118 | e.printStackTrace();
119 | }
120 | }
121 |
122 | private boolean validateInput() {
123 | String findText = (String)findCombo.getSelectedItem();
124 | if (findText == null || "".equals(findText))
125 | return false;
126 | if (!find) {
127 | String replaceText = (String)replaceCombo.getSelectedItem();
128 | if (replaceText == null || "".equals(replaceText))
129 | return false;
130 | }
131 | return true;
132 | }
133 |
134 | private void addLabel(int row, String text) {
135 | JLabel label = new JLabel(text);
136 | GridBagConstraints gbc_label = new GridBagConstraints();
137 | gbc_label.anchor = GridBagConstraints.EAST;
138 | gbc_label.insets = insetsLabel;
139 | gbc_label.gridx = 0;
140 | gbc_label.gridy = row;
141 | mainPanel.add(label, gbc_label);
142 | }
143 |
144 | private JComboBox addComboBox(int row) {
145 | JComboBox comboBox = new JComboBox();
146 | comboBox.setEditable(true);
147 | GridBagConstraints gbc_comboBox = new GridBagConstraints();
148 | gbc_comboBox.anchor = GridBagConstraints.WEST;
149 | gbc_comboBox.fill = GridBagConstraints.HORIZONTAL;
150 | gbc_comboBox.insets = insets3;
151 | gbc_comboBox.gridx = 1;
152 | gbc_comboBox.gridy = row;
153 | gbc_comboBox.gridwidth = 3;
154 | mainPanel.add(comboBox, gbc_comboBox);
155 | return comboBox;
156 | }
157 |
158 | private JCheckBox addCheckBox(int row, String text) {
159 | JCheckBox flag = new JCheckBox(text);
160 | GridBagConstraints gbc_check = new GridBagConstraints();
161 | gbc_check.anchor = GridBagConstraints.WEST;
162 | gbc_check.insets = insets3;
163 | gbc_check.gridx = 1;
164 | gbc_check.gridy = row;
165 | gbc_check.gridwidth = 3;
166 | mainPanel.add(flag, gbc_check);
167 | return flag;
168 | }
169 |
170 | private JButton addButton(int col, String name) {
171 | JButton button = new JButton(name);
172 | GridBagConstraints gbc_button = new GridBagConstraints();
173 | gbc_button.anchor = GridBagConstraints.CENTER;
174 | gbc_button.insets = insets3;
175 | gbc_button.gridx = col;
176 | gbc_button.gridy = 4;
177 | button.addActionListener(this);
178 | mainPanel.add(button, gbc_button);
179 | return button;
180 | }
181 |
182 | private void doWork(boolean direction, boolean replaceAll) {
183 | if (!validateInput())
184 | return;
185 | try {
186 | int row = -1;
187 | columnVector = new Vector();
188 | String findText = (String)findCombo.getSelectedItem();
189 | lastLoc.x = dbTable.getSelectedRow();
190 | lastLoc.y = dbTable.getSelectedColumn();
191 | if (searchRow.isSelected())
192 | row = lastLoc.x;
193 | if (searchColumn.isSelected())
194 | columnVector.add(lastLoc.y + 1);
195 | else {
196 | for (int i = 1; i <= dbTable.getColumnCount(); ++i)
197 | columnVector.addElement(i);
198 | }
199 | if (columnVector.size() == 1)
200 | lastLoc.y = 0;
201 | if (find) {
202 | if (!direction) {
203 | if (lastLoc.x == 0 && lastLoc.y == 0 && columnVector.size() > 1) {
204 | JOptionPane.showMessageDialog(null, "Finished Searching", "Message", JOptionPane.INFORMATION_MESSAGE);
205 | return;
206 | }
207 | if (lastLoc.y == 0)
208 | {
209 | lastLoc.x = lastLoc.x - 1;
210 | if (columnVector.size() > 1)
211 | lastLoc.y = columnVector.size() - 1;
212 | }
213 | else
214 | lastLoc.y = lastLoc.y - 1;
215 | }
216 | if (row == -1)
217 | lastLoc = dbTable.find(lastLoc.x, lastLoc.y, findText, columnVector, direction);
218 | else {
219 | int[] rows = { row };
220 | if (direction && lastLoc.y < columnVector.size() - 1)
221 | lastLoc = dbTable.find(lastLoc.x, lastLoc.y + 1, findText, columnVector, direction, rows);
222 | else if (!direction && lastLoc.y > 1)
223 | lastLoc = dbTable.find(lastLoc.x, lastLoc.y - 1, findText, columnVector, direction, rows);
224 | else {
225 | JOptionPane.showMessageDialog(null, "Finished Searching", "Message", JOptionPane.INFORMATION_MESSAGE);
226 | return;
227 | }
228 | }
229 | }
230 | else {
231 | String replaceText = (String)replaceCombo.getSelectedItem();
232 | if (!replaceAll) {
233 | if (!direction) {
234 | if (lastLoc.x == 0 && lastLoc.y == 0 && columnVector.size() > 1)
235 | return;
236 | if (lastLoc.y == 0)
237 | {
238 | lastLoc.x = lastLoc.x - 1;
239 | if (columnVector.size() > 1)
240 | lastLoc.y = columnVector.size() - 1;
241 | }
242 | else
243 | lastLoc.y = lastLoc.y - 1;
244 | }
245 | if (row == -1)
246 | lastLoc = dbTable.replace(lastLoc.x, lastLoc.y, findText, replaceText, columnVector, direction);
247 | else {
248 | int[] rows = { row };
249 | if (direction && lastLoc.y < columnVector.size() - 1)
250 | lastLoc = dbTable.replace(lastLoc.x, lastLoc.y + 1, findText, replaceText, columnVector, direction, rows);
251 | else if (!direction && lastLoc.y > 1)
252 | lastLoc = dbTable.replace(lastLoc.x, lastLoc.y - 1, findText, replaceText, columnVector, direction, rows);
253 | else {
254 | JOptionPane.showMessageDialog(null, "Finished Searching", "Message", JOptionPane.INFORMATION_MESSAGE);
255 | return;
256 | }
257 | }
258 | }
259 | else {
260 | if (row == -1)
261 | lastLoc = dbTable.replaceAll(0, lastLoc.y, findText, replaceText, columnVector);
262 | else {
263 | int[] rows = { row };
264 | lastLoc = dbTable.replaceAll(lastLoc.x, 1, findText, replaceText, columnVector, rows);
265 | }
266 | }
267 | }
268 | if (columnVector.size() == 1)
269 | lastLoc.y = columnVector.get(0) - 1;
270 | if (dbTable.getTable().getCellEditor() != null)
271 | dbTable.getTable().getCellEditor().stopCellEditing();
272 |
273 | dbTable.getTable().setRowSelectionInterval(lastLoc.x, lastLoc.x);
274 | dbTable.getTable().setColumnSelectionInterval(lastLoc.y, lastLoc.y);
275 | dbTable.getTable().changeSelection(lastLoc.x, lastLoc.y, false, false);
276 | }
277 | catch (Exception e) {
278 | e.printStackTrace();
279 | logger.error(e);
280 | }
281 | dbTable.repaint();
282 | }
283 |
284 | @Override
285 | public void actionPerformed(ActionEvent e) {
286 | if (e.getSource() == nextButton)
287 | doWork(true, false);
288 | else if (e.getSource() == previousButton)
289 | doWork(false, false);
290 | else if (e.getSource() == replaceAllButton)
291 | doWork(false, true);
292 | else if (e.getSource() == closeButton)
293 | setVisible(false);
294 | }
295 | }
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/FCTabbedPane.java:
--------------------------------------------------------------------------------
1 | package com.vgi.mafscaling;
2 |
3 | import java.awt.datatransfer.DataFlavor;
4 | import java.io.File;
5 | import java.util.List;
6 |
7 | import javax.swing.JFileChooser;
8 | import javax.swing.JOptionPane;
9 | import javax.swing.JTabbedPane;
10 | import javax.swing.TransferHandler;
11 | import javax.swing.filechooser.FileNameExtensionFilter;
12 |
13 | public abstract class FCTabbedPane extends JTabbedPane {
14 | private static final long serialVersionUID = -1927797105079280969L;
15 | protected static final JFileChooser fileChooser = new JFileChooser();
16 |
17 | public FCTabbedPane(int tabPlacement) {
18 | super(tabPlacement);
19 | File logsPath = new File(Config.getLastLogFilesPath());
20 | if (logsPath.exists() && logsPath.isDirectory())
21 | fileChooser.setCurrentDirectory(logsPath);
22 | else
23 | fileChooser.setCurrentDirectory(new File("."));
24 |
25 | fileChooser.setAcceptAllFileFilterUsed(false);
26 |
27 | if (fileChooser.getFileFilter() == null)
28 | fileChooser.setFileFilter(new FileNameExtensionFilter("CSV file", "csv"));
29 |
30 | setTransferHandler(new TransferHandler() {
31 | private static final long serialVersionUID = 1L;
32 |
33 | @Override
34 | public boolean canImport(TransferHandler.TransferSupport support) {
35 | boolean can = support.isDrop() && (support.getSourceDropActions() & COPY) != 0 && support.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
36 | if (can)
37 | support.setDropAction(COPY);
38 | return can;
39 | }
40 |
41 | @SuppressWarnings("unchecked")
42 | @Override
43 | public boolean importData(TransferHandler.TransferSupport info) {
44 | try {
45 | List files = (List)info.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
46 | for (int i = 0; i < files.size(); ++i) {
47 | try {
48 | String fn = files.get(i).getCanonicalPath();
49 | if (!(fn.substring(fn.lastIndexOf(".") + 1).equalsIgnoreCase("csv"))) {
50 | JOptionPane.showMessageDialog(null, "Invalid file type - only CSV file are supported: " + fn, "Invalid file", JOptionPane.ERROR_MESSAGE);
51 | return false;
52 | }
53 | }
54 | catch( java.io.IOException e ) {}
55 | }
56 | onDroppedFiles(files);
57 | return true;
58 | }
59 | catch (Exception e) {
60 | JOptionPane.showMessageDialog(null, "Error on drag'n'drop: " + e.getMessage(), "Invalid file", JOptionPane.ERROR_MESSAGE);
61 | }
62 | return false;
63 | }
64 |
65 | });
66 | }
67 |
68 | public static String getLogFilesPath() {
69 | return fileChooser.getCurrentDirectory().getAbsolutePath();
70 | }
71 |
72 | protected abstract void onDroppedFiles(List files);
73 | }
74 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/IMafChartHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | /**
22 | * Interface that defines required function for MafChartPanel holders
23 | */
24 | public interface IMafChartHolder {
25 | public void onMovePoint(int itemIndex, double valueX, double valueY);
26 | }
27 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/JMultiSelectionBox.java:
--------------------------------------------------------------------------------
1 | package com.vgi.mafscaling;
2 |
3 | import java.awt.Color;
4 | import java.awt.Dimension;
5 | import java.awt.Insets;
6 | import java.awt.Point;
7 | import java.awt.event.ActionEvent;
8 | import java.awt.event.ActionListener;
9 | import java.awt.event.MouseEvent;
10 | import java.awt.event.MouseListener;
11 | import java.awt.event.WindowEvent;
12 | import java.awt.event.WindowFocusListener;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import javax.swing.AbstractAction;
16 | import javax.swing.BoxLayout;
17 | import javax.swing.Icon;
18 | import javax.swing.ImageIcon;
19 | import javax.swing.JButton;
20 | import javax.swing.JCheckBoxMenuItem;
21 | import javax.swing.JComboBox;
22 | import javax.swing.JDialog;
23 | import javax.swing.JFrame;
24 | import javax.swing.JPanel;
25 | import javax.swing.JScrollPane;
26 | import javax.swing.SwingConstants;
27 | import javax.swing.UIDefaults;
28 | import javax.swing.UIManager;
29 | import javax.swing.border.LineBorder;
30 |
31 | public class JMultiSelectionBox extends JButton {
32 | private static final long serialVersionUID = -6780160237517176970L;
33 | private static int widthCorrection = 2;
34 | private static int heighCorrection = 2;
35 | JComboBox combo = new JComboBox();
36 | JPanel menu = new JPanel();
37 | JDialog menuFrame = null;
38 | JScrollPane scroll = null;
39 | WindowFocusListener windowFocusListener = null;
40 | MouseListener mouseListener = null;
41 | ActionListener menuActionListener = null;
42 | JButton button;
43 | boolean mouseOver = false;
44 |
45 | public JMultiSelectionBox() {
46 | this(null, null);
47 | }
48 |
49 | public JMultiSelectionBox(Icon icon) {
50 | this(null, icon);
51 | }
52 |
53 | public JMultiSelectionBox(String text) {
54 | this(text, null);
55 | }
56 |
57 | public JMultiSelectionBox(String text, Icon icon) {
58 | super(text, icon);
59 | if (UIManager.getLookAndFeel().getClass().getName().contains("Motif"))
60 | heighCorrection += 4;
61 | windowFocusListener = new WindowFocusListener() {
62 | @Override
63 | public void windowGainedFocus(WindowEvent arg0) { }
64 | @Override
65 | public void windowLostFocus(WindowEvent arg0) {
66 | button.setText(getSelectedItemsString());
67 | if (!mouseOver) {
68 | menuFrame.dispose();
69 | menuFrame = null;
70 | }
71 | }
72 | };
73 | mouseListener = new MouseListener() {
74 | @Override
75 | public void mouseClicked(MouseEvent e) { }
76 | @Override
77 | public void mousePressed(MouseEvent e) { }
78 | @Override
79 | public void mouseReleased(MouseEvent e) { }
80 | @Override
81 | public void mouseEntered(MouseEvent e) { mouseOver = true; }
82 | @Override
83 | public void mouseExited(MouseEvent e) { mouseOver = false; }
84 | };
85 | button = this;
86 | button.addMouseListener(mouseListener);
87 | menu.setBackground(Color.WHITE);
88 | menu.setLayout(new BoxLayout(menu, BoxLayout.Y_AXIS));
89 |
90 | setAction(new AbstractAction(text) {
91 | private static final long serialVersionUID = -3085698135352698778L;
92 | @Override
93 | public void actionPerformed(ActionEvent e) {
94 | if (menuFrame != null) {
95 | menuFrame.dispose();
96 | menuFrame = null;
97 | return;
98 | }
99 | if (menu.getComponentCount() == 0)
100 | return;
101 | menuFrame = new JDialog();
102 | menuFrame.addWindowFocusListener(windowFocusListener);
103 | scroll = new JScrollPane(menu);
104 | scroll.setBorder(new LineBorder(Color.BLACK, 1));
105 | scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
106 | scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
107 | menuFrame.getContentPane().add(scroll);
108 | menuFrame.setUndecorated(true);
109 | menuFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
110 | menuFrame.setResizable(false);
111 | Point location = button.getLocationOnScreen();
112 | location.y += button.getHeight();
113 | menuFrame.setLocation(location);
114 | menuFrame.setPreferredSize(new Dimension(button.getWidth(), 150));
115 | menuFrame.pack();
116 | menuFrame.setVisible(true);
117 | menuFrame.setResizable(false);
118 | menuFrame.requestFocus();
119 | }
120 | });
121 | menuActionListener = new ActionListener() {
122 | public void actionPerformed(ActionEvent event) {
123 | button.setText(getSelectedItemsString());
124 | }
125 | };
126 | setMargin(new Insets(0, 2, 0, 2));
127 | UIDefaults def = new UIDefaults();
128 | def.put("Button.contentMargins", new Insets(0, 3, 0, 3));
129 | putClientProperty("Nimbus.Overrides", def);
130 |
131 | setIcon(new ImageIcon(getClass().getResource("/down.gif")));
132 | setIconTextGap(3);
133 |
134 | setVerticalTextPosition(SwingConstants.CENTER);
135 | setHorizontalAlignment(SwingConstants.RIGHT);
136 | setHorizontalTextPosition(SwingConstants.LEFT);
137 | }
138 |
139 | public void addItem(String item) {
140 | JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(item);
141 | menuItem.addActionListener(menuActionListener);
142 | menuItem.setOpaque(false);
143 | menu.add(menuItem);
144 | }
145 |
146 | public void removeItem(String item) {
147 | for (int i = 0; i < menu.getComponentCount(); ++i) {
148 | JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) menu.getComponent(i);
149 | if (menuItem.getText().equals(item)) {
150 | menu.remove(i);
151 | break;
152 | }
153 | }
154 | }
155 |
156 | public void removeAllItems() {
157 | menu.removeAll();
158 | }
159 |
160 | public List getSelectedItems() {
161 | ArrayList list = new ArrayList();
162 | for (int i = 0; i < menu.getComponentCount(); ++i) {
163 | JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) menu.getComponent(i);
164 | if (menuItem.isSelected())
165 | list.add(menuItem.getText());
166 | }
167 | if (list.size() > 0)
168 | return list;
169 | return null;
170 | }
171 |
172 | public void setSelectedItems(List items) {
173 | if (items == null)
174 | return;
175 | for (int i = 0; i < menu.getComponentCount(); ++i) {
176 | JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) menu.getComponent(i);
177 | for (String item : items) {
178 | if (menuItem.getText().equals(item))
179 | menuItem.setSelected(true);
180 | }
181 | }
182 | button.setText(getSelectedItemsString());
183 | }
184 |
185 | public String getSelectedItemsString() {
186 | String s = " ";
187 | for (int i = 0; i < menu.getComponentCount(); ++i) {
188 | JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) menu.getComponent(i);
189 | if (menuItem.isSelected()) {
190 | if (s.trim().isEmpty())
191 | s += menuItem.getText();
192 | else
193 | s += (" + " + menuItem.getText());
194 | }
195 | }
196 | return s;
197 | }
198 |
199 | public void setPrototypeDisplayValue(String val) {
200 | combo.setPrototypeDisplayValue(val);
201 | }
202 |
203 | @Override
204 | public Dimension getPreferredSize() {
205 | Dimension d = combo.getPreferredSize();
206 | d.width += widthCorrection;
207 | d.height += heighCorrection;
208 | return d;
209 | }
210 |
211 | @Override
212 | public Dimension getMinimumSize() {
213 | Dimension d = combo.getMinimumSize();
214 | d.width += widthCorrection;
215 | d.height += heighCorrection;
216 | return d;
217 | }
218 |
219 | @Override
220 | public Dimension getMaximumSize() {
221 | Dimension d = combo.getMaximumSize();
222 | d.width += widthCorrection;
223 | d.height += heighCorrection;
224 | return d;
225 | }
226 | }
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/LCColumnsFiltersSelection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.Component;
22 | import java.awt.event.ActionEvent;
23 | import javax.swing.JEditorPane;
24 |
25 | public class LCColumnsFiltersSelection extends ColumnsFiltersSelection {
26 |
27 | protected void addColSelection() {
28 | addRPMColSelection();
29 | addThrottleAngleColSelection();
30 | addAFLearningColSelection();
31 | addAFCorrectionColSelection();
32 | addMAFVoltageColSelection();
33 | addStockAFRColSelection();
34 | addManifoldPressureColSelection();
35 | addTimeColSelection();
36 | addIATColSelection();
37 | addCruiseStatusColSelection();
38 | }
39 |
40 | protected void addFilterSelection() {
41 | addLoadCompInRatioFlag();
42 | isLoadCompInRatioBool.setSelected(Config.getIsLoadCompInRatio());
43 | addAtmPressureFilter();
44 | atmPressureFilter.setText(String.valueOf(Config.getAtmPressureValue()));
45 | addThrottleChangeMaximumFilter();
46 | thrtlChangeMaxFilter.setValue(Config.getThrottleChangeMaxValue());
47 | addRPMMaximumFilter();
48 | maxRPMFilter.setText(String.valueOf(Config.getRPMMaximumValue()));
49 | addRPMMinimumFilter();
50 | minRPMFilter.setText(String.valueOf(Config.getRPMMinimumValue()));
51 | addIATMaximumFilter();
52 | maxIatFilter.setText(String.valueOf(Config.getLCIatMaximumValue()));
53 | addAFRMaximumFilter();
54 | maxAfrFilter.setText(String.valueOf(Config.getLCAfrMaximumValue()));
55 | addAFRMinimumFilter();
56 | minAfrFilter.setText(String.valueOf(Config.getLCAfrMinimumValue()));
57 | addManifoldPressureMaximumFilter();
58 | maxMPFilter.setText(String.valueOf(Config.getLCMPMaximumValue()));
59 | addManifoldPressureMinimumFilter();
60 | minMPFilter.setText(String.valueOf(Config.getLCMPMinimumValue()));
61 | addDvDtMaximumFilter();
62 | maxDvdtFilter.setText(String.valueOf(Config.getLCDvDtMaximumValue()));
63 | addCellHitCountMinimumFilter();
64 | minCellHitCountFilter.setText(String.valueOf(Config.getLCMinCellHitCount()));
65 | addCruiseStatusFilter();
66 | cruiseStatusFilter.setValue(Config.getCruiseStatusValue());
67 | addCorrectionAppliedValue();
68 | correctionAppliedValue.setValue(Config.getLCCorrectionAppliedValue());
69 |
70 | for (Component c : filtersPanel.getComponents()) {
71 | if (c instanceof JEditorPane) {
72 | JEditorPane label = (JEditorPane)c;
73 | if (label.getText().startsWith("Remove data where RPM is above"))
74 | label.setText(label.getText() + " (hint: check max RPM in Load Comp table)");
75 | }
76 | }
77 | }
78 |
79 | protected boolean validate(StringBuffer error) {
80 | boolean ret = true;
81 | String value;
82 | String colName;
83 |
84 | // Engine Speed
85 | value = rpmName.getText().trim();
86 | colName = rpmLabelText;
87 | if (value.isEmpty()) {
88 | ret = false;
89 | error.append("\"").append(colName).append("\" column must be specified\n");
90 | }
91 | else
92 | Config.setRpmColumnName(value);
93 |
94 | // AFR Learning
95 | value = afLearningName.getText().trim();
96 | colName = afLearningLabelText;
97 | if (value.isEmpty()) {
98 | ret = false;
99 | error.append("\"").append(colName).append("\" column must be specified\n");
100 | }
101 | else
102 | Config.setAfLearningColumnName(value);
103 |
104 | // AFR Correction
105 | value = afCorrectionName.getText().trim();
106 | colName = afCorrectionLabelText;
107 | if (value.isEmpty()) {
108 | ret = false;
109 | error.append("\"").append(colName).append("\" column must be specified\n");
110 | }
111 | else
112 | Config.setAfCorrectionColumnName(value);
113 |
114 | // Maf Voltage
115 | value = mafVName.getText().trim();
116 | colName = mafVLabelText;
117 | if (value.isEmpty()) {
118 | ret = false;
119 | error.append("\"").append(colName).append("\" column must be specified\n");
120 | }
121 | else
122 | Config.setMafVoltageColumnName(value);
123 |
124 | // MP
125 | value = mpName.getText().trim();
126 | colName = mpLabelText;
127 | if (value.isEmpty()) {
128 | ret = false;
129 | error.append("\"").append(colName).append("\" column must be specified\n");
130 | }
131 | else
132 | Config.setMpColumnName(value);
133 |
134 | // Throttle Angle
135 | value = thrtlAngleName.getText().trim();
136 | colName = thrtlAngleLabelText;
137 | if (value.isEmpty()) {
138 | ret = false;
139 | error.append("\"").append(colName).append("\" column must be specified\n");
140 | }
141 | else
142 | Config.setThrottleAngleColumnName(value);
143 |
144 | // Cruise/Non-cruise Status
145 | Config.setCruiseStatusColumnName(cruiseStatusName.getText().trim());
146 |
147 | // Stock AFR
148 | value = stockAfrName.getText().trim();
149 | colName = stockAfrLabelText;
150 | if (value.isEmpty()) {
151 | ret = false;
152 | error.append("\"").append(colName).append("\" column must be specified\n");
153 | }
154 | else
155 | Config.setAfrColumnName(value);
156 |
157 | // Time
158 | value = timeName.getText().trim();
159 | colName = timeLabelText;
160 | if (value.isEmpty()) {
161 | ret = false;
162 | error.append("\"").append(colName).append("\" column must be specified\n");
163 | }
164 | else
165 | Config.setTimeColumnName(value);
166 |
167 | // Intake Air Temperature
168 | value = iatName.getText().trim();
169 | colName = iatLabelText;
170 | if (value.isEmpty()) {
171 | ret = false;
172 | error.append("\"").append(colName).append("\" column must be specified\n");
173 | }
174 | else
175 | Config.setIatColumnName(value);
176 |
177 | // Load Compensation values in ratio
178 | Config.setIsLoadCompInRatio(isLoadCompInRatioBool.isSelected());
179 |
180 | // Atm Pressure filters
181 | Config.setAtmPressureValue(Double.valueOf(atmPressureFilter.getText()));
182 |
183 | // Throttle Change % Maximum
184 | Config.setThrottleChangeMaxValue(Integer.valueOf(thrtlChangeMaxFilter.getValue().toString()));
185 |
186 | // RPM filters
187 | Config.setRPMMaximumValue(Integer.valueOf(maxRPMFilter.getText()));
188 | Config.setRPMMinimumValue(Integer.valueOf(minRPMFilter.getText()));
189 |
190 | // Minimum Cell Hit Count Filter
191 | Config.setLCMinCellHitCount(Integer.valueOf(minCellHitCountFilter.getText()));
192 |
193 | // IAT filter
194 | Config.setLCIatMaximumValue(Double.valueOf(maxIatFilter.getText()));
195 |
196 | // AFR filters
197 | Config.setLCAfrMaximumValue(Double.valueOf(maxAfrFilter.getText()));
198 | Config.setLCAfrMinimumValue(Double.valueOf(minAfrFilter.getText()));
199 |
200 | // MP filters
201 | Config.setLCMPMaximumValue(Double.valueOf(maxMPFilter.getText()));
202 | Config.setLCMPMinimumValue(Double.valueOf(minMPFilter.getText()));
203 |
204 | // dV/dt filter
205 | Config.setLCDvDtMaximumValue(Double.valueOf(maxDvdtFilter.getText()));
206 |
207 | // Cruise/Non-cruise Status
208 | value = cruiseStatusFilter.getValue().toString();
209 | if (!value.isEmpty())
210 | Config.setCruiseStatusValue(Integer.valueOf(value));
211 |
212 | // Correction applied
213 | Config.setLCCorrectionAppliedValue(Integer.valueOf(correctionAppliedValue.getValue().toString()));
214 |
215 | return ret;
216 | }
217 |
218 | protected boolean processDefaultButton(ActionEvent e) {
219 | if ("thrtlchange".equals(e.getActionCommand()))
220 | thrtlChangeMaxFilter.setValue(Integer.valueOf(Config.DefaultThrottleChangeMax));
221 | else if ("maxrpm".equals(e.getActionCommand()))
222 | maxRPMFilter.setText(Config.DefaultRPMMaximum);
223 | else if ("minrpm".equals(e.getActionCommand()))
224 | minRPMFilter.setText(Config.DefaultRPMMinimum);
225 | else if ("maxiat".equals(e.getActionCommand()))
226 | maxIatFilter.setText(Config.DefaultLCIATMaximum);
227 | else if ("maxafr".equals(e.getActionCommand()))
228 | maxAfrFilter.setText(Config.DefaultLCAfrMaximum);
229 | else if ("minafr".equals(e.getActionCommand()))
230 | minAfrFilter.setText(Config.DefaultLCAfrMinimum);
231 | else if ("maxmp".equals(e.getActionCommand()))
232 | maxMPFilter.setText(Config.DefaultMPMaximum);
233 | else if ("minmp".equals(e.getActionCommand()))
234 | minMPFilter.setText(Config.DefaultMPMinimum);
235 | else if ("maxdvdt".equals(e.getActionCommand()))
236 | maxDvdtFilter.setText(Config.DefaultDvDtMaximum);
237 | else if ("minhitcnt".equals(e.getActionCommand()))
238 | minCellHitCountFilter.setText(Config.DefaultLCMinCellHitCount);
239 | else if ("cruisestatus".equals(e.getActionCommand()))
240 | cruiseStatusFilter.setValue(Integer.valueOf(Config.DefaultCruiseStatusValue));
241 | else if ("corrapply".equals(e.getActionCommand()))
242 | correctionAppliedValue.setValue(Integer.valueOf(Config.DefaultCorrectionAppliedValue));
243 | else if ("atmpress".equals(e.getActionCommand()))
244 | atmPressureFilter.setText(Config.DefaultAtmPressure);
245 | else
246 | return false;
247 | return true;
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/MafChartPanel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.Cursor;
22 | import java.awt.Insets;
23 | import java.awt.event.KeyEvent;
24 | import java.awt.event.KeyListener;
25 | import java.awt.event.MouseEvent;
26 | import java.awt.event.MouseListener;
27 | import java.awt.event.MouseMotionListener;
28 | import java.awt.event.MouseWheelEvent;
29 | import java.awt.event.MouseWheelListener;
30 | import java.awt.geom.Point2D;
31 | import java.awt.geom.Rectangle2D;
32 | import java.util.HashSet;
33 |
34 | import org.apache.log4j.Logger;
35 | import org.jfree.chart.ChartPanel;
36 | import org.jfree.chart.JFreeChart;
37 | import org.jfree.chart.axis.ValueAxis;
38 | import org.jfree.chart.entity.ChartEntity;
39 | import org.jfree.chart.entity.XYItemEntity;
40 | import org.jfree.chart.plot.XYPlot;
41 | import org.jfree.data.xy.XYSeries;
42 | import org.jfree.data.xy.XYSeriesCollection;
43 |
44 | public class MafChartPanel implements MouseListener, MouseMotionListener, MouseWheelListener, KeyListener {
45 | private static final Logger logger = Logger.getLogger(MafChartPanel.class);
46 | private ChartPanel chartPanel = null;
47 | private IMafChartHolder chartHolder = null;
48 | private XYItemEntity xyItemEntity = null;
49 | private HashSet pointDraggableSet = null;
50 | private boolean AllowPointMove = true;
51 | private boolean IsMovable = false;
52 | private double initialMovePointY = 0;
53 |
54 | public MafChartPanel(JFreeChart chart, IMafChartHolder holder) {
55 | pointDraggableSet = new HashSet();
56 | chartPanel = new ChartPanel(chart, true, true, true, true, true);
57 | chartHolder = holder;
58 | chartPanel.setFocusable(true);
59 | chartPanel.setAutoscrolls(true);
60 | chartPanel.setMouseZoomable(false);
61 | chartPanel.addMouseMotionListener(this);
62 | chartPanel.addMouseListener(this);
63 | chartPanel.addMouseWheelListener(this);
64 | chartPanel.addKeyListener(this);
65 | }
66 |
67 | public void enablePointsDrag(int seriesIndex) {
68 | pointDraggableSet.add(seriesIndex);
69 | }
70 |
71 | public ChartPanel getChartPanel() {
72 | return chartPanel;
73 | }
74 |
75 | public void movePoint(MouseEvent event) {
76 | try {
77 | if (IsMovable) {
78 | int itemIndex = xyItemEntity.getItem();
79 | int seriesIndex = xyItemEntity.getSeriesIndex();
80 | if (!pointDraggableSet.contains(seriesIndex))
81 | return;
82 | XYSeries series = ((XYSeriesCollection)xyItemEntity.getDataset()).getSeries(seriesIndex);
83 | XYPlot plot = chartPanel.getChart().getXYPlot();
84 | Rectangle2D dataArea = chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
85 | Point2D p = chartPanel.translateScreenToJava2D(event.getPoint());
86 | double finalMovePointY = plot.getRangeAxis().java2DToValue(p.getY(), dataArea, plot.getRangeAxisEdge());
87 | double difference = finalMovePointY - initialMovePointY;
88 | if (series.getY(itemIndex).doubleValue() + difference > plot.getRangeAxis().getRange().getLength() ||
89 | series.getY(itemIndex).doubleValue() + difference < 0.0)
90 | initialMovePointY = finalMovePointY;
91 | series.updateByIndex(itemIndex, series.getY(itemIndex).doubleValue() + difference);
92 | chartHolder.onMovePoint(itemIndex, series.getX(itemIndex).doubleValue(), series.getY(itemIndex).doubleValue());
93 | chartPanel.getChart().fireChartChanged();
94 | chartPanel.updateUI();
95 | initialMovePointY = finalMovePointY;
96 | }
97 | }
98 | catch (Exception e) {
99 | e.printStackTrace();
100 | logger.error(e);
101 | }
102 | }
103 |
104 | private void zoomChartAxis(ChartPanel chart, boolean increase) {
105 | int width = chart.getMaximumDrawWidth() - chart.getMinimumDrawWidth();
106 | int height = chart.getMaximumDrawHeight() - chart.getMinimumDrawWidth();
107 | if (increase)
108 | chart.zoomInBoth(width/2, height/2);
109 | else
110 | chart.zoomOutBoth(width/2, height/2);
111 | }
112 |
113 | public void mouseWheelMoved(MouseWheelEvent e) {
114 | if (e.getScrollType() != MouseWheelEvent.WHEEL_UNIT_SCROLL)
115 | return;
116 | if (e.getWheelRotation() < 0)
117 | zoomChartAxis(chartPanel, true);
118 | else
119 | zoomChartAxis(chartPanel, false);
120 | }
121 |
122 | public void mouseDragged(MouseEvent e) {
123 | if (AllowPointMove)
124 | movePoint(e);
125 | }
126 |
127 | public void mouseExited(MouseEvent e) {
128 | IsMovable = false;
129 | initialMovePointY = 0;
130 | chartPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
131 | }
132 |
133 | public void mousePressed(MouseEvent e) {
134 | chartPanel.requestFocusInWindow();
135 | Insets insets = chartPanel.getInsets();
136 | int x = (int) ((e.getX() - insets.left) / chartPanel.getScaleX());
137 | int y = (int) ((e.getY() - insets.top) / chartPanel.getScaleY());
138 | ChartEntity entity = chartPanel.getChartRenderingInfo().getEntityCollection().getEntity(x, y);
139 | if (entity == null || !(entity instanceof XYItemEntity))
140 | return;
141 | IsMovable = true;
142 | chartPanel.setCursor(new Cursor(Cursor.HAND_CURSOR));
143 | xyItemEntity = (XYItemEntity)entity;
144 | XYPlot plot = chartPanel.getChart().getXYPlot();
145 | Rectangle2D dataArea = chartPanel.getChartRenderingInfo().getPlotInfo().getDataArea();
146 | Point2D p = chartPanel.translateScreenToJava2D(e.getPoint());
147 | initialMovePointY = plot.getRangeAxis().java2DToValue(p.getY(), dataArea, plot.getRangeAxisEdge());
148 | }
149 |
150 | public void mouseReleased(MouseEvent arg0) {
151 | IsMovable = false;
152 | initialMovePointY = 0;
153 | chartPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
154 | }
155 |
156 | public void mouseClicked(MouseEvent arg0) {
157 | }
158 |
159 | public void mouseEntered(MouseEvent arg0) {
160 | }
161 |
162 | public void mouseMoved(MouseEvent arg0) {
163 | }
164 |
165 | @Override
166 | public void keyPressed(KeyEvent e) {
167 | if (!chartPanel.hasFocus())
168 | return;
169 | int keyCode = e.getKeyCode();
170 | if (keyCode < KeyEvent.VK_LEFT || keyCode > KeyEvent.VK_DOWN)
171 | return;
172 | ValueAxis axis = null;
173 | if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT)
174 | axis = ((XYPlot)chartPanel.getChart().getXYPlot()).getDomainAxis();
175 | else
176 | axis = ((XYPlot)chartPanel.getChart().getXYPlot()).getRangeAxis();
177 | if (axis != null) {
178 | double delta = (axis.getUpperBound()- axis.getLowerBound()) / 100.0;
179 | if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_DOWN)
180 | axis.setRange(axis.getLowerBound()- delta, axis.getUpperBound() - delta);
181 | else if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_RIGHT)
182 | axis.setRange(axis.getLowerBound() + delta, axis.getUpperBound() + delta);
183 | }
184 | }
185 |
186 | @Override
187 | public void keyReleased(KeyEvent arg0) {
188 | }
189 |
190 | @Override
191 | public void keyTyped(KeyEvent arg0) {
192 | }
193 |
194 | }
195 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/MafIatColumnsFiltersSelection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.Component;
22 | import java.awt.event.ActionEvent;
23 | import javax.swing.JEditorPane;
24 |
25 | public class MafIatColumnsFiltersSelection extends ColumnsFiltersSelection {
26 | private boolean isPolfTableSet = false;
27 | private boolean isPolfTableMap = false;
28 |
29 | public MafIatColumnsFiltersSelection(boolean isPolfTableSet, boolean isPolfTableMap) {
30 | this.isPolfTableSet = isPolfTableSet;
31 | this.isPolfTableMap = isPolfTableMap;
32 | }
33 |
34 | protected void addColumnsNote() {
35 | if (!isPolfTableSet)
36 | addColumnsNote("If you don't have 'Commanded AFR' / 'Fueling Final Base' please set 'POL Fueling' table first");
37 | }
38 |
39 | protected void addColSelection() {
40 | addTimeColSelection();
41 | addRPMColSelection();
42 | if (isPolfTableMap)
43 | addManifoldAbsolutePressureColSelection();
44 | else if (isPolfTableSet)
45 | addLoadColSelection();
46 | addThrottleAngleColSelection();
47 | addAFLearningColSelection();
48 | addAFCorrectionColSelection();
49 | addMAFVoltageColSelection();
50 | addStockAFRColSelection();
51 | addWidebandAFRColSelection();
52 | addIATColSelection();
53 | addMAFColSelection();
54 | addClOlStatusColSelection();
55 | addCommandedAFRColSelection(isPolfTableSet);
56 | }
57 |
58 | protected void addFilterSelection() {
59 | addMafIatInRatioFlag();
60 | isMafIatInRatioBool.setSelected(Config.getIsMafIatInRatio());
61 | addCLOLStatusFilter();
62 | clolStatusFilter.setValue(Config.getMIClOlStatusValue());
63 | addThrottleChangeMaximumFilter();
64 | thrtlChangeMaxFilter.setValue(Config.getMIThrottleChangeMaxValue());
65 | addAFRMaximumFilter();
66 | maxAfrFilter.setText(String.valueOf(Config.getMIAfrMaximumValue()));
67 | addAFRMinimumFilter();
68 | minAfrFilter.setText(String.valueOf(Config.getMIAfrMinimumValue()));
69 | addDvDtMaximumFilter();
70 | maxDvdtFilter.setText(String.valueOf(Config.getMIDvDtMaximumValue()));
71 | addWOTEnrichmentMinimumFilter();
72 | wotEnrichmentField.setText(String.valueOf(Config.getWOTEnrichmentValue()));
73 | addWideBandAFRRowOffsetFilter();
74 | wbo2RowOffsetField.setText(String.valueOf(Config.getWBO2RowOffset()));
75 | addCellHitCountMinimumFilter();
76 | minCellHitCountFilter.setText(String.valueOf(Config.getMIMinCellHitCount()));
77 | addCorrectionAppliedValue();
78 | correctionAppliedValue.setValue(Config.getMICorrectionAppliedValue());
79 |
80 | for (Component c : filtersPanel.getComponents()) {
81 | if (c instanceof JEditorPane) {
82 | JEditorPane label = (JEditorPane)c;
83 | if (label.getText().startsWith("Filter out data using logged OL/CL status"))
84 | label.setText("Set Closed Loop status (EcuTek CL: 2, OP2/RR CL: 8, Cobb CL: 0 (on))");
85 | }
86 | }
87 | }
88 |
89 | protected boolean validate(StringBuffer error) {
90 | boolean ret = true;
91 | String value;
92 | String colName;
93 |
94 | // Engine Speed
95 | value = rpmName.getText().trim();
96 | colName = rpmLabelText;
97 | if (value.isEmpty()) {
98 | ret = false;
99 | error.append("\"").append(colName).append("\" column must be specified\n");
100 | }
101 | else
102 | Config.setRpmColumnName(value);
103 |
104 | if (isPolfTableMap) {
105 | // Manifold Absolute Pressure
106 | value = mapName.getText().trim();
107 | colName = mapLabelText;
108 | if (value.isEmpty()) {
109 | ret = false;
110 | error.append("\"").append(colName).append("\" column must be specified\n");
111 | }
112 | else
113 | Config.setMapColumnName(value);
114 | }
115 | else if (isPolfTableSet) {
116 | // Engine Load
117 | value = loadName.getText().trim();
118 | colName = loadLabelText;
119 | if (value.isEmpty()) {
120 | ret = false;
121 | error.append("\"").append(colName).append("\" column must be specified\n");
122 | }
123 | else
124 | Config.setLoadColumnName(value);
125 | }
126 |
127 | // AFR Learning
128 | value = afLearningName.getText().trim();
129 | colName = afLearningLabelText;
130 | if (value.isEmpty()) {
131 | ret = false;
132 | error.append("\"").append(colName).append("\" column must be specified\n");
133 | }
134 | else
135 | Config.setAfLearningColumnName(value);
136 |
137 | // AFR Correction
138 | value = afCorrectionName.getText().trim();
139 | colName = afCorrectionLabelText;
140 | if (value.isEmpty()) {
141 | ret = false;
142 | error.append("\"").append(colName).append("\" column must be specified\n");
143 | }
144 | else
145 | Config.setAfCorrectionColumnName(value);
146 |
147 | // Maf Voltage
148 | value = mafVName.getText().trim();
149 | colName = mafVLabelText;
150 | if (value.isEmpty()) {
151 | ret = false;
152 | error.append("\"").append(colName).append("\" column must be specified\n");
153 | }
154 | else
155 | Config.setMafVoltageColumnName(value);
156 |
157 | // Throttle Angle
158 | value = thrtlAngleName.getText().trim();
159 | colName = thrtlAngleLabelText;
160 | if (value.isEmpty()) {
161 | ret = false;
162 | error.append("\"").append(colName).append("\" column must be specified\n");
163 | }
164 | else
165 | Config.setThrottleAngleColumnName(value);
166 |
167 | // Time
168 | value = timeName.getText().trim();
169 | colName = timeLabelText;
170 | if (value.isEmpty()) {
171 | ret = false;
172 | error.append("\"").append(colName).append("\" column must be specified\n");
173 | }
174 | else
175 | Config.setTimeColumnName(value);
176 |
177 | // Intake Air Temperature
178 | value = iatName.getText().trim();
179 | colName = iatLabelText;
180 | if (value.isEmpty()) {
181 | ret = false;
182 | error.append("\"").append(colName).append("\" column must be specified\n");
183 | }
184 | else
185 | Config.setIatColumnName(value);
186 |
187 | // CL/OL Status
188 | value = clolStatusName.getText().trim();
189 | colName = clolStatusLabelText;
190 | if (value.isEmpty()) {
191 | ret = false;
192 | error.append("\"").append(colName).append("\" column must be specified\n");
193 | }
194 | else
195 | Config.setClOlStatusColumnName(value);
196 |
197 | // Stock AFR
198 | value = stockAfrName.getText().trim();
199 | colName = stockAfrLabelText;
200 | if (value.isEmpty()) {
201 | ret = false;
202 | error.append("\"").append(colName).append("\" column must be specified\n");
203 | }
204 | else
205 | Config.setAfrColumnName(value);
206 |
207 | // Wideband AFR
208 | value = wbAfrName.getText().trim();
209 | colName = wbAfrLabelText;
210 | if (value.isEmpty()) {
211 | ret = false;
212 | error.append("\"").append(colName).append("\" column must be specified\n");
213 | }
214 | else
215 | Config.setWidebandAfrColumnName(value);
216 |
217 | // Commanded AFR
218 | value = commAfrName.getText().trim();
219 | colName = commAfrLabelText;
220 | if (isPolfTableSet) {
221 | if (value.isEmpty())
222 | value = Config.NO_NAME;
223 | Config.setCommandedAfrColumnName(value);
224 | }
225 | else {
226 | if (value.isEmpty()) {
227 | ret = false;
228 | error.append("\"").append(colName).append("\" column must be specified if \"Primary Open Loop Fueling\" table is not set.\n");
229 | }
230 | else
231 | Config.setCommandedAfrColumnName(value);
232 | }
233 |
234 | // MAF
235 | value = mafName.getText().trim();
236 | colName = mafLabelText;
237 | if (value.isEmpty()) {
238 | ret = false;
239 | error.append("\"").append(colName).append("\" column must be specified\n");
240 | }
241 | else
242 | Config.setMassAirflowColumnName(value);
243 |
244 | // CL/OL Status
245 | value = clolStatusFilter.getValue().toString();
246 | colName = clolStatusLabelText;
247 | if (value.isEmpty() || value.equals("-1")) {
248 | ret = false;
249 | error.append("\"").append(colName).append("\" value must be specified\n");
250 | }
251 | else
252 | Config.setMIClOlStatusValue(Integer.valueOf(value));
253 |
254 | // MAF IAT Compensation values in ratio
255 | Config.setIsMafIatInRatio(isMafIatInRatioBool.isSelected());
256 |
257 | // Throttle Change % Maximum
258 | Config.setMIThrottleChangeMaxValue(Integer.valueOf(thrtlChangeMaxFilter.getValue().toString()));
259 |
260 | // Minimum Cell Hit Count Filter
261 | Config.setMIMinCellHitCount(Integer.valueOf(minCellHitCountFilter.getText()));
262 |
263 | // AFR filters
264 | Config.setMIAfrMaximumValue(Double.valueOf(maxAfrFilter.getText()));
265 | Config.setMIAfrMinimumValue(Double.valueOf(minAfrFilter.getText()));
266 |
267 | // dV/dt filter
268 | Config.setMIDvDtMaximumValue(Double.valueOf(maxDvdtFilter.getText()));
269 |
270 | // WOT Enrichment
271 | Config.setWOTEnrichmentValue(Double.valueOf(wotEnrichmentField.getText()));
272 |
273 | // WBO2 Row Offset
274 | Config.setWBO2RowOffset(Integer.valueOf(wbo2RowOffsetField.getText()));
275 |
276 | // Correction applied
277 | Config.setMICorrectionAppliedValue(Integer.valueOf(correctionAppliedValue.getValue().toString()));
278 |
279 | return ret;
280 | }
281 |
282 | protected boolean processDefaultButton(ActionEvent e) {
283 | if ("thrtlchange".equals(e.getActionCommand()))
284 | thrtlChangeMaxFilter.setValue(Integer.valueOf(Config.DefaultThrottleChangeMax));
285 | else if ("maxafr".equals(e.getActionCommand()))
286 | maxAfrFilter.setText(Config.DefaultMIAfrMaximum);
287 | else if ("minafr".equals(e.getActionCommand()))
288 | minAfrFilter.setText(Config.DefaultMIAfrMinimum);
289 | else if ("maxdvdt".equals(e.getActionCommand()))
290 | maxDvdtFilter.setText(Config.DefaultDvDtMaximum);
291 | else if ("minhitcnt".equals(e.getActionCommand()))
292 | minCellHitCountFilter.setText(Config.DefaultMIMinCellHitCount);
293 | else if ("wotenrich".equals(e.getActionCommand()))
294 | wotEnrichmentField.setText(Config.DefaultWOTEnrichment);
295 | else if ("wbo2offset".equals(e.getActionCommand()))
296 | wbo2RowOffsetField.setText(Config.DefaultWBO2RowOffset);
297 | else if ("corrapply".equals(e.getActionCommand()))
298 | correctionAppliedValue.setValue(Integer.valueOf(Config.DefaultCorrectionAppliedValue));
299 | else
300 | return false;
301 | return true;
302 | }
303 | }
304 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/MafScaling.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.BorderLayout;
22 | import java.awt.Color;
23 | import java.awt.Dimension;
24 | import java.awt.EventQueue;
25 | import java.awt.Font;
26 | import java.awt.Frame;
27 | import java.awt.event.WindowAdapter;
28 | import java.awt.event.WindowEvent;
29 | import javax.swing.ImageIcon;
30 | import javax.swing.JFrame;
31 | import javax.swing.JTabbedPane;
32 | import javax.swing.UIManager;
33 | import javax.swing.UnsupportedLookAndFeelException;
34 |
35 | import org.apache.log4j.Logger;
36 |
37 | public class MafScaling {
38 | private static final Logger logger = Logger.getLogger(MafScaling.class);
39 | private static final String Title = "MAF Scaling - v2.7.1";
40 | private static final String OLTabName = "Open Loop";
41 | private static final String CLTabName = "Closed Loop";
42 | private static final String MMTabName = "MAF OL/CL Merge";
43 | private static final String MRTabName = "MAF Rescale";
44 | private static final String TRTabName = "Table Rescale";
45 | private static final String TMTabName = "Throttle Maps";
46 | private static final String LCTabName = "Load Comp";
47 | private static final String MITabName = "MAF IAT Comp";
48 | private static final String VETabName = "MAF VE Calc";
49 | private static final String VCTabName = "WOT Best VVT";
50 | private static final String LSTabName = "Log Stats";
51 | private static final String LVTabName = "Log View";
52 | private JFrame frame;
53 |
54 | /**
55 | * Launch the application.
56 | * @throws UnsupportedLookAndFeelException
57 | * @throws IllegalAccessException
58 | * @throws InstantiationException
59 | * @throws ClassNotFoundException
60 | */
61 | public static void main(String[] args) throws Exception {
62 | //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
63 | //UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
64 | //UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
65 |
66 | if (UIManager.getLookAndFeel().getName().equals("Nimbus")) {
67 | UIManager.put("Table.gridColor", new Color(214, 217, 223));
68 | UIManager.put("Table.disabled", false);
69 | UIManager.put("Table.showGrid", true);
70 | UIManager.put("Table.intercellSpacing", new Dimension (1, 1));
71 | UIManager.put("TitledBorder.font", new Font(Font.SANS_SERIF, Font.PLAIN, 12));
72 | UIManager.put("Table.selectionBackground", new Color(115, 164, 209));
73 | UIManager.put("Table.selectionForeground", Color.WHITE);
74 | UIManager.put("Table.focusCellBackground", new Color(115, 164, 209));
75 | UIManager.put("Table.focusCellForeground", Color.WHITE);
76 | }
77 | EventQueue.invokeLater(new Runnable() {
78 | public void run() {
79 | try {
80 | MafScaling window = new MafScaling();
81 | window.frame.setVisible(true);
82 | }
83 | catch (Exception e) {
84 | e.printStackTrace();
85 | logger.error(e);
86 | }
87 | }
88 | });
89 | }
90 |
91 | /**
92 | * Create the application.
93 | */
94 | public MafScaling() {
95 | Config.load();
96 | initialize();
97 | }
98 |
99 | /**
100 | * Initialize the contents of the frame.
101 | */
102 | private void initialize() {
103 | PrimaryOpenLoopFuelingTable pofFuelingTable = new PrimaryOpenLoopFuelingTable();
104 | MafCompare mafCompare = new MafCompare();
105 |
106 | ImageIcon chartImage = new ImageIcon(getClass().getResource("/chart.jpg"));
107 |
108 | frame = new JFrame();
109 | frame.addWindowListener(new WindowAdapter() {
110 | public void windowClosing(WindowEvent e) {
111 | if ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) == 0) {
112 | Config.setWindowSize(frame.getSize());
113 | Config.setWindowLocation(frame.getLocation());
114 | }
115 | Config.setLastLogFilesPath(FCTabbedPane.getLogFilesPath());
116 | Config.save();
117 | }
118 | });
119 |
120 | JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
121 | tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
122 | frame.getContentPane().add(tabbedPane, BorderLayout.CENTER);
123 |
124 | JTabbedPane ol = new OpenLoop(JTabbedPane.LEFT, pofFuelingTable, mafCompare);
125 | ol.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
126 | tabbedPane.add(ol, OLTabName);
127 |
128 | JTabbedPane cl = new ClosedLoop(JTabbedPane.LEFT, pofFuelingTable, mafCompare);
129 | cl.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
130 | tabbedPane.add(cl, CLTabName);
131 |
132 | JTabbedPane mm = new MafOLCLMerge(JTabbedPane.LEFT);
133 | mm.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
134 | tabbedPane.add(mm, MMTabName);
135 |
136 | JTabbedPane mr = new MafRescale(JTabbedPane.LEFT);
137 | mr.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
138 | tabbedPane.add(mr, MRTabName);
139 |
140 | JTabbedPane tr = new TableRescale(JTabbedPane.LEFT);
141 | tr.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
142 | tabbedPane.add(tr, TRTabName);
143 |
144 | JTabbedPane tm = new ThrottleMaps(JTabbedPane.LEFT);
145 | tm.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
146 | tabbedPane.add(tm, TMTabName);
147 |
148 | JTabbedPane lc = new LoadComp(JTabbedPane.LEFT);
149 | lc.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
150 | tabbedPane.add(lc, LCTabName);
151 |
152 | JTabbedPane mi = new MafIatComp(JTabbedPane.LEFT, pofFuelingTable);
153 | mi.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
154 | tabbedPane.add(mi, MITabName);
155 |
156 | JTabbedPane ve = new VECalc(JTabbedPane.LEFT);
157 | ve.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
158 | tabbedPane.add(ve, VETabName);
159 |
160 | JTabbedPane vc = new VVTCalc(JTabbedPane.LEFT);
161 | vc.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
162 | tabbedPane.add(vc, VCTabName);
163 |
164 | JTabbedPane ls = new LogStats(JTabbedPane.LEFT);
165 | ls.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
166 | tabbedPane.add(ls, LSTabName);
167 |
168 | JTabbedPane lv = new LogView(JTabbedPane.LEFT);
169 | lv.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
170 | tabbedPane.add(lv, LVTabName);
171 |
172 | frame.pack();
173 | frame.doLayout();
174 | frame.setTitle(Title);
175 | frame.setBounds(100, 100, 621, 372);
176 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
177 | frame.setSize(Config.getWindowSize());
178 | frame.setLocation(Config.getWindowLocation());
179 | frame.setIconImage(chartImage.getImage());
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/MafTablePane.java:
--------------------------------------------------------------------------------
1 | package com.vgi.mafscaling;
2 |
3 | import java.awt.Color;
4 | import java.awt.GridBagConstraints;
5 | import java.awt.GridBagLayout;
6 | import java.awt.Insets;
7 |
8 | import javax.swing.JLabel;
9 | import javax.swing.JPanel;
10 | import javax.swing.JScrollPane;
11 | import javax.swing.JTable;
12 | import javax.swing.ListSelectionModel;
13 | import javax.swing.ScrollPaneConstants;
14 | import javax.swing.border.LineBorder;
15 | import javax.swing.border.TitledBorder;
16 | import javax.swing.table.DefaultTableModel;
17 |
18 | public class MafTablePane extends JScrollPane {
19 | private static final long serialVersionUID = 4656913571229048807L;
20 | public static final int MafTableColumnCount = 35;
21 | JTable mafTable = null;
22 | JLabel voltLabel = null;
23 | JLabel gsLabel = null;
24 |
25 | public MafTablePane(int columnWidth, String tableName, boolean editableFirstRow, boolean editableSecondRow) {
26 | Insets insets0 = new Insets(0, 0, 0, 0);
27 | JPanel dataMafPanel = new JPanel();
28 | GridBagLayout gbl_dataMafPanel = new GridBagLayout();
29 | gbl_dataMafPanel.columnWidths = new int[]{0, 0};
30 | gbl_dataMafPanel.rowHeights = new int[] {0, 0};
31 | gbl_dataMafPanel.columnWeights = new double[]{0.0, 1.0};
32 | gbl_dataMafPanel.rowWeights = new double[]{0.0, 0.0};
33 | dataMafPanel.setLayout(gbl_dataMafPanel);
34 |
35 | GridBagConstraints gbc_label = new GridBagConstraints();
36 | gbc_label.anchor = GridBagConstraints.EAST;
37 | gbc_label.insets = insets0;
38 | gbc_label.gridx = 0;
39 | gbc_label.gridy = 0;
40 | voltLabel = new JLabel("volt ");
41 | dataMafPanel.add(voltLabel, gbc_label);
42 | gbc_label.gridy = 1;
43 | gsLabel = new JLabel("g/s ");
44 | dataMafPanel.add(gsLabel, gbc_label);
45 |
46 | if (editableFirstRow && editableSecondRow)
47 | mafTable = new JTable();
48 | else if (editableFirstRow) {
49 | mafTable = new JTable() {
50 | private static final long serialVersionUID = 7749582128758153892L;
51 | public boolean isCellEditable(int row, int column) { if (row == 1) return true; return false; };
52 | };
53 | }
54 | else if (editableSecondRow) {
55 | mafTable = new JTable() {
56 | private static final long serialVersionUID = 7749582128758153892L;
57 | public boolean isCellEditable(int row, int column) { if (row == 1) return false; return true; };
58 | };
59 | }
60 | else {
61 | mafTable = new JTable() {
62 | private static final long serialVersionUID = -7484222189491449568L;
63 | public boolean isCellEditable(int row, int column) { return false; };
64 | };
65 | }
66 |
67 | mafTable.setColumnSelectionAllowed(true);
68 | mafTable.setCellSelectionEnabled(true);
69 | mafTable.setBorder(new LineBorder(new Color(0, 0, 0)));
70 | mafTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
71 | mafTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
72 | mafTable.setModel(new DefaultTableModel(2, MafTableColumnCount));
73 | mafTable.setTableHeader(null);
74 | mafTable.putClientProperty("terminateEditOnFocusLost", true);
75 | Utils.initializeTable(mafTable, columnWidth);
76 | GridBagConstraints gbc_mafTable = new GridBagConstraints();
77 | gbc_mafTable.insets = insets0;
78 | gbc_mafTable.fill = GridBagConstraints.HORIZONTAL;
79 | gbc_mafTable.weightx = 1.0;
80 | gbc_mafTable.gridx = 1;
81 | gbc_mafTable.gridy = 0;
82 | gbc_mafTable.gridheight = 2;
83 | dataMafPanel.add(mafTable, gbc_mafTable);
84 |
85 | setViewportView(dataMafPanel);
86 | if (tableName != null)
87 | setViewportBorder(new TitledBorder(null, tableName, TitledBorder.LEADING, TitledBorder.TOP, null, null));
88 | setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
89 | setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
90 | }
91 |
92 | public void hideRowHeaders() {
93 | voltLabel.setVisible(false);
94 | gsLabel.setVisible(false);
95 | }
96 |
97 | public void showRowHeaders() {
98 | voltLabel.setVisible(true);
99 | gsLabel.setVisible(true);
100 | }
101 |
102 | public JTable getJTable() {
103 | return mafTable;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/NumberFormatRenderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.Component;
22 | import java.text.DecimalFormat;
23 | import java.text.Format;
24 | import java.util.regex.Pattern;
25 | import javax.swing.JTable;
26 | import javax.swing.SwingConstants;
27 |
28 |
29 | class NumberFormatRenderer extends BgColorFormatRenderer {
30 | private static final long serialVersionUID = 4722830336189723801L;
31 | private Format[][] formats = null;
32 | private DecimalFormat formatter = new DecimalFormat("0.00");
33 |
34 | /**
35 | * Default constructor, sets cells alignement to right
36 | */
37 | public NumberFormatRenderer() {
38 | setHorizontalAlignment(SwingConstants.RIGHT);
39 | }
40 |
41 | /**
42 | * Method sets cells format matrix
43 | * @param formatMatrix
44 | */
45 | public void setFormats(Format[][] formatMatrix) {
46 | formats = formatMatrix;
47 | }
48 |
49 | /**
50 | * Method returns cells format matrix
51 | * @return format matrix
52 | */
53 | public Format[][] getFormats() {
54 | return formats;
55 | }
56 |
57 | /**
58 | * Method sets background color for a specific cell
59 | * @param color, background color
60 | * @param row, cell row index
61 | * @param column, cell column index
62 | */
63 | public void setFormatAt(Format format, int row, int column) {
64 | if (formats != null && row < formats.length && column < formats[0].length)
65 | formats[row][column] = format;
66 | }
67 |
68 | /**
69 | * Method sets numeric formatter
70 | * @param format
71 | */
72 | public void setFormatter(DecimalFormat format) {
73 | formatter = format;
74 | }
75 |
76 | @Override
77 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
78 | if (value == null)
79 | value = "";
80 | else if (formats != null) {
81 | if (Pattern.matches(Utils.fpRegex, value.toString())) {
82 | int frow = row;
83 | if (frow >= formats.length)
84 | frow = formats.length - 1;
85 | int fcol = column;
86 | if (fcol >= formats[frow].length)
87 | fcol = formats[frow].length - 1;
88 | value = formats[frow][fcol].format(Double.valueOf(value.toString()));
89 | }
90 | }
91 | else if (Pattern.matches(Utils.fpRegex, value.toString()))
92 | value = formatter.format(Double.valueOf(value.toString()));
93 | return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column );
94 | }
95 | }
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/OLColumnsFiltersSelection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.event.ActionEvent;
22 |
23 | public class OLColumnsFiltersSelection extends ColumnsFiltersSelection {
24 | private boolean isPolfTableSet = false;
25 | private boolean isPolfTableMap = false;
26 |
27 | public OLColumnsFiltersSelection(boolean isPolfTableSet, boolean isPolfTableMap) {
28 | this.isPolfTableSet = isPolfTableSet;
29 | this.isPolfTableMap = isPolfTableMap;
30 | }
31 |
32 | protected void addColumnsNote() {
33 | if (!isPolfTableSet)
34 | addColumnsNote("If you don't have 'Commanded AFR' / 'Fueling Final Base' please set 'POL Fueling' table first");
35 | }
36 |
37 | protected void addColSelection() {
38 | addRPMColSelection();
39 | if (isPolfTableMap)
40 | addManifoldAbsolutePressureColSelection();
41 | else if (isPolfTableSet)
42 | addLoadColSelection();
43 | addAFLearningColSelection();
44 | addAFCorrectionColSelection();
45 | addMAFVoltageColSelection();
46 | addWidebandAFRColSelection();
47 | addThrottleAngleColSelection();
48 | addCommandedAFRColSelection(isPolfTableSet);
49 | }
50 |
51 | protected void addFilterSelection() {
52 | addMAFVoltageMinimumFilter();
53 | minMafVFilter.setText(String.valueOf(Config.getMafVMinimumValue()));
54 | addWOTStationaryPointFilter();
55 | wotStationaryPointFilter.setValue(Config.getWOTStationaryPointValue());
56 | addAFRErrorPctFilter();
57 | afrErrorFilter.setText(String.valueOf(Config.getWidebandAfrErrorPercentValue()));
58 | addWOTEnrichmentMinimumFilter();
59 | wotEnrichmentField.setText(String.valueOf(Config.getWOTEnrichmentValue()));
60 | addWideBandAFRRowOffsetFilter();
61 | wbo2RowOffsetField.setText(String.valueOf(Config.getWBO2RowOffset()));
62 | addOLCLTransitionSkipRowsFilter();
63 | olClTransitionSkipRowsField.setText(String.valueOf(Config.getOLCLTransitionSkipRows()));
64 | }
65 |
66 | protected boolean validate(StringBuffer error) {
67 | boolean ret = true;
68 | String value;
69 | String colName;
70 |
71 | // Engine Speed
72 | value = rpmName.getText().trim();
73 | colName = rpmLabelText;
74 | if (value.isEmpty()) {
75 | ret = false;
76 | error.append("\"").append(colName).append("\" column must be specified\n");
77 | }
78 | else
79 | Config.setRpmColumnName(value);
80 |
81 | if (isPolfTableMap) {
82 | // Manifold Absolute Pressure
83 | value = mapName.getText().trim();
84 | colName = mapLabelText;
85 | if (value.isEmpty()) {
86 | ret = false;
87 | error.append("\"").append(colName).append("\" column must be specified\n");
88 | }
89 | else
90 | Config.setMapColumnName(value);
91 | }
92 | else if (isPolfTableSet) {
93 | // Engine Load
94 | value = loadName.getText().trim();
95 | colName = loadLabelText;
96 | if (value.isEmpty()) {
97 | ret = false;
98 | error.append("\"").append(colName).append("\" column must be specified\n");
99 | }
100 | else
101 | Config.setLoadColumnName(value);
102 | }
103 |
104 | // AFR Learning
105 | value = afLearningName.getText().trim();
106 | colName = afLearningLabelText;
107 | if (value.isEmpty()) {
108 | ret = false;
109 | error.append("\"").append(colName).append("\" column must be specified\n");
110 | }
111 | else
112 | Config.setAfLearningColumnName(value);
113 |
114 | // AFR Correction
115 | value = afCorrectionName.getText().trim();
116 | colName = afCorrectionLabelText;
117 | if (value.isEmpty()) {
118 | ret = false;
119 | error.append("\"").append(colName).append("\" column must be specified\n");
120 | }
121 | else
122 | Config.setAfCorrectionColumnName(value);
123 |
124 | // Maf Voltage
125 | value = mafVName.getText().trim();
126 | colName = mafVLabelText;
127 | if (value.isEmpty()) {
128 | ret = false;
129 | error.append("\"").append(colName).append("\" column must be specified\n");
130 | }
131 | else
132 | Config.setMafVoltageColumnName(value);
133 |
134 | // Wideband AFR
135 | value = wbAfrName.getText().trim();
136 | colName = wbAfrLabelText;
137 | if (value.isEmpty()) {
138 | ret = false;
139 | error.append("\"").append(colName).append("\" column must be specified\n");
140 | }
141 | else
142 | Config.setWidebandAfrColumnName(value);
143 |
144 | // Throttle Angle
145 | value = thrtlAngleName.getText().trim();
146 | colName = thrtlAngleLabelText;
147 | if (value.isEmpty()) {
148 | ret = false;
149 | error.append("\"").append(colName).append("\" column must be specified\n");
150 | }
151 | else
152 | Config.setThrottleAngleColumnName(value);
153 |
154 | // Commanded AFR
155 | value = commAfrName.getText().trim();
156 | colName = commAfrLabelText;
157 | if (isPolfTableSet) {
158 | if (value.isEmpty())
159 | value = Config.NO_NAME;
160 | Config.setCommandedAfrColumnName(value);
161 | }
162 | else {
163 | if (value.isEmpty()) {
164 | ret = false;
165 | error.append("\"").append(colName).append("\" column must be specified if \"Primary Open Loop Fueling\" table is not set.\n");
166 | }
167 | else
168 | Config.setCommandedAfrColumnName(value);
169 | }
170 |
171 | // Min MAF Voltage filter
172 | Config.setMafVMinimumValue(Double.valueOf(minMafVFilter.getText()));
173 |
174 | // WOT Stationary point
175 | Config.setWOTStationaryPointValue(Integer.valueOf(wotStationaryPointFilter.getValue().toString()));
176 |
177 | // Afr Error filter
178 | Config.setWidebandAfrErrorPercentValue(Double.valueOf(afrErrorFilter.getText()));
179 |
180 | // WOT Enrichment
181 | Config.setWOTEnrichmentValue(Double.valueOf(wotEnrichmentField.getText()));
182 |
183 | // WBO2 Row Offset
184 | Config.setWBO2RowOffset(Integer.valueOf(wbo2RowOffsetField.getText()));
185 |
186 | // OL/CL Transition Skip Rows
187 | Config.setOLCLTransitionSkipRows(Integer.valueOf(olClTransitionSkipRowsField.getText()));
188 |
189 | return ret;
190 | }
191 |
192 | protected boolean processDefaultButton(ActionEvent e) {
193 | if ("minmafv".equals(e.getActionCommand()))
194 | minMafVFilter.setText(Config.DefaultMafVMinimum);
195 | else if ("wotpoint".equals(e.getActionCommand()))
196 | wotStationaryPointFilter.setValue(Integer.valueOf(Config.DefaultWOTStationaryPoint));
197 | else if ("afrerr".equals(e.getActionCommand()))
198 | afrErrorFilter.setText(Config.DefaultWidebandAfrErrorPercent);
199 | else if ("wotenrich".equals(e.getActionCommand()))
200 | wotEnrichmentField.setText(Config.DefaultWOTEnrichment);
201 | else if ("wbo2offset".equals(e.getActionCommand()))
202 | wbo2RowOffsetField.setText(Config.DefaultWBO2RowOffset);
203 | else if ("olcltransit".equals(e.getActionCommand()))
204 | olClTransitionSkipRowsField.setText(Config.DefaultOLCLTransitionSkipRows);
205 | else
206 | return false;
207 | return true;
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/RestrictedFileSystemView.java:
--------------------------------------------------------------------------------
1 | package com.vgi.mafscaling;
2 |
3 | import java.io.File;
4 | import javax.swing.filechooser.FileSystemView;
5 |
6 | public class RestrictedFileSystemView extends FileSystemView {
7 | private final File rootDirectory;
8 | RestrictedFileSystemView(File rootDirectory) {
9 | this.rootDirectory = rootDirectory;
10 | }
11 | @Override
12 | public File createNewFolder(File dir) {
13 | return null;
14 | }
15 | @Override
16 | public File getDefaultDirectory() {
17 | return rootDirectory;
18 | }
19 | @Override
20 | public File getHomeDirectory() {
21 | return rootDirectory;
22 | }
23 | @Override
24 | public File getParentDirectory(File dir) {
25 | return rootDirectory;
26 | }
27 | @Override
28 | public File[] getRoots() {
29 | return new File[] {rootDirectory};
30 | }
31 | @Override
32 | public boolean isRoot(File file) {
33 | if (file.equals(rootDirectory))
34 | return true;
35 | return false;
36 | }
37 | @Override
38 | public boolean isFileSystemRoot(File file) {
39 | return isRoot(file);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/TableCellListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.event.*;
22 | import javax.swing.*;
23 | import java.beans.*;
24 |
25 | /*
26 | * This class listens for changes made to the data in the table via the
27 | * TableCellEditor. When editing is started, the value of the cell is saved
28 | * When editing is stopped the new value is saved. When the old and new
29 | * values are different, then the provided Action is invoked.
30 | *
31 | * The source of the Action is a TableCellListener instance.
32 | */
33 | public class TableCellListener implements PropertyChangeListener, Runnable
34 | {
35 | private JTable table;
36 | private Action action;
37 | private int row;
38 | private int column;
39 | private Object oldValue;
40 | private Object newValue;
41 |
42 | /**
43 | * Create a TableCellListener.
44 | * @param table the table to be monitored for data changes
45 | * @param action the Action to invoke when cell data is changed
46 | */
47 | public TableCellListener(JTable table, Action action)
48 | {
49 | this.table = table;
50 | this.action = action;
51 | table.addPropertyChangeListener(this);
52 | }
53 |
54 | /**
55 | * Create a TableCellListener with a copy of all the data relevant to
56 | * the change of data for a given cell.
57 | * @param row the row of the changed cell
58 | * @param column the column of the changed cell
59 | * @param oldValue the old data of the changed cell
60 | * @param newValue the new data of the changed cell
61 | */
62 | private TableCellListener(JTable table, int row, int column, Object oldValue, Object newValue)
63 | {
64 | this.table = table;
65 | this.row = row;
66 | this.column = column;
67 | this.oldValue = oldValue;
68 | this.newValue = newValue;
69 | }
70 |
71 | /**
72 | * Get the column that was last edited
73 | * @return the column that was edited
74 | */
75 | public int getColumn()
76 | {
77 | return column;
78 | }
79 |
80 | /**
81 | * Get the new value in the cell
82 | * @return the new value in the cell
83 | */
84 | public Object getNewValue()
85 | {
86 | return newValue;
87 | }
88 |
89 | /**
90 | * Get the old value of the cell
91 | * @return the old value of the cell
92 | */
93 | public Object getOldValue()
94 | {
95 | return oldValue;
96 | }
97 |
98 | /**
99 | * Get the row that was last edited
100 | * @return the row that was edited
101 | */
102 | public int getRow()
103 | {
104 | return row;
105 | }
106 |
107 | /**
108 | * Get the table of the cell that was changed
109 | * @return the table of the cell that was changed
110 | */
111 | public JTable getTable()
112 | {
113 | return table;
114 | }
115 |
116 | /**
117 | * Implement the PropertyChangeListener interface
118 | */
119 | @Override
120 | public void propertyChange(PropertyChangeEvent e)
121 | {
122 | // A cell has started/stopped editing
123 | if ("tableCellEditor".equals(e.getPropertyName()))
124 | {
125 | if (table.isEditing())
126 | processEditingStarted();
127 | else
128 | processEditingStopped();
129 | }
130 | }
131 |
132 | /**
133 | * Save information of the cell about to be edited
134 | */
135 | private void processEditingStarted()
136 | {
137 | /* The invokeLater is necessary because the editing row and editing column of the table have
138 | * not been set when the "tableCellEditor" PropertyChangeEvent is fired.
139 | * This results in the "run" method being invoked
140 | */
141 | SwingUtilities.invokeLater(this);
142 | }
143 |
144 | /**
145 | * Override for the above.
146 | */
147 | @Override
148 | public void run()
149 | {
150 | row = table.convertRowIndexToModel(table.getEditingRow());
151 | column = table.convertColumnIndexToModel(table.getEditingColumn());
152 | oldValue = table.getModel().getValueAt(row, column);
153 | newValue = null;
154 | }
155 |
156 | /**
157 | * Update the Cell history when necessary
158 | */
159 | private void processEditingStopped()
160 | {
161 | newValue = table.getModel().getValueAt(row, column);
162 | // The data has changed, invoke the supplied Action
163 | if (!newValue.equals(oldValue))
164 | {
165 | // Make a copy of the data in case another cell starts editing while processing this change
166 | TableCellListener tcl = new TableCellListener(getTable(), getRow(), getColumn(), getOldValue(), getNewValue());
167 | ActionEvent event = new ActionEvent(tcl, ActionEvent.ACTION_PERFORMED, "");
168 | action.actionPerformed(event);
169 | }
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/VVTColumnsFiltersSelection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.event.ActionEvent;
22 |
23 | public class VVTColumnsFiltersSelection extends ColumnsFiltersSelection {
24 |
25 | protected void addColSelection() {
26 | addThrottleAngleColSelection();
27 | addRPMColSelection();
28 | addVVTSystem1ColSelection();
29 | addVVTSystem2ColSelection();
30 | addIATColSelection();
31 | addManifoldAbsolutePressureColSelection();
32 | addMAFColSelection();
33 | }
34 |
35 | protected void addFilterSelection() {
36 | addWOTStationaryPointFilter();
37 | wotStationaryPointFilter.setValue(Config.getWOTStationaryPointValue());
38 | addOLCLTransitionSkipRowsFilter();
39 | olClTransitionSkipRowsField.setText(String.valueOf(Config.getOLCLTransitionSkipRows()));
40 | addRPMMaximumFilter();
41 | maxRPMFilter.setText(String.valueOf(Config.getVVTRPMMaximumValue()));
42 | addTemperatureScaleFilter();
43 | temperatureScaleField.setSelectedItem(Character.toString(Config.getTemperatureScale()));
44 | addManifoldAbsolutePressureUnitFilter();
45 | mapUnitField.setSelectedItem(('P' == Config.getMapUnit() ? "Psi" : ('B' == Config.getMapUnit() ? "Bar" : "kPa")));
46 | }
47 |
48 | protected boolean validate(StringBuffer error) {
49 | boolean ret = true;
50 | String value;
51 | String colName;
52 |
53 | // Throttle Angle
54 | value = thrtlAngleName.getText().trim();
55 | colName = thrtlAngleLabelText;
56 | if (value.isEmpty()) {
57 | ret = false;
58 | error.append("\"").append(colName).append("\" column must be specified\n");
59 | }
60 | else
61 | Config.setThrottleAngleColumnName(value);
62 |
63 | // Engine Speed
64 | value = rpmName.getText().trim();
65 | colName = rpmLabelText;
66 | if (value.isEmpty()) {
67 | ret = false;
68 | error.append("\"").append(colName).append("\" column must be specified\n");
69 | }
70 | else
71 | Config.setRpmColumnName(value);
72 |
73 | // VVT System 1
74 | value = vvt1Name.getText().trim();
75 | colName = vvt1LabelText;
76 | if (value.isEmpty()) {
77 | ret = false;
78 | error.append("\"").append(colName).append("\" column must be specified\n");
79 | }
80 | else
81 | Config.setVvt1ColumnName(value);
82 |
83 | // VVT System 2
84 | value = vvt2Name.getText().trim();
85 | colName = vvt2LabelText;
86 | if (value.isEmpty())
87 | Config.setVvt2ColumnName(Config.NO_NAME);
88 | else
89 | Config.setVvt2ColumnName(value);
90 |
91 | // Intake Air Temperature
92 | value = iatName.getText().trim();
93 | colName = iatLabelText;
94 | if (value.isEmpty()) {
95 | ret = false;
96 | error.append("\"").append(colName).append("\" column must be specified\n");
97 | }
98 | else
99 | Config.setIatColumnName(value);
100 |
101 | // MAP
102 | value = mapName.getText().trim();
103 | colName = mapLabelText;
104 | if (value.isEmpty()) {
105 | ret = false;
106 | error.append("\"").append(colName).append("\" column must be specified\n");
107 | }
108 | else
109 | Config.setMapColumnName(value);
110 |
111 | // MAF
112 | value = mafName.getText().trim();
113 | colName = mafLabelText;
114 | if (value.isEmpty()) {
115 | ret = false;
116 | error.append("\"").append(colName).append("\" column must be specified\n");
117 | }
118 | else
119 | Config.setMassAirflowColumnName(value);
120 |
121 | // WOT Stationary point
122 | Config.setWOTStationaryPointValue(Integer.valueOf(wotStationaryPointFilter.getValue().toString()));
123 |
124 | // OL/CL Transition Skip Rows
125 | Config.setOLCLTransitionSkipRows(Integer.valueOf(olClTransitionSkipRowsField.getText()));
126 |
127 | // RPM filter
128 | Config.setVVTRPMMaximumValue(Integer.valueOf(maxRPMFilter.getText()));
129 |
130 | // Temperature Scale
131 | Config.setTemperatureScale(temperatureScaleField.getSelectedItem().toString().charAt(0));
132 |
133 | // Manifold Absolute Pressure Unit
134 | Config.setMapUnit(Character.toUpperCase(mapUnitField.getSelectedItem().toString().charAt(0)));
135 |
136 | return ret;
137 | }
138 |
139 | protected boolean processDefaultButton(ActionEvent e) {
140 | if ("wotpoint".equals(e.getActionCommand()))
141 | wotStationaryPointFilter.setValue(Integer.valueOf(Config.DefaultWOTStationaryPoint));
142 | else if ("olcltransit".equals(e.getActionCommand()))
143 | olClTransitionSkipRowsField.setText(Config.DefaultOLCLTransitionSkipRows);
144 | else if ("maxrpm".equals(e.getActionCommand()))
145 | maxRPMFilter.setText(Config.DefaultVVTRPMMaximum);
146 | else if ("tempscale".equals(e.getActionCommand()))
147 | temperatureScaleField.setSelectedItem(Config.DefaultTempScale);
148 | else if ("mapunit".equals(e.getActionCommand()))
149 | mapUnitField.setSelectedItem(Config.DefaultMapUnit);
150 | else
151 | return false;
152 | return true;
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/WotPullsGroups.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Open-Source tuning tools
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | package com.vgi.mafscaling;
20 |
21 | import java.awt.Color;
22 | import java.awt.Dimension;
23 | import java.awt.GridBagConstraints;
24 | import java.awt.GridBagLayout;
25 | import java.awt.Insets;
26 | import java.awt.event.ActionEvent;
27 | import java.awt.event.ActionListener;
28 | import java.util.ArrayList;
29 | import java.util.Collections;
30 | import java.util.List;
31 | import java.util.TreeMap;
32 | import java.util.TreeSet;
33 | import javax.swing.BorderFactory;
34 | import javax.swing.Box;
35 | import javax.swing.BoxLayout;
36 | import javax.swing.ImageIcon;
37 | import javax.swing.JButton;
38 | import javax.swing.JOptionPane;
39 | import javax.swing.JPanel;
40 | import javax.swing.JScrollPane;
41 | import javax.swing.JTable;
42 | import javax.swing.ListSelectionModel;
43 | import javax.swing.UIDefaults;
44 | import javax.swing.border.LineBorder;
45 | import javax.swing.event.ListSelectionEvent;
46 | import javax.swing.event.ListSelectionListener;
47 | import javax.swing.table.DefaultTableModel;
48 |
49 | class WotPullsGroups implements ActionListener {
50 | private List columns = null;
51 | private JTable groupTable = null;
52 | private DefaultTableModel groupModel = null;
53 | private JTable selectionTable = null;
54 | private DefaultTableModel selectionModel = null;
55 | private JTable columnsTable = null;
56 | private DefaultTableModel columnsModel = null;
57 | private JPanel columnsPanel = null;
58 | private Insets insets0 = new Insets(0, 0, 0, 0);
59 | private Insets insets2 = new Insets(1, 0, 0, 1);
60 | private TreeMap> groups = new TreeMap>();
61 |
62 | private ImageIcon arrowImageLeft = new ImageIcon(getClass().getResource("/arrow.jpg"));
63 | private ImageIcon arrowImageRigth = new ImageIcon(getClass().getResource("/arrowr.jpg"));
64 | private UIDefaults zeroInsets = new UIDefaults();
65 |
66 | public WotPullsGroups() {
67 | zeroInsets.put("Button.contentMargins", insets0);
68 | }
69 |
70 | public void getGroups(JMultiSelectionBox wotPlotsColumn, ArrayList> wotYAxisGroups) {
71 | columns = wotPlotsColumn.getSelectedItems();
72 | if (columns == null || columns.size() < 2)
73 | return;
74 | Collections.sort(columns);
75 |
76 | columnsPanel = new JPanel();
77 | GridBagLayout gbl_dataPanel = new GridBagLayout();
78 | gbl_dataPanel.columnWidths = new int[]{0, 0, 0, 0, 0, 0};
79 | gbl_dataPanel.rowHeights = new int[] {0, 0, 0};
80 | gbl_dataPanel.columnWeights = new double[]{1.0, 0.0, 1.0, 0.0, 1.0, 1.0};
81 | gbl_dataPanel.rowWeights = new double[]{0.0, 1.0, 1.0};
82 | columnsPanel.setLayout(gbl_dataPanel);
83 |
84 | JPanel buttons = new JPanel();
85 | buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
86 | buttons.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
87 |
88 | JButton button = new JButton("Add group");
89 | button.setActionCommand("addgrp");
90 | button.addActionListener(this);
91 | buttons.add(button);
92 | buttons.add(Box.createRigidArea(new Dimension(5,0)));
93 |
94 | button = new JButton("Remove group");
95 | button.setActionCommand("remgrp");
96 | button.addActionListener(this);
97 | buttons.add(button);
98 |
99 | GridBagConstraints gbc_pane = new GridBagConstraints();
100 | gbc_pane.insets = insets0;
101 | gbc_pane.anchor = GridBagConstraints.PAGE_START;
102 | gbc_pane.fill = GridBagConstraints.HORIZONTAL;
103 | gbc_pane.gridx = 0;
104 | gbc_pane.gridy = 0;
105 | gbc_pane.gridwidth = 5;
106 | columnsPanel.add(buttons, gbc_pane);
107 |
108 | gbc_pane = new GridBagConstraints();
109 | gbc_pane.insets = insets2;
110 | gbc_pane.anchor = GridBagConstraints.PAGE_START;
111 | gbc_pane.fill = GridBagConstraints.BOTH;
112 | gbc_pane.gridx = 0;
113 | gbc_pane.gridy = 1;
114 | gbc_pane.gridheight = 2;
115 | groupTable = createTable(true, "Groups");
116 | groupTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
117 | @Override
118 | public void valueChanged(ListSelectionEvent event) {
119 | int idx = groupTable.getSelectedRow();
120 | if (idx >= 0) {
121 | while (selectionModel.getRowCount() > 0)
122 | selectionModel.removeRow(0);
123 | TreeSet group = groups.get(groupTable.getValueAt(idx, 0));
124 | for (String val : group)
125 | selectionModel.addRow(new Object[]{val});
126 | }
127 | }
128 | });
129 | groupModel = (DefaultTableModel) groupTable.getModel();
130 | JScrollPane tableScroll = new JScrollPane (groupTable);
131 | tableScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
132 | tableScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
133 | tableScroll.getViewport().setBackground(Color.WHITE);
134 | tableScroll.setPreferredSize(new Dimension(200, 200));
135 | columnsPanel.add(tableScroll, gbc_pane);
136 |
137 | gbc_pane = new GridBagConstraints();
138 | gbc_pane.insets = insets2;
139 | gbc_pane.anchor = GridBagConstraints.PAGE_START;
140 | gbc_pane.fill = GridBagConstraints.BOTH;
141 | gbc_pane.gridx = 2;
142 | gbc_pane.gridy = 1;
143 | gbc_pane.gridheight = 2;
144 | selectionTable = createTable(false, "Grouped Columns");
145 | selectionModel = (DefaultTableModel) selectionTable.getModel();
146 | tableScroll = new JScrollPane (selectionTable);
147 | tableScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
148 | tableScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
149 | tableScroll.getViewport().setBackground(Color.WHITE);
150 | tableScroll.setPreferredSize(new Dimension(200, 200));
151 | columnsPanel.add(tableScroll, gbc_pane);
152 |
153 | gbc_pane = new GridBagConstraints();
154 | gbc_pane.insets = insets2;
155 | gbc_pane.anchor = GridBagConstraints.PAGE_START;
156 | gbc_pane.fill = GridBagConstraints.BOTH;
157 | gbc_pane.gridx = 4;
158 | gbc_pane.gridy = 1;
159 | gbc_pane.gridheight = 2;
160 | columnsTable = createTable(false, "Available Columns");
161 | columnsModel = (DefaultTableModel) columnsTable.getModel();
162 | for (String column : columns)
163 | columnsModel.addRow(new Object[]{column});
164 | tableScroll = new JScrollPane (columnsTable);
165 | tableScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
166 | tableScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
167 | tableScroll.getViewport().setBackground(Color.WHITE);
168 | tableScroll.setPreferredSize(new Dimension(200, 200));
169 | columnsPanel.add(tableScroll, gbc_pane);
170 |
171 | gbc_pane = new GridBagConstraints();
172 | gbc_pane.anchor = GridBagConstraints.NORTH;
173 | gbc_pane.insets = insets0;
174 | gbc_pane.gridx = 1;
175 | gbc_pane.gridy = 1;
176 | gbc_pane.gridheight = 2;
177 | columnsPanel.add(Box.createRigidArea(new Dimension(25, 0)), gbc_pane);
178 |
179 | gbc_pane = new GridBagConstraints();
180 | gbc_pane.anchor = GridBagConstraints.SOUTH;
181 | gbc_pane.insets = insets0;
182 | gbc_pane.gridx = 3;
183 | gbc_pane.gridy = 1;
184 | button = new JButton("", arrowImageLeft);
185 | button.putClientProperty("Nimbus.Overrides", zeroInsets);
186 | button.setMargin(insets0);
187 | button.setBorderPainted(false);
188 | button.setContentAreaFilled(false);
189 | button.setActionCommand("select");
190 | button.addActionListener(this);
191 | columnsPanel.add(button, gbc_pane);
192 |
193 | gbc_pane = new GridBagConstraints();
194 | gbc_pane.anchor = GridBagConstraints.NORTH;
195 | gbc_pane.insets = insets0;
196 | gbc_pane.gridx = 3;
197 | gbc_pane.gridy = 2;
198 | button = new JButton("", arrowImageRigth);
199 | button.putClientProperty("Nimbus.Overrides", zeroInsets);
200 | button.setMargin(insets0);
201 | button.setBorderPainted(false);
202 | button.setContentAreaFilled(false);
203 | button.setActionCommand("unselect");
204 | button.addActionListener(this);
205 | columnsPanel.add(button, gbc_pane);
206 | columnsPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
207 |
208 | for (int i = 0; i < wotYAxisGroups.size(); ++i) {
209 | if (wotYAxisGroups.get(i).size() > 1) {
210 | String group = "Group " + (i + 1);
211 | groups.put(group, wotYAxisGroups.get(i));
212 | groupModel.addRow(new Object[]{group});
213 | for (String val : wotYAxisGroups.get(i)) {
214 | int idx = columns.indexOf(val);
215 | columns.remove(idx);
216 | columnsModel.removeRow(idx);
217 | }
218 | }
219 | }
220 | if (groupModel.getRowCount() > 0)
221 | groupTable.changeSelection(0, 0, false, false);
222 |
223 | if (JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(null, columnsPanel, "Columns Y-Axis Grouping", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE))
224 | return;
225 | wotYAxisGroups.clear();
226 | for (String key : groups.keySet()) {
227 | TreeSet group = groups.get(key);
228 | if (group.size() > 0)
229 | wotYAxisGroups.add(group);
230 | }
231 | }
232 |
233 | protected JTable createTable(boolean isGroup, String name) {
234 | JTable table = new JTable() {
235 | private static final long serialVersionUID = 1L;
236 | public boolean isCellEditable(int row, int column) { return false; };
237 | public boolean getScrollableTracksViewportWidth() {
238 | return getPreferredSize().width < getParent().getWidth();
239 | }
240 | };
241 | table.setColumnSelectionAllowed(false);
242 | table.setCellSelectionEnabled(true);
243 | table.setSelectionMode(isGroup ? ListSelectionModel.SINGLE_SELECTION : ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
244 | table.setModel(new DefaultTableModel(0, 1));
245 | table.setBorder(new LineBorder(new Color(0, 0, 0)));
246 | table.getColumnModel().getColumn(0).setHeaderValue(name);
247 | table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
248 | return table;
249 | }
250 |
251 | @Override
252 | public void actionPerformed(ActionEvent e) {
253 | if ("addgrp".equals(e.getActionCommand())) {
254 | int idx = groupModel.getRowCount();
255 | String group = "Group " + (idx + 1);
256 | groups.put(group, new TreeSet());
257 | groupModel.addRow(new Object[]{group});
258 | while (selectionModel.getRowCount() > 0)
259 | selectionModel.removeRow(0);
260 | groupTable.requestFocus();
261 | groupTable.changeSelection(idx, 0, false, false);
262 | }
263 | else if ("remgrp".equals(e.getActionCommand())) {
264 | int idx = groupTable.getSelectedRow();
265 | if (idx >= 0) {
266 | while (selectionModel.getRowCount() > 0) {
267 | String val = (String) selectionModel.getValueAt(0, 0);
268 | columns.add(val);
269 | columnsModel.addRow(new Object[]{val});
270 | selectionModel.removeRow(0);
271 | }
272 | groups.remove(groupModel.getValueAt(idx, 0));
273 | groupModel.removeRow(groupTable.getSelectedRow());
274 | Collections.sort(columns);
275 | }
276 | else
277 | JOptionPane.showMessageDialog(null, "Please select the group", "Error", JOptionPane.ERROR_MESSAGE);
278 | }
279 | else if ("select".equals(e.getActionCommand())) {
280 | int idx = groupTable.getSelectedRow();
281 | if (idx >= 0) {
282 | TreeSet group = groups.get(groupModel.getValueAt(idx, 0));
283 | int[] selected = columnsTable.getSelectedRows();
284 | if (selected.length > 0) {
285 | for (int i = selected.length - 1; i >= 0; --i) {
286 | idx = selected[i];
287 | String val = (String)columnsModel.getValueAt(idx, 0);
288 | group.add(val);
289 | selectionModel.addRow(new Object[]{val});
290 | columns.remove(val);
291 | columnsModel.removeRow(idx);
292 | }
293 | }
294 | selectionTable.clearSelection();
295 | columnsTable.clearSelection();
296 | }
297 | else
298 | JOptionPane.showMessageDialog(null, "Please select the group", "Error", JOptionPane.ERROR_MESSAGE);
299 | }
300 | else if ("unselect".equals(e.getActionCommand())) {
301 | int idx = groupTable.getSelectedRow();
302 | if (idx >= 0) {
303 | TreeSet group = groups.get(groupModel.getValueAt(idx, 0));
304 | int[] selected = selectionTable.getSelectedRows();
305 | if (selected.length > 0) {
306 | for (int i = selected.length - 1; i >= 0; --i) {
307 | idx = selected[i];
308 | String val = (String)selectionModel.getValueAt(idx, 0);
309 | group.remove(val);
310 | columnsModel.addRow(new Object[]{val});
311 | columns.add(val);
312 | selectionModel.removeRow(idx);
313 | }
314 | }
315 | selectionTable.clearSelection();
316 | columnsTable.clearSelection();
317 | }
318 | else
319 | JOptionPane.showMessageDialog(null, "Please select the group", "Error", JOptionPane.ERROR_MESSAGE);
320 | }
321 | }
322 | }
323 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/XYDomainMutilineAnnotation.java:
--------------------------------------------------------------------------------
1 | package com.vgi.mafscaling;
2 |
3 | import java.awt.BasicStroke;
4 | import java.awt.Color;
5 | import java.awt.Font;
6 | import java.awt.Graphics2D;
7 | import java.awt.Paint;
8 | import java.awt.Shape;
9 | import java.awt.Stroke;
10 | import java.awt.geom.Line2D;
11 | import java.awt.geom.Point2D;
12 | import java.awt.geom.Rectangle2D;
13 | import java.util.Arrays;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 | import org.jfree.chart.annotations.AbstractAnnotation;
17 | import org.jfree.chart.annotations.XYAnnotation;
18 | import org.jfree.chart.axis.ValueAxis;
19 | import org.jfree.chart.entity.ChartEntity;
20 | import org.jfree.chart.entity.EntityCollection;
21 | import org.jfree.chart.plot.Plot;
22 | import org.jfree.chart.plot.PlotRenderingInfo;
23 | import org.jfree.chart.plot.XYPlot;
24 | import org.jfree.chart.ui.RectangleEdge;
25 | import org.jfree.text.TextUtilities;
26 | import org.jfree.ui.LengthAdjustmentType;
27 | import org.jfree.ui.RectangleAnchor;
28 | import org.jfree.ui.RectangleInsets;
29 | import org.jfree.ui.TextAnchor;
30 | import org.jfree.util.ShapeUtilities;
31 |
32 | public class XYDomainMutilineAnnotation extends AbstractAnnotation implements XYAnnotation {
33 | private static final long serialVersionUID = -6654378602438420832L;
34 |
35 | public class AxisAnnotationEntity extends ChartEntity {
36 | private static final long serialVersionUID = -6152531745073523000L;
37 | private int rendererIndex;
38 | private AbstractAnnotation annotation;
39 |
40 | public AxisAnnotationEntity(Shape hotspot, int rendererIndex, AbstractAnnotation annotation) {
41 | super(hotspot, "", "");
42 | this.rendererIndex = rendererIndex;
43 | this.annotation = annotation;
44 | }
45 |
46 | public int getRendererIndex() {
47 | return this.rendererIndex;
48 | }
49 |
50 | public AbstractAnnotation getAnnotation() {
51 | return this.annotation;
52 | }
53 |
54 | public void setRendererIndex(int index) {
55 | this.rendererIndex = index;
56 | }
57 |
58 | public boolean equals(Object obj) {
59 | if (obj == this)
60 | return true;
61 | if (!super.equals(obj))
62 | return false;
63 | if (!(obj instanceof AxisAnnotationEntity))
64 | return false;
65 | AxisAnnotationEntity that = (AxisAnnotationEntity) obj;
66 | if (this.rendererIndex != that.rendererIndex)
67 | return false;
68 | return true;
69 | }
70 | }
71 |
72 | private HashMap labels = new HashMap();
73 | private Stroke stroke = new BasicStroke(1.0f);
74 | private Paint paint = Color.WHITE;
75 | private Font labelFont = new Font("Verdana", Font.PLAIN, 11);
76 | private RectangleAnchor labelAnchor = RectangleAnchor.TOP;
77 | private TextAnchor labelTextAnchor;
78 | private double value;
79 |
80 | public void setDefaultPaint(Paint paint) {
81 | this.paint = paint;
82 | }
83 |
84 | public double getValue() {
85 | return this.value;
86 | }
87 |
88 | public void setValue(double value) {
89 | this.value = value;
90 | fireAnnotationChanged();
91 | }
92 |
93 | public void setLabelAnchor(RectangleAnchor labelAnchor) {
94 | this.labelAnchor = labelAnchor;
95 | }
96 |
97 | public void setLabelTextAnchor(TextAnchor labelTextAnchor) {
98 | this.labelTextAnchor = labelTextAnchor;
99 | }
100 | /*
101 | public void addLabel(String label, Paint color, boolean notify) {
102 | labels.put(color, new String[] { label, "" });
103 | if (notify)
104 | fireAnnotationChanged();
105 | }*/
106 |
107 | public void addLabel(String label, Paint color, String label2, boolean notify) {
108 | labels.put(color, new String[] { label, label2 });
109 | if (notify)
110 | fireAnnotationChanged();
111 | }
112 |
113 | public void removeLabel(Paint paint2) {
114 | labels.remove(paint2);
115 | fireAnnotationChanged();
116 | }
117 |
118 | public void clearLabels(boolean notify) {
119 | labels.clear();
120 | if (notify)
121 | fireAnnotationChanged();
122 | }
123 |
124 | public int count() {
125 | return labels.size();
126 | }
127 |
128 | public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea, ValueAxis domainAxis, ValueAxis rangeAxis, int rendererIndex, PlotRenderingInfo info) {
129 | if (labels.size() == 0)
130 | return;
131 | if (info == null)
132 | return;
133 | EntityCollection entities = info.getOwner().getEntityCollection();
134 | if (entities == null)
135 | return;
136 | int index = plot.getDomainAxisIndex(domainAxis);
137 | if (index < 0)
138 | return;
139 | RectangleEdge axisEdge = Plot.resolveDomainAxisLocation(plot.getDomainAxisLocation(index), plot.getOrientation());
140 | double value = domainAxis.valueToJava2D(this.value, dataArea, axisEdge);
141 | Line2D line = null;
142 | if (axisEdge.equals(RectangleEdge.LEFT))
143 | line = new Line2D.Double(dataArea.getMinX(), value, dataArea.getMaxX(), value);
144 | else if (axisEdge.equals(RectangleEdge.RIGHT))
145 | line = new Line2D.Double(dataArea.getMaxX(), value, dataArea.getMinX(), value);
146 | else if (axisEdge.equals(RectangleEdge.TOP))
147 | line = new Line2D.Double(value, dataArea.getMinY(), value, dataArea.getMaxY());
148 | else if (axisEdge.equals(RectangleEdge.BOTTOM))
149 | line = new Line2D.Double(value, dataArea.getMaxY(), value, dataArea.getMinY());
150 | if (line == null)
151 | return;
152 | g2.setPaint(paint);
153 | g2.setStroke(stroke);
154 | g2.draw(line);
155 | drawLabels(g2, dataArea, line.getBounds2D(), axisEdge);
156 | AxisAnnotationEntity entity = new AxisAnnotationEntity(ShapeUtilities.createLineRegion(line, 6), rendererIndex, this);
157 | entities.add(entity);
158 | }
159 |
160 | protected void drawLabels(Graphics2D g2, Rectangle2D dataArea, Rectangle2D markerArea, RectangleEdge axisEdge) {
161 | g2.setFont(labelFont);
162 | int offset = 0;
163 | Point2D coordinates;
164 | for (Map.Entry entry : labels.entrySet()) {
165 | RectangleInsets labelOffset = new RectangleInsets(2 + offset, 5, 2, 5);
166 | offset += 20;
167 | if (RectangleEdge.isLeftOrRight(axisEdge))
168 | coordinates = RectangleAnchor.coordinates(labelOffset.createAdjustedRectangle(markerArea, LengthAdjustmentType.CONTRACT, LengthAdjustmentType.EXPAND), labelAnchor);
169 | else
170 | coordinates = RectangleAnchor.coordinates(labelOffset.createAdjustedRectangle(markerArea, LengthAdjustmentType.EXPAND, LengthAdjustmentType.CONTRACT), labelAnchor);
171 | g2.setPaint(entry.getKey());
172 | String label = entry.getValue()[0];
173 | if (entry.getValue()[1].length() > 0) {
174 | char[] array = new char[(int)(entry.getValue()[1].length() * 1.8)];
175 | Arrays.fill(array, ' ');
176 | label += new String(array);
177 | }
178 | TextUtilities.drawRotatedString(label, g2, (float) coordinates.getX(), (float) coordinates.getY(), labelTextAnchor, 0, TextAnchor.TOP_CENTER);
179 | if (entry.getValue()[1].length() > 0) {
180 | g2.setPaint(paint);
181 | Shape shape = TextUtilities.calculateRotatedStringBounds(entry.getValue()[0], g2, (float) coordinates.getX(), (float) coordinates.getY(), labelTextAnchor, 0, TextAnchor.TOP_CENTER);
182 | TextUtilities.drawRotatedString(entry.getValue()[1], g2, (float) shape.getBounds().getMaxX(), (float) coordinates.getY(), labelTextAnchor, 0, TextAnchor.TOP_CENTER);
183 | }
184 | }
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/closedloop.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool is originally based on Mickeyd2005's spreadsheet, however changes were made as per Kodename47 suggestions. \
5 | The usage guide is based on wrxsti-l's post. Big thanks to all who have been active in MAF scaling discussions and providing methodology - williaty, Rene2.5RS, and others.
A special 'thank you' to Td-d and Kodename47 for providing feedback.
\
6 | Logic:
\
7 | Logged average LTFT and STFT correction are fitted to your current MAF scaling and new scaling is suggested.
\
8 |
The Correction Error is calculated as LTFT + STFT per cell based on how far your data point is from the cell. The closest cell is determined by lookup in the original MAF scale table using (load * rpm / 60.0) MAF value.
\
9 |
The Total Correction % is then calculated for each cell as average of mean and mode of Correction Error values.
\
10 |
The correction will only be applied to cells where count of corrections is more than the cell hit count specified in settings.
\
11 |
The corrected g/sec is calculated from the Total Correction % and the current g/sec as current_gsec * ((tot_corr% / 100) + 1).
\
12 |
Also, please note that collected data and correction applied may be greater than the full MAF scaling voltage and thus several of the first table cell would be uncorrected. In this case the first calculated Total Correction % value is applied to all cells prior to it except the first cell.\
13 |
\
14 |
Usage:
\
15 | You may not nail the calibration in one shot, so rinse and repeat until you're happy with the scaling. Also, it is VERY important that you collect data at a constant temperature. If you collect data at 30F one day and then 60F next week, it will totally screw up the process.
\
16 | Data Tab
\
17 | Note:
\
18 | use right mouse button click to see the menu of available actions on tables.
\
19 | for quick selection of cells in a table click on the first cell, hold shift key and click on the last cell; all the cells in between will be highlighted.
\
20 | \
21 | - Go for a drive to ensure car as it normal operating temp (5 minute drive should be fine in warm areas, longer for colder areas).
\
22 | - Make sure you're logging "Time", "MAF Voltage", "IAT", "CL/OL Status", "AFR Learning (LTFT)", "AFR Correction (STFT)", "AFR Stock Sensor", "Engine Speed", and "Engine Load (g/rev)". Additionally you should log "Manifold Absolute Pressure (psi absolute)" if you intend to use "Primary Open Loop Fueling" table and its Y-Axis is MAP-based (instead of load).
\
23 | \
24 | - NO SUDDEN THROTTLE CHANGES - it is very important to keep throttle as smooth and consistent as possible. It is best to ONLY enable/start logging once you are at the signed speed for the street you are driving on and there is a good stretch of road for logging (ie. no stop lights etc). If you need to stop, slowdown, speed up quickly - you should disable/stop logging. Then when you are back at correct speed, enable/start logging again. If you continue to log data while you stop, start, speed up, slow down, with constant sudden throttle changes, the data collected can skew the results and your MAF scaling can be dramatically out for any MAFv where these sudden throttle changes occurred.
\
25 | - RECORD AT LEAST 30 minutes of highway/freeway driving in your top gear as close to the point where you switch from closed loop to open loop (eg if you use RomRaider for logging you can see when you switch from closed loop to open loop as the "CL/OL Fueling" value will change from "8" to "10"). A highway/freeway with a long, constant incline is best - this will allow you to gather data points for the upper most region of the closed loop section of your MAF Sensor Scaling table (MAFv of around 2.8v).
\
26 | - RECORD AT LEAST 30 minutes of general driving. This can include driving to/from shops, movies, work etc.
\
27 | - RECORD AT LEAST 15 minutes of slow speed driving - around an empty car park is best.
\
28 | \
29 |
\
30 | - Open your tune in RomRaider.
\
31 | - Expand "Mass Airflow /Engine Load" tables group and copy "MAF Sensor Scaling" table by clicking "Edit"->"Copy Table" into the first cell of "Current MAF Scaling" table on the tool. If you copy MAF scaling from a vertically laid out table then use "Paste Vertical" right click menu option.
\
32 | - Click "POL Fueling" button to set open loop fueling data (optional, does not affect scaling calculations). Open loop fueling table X/Y-Axis are used to display "AFR Average" and "AFR Cell Hit Count" tables which serve only informational purpose.
\
33 | \
34 | - Open your tune in RomRaider.
\
35 | - Expand "Fueling - Primary Open Loop" tables group and copy "Primary Open Loop Fueling" table by clicking "Edit"->"Copy Table" into the first cell of "Primary Open Loop Fueling" table on the tool.
\
36 | - Click "Validate" button to make sure all is fine (validation is done on setting the table as default and saving it or on submitting the table so it's not required).
\
37 | - Most likely the Primary Open Loop Fueling table will stay the same, so for auto-loading next time you can click on "Set Default" and save this table in a new file. If you do have another tune with a different Primary Open Loop Fueling table, you can click on "Clear" to clear out table, then paste data from second Primary Open Loop Fueling table, click on "Set Default" and save this table in a new file. To switch between different Primary Open Loop Fueling tables saved in files click on "Clear" to clear table, then click on "Load" to load data from file, then click on "Set Default" so that next time it will be loaded automatically.
\
38 |
\
39 | - Now you have two ways to proceed:
\
40 | \
41 | - If you have saved data from previous run and would like to see the graphs or modify some data manually you can load that run using "Load" button.
\
42 | - If you just log file(s) (make sure that log starts with column headers) then click on "Load Log" button, select your log file, select asked columns from log file AND set desired filters values. Please pay attention to filters on some columns to filter out noisy data. Once the log file is processed you should see closed loop data populated in the table. Repeat this procedure to load more log files - the data will be appended to the table.
\
43 |
\
44 | \
45 | - At this point you can save all the input data for future reference or re-scaling by clicking on "Save" button at the top bar.
\
46 | - Click on "GO" button at the top bar right corner to generate AFR data table and corrected MAF curve.
\
47 | - Click on the "Chart" tab to see MAF corrected curve.
\
48 |
\
49 | Chart Tab
\
50 | Note:
\
51 | use mouse wheel to zoom in/out.
\
52 | use Ctrl + left mouse button click to move the chart left/right/up/down (useful when chart is zoomed).
\
53 | hover mouse over a point to see point values for x/y axes.
\
54 | use left mouse button click-and-drag a curve point to move that point up/down (enabled for smoothing chart only).
\
55 | apply smoothing only to Closed Loop points.
\
56 | \
57 | - You can click on "dV/dt" checkbox to view dV/dt scatter plot over time.
\
58 | - You can click on "IAT" checkbox to view IAT scatter plot over time.
\
59 | - You can click on "Trims/RPM" checkbox to view trims change over RPM change and the trend line.
\
60 | - You can click on "Mean/Mode" checkbox to view trims change over Maf Voltage change and the Mean and Mode curves.
\
61 | - You can click on "Total Correction" checkbox to view Total Correction % placement (scaling is on the right hand side).
\
62 | - You can click on "Current" checkbox to view current MAF curve pasted into input "Current MAF Scaling" table on the "Data" tab.
\
63 | - You can click on "Corrected" checkbox to view corrected MAF curve generated based on the CL data.
\
64 | - You can click on "Smoothed" checkbox to view smoothed MAF curve. Keep in mind that initially this curve is the same as corrected curve. It will change if you apply smoothing and/or manual correction(s).
\
65 | - Resulting MAF Scaling table is at the bottom of the Chart Tab screen.
\
66 |
\
67 | - This is where you have now two ways to proceed:
\
68 |
\
77 | \
78 | - All smoothing changes are immediate and can be seen on the smoothing graph.
\
79 | - If you have overdone smoothing, simply click on "Reset" button to set the smoothed curve back to corrected curve.
\
80 | - You can apply smoothing by selecting the cells in MAF scaling table and the smoothing degree and then clicking "Apply" button. Smoothing degree is simply a moving window size where 3 - uses 1 cell to left and right, 5 - uses 2 cells to left and right, and 7 - uses 3 cells to left and right.
\
81 | - Please note that due to how smoothing algorithm works one, two, or three (depending on smoothing degree you chose) the first cells and last cell will not get modified. You can raise/lower those manually if needed by the same value the cell after or cell before was modified.
\
82 | - BE CAREFULL not to smooth too much or you will end up making your MAF scaling worse. General suggestion is to apply either degree "3" or "5" once.
\
83 | - In addition, you can manually smooth values by either dragging the smoothed curve slope line's point or by applying custom +/- value to the highlighted cells using buttons on the left from the result table. Keep in mind that selection of all cells will raise or lower the whole curve. Thus you can raise certain parts of the curve by selecting appropriate cells.
\
84 | - Finally, there is a compare screen. You copy original MAF scaling and the new MAF scaling and see change % difference. You can also manually alter change % difference if you feel it's needed and it will modify you new MAF scaling.
\
85 | - Once you have smoothed the data to your liking, copy the data to your "MAF Sensor Scaling" table. If your table has a vertical layout, use "Copy Vertical" from right-click menu.
\
86 |
\
87 | \
88 | \
89 | \
90 | Once you have copied your new MAF scaling values from the result table to your ROM, save a new ROM with the changes made.\
91 | Flash the modified ROM to your ECU and do another set of logs.\
92 | \
93 | More info can be found here
\
94 | \
95 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/loadcomp.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool addition was requested by Kodename47 and is based on his tweaks to Airboy's Load Comp spreadsheet.\
5 | The tool should work for Load Comp table tuning based on Manifold Pressure as well as Per-Cylinder Compensation based on Injector Pulse Width as long as proper params are logged in proper units (see the note in Usage section).\
6 |
Logic:
\
7 | The tool is for adjusting Load Compensation table based on an adjustment which is calculated as a average between mean and mode of AFR error % values for a specific cell.
\
8 |
The correction will only be applied to cells where count of corrections is more than the cell hit count specified in settings.
\
9 |
The logic is as follow:
\
10 |
Caclulate AFR error % for each row in a log as: \
11 |
\
12 |
Code:
\
13 |
AFR error % = LTFT + STFT
\
14 |
\
15 | Get per cell log data samples by finding nearest cell based on RPM and Manifold Pressure. If sample set is less than the cell hit count - discard it.\
16 |
For each sample set with count more than the specified cell hit count calculate mean value and mode value for AFR error %. \
17 |
Calculate AFR error% for cell as: \
18 |
\
19 |
Code:
\
20 |
cell_error = (err_mean + err_mode) / 2
\
21 |
\
22 | Calculate correction for cell as: \
23 |
\
24 |
Code:
\
25 |
cell_corr = 1 + cell_error/100
\
26 |
\
27 | Calculate new cell value as: \
28 |
Table values as ratio (EcuTek):\
29 |
\
30 |
Code:
\
31 |
new_val = cell_corr * orig_val
\
32 |
\
33 | Table values as % from 100 (RomRaider):\
34 |
\
35 |
Code:
\
36 |
new_val = cell_corr * (100 + orig_val) - 100
\
37 |
\
38 | Usage:
\
39 | You really need to nail MAF scaling first!
\
40 | Note:
\
41 | Depending on what tuning program you use have a look at "Engine Load Compensation" table and see what X-Axis is defined in and units (eg "Manifold Absolute Pressure (Bar)" or "Manifold Relative Pressure (psi sea level)")
\
42 | you will need to log exactly what the table X-Axis specifies.
\
43 | \
44 |
Eg people with OP2 and using RomRaider would have to log MRP (psi relative sea level):
\
45 |
scalingrpn = x,760,-,0.01933677,*
\
46 |
\
47 | \
48 | - Log "Time%", "Engine Speed", "Throttle Angle %", "IAT", "AFR Learning (LTFT)", "AFR Correction (STFT)", "MAF Voltage", "AFR Stock Sensor", and "Manifold Pressure" (see the note above). \
49 |
- Open your tune in RomRaider.
\
50 | - Expand "Mass Airflow /Engine Load" tables group and copy "Engine Load Compensation (MP)" table by clicking "Edit"->"Copy Table" into the first cell of "Current MP table" table on the tool.
\
51 | - Click on "Load Log" button, select your log file(s), select asked columns from log file AND set desired filters values. Once the log file is processed you should see data populated in the table with calculated total trims and dV/dt. At this point you may review the charts of the data
\
52 | - Click on "GO" button at the top bar right corner to generate new Load Compensation data table.
\
53 | - Copy the data to your "Engine Load Compensation (MP)" table.
\
54 | - Once you have copied your new Load Compensation table values from the result table to your ROM, save a new ROM with the changes made.
\
55 |
\
56 | More info can be found here
\
57 | \
58 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/logstats.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool was done based on screenshot from BrzEdit Log Viewer.\
5 | Logic:
\
6 | The tool is to help in analyzing the log data and visualizing data distribution by applying different statistics methods and filters.\
7 |
Usage:
\
8 | \
9 | - Select log file(s) to be analyzed. Please note that if more than one files are being opened the Time column would not be added to the drop downs. In addition, all files must have the same columns.
\
10 | - Select X-Axis column from available columns in log file (eg Engine Load).
\
11 | - Select Y-Axis column from available columns in log file (eg Engine Speed).
\
12 | - Select Data column to be analyzed from available columns in log file (eg AFR).
\
13 | - Set X-Axis rounding - 'step' (eg 0.1 for Engine Load) or set the fixed scaling values for X-Axis column (please note that setting step takes priority over fixed scale values).
\
14 | - Set Y-Axis rounding - 'step' (eg 200 for Engine Speed) or set the fixed scaling values for Y-Axis column (please note that setting step takes priority over fixed scale values).
\
15 | - Select statistics method for analyzes (eg Mean).
\
16 | - Optionally set the filter(s) columns, comparison method, and value to be compared against. Please note that the row log data value for Data column will be compared against the filter. \
17 | Also note that for equality the Data column values are rounded to the same number of decimal points as the filter input value.
\
18 | - Click on 'GO' button.
\
19 |
\
20 | \
21 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/logview.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | The 'Data' tab was initially aped after www.datazap.me which is an excellent web-based application. \
5 | The reasons for its development were to be able to look at logs without a need for an internet connection \
6 | and be able to process fairly large files (OP2 files can be pretty large, eg 8Mb for 20 mins).\
7 | The 'Log Replay' functionality (map tracing) was added to help in analyzing the log data and visualizing data \
8 | distribution by interpolating value from 3D table, highlighting cells used for value interpolation, and marking \
9 | the most significant cell.\
10 |
The WOT Pulls tab is added based on suggestion from covertrussian to be able to look at mutiple WOT pulls from the same or different files.\
11 |
Logic:
\
12 | The tool displays data in a table format, allows single column filtering, and displays data curves based on selected columns.\
13 |
Usage:
\
14 | Data Tab\
15 | \
16 | - Click on 'Load Log File' icon to load desired log file.
\
17 | - To apply filter to one column at a time please select column and filter comparison, specify filter value, and click 'Set' button. \
18 | In order to clear filter - clear filter value and click 'Set' button.
\
19 | - Right-click on column header for sorting menu.
\
20 | - Click on desired column header to display data curves or you can switch to column headers view and select columns from a list. Please \
21 | note that curves are displayed based on filtered data set but disregards applied sorting.
\
22 | - Multiple column can be selected to display multiple curves.
\
23 | - To zoom in the plot use mouse to select area from top-left to right-bottom by clicking and dragging the cursor.
\
24 | - To zoom out the plot use mouse to select area from right to left by clicking and dragging the cursor.
\
25 | - Use zoom to increase performance, when the plot is zoomed in the program works faster.
\
26 | - Use Ctrl + left mouse button click and drag the mouse to move the chart.
\
27 | - If plot is zoomed in then adding or removing columns to plot do not automatically rescale the plot. So please zoom out first.
\
28 | - Drag the splitter bar to increase/decrease the panels. You can also click on arrows on the left-hand side of the splitter bar to extend desired panel
\
29 | - Log Replay:
\
30 | \
31 | - Click on 'Log Replay to bring up the replay window.
\
32 | - Select the X-Axis of the 3D table you're planning to use.
\
33 | - Select the Y-Axis of the 3D table you're planning to use.
\
34 | - If you have you can select the Data column from your log file which your 3D table represents (eg AFR column for Primary Open Loop Fueling table).
\
35 | - Click 'New Play Table' button to open a new window and paste the 3D table into the first cell.
\
36 | - Repeat the process if you'd like to use more than one table.
\
37 | - Log replay starts from the current cell in the table and goes until the end of the file.
\
38 | - If you want to replay just a specific area of the log file you can set start and/or end rows using left and right mouse click to set the markers:
\
39 | \
40 | - Left-click sets the first bar for the area.
\
41 | - If you don't want to run until the end of the file, right-click to set the second bar to indicate the end of replay area.
\
42 |
\
43 | - The replay can be pretty slow when big log file is loaded. To speed up the replay you should zoom in the plot to the area you'd like to replay. \
44 | You can also uncheck all the columns or those that you don't necessarily want to watch on the plot screen.\
45 |
\
46 |
\
47 |
\
48 |
3D Chart\
49 | \
50 | - Click on 'X-Axis' to select X data column
\
51 | - Click on 'Y-Axis' to select Y data column
\
52 | - Click on 'Plots' to select data column(s) to be plotted against X/Y Axes
\
53 | - Click on 'View' button to plot data
\
54 |
\
55 |
WOT Pulls\
56 | \
57 | - Click on 'Load Log' to load WOT pull data from one or more files.
\
58 | - Select 'Engine Speed', 'Throttle Angle' columns and 'WOT stationary point' for your log file and click 'OK' button. (You will need to do this for each file being loaded in case they have different headers)
\
59 | - All pulls will appear on the left hand side of the split panel under their file name(s).
\
60 | - Select the WOT pulls you would like to view/compare.
\
61 | - Select the curves to display.
\
62 | - Select the view mode:\
63 |
\
64 | - RPM - all data points are plotted in ascending order of corresponding RPM value for the same row.
\
65 | - RPM (skip down spikes) - all data points are plotted in ascending order of corresponding RPM value for the same row, however while log data is processed processed all subsequent rows that have RPM value lower than the previous row will be skipped as RPM is expected to increase constantly during WOT.
\
66 | - Time (RPM aligned) - all data points are plotted in ascending order of corresponding Time value for the same row, however the start of each curve is aligned by RPM - another words it starts at a time other curve(s) has(ve) reached RPM this WOT pull starts at.
\
67 |
\
68 | \
69 | - Click on 'View' button.
\
70 | - You can export selected WOT Pulls into separate CSV files (eg to use for Virtual Dyno) - click on 'Export Selected Pulls' button and pick a directory to save files into.
\
71 |
\
72 | \
73 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/mafiatcomp.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool addition is a port of Kodename47's spreadsheet.\
5 | Logic:
\
6 | The tool is for adjusting MAF IAT Compensation table based on an adjustment which is calculated as a average between mean and mode of AFR correction values for a specific cell.
\
7 |
The correction will only be applied to cells where count of corrections is more than the cell hit count specified in settings.
\
8 |
The logic is as follows:
\
9 | <>Calculate AFR error correction ratio for each row in a log as: \
10 |
\
11 |
Code:
\
12 |
CL corr = (100 + LTFT + STFT) / 100
\
13 |
OL corr = (AFR / ((100 - (LTFT + STFT)) / 100)) / ECU Target AFR
\
14 |
\
15 | Get per cell log data samples by finding nearest cell based on IAT and MAF. If sample set is less than the cell hit count - discard it.\
16 |
Calculate cell correction as: \
17 |
\
18 |
Code:
\
19 |
cell_corr = (corr_mean + corr_mode) / 2
\
20 |
\
21 | Calculate new cell value as: \
22 |
Table values as ratio (EcuTek):\
23 |
\
24 |
Code:
\
25 |
new_val = cell_corr * orig_val
\
26 |
\
27 | Table values as % from 100 (RomRaider):\
28 |
\
29 |
Code:
\
30 |
new_val = cell_corr * (100 + orig_val) - 100
\
31 |
\
32 | Usage:
\
33 | You really need to nail MAF scaling first!
\
34 | Note:
\
35 | Depending on what tuning program you use have a look at "MAF (IAT) Compensation" table and see in what units X-Axis (IAT) is defined in
\
36 | you will need to log in the same exactly units what the table X-Axis specifies.
\
37 | \
38 | - Log "Time", "Engine Speed", "Throttle Angle %", "IAT" (see the note above), "AFR Learning (LTFT)", "AFR Correction (STFT)", "MAF Voltage", "Wideband AFR", "Mass Airflow", "CL/OL Status", and if your logging tool has it - "Commanded AFR" / "Fueling Final Base" to use as "ECU Target AFR". Additionally if you intend to use "Primary Open Loop Fueling" table (i.e. you do not have "Commanded Afr" or "FFB" available) you must log "Engine Load (g/rev)" if table has load-based Y-Axis or "Manifold Absolute Pressure (psi absolute)" if table's Y-Axis is MAP-based.\
39 |
- Open your tune in RomRaider.
\
40 | - Expand "Mass Airflow /Engine Load" tables group and copy "MAF Compensation (IAT)" table by clicking "Edit"->"Copy Table" into the first cell of "Current MAF IAT compensation table" table on the tool.
\
41 | - \If you did not log "Commanded Afr" / "Fueling Final Base", click "POL Fueling" button to set open loop fueling data.
\
42 | \
43 | - Open your tune in RomRaider.
\
44 | - Expand "Fueling - Primary Open Loop" tables group and copy "Primary Open Loop Fueling" table by clicking "Edit"->"Copy Table" into the first cell of "Primary Open Loop Fueling" table on the tool.
\
45 | - Click "Validate" button to make sure all is fine (validation is done on setting the table as default and saving it or on submitting the table so it's not required).
\
46 | - Most likely the "Primary Open Loop Fueling" table will stay the same, so for auto-loading next time you can click on "Set Default" and save this table in a new file. If you do have another tune with a different "Primary Open Loop Fueling" table, you can click on "Clear" to clear out table, then paste data from second "Primary Open Loop Fueling" table, click on "Set Default" and save this table in a new file. To switch between different Primary Open Loop Fueling tables saved in files click on "Clear" to clear table, then click on "Load" to load data from file, then click on "Set Default" so that next time it will be loaded automatically.
\
47 |
\
48 | \
49 | - Click on "Load Log" button, select your log file(s), select asked columns from log file AND set desired filters values. Once the log file is processed you should see data populated in the table with calculated AFR Correction and dV/dt. At this point you may review the charts of the data
\
50 | - Click on "GO" button at the top bar right corner to generate new MAF IAT Compensation data table.
\
51 | - Copy the data to your "MAF Compensation (IAT)" table.
\
52 | - Once you have copied your new MAF IAT Compensation table values from the result table to your ROM, save a new ROM with the changes made.
\
53 |
\
54 | More info can be found here
\
55 | \
56 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/mafolclmerge.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Logic:
\
4 | The tool is to help merging and fitting Open Loop and Closed Loop generated curves or just certain parts of the curve with at least 10 points. \
5 |
Please keep in mind that the tool simply applies fitting algos (none of which were specifically customized for MAF curve) for a best fitting of generated curve points (voltage, g/s) thus there is no guarantee that the fitted curve would make the best MAF curve.\
6 |
This tool can also be used as pure curve fitting/smoothing if the same MAF curve is pasted in OL and CL tables.\
7 |
The logic is as follow:
\
8 |
The g/s values from Closed Loop curve are taken if voltage value for the point is less than or equal to the value specified in "CL Max V" text box. \
9 | In the same manner g/s values from Open Loop curve are taken if voltage value for the point is greater than or equal to the value specified in "OL Min V" text box. \
10 | All the g/s values for points where voltage falls in between the "CL Max V" and "OL Min V" will be calculated as average of CL/OL g/s values. \
11 | If "Fitting Algo" is left as "Auto Select"tThe program will run the curve through all defined fitting algorithms and pick the best fit \
12 | (A measure of "goodness of fit" where 1.0 is best. Approaches R^2 if the number of points is much larger than the number of fit parameters. \
13 | For power, exp by linear regression and 'Rodbard NIH Image', this is calculated for the fit actually done, not for the residuals of the original data). \
14 | However you can change the algo selection and see if anything will provide the fit you prefer. \
15 |
Usage:
\
16 | \
17 | - Set "CL Max V" value, all g/s values from Closed Loop curve will be used until this value.
\
18 | - Set "OL Min V" value, all g/s values from Open Loop curve will be used from this value on.
\
19 | - Optionally select fitting algorithm, otherwise the program will determine the best one based on algo fit goodness.
\
20 | - Paste generated OL curve into the first table - Open Loop MAF Scaling.
\
21 | - Paste generated CL curve into the second table - Closed Loop MAF Scaling.
\
22 | - Select curve fitting algorithm to apply.
\
23 | - The third table - Merged MAF Scaling should be populated and changed automatically.
\
24 | - Copy the data to your "MAF Sensor Scaling" table.
\
25 | - Once you have copied your new MAF scaling values from the result table to your ROM, save a new ROM with the changes made.
\
26 | - Flash the modified ROM to your ECU.
\
27 |
\
28 | \
29 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/mafrescale.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool development has been driven by Kodename47.\
5 | Logic:
\
6 | The tool is about changing the MAF scale but keeping the curve the same. As with all mapping it's a resolution trade off. \
7 | The larger the scale, the less accurate that it is. If you're NA, the likelihood that the maximum voltage you are logging \
8 | at max RPM is little over 4.1/4.2v. Therefore the scale going all the way to 5v is a waste of potentially better resolution. \
9 | The same applies to several points at the start of the curve. You can only use the same amount of data points so by closing \
10 | the gaps, you're improving the accuracy due the way the ECU interpolates the cells. So by lowering maximum V value and removing \
11 | some unused V down low the new scale increases resolution for those cell where difference between points starts increasing and \
12 | therefore much more accurate.\
13 |
The logic is as follow:
\
14 |
First the point grater or equal to Min V is found and mid point is calculated between that point and the first point - reference point. \
15 | This is done in case your MAFv drops into the low range of the MAF scaling, the three points should provide a fair resolution.\
16 |
Mode of spacing between points is calculated and Max Unchanged value determined as the point after which spacing starts increasing from Mode. \
17 | The Max Unchanged value though can be reset from suggested by the user.\
18 |
Once the original MAF scale is pasted the new MAF voltage scale is calculated where first point is unchanged, second point is the mid point between first and third point, \
19 | third point is point greater or equal to Min V, then original values are copied until Max Unchanged point, and finally rescaled points calculated based on original \
20 | scaling % increase between sections of two points.\
21 |
After the new MAF Voltage values are calculated, for each MAF Voltage cell a new GS value is interpolated from the original curve for the new MafV using linear interpolation.\
22 |
Usage:
\
23 | \
24 | - Put the new maximum desired voltage into the text box.
\
25 | - Put the new minimum voltage into the text box.
\
26 | - Paste original MAF scale into the top table.
\
27 | - Modify Unchanged MaxV if desired or paste different MafV values into new MAF scaling or modify manually to adjust the curve if needed.
\
28 | - Copy the data to your "MAF Sensor Scaling" table.
\
29 | - Once you have copied your new MAF scaling values from the result table to your ROM, save a new ROM with the changes made.
\
30 | - Flash the modified ROM to your ECU.
\
31 |
\
32 | \
33 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/openloop.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool is originally based on BadNoodle's spreadsheet, however changes were made as per Kodename47 suggestions. \
5 | The usage guide is based on wrxsti-l's post. Big thanks to all who have been active in MAF scaling discussions and providing methodology - williaty, Rene2.5RS, and others.
A special 'thank you' to Td-d and Kodename47 for providing feedback.
\
6 | Logic:
\
7 | Logged MAF voltage and AFR % error are fitted to your current MAF scaling and new scaling is suggested.
\
8 |
The raw AFR is calculated as wideband AFR / ((100 - (LTFT + STFT)) / 100). The AFR % error is calculated as (raw AFR - interpolated AFR) / interpolated AFR * 100), where interpolated AFR is interpolated from "Primary Open Loop Fueling" table or (raw AFR - ECU Target AFR) / ECU Target AFR * 100) if you log "Commanded AFR" / "Fueling Final Base" and set the "ECU Target AFR" column in settings.
\
9 |
The 'advantage' is that since a lot of the data points are between cells, it distributes the % error between cells based on how far your data point is from the cell value.
\
10 |
Say your maf was scaled like:
\
11 |
\
12 |
Code:
\
13 |
MAFv: 0 1 2 3 4 5
g/s: 0 10 20 30 40 50
\
14 |
and your data point was:
\
15 | mafv: 1.75
\
16 | % error: 10
\
17 | The idea is by distribution the data between cells you get a smoother scaling.
\
18 |
then the % error would get distributed like:
\
19 | \
20 |
Code:
\
21 |
MAFv: 0 1 2 3 4 5
g/s: 0 2.5 7.5 0 0 0
\
22 |
\
23 | Also, please note that collected data and correction applied may be less than the full MAF scaling voltage. In this case error correction is also applied to those table cells after the one corrected. The % error for those correction is calculated as average of 10 highest correction for the last cell. \
24 |
\
25 | Usage:
\
26 | You really need to nail CL portion of your MAF scaling first!
\
27 | You may not nail the calibration in one shot, so rinse and repeat until you're happy with the scaling. Also, it is VERY important that you collect data at a constant temperature. If you collect data at 30F one day and then 60F next week, it will totally screw up the process.
\
28 | Data Tab
\
29 | Note:
\
30 | use right mouse button click to see the menu of available actions on tables.
\
31 | for quick selection of cells in a table click on the first cell, hold shift key and click on the last cell; all the cells in between will be highlighted.
\
32 | \
33 | - Do several 3rd or 4th gear WOT logs from 2000 rpm to redline, log "Throttle Angle %", "AFR Learning (LTFT)", "AFR Correction (STFT)", "MAF Voltage", "AFR" from Wideband O2 (unless your car O2 is WB), and "Engine Speed". If your logging tool allows it, also log "Commanded Afr" or "Fueling Final Base" to use as "ECU Target AFR". Additionally if you intend to use "Primary Open Loop Fueling" table (i.e. you do not have "Commanded Afr" or "FFB" available) you must log "Engine Load (g/rev)" if table has load-based Y-Axis or "Manifold Absolute Pressure (psi absolute)" if table's Y-Axis is MAP-based.
\
34 | - If you have map switching option and log a single file with multiple maps then you must log "Commanded Afr" / "Fueling Final Base" as there is no on-the-fly switching of "Primary Open Loop Fueling" table.
\
35 | - Open your tune in RomRaider.
\
36 | - Expand "Mass Airflow /Engine Load" tables group and copy "MAF Sensor Scaling" table by clicking "Edit"->"Copy Table" into the first cell of "Current MAF Scaling" table on the tool. If you copy MAF scaling from a vertically laid out table then use "Paste Vertical" right click menu option.
\
37 | - \If you did not log "Commanded Afr" / "Fueling Final Base", click "POL Fueling" button to set open loop fueling data.
\
38 | \
39 | - Open your tune in RomRaider.
\
40 | - Expand "Fueling - Primary Open Loop" tables group and copy "Primary Open Loop Fueling" table by clicking "Edit"->"Copy Table" into the first cell of "Primary Open Loop Fueling" table on the tool.
\
41 | - Click "Validate" button to make sure all is fine (validation is done on setting the table as default and saving it or on submitting the table so it's not required).
\
42 | - Most likely the "Primary Open Loop Fueling" table will stay the same, so for auto-loading next time you can click on "Set Default" and save this table in a new file. If you do have another tune with a different "Primary Open Loop Fueling" table, you can click on "Clear" to clear out table, then paste data from second "Primary Open Loop Fueling" table, click on "Set Default" and save this table in a new file. To switch between different Primary Open Loop Fueling tables saved in files click on "Clear" to clear table, then click on "Load" to load data from file, then click on "Set Default" so that next time it will be loaded automatically.
\
43 |
\
44 | \
45 | - \If you did log "Commanded Afr" / "Fueling Final Base" then you should set the "ECU Target AFR" column name in settings screen while loading log file. If that column is left empty then "Primary Open Loop Fueling" table is used and values are interpolated from table (much slower).
\
46 | - Now you have two ways to proceed:
\
47 | \
48 | - If you have saved data from previous run and would like to see the graphs or modify some data manually you can load that run using "Load" button.
\
49 | - If you just have log file(s) (make sure that log starts with column headers) with WOT pulls, then click on "Load Log" button, select your log file with WOT runs, select asked columns from log file AND set desired filters values. Please pay attention to filters on some columns to filter out noisy data. Once the log file is processed you should see WOT pull tables on the tool populated with data. If you have more log files just repeat this procedure until all 12 tables are loaded.\
50 |
\
51 | - Maf Voltage Minimum - this filter will throw away all data rows from log file where MAFV is below the specified value.
\
52 | - WOT Stationary Point - this filter will throw away all data rows from log file where specified column (Throttle Angle, Accel Pedal Angle, or other) value is below the specified value.
\
53 | - AFR Error +/- % Value - this filter will throw away all data rows from log file where calculated AFR Error % is greater than or less than specified deviation % value.
\
54 | - Min WOT Enrichment - this is an override for values in Primary Open Loop Fueling table that exceed specified value. Some ROMs have "Minimum Primary Open Loop Enrichment (Throttle)" table which specifies minimum enrichment based on throttle position. Since this is a WOT MAF tool you should set this override to the value in that table set for the maximum throttle position. If your ROM does not have this table keep this value above 16
\
55 | - OL/CL Transition - Number of Rows to Skip - this option may be used because some rows at the start and end of WOT may be incorrect due to variable WB delay.
\
56 |
\
57 | \
58 |
\
59 | \
60 | - At this point you can save all the input data for future reference or re-scaling by clicking on "Save" button at the top bar.
\
61 | - Click on "GO" button at the top bar right corner to generate corrected MAF curve. The "Chart" tab will open once data is processed.
\
62 |
\
63 | Chart Tab
\
64 | Note:
\
65 | use mouse wheel to zoom in/out.
\
66 | use Ctrl + left mouse button click to move the chart left/right/up/down (useful when chart is zoomed).
\
67 | hover mouse over a point to see point values for x/y axes.
\
68 | use left mouse button click-and-drag a curve point to move that point up/down (enabled for smoothing chart only).
\
69 | apply smoothing only to Open Loop points.
\
70 | \
71 | - You can click on "MafV/RPM" checkbox to view MAF Voltage change over RPM change.
\
72 | - You can click on "AFR Error" checkbox to view AFR Error % placement (scaling is on the right hand side).
\
73 | - You can click on "Current" checkbox to view current MAF curve pasted into input "Current MAF Scaling" table on the "Data" tab.
\
74 | - You can click on "Corrected" checkbox to view corrected MAF curve generated based on the WOT pulls.
\
75 | - You can click on "Smoothed" checkbox to view smoothed MAF curve. Keep in mind that initially this curve is the same as corrected curve. It will change if you apply smoothing and/or manual correction(s).
\
76 | - Resulting MAF Scaling table is at the bottom of the Chart Tab screen.
\
77 |
\
78 | - This is where you have now two ways to proceed:
\
79 | \
100 | \
101 | - Once you have copied your new MAF scaling values from the result table to your ROM, save a new ROM with the changes made.
\
102 | - Flash the modified ROM to your ECU and do another set of WOT logs.
\
103 | - If you do 6 or so WOT pulls each time, you should be able to get your OL MAF scaling to under 2-3% (use "AFR Error" scattered plot for visualization) within a couple of revisions. It will take many more revisions if you only do 1 or 2 WOT pulls at a time.
\
104 |
\
105 | More info can be found here
\
106 | \
107 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/tablerescale.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool was requested by MFB.\
5 | Logic:
\
6 | The tool rescales existing 2D/3D tables. \
7 |
All the calculation are done as real numbers and no rounding is done at any step. The screen though does allow the user to display X/Y-Axis (headers) and data values as integers \
8 | as well as specify desired decimal precision number.\
9 |
There are two interpolation methods provided by the program: linear and cubic spline for 2D tables; bi-linear and bi-cubic spline for 3D tables.\
10 | ECU uses linear/bilinear interpolation, however when rescaling it may make sense to use cubic spline/bicubic spline to smooth the surface as cubic spline \
11 | interpolation may better match slopes and the concavities of each individual interpolating segment.\
12 |
If you're not sure which interpolation method to use it is always safe to use linear interpolation. If you're willing to play with the surface and values \
13 | you can open another instance of the program and try out cubic spline interpolation and then compare values and/or surfaces side by side.\
14 |
In any case, the rescaled table should be retuned based on new logs collected after rescaling.\
15 |
The logic is as follow:
\
16 |
If new value for X/Y header cell falls in the range of the current table then new value(s) are interpolated using user selected interpolation method. \
17 |
If new value for X/Y header cell falls outside of the range of the current table and "extrapolate" checkbox is selected then:\
18 |
\
19 | - the new value for 2D table is extrapolated based on values in the two nearest columns for horizontal table or rows for vertical table.
\
20 | - the new values for 3D table are calculated as 2D extrapolation for each row if column header value was modified or 2D extrapolation for each column if row header value was modified.
\
21 |
\
22 | Otherwise, if "extrapolate" checkbox is not selected, values from last/first column/row are used.\
23 | Note:
\
24 | Even 2D tables extrapolation is prone to error and it has a higher risk of producing meaningless data. For 3D tables extrapolation will be erroneous and \
25 | provided just as a convenience to get a starting point. \
26 | Usage:
\
27 | \
28 | - Paste your table into the first cell of the "Original Table".
\
29 | - Select interpolation method (default is linear).
\
30 | - Start modifying header values.
\
31 | - Once you start making your changes the 3D Chart panel will display the new surface for 3D table or new curve for 2D table.
\
32 | - You can reset your changes by clicking "Reset Rescaled" button.
\
33 | - You can change numeric precision and/or chose to display header values and/or data values as integers at any time.
\
34 |
\
35 | \
36 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/thrtlmaps.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool addition was requested and driven by Welaish.\
5 | Logic:
\
6 | The tool is to generate throttle plate versus accelerator pedal table where x-axis is accelerator pedal angle (%), y-axis is engine speed (RPM), and values are target throttle plate opening angle (%), which should help in making changes to any of the base tables.
\
7 | The logic is as follow:
\
8 |
Requested Torque (Accelerator Pedal) table is taken as a base and the resulting table will have the same X and Y Axis\
9 |
For every value in Requested Torque (Accelerator Pedal) table a new value is being calculated for resulting table.\
10 |
The calculated value is 2D bilinear interpolation for RPM from Requested Torque (Accelerator Pedal) and calculated ratio of Requested Torque (Accelerator Pedal) to Requested Torque Base (RPM).\
11 |
The latter ratio is calculated as: \
12 |
\
13 |
Code:
\
14 |
value = RequestedTorque (Accel Pedal) \\ RequestedTorque (RPM)
\
15 |
\
16 | Where RequestedTorque (RPM) is interpolated from Requested Torque Base (RPM) table based on RPM from Requested Torque (Accelerator Pedal) table.
\
17 | Usage:
\
18 | \
19 | - Open your tune in RomRaider.
\
20 | - Expand "Drive-By-Wire Throttle" tables group.
\
21 | - Copy "Requested Torque Base (RPM)" table by clicking "Edit"->"Copy Table" into the first cell of "Requested Torque - RPM" table on the tool (first table on top panel) using "Paste" if your table has vertical layout. If your table has horizontal layout use "Paste Vertical" right-click menu option to convert layout into vertical.
\
22 | - Copy "Requested Torque (Accelerator Pedal)" table by clicking "Edit"->"Copy Table" into the first cell of "Requested Torque - Accelerator Pedal" table on the tool (second table on top panel).
\
23 | - Copy "Target Throttle Plate Position (Requested Torque)" table by clicking "Edit"->"Copy Table" into the first cell of "Target Throttle Plate Position" table on the tool (third table on top panel).
\
24 | - Click on "GO" button at the top bar right corner to generate Throttle Plate vs Accelerator Pedal table.
\
25 |
\
26 | Note:
\
27 | Selecting cell in the "Requested Torque (Accelerator Pedal)" table will highlight all cells used for calculation in "Requested Torque Base (RPM)" and "Target Throttle Plate Position (Requested Torque)" tables as well as result cell in "Throttle Plate vs Accelerator Pedal" table.\
28 | \
29 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/vecalc.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool is a port of Merp's 32-Bit Speed Density Map Builder spreadsheet which is used to build a VE base map using your current MAF.
A special 'thank you' to 04ssti for testing this.
\
5 | There are essentially two main functions selectable via a drop down list:\
6 |
- MAF Builder - used to build Speed Density map based on your existing well working MAF scale by having your tune in MAF/SD mode
\
7 | - AFR Tuner - used to fine-tune existing SD table based on AFR. 'Closed Loop' or 'Open Loop' tuning can be selected when loading a log file
\
8 | Logic:
\
9 | The tool is for adjusting Speed Density VE table based on an adjustment which is calculated as a average of corrections for a specific table cell.
\
10 |
The correction will only be applied to cells where count of corrections is more than the cell hit count specified in settings.
\
11 |
The logic is as follow:
\
12 |
Get per cell log data samples by finding nearest cell based on RPM and Manifold Pressure. If sample set is less than the cell hit count - discard it.\
13 |
For each sample set with count more than the specified cell hit count calculate average error % value . \
14 |
Error % for MAF Builder: \
15 |
\
16 |
Code:
\
17 |
error % = (SD - MAF) / MAF) * 100
\
18 |
\
19 | Error % for AFR Tuner: \
20 |
\
30 | For MAF the new VE table value for the cell is set as original cell value - adjustment.\
31 |
For AFR the new VE table value for the cell is set as original cell value + adjustment.\
32 |
Usage:
\
33 | You really need to nail MAF scaling first!
\
34 | \
35 | - Log "Engine Speed", "Throttle Angle %", "Manifold Pressure", "IAT", "Wideband AFR" and/or "Stock AFR" (for CL/OL), "Mass Airflow", "Final Fueling Base", "Volumetric Efficiency", and "CL/OL Status". \
36 |
- Open your tune in RomRaider/Cobb AP and copy your current VE table into the first cell of "Current VE table" table on the tool.
\
37 | - Click on "Load Log" button, select your log file(s), select asked columns from log file AND set desired filters values. Once the log file is processed you should see data populated in the table
\
38 | - Select SD implementation you have from the drop down menu.
\
39 | - Select logged Manifold Pressure and units.
\
40 | - Select if you want to build SD correction based on MAF or based on AFR.
\
41 | - Click on "GO" button at the top bar right corner to generate new VE table data.
\
42 | - Copy the data to your SD table.
\
43 | - Once you have copied your new VE table values from the result table to your ROM, save a new ROM with the changes made.
\
44 |
\
45 | More info can be found here
\
46 | \
47 |
--------------------------------------------------------------------------------
/src/com/vgi/mafscaling/vvtcalc.properties:
--------------------------------------------------------------------------------
1 | usage=\
2 | \
3 | Credits:
\
4 | This tool development as well as this usage guide has been driven by Kodename47.\
5 | Logic:
\
6 | Logged VVT angles are compared to volumetric efficiency of each WOT pull allowing \
7 | changes to be made to VVT systems and compared for the best settings. The logged VVT \
8 | with the best VE will be the ideal VVT setting.\
9 | Logged intake air temperature, intake air volume, manifold absolute pressure and RPM are calculated to generate the volumetric efficiency.\
10 |
VE calculations are as follow:
\
11 | Temperature is in Fahrenheit, pressure is in Psi:\
12 |
\
13 |
Code:
\
14 |
\
15 | ve = (maf / ((map * 6894.76) / ((((iat - 32) / 1.8) + 273.15) * 287.05) * 1000)) / (121.9254 * rpm / 3456 * 0.0283 / 60) * 100\
16 |
\
17 |
\
18 | Temperature is in Fahrenheit, pressure is in Bar:\
19 | \
20 |
Code:
\
21 |
\
22 | ve = (maf / ((map * 100000) / ((((iat - 32) / 1.8) + 273.15) * 287.05) * 1000)) / (121.9254 * rpm / 3456 * 0.0283 / 60) * 100\
23 |
\
24 |
\
25 | Temperature is in Fahrenheit, pressure is in kPa:\
26 | \
27 |
Code:
\
28 |
\
29 | ve = (maf / ((map * 1000) / ((((iat - 32) / 1.8) + 273.15) * 287.05) * 1000)) / (121.9254 * rpm / 3456 * 0.0283 / 60) * 100\
30 |
\
31 |
\
32 | Temperature is in Celcius, pressure is in Psi:\
33 | \
34 |
Code:
\
35 |
\
36 | ve = (maf / ((map * 6894.76) / ((iat + 273.15) * 287.05) * 1000)) / (121.9254 * rpm / 3456 * 0.0283 / 60) * 100\
37 |
\
38 |
\
39 | Temperature is in Celcius, pressure is in Bar:\
40 | \
41 |
Code:
\
42 |
\
43 | ve = (maf / ((map * 100000) / ((iat + 273.15) * 287.05) * 1000)) / (121.9254 * rpm / 3456 * 0.0283 / 60) * 100\
44 |
\
45 |
\
46 | Temperature is in Celcius, pressure is in kPa:\
47 | \
48 |
Code:
\
49 |
\
50 | ve = (maf / ((map * 1000) / ((iat + 273.15) * 287.05) * 1000)) / (121.9254 * rpm / 3456 * 0.0283 / 60 ) * 100\
51 |
\
52 |
\
53 | Usage:
\
54 | This can be used to view changes in both single and dual VVT engines. VVT2 is optional. If you have dual VVT but are only \
55 | changing either intake or exhaust then VVT1 can be used for the tested system or both can be input for consistency for future use.\
56 | Log Parameters\
57 |
\
58 | - Throttle/Accelerator Angle
\
59 | - Engine Speed
\
60 | - VVT System #1 (Note: Use a log parameter that replicate the VVT table values, this may be different to actual VVT angle dependent on the system)
\
61 | - VVT System #2 (Optional)
\
62 | - Intake Air Temperature
\
63 | - Manifold Absolute Pressure
\
64 | - Mass Airflow
\
65 |
\
66 |
Data Tab\
67 | Copy your VVT table and paste into the RPM #1 column (RPM #2 optional). This will leave the RPM Y-Axis values. Click Save RPM Columns button if these \
68 | will be used for all future uses of this tool.\
69 |
Click Load Log button and select log file. Select column headers from the log and set the parameters. Note that VVT System #2 is only required if \
70 | values in RPM #2 column of the main screen.\
71 |
You can load multiple logs into one comparison, so click Load Log button again and repeat until all logs are loaded.\
72 |
Click GO button.\
73 |
The best VE at the RPM axis points are calculated and the corresponding VVT values from the logs are shown in the VVT1 and VVT2 columns.\
74 |
Chart Tab\
75 |
You can select/deselect viewed pulls using the tick boxes in the left column. Note that this does not affect calculations.\
76 | VVT1 and VVT2 show the logged angles for the respective VVT system. The angles that correspond to the best VE are shown by \
77 | the Best VVT line.\
78 |
The VE chart compares the VE for each pull and also shows the best VE line for reference.\
79 |
3D Chart Tab\
80 |
X-Axis is RPM
\
81 | Y-Axis is VE
\
82 | Z-Axis is VVT Value
\
83 | Select individual pull from the drop down menu
\
84 | Click on 'View' button to plot data
\
85 | \
86 |
--------------------------------------------------------------------------------
/src/ij/measure/IJMath.java:
--------------------------------------------------------------------------------
1 | package ij.measure;
2 |
3 | public class IJMath {
4 |
5 | static double A = 0.05857895078654250866288;
6 | static double B = -0.00626245895772819579;
7 | static double C = -0.00299946450696036814;
8 | static double D = 0.289389696496082416;
9 | static double E = 0.0539962589851632982;
10 | static double F = 0.00508516909930653109;
11 | static double G = 0.000215969713046142876;
12 | static double H = -0.000225663858340491571;
13 | static double I = -3.06833213472529049e-7;
14 |
15 | /* This approximation of the error function erf has maximum absolute and relative errors below 1e-12
16 | * Except for low and high x, it is based on the type erf(x) = sgn(x) * sqrt(1-exp(-x^2*f(x)),
17 | * with the function f(x) having a smooth transition from 4/pi = 1.273... at x=0 to 1 at high x */
18 | public static double erf(double x) {
19 | double x2 = sqr(x);
20 | if (x2 < 1e-8)
21 | return (2/Math.sqrt(Math.PI))*x*(1+x2*(-1./3.+x2*(1./10.))); // Taylor series for low x
22 | double erf = x2 > 36 ? 1 : //the polynomials go crazy for some large x2; erf(6) is 1 - 2e-17, less than ulp from 1
23 | Math.sqrt(1 - Math.exp(-sqr(x*((2/Math.sqrt(Math.PI) - A) + A *
24 | (1 + x2*x2*(B + x2*(C + x2*(H + x2*I)))) /
25 | (1 + x2*(D + x2*(E + x2*(F + x2*G))))
26 | ))));
27 | return x>0 ? erf : -erf; //could be Math.copySign in Java 1.6 & up
28 | }
29 |
30 | static double sqr(double x) {
31 | return x*x;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/testfiles/ThrottleMaps.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vimsh/mafscaling/b329e778f629bf942b25ce1e3b3276affa9d989b/testfiles/ThrottleMaps.xlsx
--------------------------------------------------------------------------------
/testfiles/mafscaling_table.csv:
--------------------------------------------------------------------------------
1 | 0.8984375,0.9375,0.9765625,1.015625,1.0546875,1.09375,1.1328125,1.171875,1.2109375,1.25,1.2890625,1.328125,1.3671875,1.40625,1.4453125,1.484375,1.5234375,1.5625,1.6015625,1.640625,1.6796875,1.71875,1.7578125,1.796875,1.8359375,1.875,1.9140625,1.953125,1.9921875,2.03125,2.0703125,2.109375,2.1484375,2.1875,2.2265625,2.265625,2.3046875,2.34375,2.3828125,2.421875,2.4609375,2.5,2.578125,2.7734375,2.96875,3.203125,3.4375,3.7109375,3.90625,4.0625,4.296875,4.4921875,4.7265625,5
2 | 0.850000024,1,1.159999967,1.429999948,1.590000033,1.820000052,2.019999981,2.289999962,2.569999933,2.869999886,3.119999886,3.430000067,3.789999962,4.21999979,4.619999886,5.019999981,5.480000019,6.019999981,6.570000172,7.210000038,7.760000229,8.510000229,9.260000229,9.970000267,10.72999954,11.52999973,12.61999989,13.47999954,14.31000042,15.27000046,16.12000084,17.15999985,18.22999954,19.5,20.45000076,21.62000084,22.85000038,24.01000023,25.30999947,26.52000046,27.93000031,29.71999931,32.84000015,40.65999985,49.61999893,64.72000122,80.87999725,103.7600021,124.2099991,141.5899963,169.3099976,197,234.25,290.2600098
3 |
--------------------------------------------------------------------------------
/testfiles/polf_table.csv:
--------------------------------------------------------------------------------
1 | ,0.300000012,0.400000006,0.5,0.600000024,0.699999988,0.800000012,0.850000024,0.899999976,1,1.098999977,1.200000048,1.299999952,1.399999976
2 | 800,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.62818792,12.62818792,12.544,12.544,12.544,12.544
3 | 1000,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.62818792,12.62818792,12.544,12.544,12.544,12.544
4 | 1200,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.62818792,12.62818792,12.544,12.544,12.544,12.544
5 | 1600,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.62818792,12.62818792,12.544,12.544,12.544,12.544
6 | 2000,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.62818792,12.62818792,12.544,12.544,12.544,12.544
7 | 2200,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.62818792,12.62818792,12.544,12.544,12.544,12.544
8 | 2400,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.62818792,12.544,12.46092715,12.46092715,12.46092715,12.46092715
9 | 2600,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.62818792,12.46092715,12.37894737,12.37894737,12.37894737,12.37894737
10 | 2800,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.62818792,12.37894737,12.29803922,12.29803922,12.29803922,12.29803922
11 | 3200,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.544,12.29803922,12.21818182,12.21818182,12.21818182,12.21818182
12 | 3600,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.544,12.29803922,12.21818182,12.21818182,12.21818182,12.21818182
13 | 4000,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.544,12.29803922,12.21818182,12.21818182,12.21818182,12.21818182
14 | 4400,14.7,14.7,14.7,14.7,13.93777778,12.71351351,12.62818792,12.46092715,12.21818182,12.13935484,12.13935484,12.13935484,12.13935484
15 | 4600,14.7,14.7,14.7,13.93777778,13.93777778,12.71351351,12.62818792,12.46092715,12.13935484,12.06153846,12.06153846,12.06153846,12.06153846
16 | 4800,14.7,14.7,14.7,13.93777778,13.93777778,12.71351351,12.62818792,12.46092715,12.06153846,11.98471338,11.98471338,11.98471338,11.98471338
17 | 5200,14.7,14.7,14.7,13.93777778,13.93777778,12.71351351,12.62818792,12.37894737,11.98471338,11.90886076,11.90886076,11.90886076,11.90886076
18 | 5600,14.7,14.7,14.7,13.93777778,13.63478261,12.71351351,12.62818792,12.37894737,11.90886076,11.83396226,11.83396226,11.83396226,11.83396226
19 | 6000,13.93777778,13.93777778,13.93777778,13.63478261,13.34468085,12.71351351,12.62818792,12.29803922,11.83396226,11.76,11.76,11.76,11.76
20 | 6400,13.93777778,13.93777778,13.93777778,13.63478261,13.25070423,12.544,12.46092715,12.13935484,11.76,11.68695652,11.68695652,11.68695652,11.68695652
21 | 6800,13.93777778,13.93777778,13.93777778,13.63478261,12.97655172,12.46092715,12.37894737,11.98471338,11.83396226,11.76,11.76,11.76,11.76
22 | 7000,13.93777778,13.93777778,13.63478261,13.25070423,12.8,12.13935484,12.06153846,11.83396226,11.76,11.76,11.76,11.76,11.76
23 | 7200,13.93777778,13.93777778,13.63478261,13.15804196,12.71351351,11.98471338,11.98471338,11.83396226,11.76,11.76,11.76,11.76,11.76
24 | 7400,13.93777778,13.63478261,13.34468085,12.97655172,12.37894737,12.06153846,12.06153846,11.83396226,11.76,11.76,11.76,11.76,11.76
25 |
--------------------------------------------------------------------------------