diy mpg gauge - Page 4 - Fuelly Forums

Android Users - Coming Soon! - Migrating from aCar 4.8 to 5.0

Reply
 
Thread Tools Display Modes
 
Old 07-21-2007, 01:12 PM   #31
Registered Member
 
sonyhome's Avatar
 
Join Date: Jul 2007
Posts: 150
Country: United States
Pretty cool ... but I don't quite understand your diode clamp interface you used.

Could you explain how you make it work?

You connected directly to the injector via a 10K resistor?
And then you grounded the signal via a diode bridge? Is that to avoid having signals above 0.6V? Don't understand...

And what's VSS for?

I though you'd use a coil to detect the pulses so the laptop would be totally independant from the car's electrical circuit...

All you have to do now to compute duty cycle is count the number of samples above a threshold vs all the samples.
You may need to adjust with a constant, or adjusting the threshold since the ramp up slope is not vertical, but seems constant.
__________________

__________________

sonyhome is offline   Reply With Quote
Old 07-22-2007, 01:40 AM   #32
Registered Member
 
skewbe's Avatar
 
Join Date: Jan 2007
Posts: 771
Country: United States
We have gui

Tada!!, it's somewhere in the ballpark for a 98'tro!! Now anyone who has a laptop or tablet in their car can monitor MPG

***you need to be logged in to see the pictures,
You can go here to see the pictures without logging in:
http://opengauge.org/diympggauge/
***

*tank will persist when window is closed


Using this circuit, with right and left switched



Zoom in on recording of line in (44100 8 bit stereo) for anylizing the waveform (vss* on top, injector on bottom) and general futzing in response. I don't think the diodes are doing much on the vss side

*Yellow line is default threshold for the vss,
*Cyan "..." injector
*I adapted the code to the latest wave form (inj pulse was on other channel and right side up?!?)
*vss is the misnamed Vehicle Speed Sensor. It really only measures distance. The computer watching the vss still has to keep track of time to figure out the velocity.



