added alpha version of maf scaler

git-svn-id: http://svn.3splooges.com/romraider-arch/trunk@777 d2e2e1cd-ba16-0410-be16-b7c4453c7c2d
This commit is contained in:
kascade 2007-08-20 13:22:11 +00:00
parent 063177f401
commit f49e30d36d
7 changed files with 712 additions and 82 deletions

View File

@ -647,10 +647,10 @@
<parameter id="P200" name="Engine Load (Calculated)" desc="Engine load as calculated from MAF and RPM."> <parameter id="P200" name="Engine Load (Calculated)" desc="Engine load as calculated from MAF and RPM.">
<depends> <depends>
<ref parameter="P8"/>
<!-- Engine Speed --> <!-- Engine Speed -->
<ref parameter="P12"/> <ref parameter="P8"/>
<!-- MAF --> <!-- MAF -->
<ref parameter="P12"/>
</depends> </depends>
<conversions> <conversions>
<conversion units="g/rev" expr="(P12*60)/P8" format="0.00"/> <conversion units="g/rev" expr="(P12*60)/P8" format="0.00"/>
@ -661,10 +661,10 @@
<parameter id="P201" name="Injector Duty Cycle" desc=""> <parameter id="P201" name="Injector Duty Cycle" desc="">
<depends> <depends>
<ref parameter="P8"/>
<!-- Engine Speed --> <!-- Engine Speed -->
<ref parameter="P21"/> <ref parameter="P8"/>
<!-- Fuel Inj. #1 Pulse Width --> <!-- Fuel Inj. #1 Pulse Width -->
<ref parameter="P21"/>
</depends> </depends>
<conversions> <conversions>
<conversion units="%" expr="(P8*P21)/1200" format="0.00"/> <conversion units="%" expr="(P8*P21)/1200" format="0.00"/>
@ -674,10 +674,10 @@
<parameter id="P202" name="Manifold Rel. Pressure (Corrected)" <parameter id="P202" name="Manifold Rel. Pressure (Corrected)"
desc="Difference between Manifold Absolute Pressure and Atmospheric Pressure."> desc="Difference between Manifold Absolute Pressure and Atmospheric Pressure.">
<depends> <depends>
<ref parameter="P7"/>
<!-- MAP --> <!-- MAP -->
<ref parameter="P24"/> <ref parameter="P7"/>
<!-- Atmos. Pressure --> <!-- Atmos. Pressure -->
<ref parameter="P24"/>
</depends> </depends>
<conversions> <conversions>
<conversion units="psi" expr="[P7:psi]-[P24:psi]" format="0.00"/> <conversion units="psi" expr="[P7:psi]-[P24:psi]" format="0.00"/>
@ -688,12 +688,12 @@
<parameter id="P203" name="Fuel Consumption (Est.)" <parameter id="P203" name="Fuel Consumption (Est.)"
desc="Estimated fuel consumption based on MAF, AFR and vehicle speed."> desc="Estimated fuel consumption based on MAF, AFR and vehicle speed.">
<depends> <depends>
<ref parameter="P9"/>
<!-- Vehicle Speed --> <!-- Vehicle Speed -->
<ref parameter="P12"/> <ref parameter="P9"/>
<!-- MAF--> <!-- MAF-->
<ref parameter="P58"/> <ref parameter="P12"/>
<!-- AFR--> <!-- AFR-->
<ref parameter="P58"/>
</depends> </depends>
<conversions> <conversions>
<conversion units="mpg (US)" expr="([P9:mph]/3600)/((P12/[P58:AFR])/2880)" format="0.00"/> <conversion units="mpg (US)" expr="([P9:mph]/3600)/((P12/[P58:AFR])/2880)" format="0.00"/>

View File

