This page is for developers, about the heart of IonSense: how to find the peak pressure point (PPP) efficiently, precisely and reliably

you can start to work on the ion-data crunching today (no excuses :)

If you want an ion-sense datafile to look at, grab my one on


I think this could be interesting!PSIplugs:

Okay, I looked at all the exisiting algorithms and came up with another one that I think works best. (It works nicely with James data)

I'll still need some more data to further test it. Anyone know where I can get it?

Anyway, here's a code snipit with an explanation of the algorithm:

// This function finds the peak pressure point in a ion sensing signal sample.
// It finds it by working backwards from the end of the signal, as the peak is last 
// major peak in the signal (above noise).  
// It seems most efficient to work backwards as ionisation during the flame front 
// is very unpredictable and therefore computationally expensive to eliminate when 
// working forward from the start of the signal.
// This algorithm finds the peak by firstly looking for a zero rate of change 
// (indicating the end of a peak) and then finding the next reversal 
// (indicating the start of the peak) where it halves the peak plateau to find 
// the exact peak center.

// It assumes that sampling started immediately after spark event
void differentialPeakFind(void)
	// init some vars
	int prev, highest, peakCount;
	int bitWordLength = 10;  // 10 bit word length
	int noiseRatio = 100; //1:100 SNR

	int noiseFloor = (2 << (bitWordLength - 1)) / noiseRatio;
	highest = 1;
	peakCount = 0;

	// lastSample is just that..the last sample
	// so, we work backwards
	// ...until we find the end of the signal above the noise floor
	while(sample[lastSample] < noiseFloor)

	// now, work back across the signal
	for(i = lastSample; i > 0; i--)
		// from the last sample to the end of the spark event
		if(sample[i] > highest)
			// record the highest peak
			highest = sample[i];
			peakCount = 0;
		else if( (sample[i] < highest) && (highest >  noiseFloor) )
			// dropping back down again (begining of peak plateau)
			// halve it to get the peak center and bail with the sample number (and value if needed)
			peakX = i + (peakCount / 2) + 1;
			peakY = sample[peakX];
		else if(sample[i] == highest)
			// peak plateau - measure it so we can find the center after finding the start


I have looked at the different samples available in some of the ION papers and I don't think that the above procedure will work very well. In many of the samples the pressure phase looks like a notch on the falling flank of the flame front phase. By reading the papers available on the ION page get the impression that the same engine can have the same PPP in two consecutive strokes and still have a 'school book' ION signal in one of them and almost no visible post flame phase in the next! I guess that working with averaged data could take care of that. -Jörgen''

Yes, the flame front can vary a lot and that's the issue, but I expect (this is why I need more data) that we get a distinct PPP in the signal most of the time, where the above algorithm, combined with Mode statistics will work well.

Some of the papers show that a subtracting a gaussian curve fitted to the post flame phase will work very well for elimintating it. Unfortunately I'm lost when it comes to math and I don't know what is involved in doing this.

Fitting the curve mathematically is very computationaly expensive. One method is to map a curve but that requires quality peak information (i.e no flame front overlap or noise) so I concluded that the error margin would be much the same as the above algorithm.

They also show that fitting a gausian curve to the remainder will effectively pin down PPP. Even if I don't know what's involved in the curve fitting I think that it feels like overkill. Just finding the flanks and take the average of their position should get us close.

I tried curve fitting to eliminate the flame front, etc, but again, it is difficult due to the flame front variance, i.e you don't elimate it every time, so we still get a margin of error.

The danger involved in ignition tuning makes it important to work with good data. I suggest that knock detection is taken care of each event, should be simple. (And missfire detection if that is easy to find in one sample.)

The above algorithm will easily detect missed PPP and can therefore drop it. When we get more data, we should be able to come up with a constant point in the signal (x amount of samples after spark event) at which we can stop analysing, i.e. ignore the expected normal flame front.

Then the data from 5-10samples is averaged and used to find PPP, the more averaging we have the closer to the school book ION signal we will get. We then store 5-7 of the PPP results, kill the highest and the lowest and take an average of the remaining samples. _IF_ the engine has been in steady state (RPM, LOAD, AFR,TPS and no missfires or detonation) throughout the process the average is used to update a 'short term suggested change map' Given the 5 sample averaging and steady state this table would be updated once every 2nd second at 2k. This could be promoted by hand to the long term table or used to slowly change the long term table.

I think finding the Mode will be best, as opposed to average

Can you explain that further? -jörgen

By Mode, I mean the most frequent value, i.e. IonSense code should sample say 10 combustion cycles then find the most frequent ppp value as opposed to an average value. e.g 10 cycles have calculated ppp @ 2, 15, 10, 15, 15, 10, 15, 21, 15, 15 degrees, then the most frequent value (Mode) is 15 degrees so we use that value (average would be 13).

Ok, that makes sense if we can find PPP on a cycle to cycle basis. But I don't like the shortcuts in finding PPP! Ignition is not something to play around with. I'm helping install an engine with $5k of repairs in it this week because someone who _really_ should know better did play around with ignition. -Jörgen