Speaking of code, here it is in it's entirety, 6 drama filled pages to chew on in one file called Mpg.java :
Code:
import java.awt.Color;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.text.NumberFormat;
import java.util.Properties;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Mpg extends Thread {
	static String propFile = "./mpg.properties";	// place to persist confguration and trips. 
												//Will be created on first run if it doesnt exist.

	static int injThreshold = Integer
			.parseInt(getProperty("injThreshold", "-30")); // value above the noise

	static int vssThreshold = Integer
			.parseInt(getProperty("vssThreshold", "100")); // value above the noise

	static double distanceFudge = Double.parseDouble(getProperty("distanceFudge", "3200.0"));

	static double fuelFudge = Double.parseDouble(getProperty("fuelFudge",	"8000000.00"));

	static String dummyFile = getProperty("dummyFile", "");

	// low level stats tracked in the "trip" class.
	class Trip {
		String name;

		long sampleCount; // num samples, used to compute elapsed time, good
							// for about 58 billion hours @ 44100hz

		long injHi; // stores number of samples that were "HI" (injector was
					// open)

		long vssTot; // how many pulses from the vss, indication of distance
						// travelled

		public Trip(String _name) {
			name = _name;
		}

		// real lightweight update process, gets called at end of audio chunk
		public void Update(long _sampleCount, long _injHi, long _vssTot) {
			sampleCount += _sampleCount;
			injHi += _injHi;
			vssTot += _vssTot;
		}

		public String toString() {
			return "name=" + name + ";sampleCount=" + sampleCount + ";injHi="
					+ injHi + ";vssTot=" + vssTot;
		}

		public void reset() {
			sampleCount = 0;
			injHi = 0;
			vssTot = 0;
		}

		public Trip load() {
			sampleCount = Long
					.parseLong(getProperty(name + ".sampleCount", "0"));
			injHi = Long.parseLong(getProperty(name + ".injHi", "0"));
			vssTot = Long.parseLong(getProperty(name + ".vssTot", "0"));
			return this;
		}

		public void save() {
			properties.put(name + ".sampleCount", "" + sampleCount);
			properties.put(name + ".injHi", "" + injHi);
			properties.put(name + ".vssTot", "" + vssTot);
		}

		public double miles() {
			return (double) vssTot / distanceFudge;
		}

		public double hours() {
			return ((double) sampleCount) / (44100.0D * 3600.0D);
		}

		public double gallons() {
			return (double) injHi / fuelFudge;
		}

		public double mpg() {
			return gallons() > 0.0D ? (miles() / gallons())
					: Double.POSITIVE_INFINITY;
		}
	}

	class TripPanel extends JPanel {
		Trip trip = null;

		JLabel name = new JLabel("name");

		JLabel miles = new JLabel("miles");

		JLabel gallons = new JLabel("gallons");

		JLabel mpg = new JLabel("mpg");

		JLabel hours = new JLabel("gallons");

		JLabel mph = new JLabel("mph");

		JButton reset = new JButton("reset");

		/** used for limiting numbers to 4 decimal places*/
		NumberFormat fm = NumberFormat.getNumberInstance();

		public TripPanel(Trip _trip) {
			trip = _trip;
			setLayout(new GridLayout(1, 8));
			setBorder(BorderFactory.createLineBorder(Color.BLACK));
			add(name);
			add(miles);
			add(gallons);
			add(mpg);
			add(hours);
			add(mph);
			add(reset);
			reset.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					trip.reset();
				}
			});
			fm.setMaximumFractionDigits(4);
		}

		public void upDateLabels() {
			name.setText(" " + trip.name);
			miles.setText(fm.format(trip.miles()));
			gallons.setText(fm.format(trip.gallons()));
			mpg.setText(fm.format(trip.mpg()));
			hours.setText(fm.format(trip.hours()));
			mph.setText(fm.format(trip.miles() / trip.hours()));
		}

	}

	private TargetDataLine m_line;

	protected boolean m_bRecording = true;

	Trip instant = new Trip("instant");

	TripPanel instantPanel = new TripPanel(instant);

	Trip current = new Trip("current");

	TripPanel currentPanel = new TripPanel(current);

	Trip tank = new Trip("tank").load();

	TripPanel tankPanel = new TripPanel(tank);

	public Mpg(TargetDataLine line, AudioFileFormat.Type targetType) {
		m_line = line;

		new Thread(new Runnable() {// thread to update the view every second
					public void run() {
						while (m_bRecording) {
							instantPanel.upDateLabels();
							instant.reset();// reset the instant trip after
											// displaying it
							currentPanel.upDateLabels();
							tankPanel.upDateLabels();
							try {
								Thread.sleep(1000);
							} catch (Exception e) {
							}
						}
					}
				}).start();

	}

	public void start() {
		m_line.start();
		super.start();
	}

	public void stopRecording() {
		m_line.stop();
		m_line.close();
		m_bRecording = false;
		System.out.println(" inj sampleCount = " + current.sampleCount
				+ " inj hi = " + current.injHi + " inj vssTot = "
				+ current.vssTot);
	}

	boolean ig = true;

	boolean vg = true;

	void processChunk(byte[] b, int c) {
		long ih = 0;
		long vt = 0;

		for (int x = 0; x < c; x += 2) {
			int val = ((int) b[x] & 255) - 127;
			if (val > vssThreshold && vg) {
				vt++;
				System.out.println(" vss going hi "
						+ (current.sampleCount + (x / 2)));
				vg = false;
			}
			if (val < 0) {
				vg = true;
			}

			val = ((int) b[x + 1] & 255) - 127;
			if (val < injThreshold) {
				ig = true;
			}
			if (val > 0)
				ig = false;
			if (ig)
				ih++;
		}
		instant.Update(c / 2, ih, vt);
		current.Update(c / 2, ih, vt);
		tank.Update(c / 2, ih, vt);
	}

	public void realrun() {
		byte[] buffer = new byte[m_line.getBufferSize()];
		while (m_bRecording) {
			int c = m_line.read(buffer, 0, m_line.available());
			if (c != 0) {
				processChunk(buffer, c);
			}
		}
	}

	public void run() {
		if ("".equals(dummyFile))
			realrun();
		else
			dummyrun();
	}

	public void dummyrun() {
		try {
			String strFilename = dummyFile;
			File soundFile = new File(strFilename);
			AudioInputStream audioInputStream = null;
			audioInputStream = AudioSystem.getAudioInputStream(soundFile);

			int nBytesRead = 0;
			byte[] abData = new byte[44100];
			while (nBytesRead != -1) {
				nBytesRead = audioInputStream.read(abData, 0, abData.length);
				if (nBytesRead >= 0) {
					processChunk(abData, nBytesRead);
				}
				try {
					Thread.sleep(1000);
				} catch (Exception e) {
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {

		AudioFormat audioFormat = new AudioFormat(
				AudioFormat.Encoding.PCM_SIGNED, 44100.0F, 8, 2, 2, 44100.0F,
				false);
		DataLine.Info info = new DataLine.Info(TargetDataLine.class,
				audioFormat);
		TargetDataLine targetDataLine = null;
		targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
		targetDataLine.open(audioFormat);
		AudioFileFormat.Type targetType = AudioFileFormat.Type.WAVE;

		final Mpg recorder = new Mpg(targetDataLine, targetType);
		JFrame j = new JFrame("MPG Monitor!!!");
		j.setSize(640, 125);
		Container c = j.getContentPane();
		c.setLayout(new GridLayout(4, 1));

		JPanel hd = new JPanel();
		hd.setLayout(new GridLayout(1, 8));
		hd.add(new JLabel(""));
		hd.add(new JLabel("MILES"));
		hd.add(new JLabel("GAL"));
		hd.add(new JLabel("MPG"));
		hd.add(new JLabel("HRS"));
		hd.add(new JLabel("MPH"));
		hd.add(new JLabel(""));

		c.add(hd);
		c.add(recorder.instantPanel);
		c.add(recorder.currentPanel);
		c.add(recorder.tankPanel);

		j.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				recorder.stopRecording();
				recorder.tank.save();//this just adds the trip fields to the properties object
				try {
					properties.store(new FileOutputStream(new File(propFile)),"");
				} catch (Exception f) {
				}
				System.exit(0);
			}
		});

		j.setVisible(true);
		recorder.start();

	}

	static Properties properties;

	static String getProperty(String tag, String dflt) {
		String s = "";

		try {
			if (properties == null) {
				properties = new Properties();
				try {
					properties.load(new FileInputStream(new File(propFile)));
				} catch (Exception e) {
				}
				;
			}
			s = properties.getProperty(tag);
			if (s == null) {
				s = dflt;
				properties.put(tag, s);// will propogate default values to the
										// file
			}
		} catch (Exception e) {
		}
		return s;

	}

}
So, believe it or not, it's all there. I think its a solid proof of concept anyway. Every car will be different, and there's plenty else that can be done to it: RPM column, invert signal/swap channel from mpg.properties file. A a collection of presets for different cars... But I, personally, am gonna try and do other stuff for a while
Attached Thumbnails
Click image for larger version