@ -21,6 +21,59 @@
package enginuity.logger.ecu; package enginuity.logger.ecu;
import java.awt.BorderLayout;
import static java.awt.BorderLayout.CENTER;
import static java.awt.BorderLayout.EAST;
import static java.awt.BorderLayout.NORTH;
import static java.awt.BorderLayout.SOUTH;
import static java.awt.BorderLayout.WEST;
import static java.awt.Color.BLACK;
import static java.awt.Color.RED;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import static java.util.Collections.sort;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import static javax.swing.BorderFactory.createLoweredBevelBorder;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import static javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW;
import javax.swing.JFrame;
import javax.swing.JLabel;
import static javax.swing.JLabel.RIGHT;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import static javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED;
import static javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_NEVER;
import static javax.swing.JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED;
import javax.swing.JSeparator;
import static javax.swing.JSeparator.VERTICAL;
import javax.swing.JSplitPane;
import static javax.swing.JSplitPane.HORIZONTAL_SPLIT;
import static javax.swing.JSplitPane.VERTICAL_SPLIT;
import javax.swing.JTabbedPane;
import static javax.swing.JTabbedPane.BOTTOM;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import static javax.swing.KeyStroke.getKeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumn;
import enginuity.ECUEditor;
import enginuity.Settings; import enginuity.Settings;
import enginuity.io.port.SerialPortRefresher; import enginuity.io.port.SerialPortRefresher;
import enginuity.logger.ecu.comms.controller.LoggerController; import enginuity.logger.ecu.comms.controller.LoggerController;
@ -62,6 +115,7 @@ import enginuity.logger.ecu.ui.handler.file.FileUpdateHandlerImpl;
import enginuity.logger.ecu.ui.handler.graph.GraphUpdateHandler; import enginuity.logger.ecu.ui.handler.graph.GraphUpdateHandler;
import enginuity.logger.ecu.ui.handler.livedata.LiveDataTableModel; import enginuity.logger.ecu.ui.handler.livedata.LiveDataTableModel;
import enginuity.logger.ecu.ui.handler.livedata.LiveDataUpdateHandler; import enginuity.logger.ecu.ui.handler.livedata.LiveDataUpdateHandler;
import enginuity.logger.ecu.ui.handler.maf.MafUpdateHandler;
import enginuity.logger.ecu.ui.handler.table.TableUpdateHandler; import enginuity.logger.ecu.ui.handler.table.TableUpdateHandler;
import enginuity.logger.ecu.ui.paramlist.ParameterListTable; import enginuity.logger.ecu.ui.paramlist.ParameterListTable;
import enginuity.logger.ecu.ui.paramlist.ParameterListTableModel; import enginuity.logger.ecu.ui.paramlist.ParameterListTableModel;
@ -75,59 +129,6 @@ import static enginuity.util.ThreadUtil.runAsDaemon;
import static enginuity.util.ThreadUtil.sleep; import static enginuity.util.ThreadUtil.sleep;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import static javax.swing.BorderFactory.createLoweredBevelBorder;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import static javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW;
import javax.swing.JFrame;
import javax.swing.JLabel;
import static javax.swing.JLabel.RIGHT;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import static javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED;
import static javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_NEVER;
import static javax.swing.JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED;
import javax.swing.JSeparator;
import static javax.swing.JSeparator.VERTICAL;
import javax.swing.JSplitPane;
import static javax.swing.JSplitPane.HORIZONTAL_SPLIT;
import static javax.swing.JSplitPane.VERTICAL_SPLIT;
import javax.swing.JTabbedPane;
import static javax.swing.JTabbedPane.BOTTOM;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import static javax.swing.KeyStroke.getKeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumn;
import java.awt.BorderLayout;
import static java.awt.BorderLayout.CENTER;
import static java.awt.BorderLayout.EAST;
import static java.awt.BorderLayout.NORTH;
import static java.awt.BorderLayout.SOUTH;
import static java.awt.BorderLayout.WEST;
import static java.awt.Color.BLACK;
import static java.awt.Color.RED;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import static java.util.Collections.sort;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/* /*
TODO: add better debug logging, preferably to a file and switchable (on/off) TODO: add better debug logging, preferably to a file and switchable (on/off)
TODO: Clean up this class! TODO: Clean up this class!
@ -147,6 +148,7 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC
private static final String HEADING_EXTERNAL = "External"; private static final String HEADING_EXTERNAL = "External";
private static final String CAL_ID_LABEL = "CAL ID"; private static final String CAL_ID_LABEL = "CAL ID";
private static final String ECU_ID_LABEL = "ECU ID"; private static final String ECU_ID_LABEL = "ECU ID";
private ECUEditor ecuEditor;
private Settings settings; private Settings settings;
private LoggerController controller; private LoggerController controller;
private ResetManager resetManager; private ResetManager resetManager;
@ -178,12 +180,24 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC
private GraphUpdateHandler graphUpdateHandler; private GraphUpdateHandler graphUpdateHandler;
private JPanel dashboardPanel; private JPanel dashboardPanel;
private DashboardUpdateHandler dashboardUpdateHandler; private DashboardUpdateHandler dashboardUpdateHandler;
private JPanel mafPanel;
private MafUpdateHandler mafUpdateHandler;
private EcuInit ecuInit; private EcuInit ecuInit;
private JToggleButton logToFileButton; private JToggleButton logToFileButton;
private List<ExternalDataSource> externalDataSources; private List<ExternalDataSource> externalDataSources;
public EcuLogger(Settings settings) { public EcuLogger(Settings settings) {
super(ENGINUITY_ECU_LOGGER_TITLE); super(ENGINUITY_ECU_LOGGER_TITLE);
construct(settings);
}
public EcuLogger(ECUEditor ecuEditor) {
super(ENGINUITY_ECU_LOGGER_TITLE);
this.ecuEditor = ecuEditor;
construct(ecuEditor.getSettings());
}
private void construct(Settings settings) {
bootstrap(settings); bootstrap(settings);
loadEcuDefs(); loadEcuDefs();
loadLoggerPlugins(); loadLoggerPlugins();
@ -229,8 +243,10 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC
graphUpdateHandler = new GraphUpdateHandler(graphPanel); graphUpdateHandler = new GraphUpdateHandler(graphPanel);
dashboardPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 3)); dashboardPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 3));
dashboardUpdateHandler = new DashboardUpdateHandler(dashboardPanel); dashboardUpdateHandler = new DashboardUpdateHandler(dashboardPanel);
mafPanel = new JPanel(new BorderLayout(2, 2));
mafUpdateHandler = new MafUpdateHandler(mafPanel, ecuEditor);
controller = new LoggerControllerImpl(settings, ecuInitCallback, this, liveDataUpdateHandler, controller = new LoggerControllerImpl(settings, ecuInitCallback, this, liveDataUpdateHandler,
graphUpdateHandler, dashboardUpdateHandler, fileUpdateHandler, TableUpdateHandler.getInstance()); graphUpdateHandler, dashboardUpdateHandler, mafUpdateHandler, fileUpdateHandler, TableUpdateHandler.getInstance());
resetManager = new ResetManagerImpl(settings, this); resetManager = new ResetManagerImpl(settings, this);
messageLabel = new JLabel(ENGINUITY_ECU_LOGGER_TITLE); messageLabel = new JLabel(ENGINUITY_ECU_LOGGER_TITLE);
calIdLabel = new JLabel(buildEcuInfoLabelText(CAL_ID_LABEL, null)); calIdLabel = new JLabel(buildEcuInfoLabelText(CAL_ID_LABEL, null));
@ -565,6 +581,7 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC
tabbedPane.add("Data", buildSplitPane(buildParamListPane(dataTabParamListTableModel, dataTabSwitchListTableModel, dataTabExternalListTableModel), buildDataTab())); tabbedPane.add("Data", buildSplitPane(buildParamListPane(dataTabParamListTableModel, dataTabSwitchListTableModel, dataTabExternalListTableModel), buildDataTab()));
tabbedPane.add("Graph", buildSplitPane(buildParamListPane(graphTabParamListTableModel, graphTabSwitchListTableModel, graphTabExternalListTableModel), buildGraphTab())); tabbedPane.add("Graph", buildSplitPane(buildParamListPane(graphTabParamListTableModel, graphTabSwitchListTableModel, graphTabExternalListTableModel), buildGraphTab()));
tabbedPane.add("Dashboard", buildSplitPane(buildParamListPane(dashboardTabParamListTableModel, dashboardTabSwitchListTableModel, dashboardTabExternalListTableModel), buildDashboardTab())); tabbedPane.add("Dashboard", buildSplitPane(buildParamListPane(dashboardTabParamListTableModel, dashboardTabSwitchListTableModel, dashboardTabExternalListTableModel), buildDashboardTab()));
tabbedPane.add("MAF", mafPanel);
return tabbedPane; return tabbedPane;
} }
@ -948,23 +965,36 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC
//********************************************************************** //**********************************************************************
public static void startLogger(final int defaultCloseOperation, final Settings settings) { public static void startLogger(int defaultCloseOperation, ECUEditor ecuEditor) {
// instantiate the controlling class.
final EcuLogger ecuLogger = new EcuLogger(ecuEditor);
createAndShowGui(defaultCloseOperation, ecuLogger);
}
public static void startLogger(int defaultCloseOperation, Settings settings) {
// instantiate the controlling class.
final EcuLogger ecuLogger = new EcuLogger(settings);
createAndShowGui(defaultCloseOperation, ecuLogger);
}
private static void createAndShowGui(final int defaultCloseOperation, final EcuLogger ecuLogger) {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
public void run() { public void run() {
createAndShowGUI(defaultCloseOperation, settings); doCreateAndShowGui(defaultCloseOperation, ecuLogger);
} }
}); });
} }
private static void createAndShowGUI(int defaultCloseOperation, Settings settings) { private static void doCreateAndShowGui(int defaultCloseOperation, EcuLogger ecuLogger) {
// instantiate the controlling class. Settings settings = ecuLogger.getSettings();
EcuLogger ecuLogger = new EcuLogger(settings);
// set default close operation
ecuLogger.setDefaultCloseOperation(defaultCloseOperation);
// set remaining window properties // set remaining window properties
ecuLogger.pack(); ecuLogger.pack();
ecuLogger.setSize(settings.getLoggerWindowSize()); ecuLogger.setSize(settings.getLoggerWindowSize());
ecuLogger.setIconImage(new ImageIcon("./graphics/enginuity-ico.gif").getImage()); ecuLogger.setIconImage(new ImageIcon("./graphics/enginuity-ico.gif").getImage());
ecuLogger.setDefaultCloseOperation(defaultCloseOperation);
ecuLogger.addWindowListener(ecuLogger); ecuLogger.addWindowListener(ecuLogger);
// display the window // display the window
@ -974,5 +1004,4 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC
} }
ecuLogger.setVisible(true); ecuLogger.setVisible(true);
} }
} }

View File

@ -0,0 +1,132 @@
package enginuity.logger.ecu.ui.handler.maf;
import static java.awt.BorderLayout.CENTER;
import static java.awt.BorderLayout.WEST;
import java.util.Set;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import enginuity.ECUEditor;
import enginuity.logger.ecu.comms.query.Response;
import enginuity.logger.ecu.definition.LoggerData;
import enginuity.logger.ecu.ui.handler.DataUpdateHandler;
import enginuity.logger.ecu.ui.tab.maf.MafChartPanel;
import enginuity.logger.ecu.ui.tab.maf.MafControlPanel;
import org.jfree.data.xy.XYSeries;
public final class MafUpdateHandler implements DataUpdateHandler {
private static final String MAFV = "P18";
private static final String AF_LEARNING_1 = "P4";
private static final String AF_CORRECTION_1 = "P3";
private final XYSeries series = new XYSeries("MAF Analysis");
private final XYTrendline trendline = new XYTrendline();
private final JPanel mafPanel;
private final ECUEditor ecuEditor;
private final MafControlPanel controlPanel;
public MafUpdateHandler(JPanel mafPanel, ECUEditor ecuEditor) {
this.mafPanel = mafPanel;
this.ecuEditor = ecuEditor;
controlPanel = buildControlPanel();
mafPanel.add(controlPanel, WEST);
mafPanel.add(buildGraphPanel(), CENTER);
}
private MafControlPanel buildControlPanel() {
return new MafControlPanel(mafPanel, trendline, series, ecuEditor);
}
private MafChartPanel buildGraphPanel() {
return new MafChartPanel(trendline, series);
}
public synchronized void registerData(LoggerData loggerData) {
}
public synchronized void handleDataUpdate(Response response) {
if (controlPanel.isRecordData() && containsData(response, MAFV, AF_LEARNING_1, AF_CORRECTION_1)) {
boolean valid = true;
// cl/ol check
// if (valid && (containsData(response, "E3") || containsData(response, "E27"))) {
// double clOl = -1;
// if (containsData(response, "E3")) {
// clOl = (int) findValue(response, "E3");
// }
// if (containsData(response, "E27")) {
// clOl = (int) findValue(response, "E27");
// }
// valid = clOl == 8;
// }
// afr check
if (valid && containsData(response, "P58")) {
double afr = findValue(response, "P58");
valid = controlPanel.isValidAfr(afr);
}
// rpm check
if (valid && containsData(response, "P8")) {
double rpm = findValue(response, "P8");
valid = controlPanel.isValidRpm(rpm);
}
// maf check
if (valid && containsData(response, "P12")) {
double maf = findValue(response, "P12");
valid = controlPanel.isValidMaf(maf);
}
// coolant temp check
if (valid && containsData(response, "P2")) {
double temp = findValue(response, "P2");
valid = controlPanel.isValidCoolantTemp(temp);
}
if (valid) {
final double mafv = findValue(response, MAFV);
final double learning = findValue(response, AF_LEARNING_1);
final double correction = findValue(response, AF_CORRECTION_1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
series.add(mafv, learning + correction);
}
});
}
}
}
private boolean containsData(Response response, String... ids) {
Set<LoggerData> datas = response.getData();
for (String id : ids) {
boolean found = false;
for (LoggerData data : datas) {
if (data.getId().equals(id)) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
private double findValue(Response response, String id) {
for (final LoggerData loggerData : response.getData()) {
if (id.equals(loggerData.getId())) {
return response.getDataValue(loggerData);
}
}
throw new IllegalStateException("Expected data item " + id + " not in response.");
}
public synchronized void deregisterData(LoggerData loggerData) {
}
public synchronized void cleanUp() {
}
public synchronized void reset() {
}
}

View File

@ -0,0 +1,66 @@
package enginuity.logger.ecu.ui.handler.maf;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.List;
import jamlab.Polyfit;
import jamlab.Polyval;
import org.jfree.data.xy.AbstractXYDataset;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
public final class XYTrendline extends AbstractXYDataset {
private List<XYDataItem> items = new ArrayList<XYDataItem>();
private double[] xVals = new double[0];
private double[] yPoly = new double[0];
private Polyfit polyfit;
public int getSeriesCount() {
return 1;
}
public Comparable getSeriesKey(int seriesIndex) {
return "foo";
}
public synchronized int getItemCount(int seriesIndex) {
return yPoly.length;
}
public synchronized Number getY(int seriesIndex, int item) {
return yPoly[item];
}
public synchronized Number getX(int seriesIndex, int item) {
return xVals[item];
}
public synchronized void update(XYSeries series, int order) {
if (series.getItemCount() <= order) return;
items = new ArrayList<XYDataItem>(series.getItems());
xVals = new double[items.size()];
double[] yVals = new double[items.size()];
for (int i = 0; i < items.size(); i++) {
XYDataItem dataItem = items.get(i);
xVals[i] = dataItem.getX().doubleValue();
yVals[i] = dataItem.getY().doubleValue();
}
try {
polyfit = new Polyfit(xVals, yVals, order);
yPoly = calculate(xVals);
} catch (Exception e) {
throw new UndeclaredThrowableException(e);
}
}
public synchronized double[] calculate(double[] x) {
Polyval polyval = new Polyval(x, polyfit);
return polyval.getYout();
}
public synchronized void clear() {
items.clear();
xVals = new double[0];
yPoly = new double[0];
}
}

View File

@ -0,0 +1,89 @@
package enginuity.logger.ecu.ui.tab.maf;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import enginuity.logger.ecu.ui.handler.graph.SpringUtilities;
import enginuity.logger.ecu.ui.handler.maf.XYTrendline;
import static enginuity.util.ParamChecker.checkNotNull;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import static org.jfree.chart.plot.PlotOrientation.VERTICAL;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYDotRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public final class MafChartPanel extends JPanel {
private static final Color DARK_GREY = new Color(80, 80, 80);
private static final Color LIGHT_GREY = new Color(110, 110, 110);
private final XYTrendline trendline;
private final XYSeries series;
public MafChartPanel(XYTrendline trendline, XYSeries series) {
super(new SpringLayout());
checkNotNull(trendline, series);
this.trendline = trendline;
this.series = series;
addChart();
}
private void addChart() {
ChartPanel chartPanel = new ChartPanel(createChart(), false, true, true, true, true);
chartPanel.setMinimumSize(new Dimension(500, 400));
chartPanel.setPreferredSize(new Dimension(500, 400));
add(chartPanel);
SpringUtilities.makeCompactGrid(this, 1, 1, 2, 2, 2, 2);
}
private JFreeChart createChart() {
XYDataset dataset = buildDataset();
return buildChart(dataset);
}
private XYSeriesCollection buildDataset() {
return new XYSeriesCollection(series);
}
private JFreeChart buildChart(XYDataset dataset) {
JFreeChart chart = ChartFactory.createScatterPlot(null, "MAF (v)", "Total Correction (%)", dataset, VERTICAL, false, true, false);
chart.setBackgroundPaint(Color.BLACK);
configurePlot(chart);
addTrendLine(chart);
return chart;
}
private void configurePlot(JFreeChart chart) {
XYPlot plot = chart.getXYPlot();
plot.setBackgroundPaint(Color.BLACK);
plot.getDomainAxis().setLabelPaint(Color.WHITE);
plot.getRangeAxis().setLabelPaint(Color.WHITE);
plot.getDomainAxis().setTickLabelPaint(LIGHT_GREY);
plot.getRangeAxis().setTickLabelPaint(LIGHT_GREY);
plot.setDomainGridlinePaint(DARK_GREY);
plot.setRangeGridlinePaint(DARK_GREY);
plot.setOutlinePaint(DARK_GREY);
plot.setRenderer(buildScatterRenderer());
}
private XYDotRenderer buildScatterRenderer() {
XYDotRenderer renderer = new XYDotRenderer();
renderer.setDotHeight(2);
renderer.setDotWidth(2);
return renderer;
}
private void addTrendLine(JFreeChart chart) {
XYPlot plot = chart.getXYPlot();
plot.setDataset(1, trendline);
plot.setRenderer(1, buildTrendLineRenderer());
}
private StandardXYItemRenderer buildTrendLineRenderer() {
return new StandardXYItemRenderer();
}
}

View File

@ -0,0 +1,315 @@
package enginuity.logger.ecu.ui.tab.maf;
import java.awt.Component;
import java.awt.GridBagConstraints;
import static java.awt.GridBagConstraints.CENTER;
import static java.awt.GridBagConstraints.HORIZONTAL;
import static java.awt.GridBagConstraints.NONE;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.OK_OPTION;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
import static javax.swing.JOptionPane.YES_NO_OPTION;
import static javax.swing.JOptionPane.showConfirmDialog;
import static javax.swing.JOptionPane.showMessageDialog;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.border.TitledBorder;
import enginuity.ECUEditor;
import enginuity.logger.ecu.ui.handler.maf.XYTrendline;
import enginuity.maps.DataCell;
import enginuity.maps.Rom;
import enginuity.maps.Table2D;
import static enginuity.util.ParamChecker.checkNotNull;
import org.jfree.data.xy.XYSeries;
public final class MafControlPanel extends JPanel {
private final JToggleButton recordDataButton = new JToggleButton("Record Data");
private final JTextField mafvMin = new JTextField("1.20", 3);
private final JTextField mafvMax = new JTextField("2.60", 3);
private final JTextField afrMin = new JTextField("14.0", 3);
private final JTextField afrMax = new JTextField("16.0", 3);
private final JTextField rpmMin = new JTextField("0", 3);
private final JTextField rpmMax = new JTextField("4500", 3);
private final JTextField mafMin = new JTextField("0", 3);
private final JTextField mafMax = new JTextField("100", 3);
private final JTextField coolantMin = new JTextField("80", 3);
private final Component parent;
private final XYTrendline trendline;
private final XYSeries series;
private final ECUEditor ecuEditor;
public MafControlPanel(Component parent, XYTrendline trendline, XYSeries series, ECUEditor ecuEditor) {
checkNotNull(parent, trendline, series);
this.parent = parent;
this.trendline = trendline;
this.series = series;
this.ecuEditor = ecuEditor;
addControls();
}
public boolean isRecordData() {
return recordDataButton.isSelected();
}
public boolean isValidAfr(double value) {
return checkInRange("AFR", afrMin, afrMax, value);
}
public boolean isValidRpm(double value) {
return checkInRange("RPM", rpmMin, rpmMax, value);
}
public boolean isValidMaf(double value) {
return checkInRange("MAF", mafMin, mafMax, value);
}
public boolean isValidMafv(double value) {
return checkInRange("MAFv", mafvMin, mafvMax, value);
}
public boolean isValidCoolantTemp(double value) {
return checkGreaterThan("Coolant Temp.", coolantMin, value);
}
private boolean checkInRange(String name, JTextField min, JTextField max, double value) {
if (isValidRange(min, max)) {
return inRange(value, min, max);
} else {
showMessageDialog(parent, "Invalid " + name + " range specified.", "Error", ERROR_MESSAGE);
recordDataButton.setSelected(false);
return false;
}
}
private boolean checkGreaterThan(String name, JTextField min, double value) {
if (isNumber(min)) {
return value >= parseDouble(min);
} else {
showMessageDialog(parent, "Invalid " + name + " specified.", "Error", ERROR_MESSAGE);
recordDataButton.setSelected(false);
return false;
}
}
private void addControls() {
JPanel panel = new JPanel();
GridBagLayout gridBagLayout = new GridBagLayout();
panel.setLayout(gridBagLayout);
add(panel, gridBagLayout, buildFilterPanel(), 0, 0, 1, HORIZONTAL);
add(panel, gridBagLayout, buildInterpolatePanel(), 0, 1, 1, HORIZONTAL);
add(panel, gridBagLayout, buildUpdateMafPanel(), 0, 2, 1, HORIZONTAL);
add(panel, gridBagLayout, buildResetPanel(), 0, 3, 1, HORIZONTAL);
add(panel);
}
private void add(JPanel panel, GridBagLayout gridBagLayout, JComponent component, int x, int y, int spanX, int fillType) {
GridBagConstraints constraints = buildBaseConstraints();
updateConstraints(constraints, x, y, spanX, 1, 1, 1, fillType);
gridBagLayout.setConstraints(component, constraints);
panel.add(component);
}
private JPanel buildResetPanel() {
JPanel panel = new JPanel();
panel.setBorder(new TitledBorder("Reset"));
panel.add(buildResetButton());
return panel;
}
private JPanel buildUpdateMafPanel() {
JPanel panel = new JPanel();
panel.setBorder(new TitledBorder("Update MAF"));
GridBagLayout gridBagLayout = new GridBagLayout();
panel.setLayout(gridBagLayout);
addMinMaxFilter(panel, gridBagLayout, "MAFv Range", mafvMin, mafvMax, 0);
addComponent(panel, gridBagLayout, buildUpdateMafButton(), 3);
return panel;
}
private JPanel buildInterpolatePanel() {
JPanel panel = new JPanel();
panel.setBorder(new TitledBorder("Interpolate"));
GridBagLayout gridBagLayout = new GridBagLayout();
panel.setLayout(gridBagLayout);
JComboBox orderComboBox = buildPolyOrderComboBox();
addLabeledComponent(panel, gridBagLayout, "Poly. order", orderComboBox, 0);
addComponent(panel, gridBagLayout, buildInterpolateButton(orderComboBox), 2);
return panel;
}
private void addLabeledComponent(JPanel panel, GridBagLayout gridBagLayout, String name, JComponent component, int y) {
add(panel, gridBagLayout, new JLabel(name), 0, y, 3, HORIZONTAL);
add(panel, gridBagLayout, component, 0, y + 1, 3, NONE);
}
private JPanel buildFilterPanel() {
JPanel panel = new JPanel();
panel.setBorder(new TitledBorder("Filter Data"));
GridBagLayout gridBagLayout = new GridBagLayout();
panel.setLayout(gridBagLayout);
addMinMaxFilter(panel, gridBagLayout, "AFR Range", afrMin, afrMax, 0);
addMinMaxFilter(panel, gridBagLayout, "RPM Range", rpmMin, rpmMax, 3);
addMinMaxFilter(panel, gridBagLayout, "MAF Range (g/s)", mafMin, mafMax, 6);
addLabeledComponent(panel, gridBagLayout, "Min. Coolant Temp.", coolantMin, 9);
addComponent(panel, gridBagLayout, recordDataButton, 12);
return panel;
}
private void addComponent(JPanel panel, GridBagLayout gridBagLayout, JComponent component, int y) {
add(panel, gridBagLayout, component, 0, y, 3, HORIZONTAL);
}
private void addMinMaxFilter(JPanel panel, GridBagLayout gridBagLayout, String name, JTextField min, JTextField max, int y) {
add(panel, gridBagLayout, new JLabel(name), 0, y, 3, HORIZONTAL);
y += 1;
add(panel, gridBagLayout, min, 0, y, 1, NONE);
add(panel, gridBagLayout, new JLabel(" - "), 1, y, 1, NONE);
add(panel, gridBagLayout, max, 2, y, 1, NONE);
}
private GridBagConstraints buildBaseConstraints() {
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = CENTER;
constraints.fill = NONE;
return constraints;
}
private void updateConstraints(GridBagConstraints constraints, int gridx, int gridy, int gridwidth, int gridheight, int weightx, int weighty, int fill) {
constraints.gridx = gridx;
constraints.gridy = gridy;
constraints.gridwidth = gridwidth;
constraints.gridheight = gridheight;
constraints.weightx = weightx;
constraints.weighty = weighty;
constraints.fill = fill;
}
private JButton buildResetButton() {
JButton resetButton = new JButton("Reset Data");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
trendline.clear();
series.clear();
parent.repaint();
}
});
return resetButton;
}
private JButton buildInterpolateButton(final JComboBox orderComboBox) {
JButton interpolateButton = new JButton("Interpolate");
interpolateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
trendline.update(series, (Integer) orderComboBox.getSelectedItem());
parent.repaint();
}
});
return interpolateButton;
}
private JComboBox buildPolyOrderComboBox() {
final JComboBox orderComboBox = new JComboBox(new Object[]{3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20});
orderComboBox.setSelectedItem(10);
return orderComboBox;
}
private JButton buildUpdateMafButton() {
final JButton updateMafButton = new JButton("Update MAF");
updateMafButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
Table2D table = getMafTable(ecuEditor);
if (table != null) {
if (showUpdateMafConfirmation() == OK_OPTION) {
if (isValidRange(mafvMin, mafvMax)) {
DataCell[] axisCells = table.getAxis().getData();
double[] x = new double[axisCells.length];
for (int i = 0; i < axisCells.length; i++) {
DataCell cell = axisCells[i];
x[i] = cell.getValue();
}
double[] percentChange = trendline.calculate(x);
DataCell[] dataCells = table.getData();
for (int i = 0; i < dataCells.length; i++) {
if (inRange(axisCells[i].getValue(), mafvMin, mafvMax)) {
DataCell cell = dataCells[i];
double value = cell.getValue();
cell.setRealValue(String.valueOf(value * (1.0 + percentChange[i] / 100.0)));
}
}
table.colorize();
} else {
showMessageDialog(parent, "Invalid MAFv range specified.", "Error", ERROR_MESSAGE);
}
}
}
}
});
return updateMafButton;
}
private boolean areNumbers(JTextField... textFields) {
for (JTextField field : textFields) {
if (!isNumber(field)) return false;
}
return true;
}
private boolean isValidRange(JTextField min, JTextField max) {
return areNumbers(min, max) && parseDouble(min) < parseDouble(max);
}
private boolean isNumber(JTextField textField) {
try {
parseDouble(textField);
return true;
} catch (Exception e) {
return false;
}
}
private boolean inRange(double val, double min, double max) {
return val >= min && val <= max;
}
private boolean inRange(double value, JTextField min, JTextField max) {
return inRange(value, parseDouble(min), parseDouble(max));
}
private double parseDouble(JTextField field) {
return Double.parseDouble(field.getText().trim());
}
private int showUpdateMafConfirmation() {
return showConfirmDialog(parent, "Update MAF Sensor Scaling table?", "Confirm Update", YES_NO_OPTION, WARNING_MESSAGE);
}
private Table2D getMafTable(ECUEditor ecuEditor) {
try {
Rom rom = ecuEditor.getLastSelectedRom();
return (Table2D) rom.getTable("MAF Sensor Scaling");
} catch (Exception e) {
showMessageDialog(parent, "MAF Sensor Scaling table not found.", "Error", ERROR_MESSAGE);
return null;
}
}
}

View File

@ -21,13 +21,10 @@
package enginuity.swing; package enginuity.swing;
import com.centerkey.utils.BareBonesBrowserLaunch; import java.awt.event.ActionEvent;
import enginuity.ECUEditor; import java.awt.event.ActionListener;
import enginuity.logger.ecu.EcuLogger; import java.io.File;
import enginuity.logger.utec.gui.JutecGUI; import java.io.FileOutputStream;
import enginuity.maps.Rom;
import enginuity.ramtune.test.RamTuneTestApp;
import javax.swing.ButtonGroup; import javax.swing.ButtonGroup;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import static javax.swing.JFrame.DISPOSE_ON_CLOSE; import static javax.swing.JFrame.DISPOSE_ON_CLOSE;
@ -41,10 +38,12 @@ import static javax.swing.JOptionPane.showConfirmDialog;
import static javax.swing.JOptionPane.showMessageDialog; import static javax.swing.JOptionPane.showMessageDialog;
import javax.swing.JRadioButtonMenuItem; import javax.swing.JRadioButtonMenuItem;
import javax.swing.JSeparator; import javax.swing.JSeparator;
import java.awt.event.ActionEvent; import com.centerkey.utils.BareBonesBrowserLaunch;
import java.awt.event.ActionListener; import enginuity.ECUEditor;
import java.io.File; import enginuity.logger.ecu.EcuLogger;
import java.io.FileOutputStream; import enginuity.logger.utec.gui.JutecGUI;
import enginuity.maps.Rom;
import enginuity.ramtune.test.RamTuneTestApp;
public class ECUEditorMenuBar extends JMenuBar implements ActionListener { public class ECUEditorMenuBar extends JMenuBar implements ActionListener {
@ -289,7 +288,7 @@ public class ECUEditorMenuBar extends JMenuBar implements ActionListener {
parent.setUserLevel(5); parent.setUserLevel(5);
} else if (e.getSource() == openLogger) { } else if (e.getSource() == openLogger) {
EcuLogger.startLogger(DISPOSE_ON_CLOSE, parent.getSettings()); EcuLogger.startLogger(DISPOSE_ON_CLOSE, parent);
} else if (e.getSource() == utecLogger) { } else if (e.getSource() == utecLogger) {
JutecGUI.startLogger(DISPOSE_ON_CLOSE, parent.getSettings()); JutecGUI.startLogger(DISPOSE_ON_CLOSE, parent.getSettings());