I'm not taking any shortcuts either as I've spent over 25K on my engine. I believe that this algorithm has potential and it's not a shortcut, it's just the result of applying some lateral thinking to come up with something simpler and as good or better....I just need to properly test it (on a cheap spare engine that I have).

If you need help with testing later, I have access to a engine dyno and a really cheap engine... //Emil

Some thoughts on Gaussian curve fitting and computational load.

The 'burn-time' of the fuel-air mixture is dependant on (except for engine specific constant variables) the presure of the mixture.

This presure is dependant on inlet manifold presure AND in a dynamic sense the rpm. That is why you need ignition-advance based on MAP/MASS and rpm.

However if you look at the absolute 'burn-time' (flame-front) of the mixture this does not have a large variation (around 0.4 ms??).

If you would have a look-up table with for example 3 gaussian curve models (pre-computed, normalised, gaussian values for the expected sample moments) which could you interpolate relative the ignition advance. Combine this with your actual samples to find the maximum amplitude of the flame-front-ion-current and use this to adjust the amplitude of the gaussian-curve. Then you would have a very light computational way of creating a matching gaussian function for the flame-front fase of the ion-current.

Subtract this from the actual samples and you have the remaining ion-current in which you look for the peak and that is your PPP.

Voila..., something you might even be able to implement in the Atmel with some nice smart piece of hand crafted assembly!!!!

Comments please!

This is basically the method described here: [DIY ion sensing]

The problem with this is that due to different reactions during combustion, the flame front ionisation current can apparently contain one, two or even three curves, so the only way to completely emliminate it is by applying some "burn time" coefficient (like the 0.4 ms proposed), but I'm not convinced that this can be determined given variances in combustion chamber design, fuels (methanol, nitromethane), etc.

I still think that analysing the signal in reverse may provide the most predicatable outcome, i.e. the PPP is in the last substancial curve found in the signal. It's clear that we need much more data to finalise this so I'm going to work on collecting it.


Yes, you are right there is quite some variation due to cylinderhead design, fuel, etc. However these are fairly constant for a given engine-fuel combination. Also, if you have multiple curves in the flame front, I expect the sum of these curves again to approximate a gaussian curve.

Now the goal is not to completely eliminate all flame-front ion-current from the signal, but to obtain a cleaner second-part of the ion-current signal (where the PPP is). Because the critical part of the total signal is the area between the flame-front current and the PPP, if you clean-up the signal in this area you will be better able to find PPP.

If by clean-up, you mean remove then I think we still have a problem with PPP that is overlapped by the flame front, i.e we also remove the peak of the PPP curve. My suggestion is that that we have two possible choices for the algorithm:

* Find the PPP only when the peak is not overlapped or obscured by the flame front using the reverse rate of change algorithm (as shown in code snipit above) and approximate (using Mode) when it is obscured.

* Fit mapped Gaussian curves to the last curve in the signal in reverse, i.e. start the fit at the end of the signal and work backwards.

Either way, I believe that the PPP is always the last substantial curve in the signal and it's therefore inefficient to work forwards from the start of the signal (through the flame front). Anyone agree with this?

This would fit in with your approach of finding PPP by identifying the last peak in the signal.

My approach would require mapping, just like ignition mapping, it might even use the same map (as there is relation between ignition advance and the width of the gaussian-bell curve).

You then have the choice of making a feedback loop in your code to adjust/finetune your 'map' in order to further optimize the curve-fit.

As you have pointed out, my approach resembles the one in the paper. I think that approach is very nice, but requires quite somebit of computation because everytime the curve is computed through quite computation intensive routines. I suggest using pre-computed 'maps' of a number of curves and interpolate between them related to ignition advance. The computation then reduces to some scaling of the pre-computed values. The complexity of this can be further reduced is you relate the samples to fixed time-intervals instead of crank-degrees as the 'burn-time' of the mixture is relative constant.

Please comment.

I agree with this. By using the processor clock, the algorithm could learn the signal and then not even sample parts of it, e.g. the flame front.

Gaussian curve fitting

A Gaussian curve has 3 parameters ( a 3 dimension vector):

Assume we have


Altogether this is appr. 5 multiplications and 5 additions for every sample. Some tiny overhead at the start of the iteration (to decide next vector).

Computation time:

No division needed. Fixpoint is good (16 bit is probably better than 8).

As the Gaussian bell curve is essential symetric you could limit the matching to one half of it, essentially halfing the number of computations.

You could match to the last part of the ion-current (the right-half of the PPP-curve) because this part is the least influenced by the flame-front current and thereby find PPP.

You could also do this for the first half of the flame front current (as in the paper) and get rid of the brink of the flamefront current. So you might have three matching factors; Fit to front of flame-front curve, match to rear of PPP-curve, match of both curves added to totaal ion-current. Don't know what is best but it leaves some options open....

Further, you can also spread the number of approximation steps over multiple samples. I mean, if you know where the PPP-curve and/or the flamefront-curve should be from previous combustion cycles (just the previous combustion cycle of the particular cylinder or from a historic-map in memory) you might not need so many iterations.

I would even consider making the number of iterations in the algorithm a fixed number as it makes the execution a fixed time process, so it is easier to schedule (as it will require a fixed cycle-budget). It even makes the program easier as you have to build less decision-logic.