Name:	Mpg.GIF
Views:	1173
Size:	10.2 KB
ID:	641   Click image for larger version

Name:	graph.GIF
Views:	1173
Size:	15.6 KB
ID:	642  
__________________

__________________
Standard Disclaimer
skewbe is offline   Reply With Quote
Old 07-22-2007, 08:26 AM   #33
Registered Member
 
skewbe's Avatar
 
Join Date: Jan 2007
Posts: 771
Country: United States
Quote:
Originally Posted by sonyhome View Post
Pretty cool ... but I don't quite understand your diode clamp interface you used.

Could you explain how you make it work?
You connected directly to the injector via a 10K resistor?
And then you grounded the signal via a diode bridge? Is that to avoid having signals above 0.6V? Don't understand...
the diodes are supposed to limit the max voltage going into the sound card, yes. The resistor is supposed to prevent the diodes from trying to clamp the vss and injector to .6 volts. The VSS side could use some work in my case.


Quote:
Originally Posted by sonyhome View Post

And what's VSS for?

I though you'd use a coil to detect the pulses so the laptop would be totally independant from the car's electrical circuit...
To do Miles per Gallon, you need to know how many miles you have gone. A direct signal is much easier to parse than an induced signal in a coil. The resistor provides enough independance.


Quote:
Originally Posted by sonyhome View Post
All you have to do now to compute duty cycle is count the number of samples above a threshold vs all the samples.
You may need to adjust with a constant, or adjusting the threshold since the ramp up slope is not vertical, but seems constant.
Yah, I just have a fudge number, there probably is a constant component to the injector pulse that could be factored in for greater accuracy.

*Note, if one were to add a "injectorPulseCount" field to the Trip class, and detect it like the vss pulses, then RPM and a constant value adjustment per pulse could be accomplished.

*also note that it is trivial to add more trips, like "trip 1", "trip 2", etc, and have them save to disk when the window is closed.

Here is the sample a mpg.properties file it creates in the current directory, you can tweak the thresholds and fudge factors (and even pipe in a .wav file of a recording of your probes):
#
#Sun Jul 22 11:13:47 CDT 2007
dummyFile=
tank.injHi=3984869
tank.vssTot=1076
fuelFudge=8000000.00
injThreshold=-30
vssThreshold=100
tank.sampleCount=3984876
distanceFudge=3200.0
__________________
Standard Disclaimer
skewbe is offline   Reply With Quote
Old 07-22-2007, 02:55 PM   #34
|V3|2D
 
thisisntjared's Avatar
 
Join Date: Mar 2006
Posts: 1,186
Country: United States
Send a message via AIM to thisisntjared
thanks for the open source project
__________________
don't waste your time or time will waste you
thisisntjared is offline   Reply With Quote
Old 07-22-2007, 06:37 PM   #35
Registered Member
 
MetroMPG's Avatar
 
Join Date: Dec 2005
Posts: 4,223
Country: United States
I am duly, duly impressed! (And in over my head.) Congratulations are in order!
MetroMPG is offline   Reply With Quote
Old 07-23-2007, 06:29 PM   #36
Registered Member
 
skewbe's Avatar
 
Join Date: Jan 2007
Posts: 771
Country: United States
MPG cruise control

Thanks yall, I wanted to get this idea down somewhere after looking up DWL again.


Ok, so now the computer knows the mpg, big whup. BUT, that old parallel port... It is great for driving, say, a stepper motor, which could, say, be chained up to, say, the throttle to...

Yah, you got it...


Maintain a pre-determined MPG, exactly
__________________
Standard Disclaimer
skewbe is offline   Reply With Quote
Old 07-23-2007, 06:40 PM   #37
Registered Member
 
MetroMPG's Avatar
 
Join Date: Dec 2005
Posts: 4,223
Country: United States
Inspired. Creativity is cool.
MetroMPG is offline   Reply With Quote
Old 07-23-2007, 08:59 PM   #38
Registered Member
 
skewbe's Avatar
 
Join Date: Jan 2007
Posts: 771
Country: United States
Heh, a couple more goodies that could be added by providing things like car weight:

1. monitor acceleration (based on change to vss pulses) and other dynomometer/ET type stuff.

2. provide indication of acceleration/fuel consumption (find the peak when accelerating?) Might be good to have an audio signal for this so you can watch the road while accelerating. Make small adjustments in the gas pedal till the pitch frequency tops out.

3. Compute CDA, accelerate to 60 on a flat road and coast to a stop, let it figure out the rest.
__________________
Standard Disclaimer
skewbe is offline   Reply With Quote
Old 07-24-2007, 06:04 AM   #39
Registered Member
 
MetroMPG's Avatar
 
Join Date: Dec 2005
Posts: 4,223
Country: United States
Ooo! I like the audio signal idea. Sort of like version 1.0 of the DWL cruise control.

An audio tone to help you stay near your target FE, rather than spending a lot of time glancing at a screen.
MetroMPG is offline   Reply With Quote
Old 07-24-2007, 06:18 AM   #40
Registered Member
 
psyshack's Avatar
 
Join Date: May 2006
Posts: 443
Country: United States
Boy there are some smart folks in this old world. WOW
__________________

__________________
09 HCHII, w/Navi
07 Mazda3 S Touring, 5MT
Mild Hypermiler or Mad Man?
psyshack is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Not very precise mpg calculation larjerr Fuelly Web Support and Community News 4 08-20-2012 02:03 AM
epa estimates cseverens Fuelly Web Support and Community News 2 06-09-2010 04:48 AM
Keeping my distance in traffic khurt General Fuel Topics 8 09-07-2008 04:23 AM
Electrical power and cars. DracoFelis Automotive News, Articles and Products 2 09-16-2006 02:31 PM
"active" aero grille slats on 06 civic concept MetroMPG General Fuel Topics 21 01-03-2006 01:02 PM

Powered by vBadvanced CMPS v3.2.3


All times are GMT -8. The time now is 05:26 AM.


Powered by vBulletin® Version 3.8.8 Beta 1
Copyright ©2000 - 2017, vBulletin Solutions, Inc.