I\'m trying to implement heart beat recording functionality in an app i\'m developing.
The preferred method of doing this is by using the iPhone\'s camera with the light
You're trying to do detect a single heart beat "manually", that won't be very robust. I'd say that your best bet is something like a pitch or frequency detection library (the math for detecting the frequency of a color change and for detecting the frequency of a sound has to be identical).
Perhaps something like aubio which I found via this stackoverflow answer to the search "frequency detection" can help you. Otherwise check wikipedia for pitch detection and/or some of the tons of signal processing libraries out there.
I would :
1) Detect the period from peak to peak... If the period is consistent within a certain period threshold.. Then flag the HB as valid.
2) I would implement an outliar detection algorithm... Any beat that goes beyond a certain normalized threshold.. Would be considered an outlier an thus i would use the last detected beat instead to compute my BPM.
Another more complex approach would be to use a Kalman filter or something of sorts to be able to predict the bpm and get more accurate readings.. It is only after a few skips that the app will sense that the readings are not valid and stop the reading.
I presume you're using your own finger. Are you sure you don't have an irregular heartbeat? Plus, you're going to want to handle people with irregular heartbeats. In other words, you should test with a wide variety of input values. Definitely try it on your parents or other older relatives, as they might be more likely to have heart issues. Other than that, your basic problem is that your input source is going to be noisy; you're basically trying to recover signal from that noise. Sometimes that will be impossible, and you're going to have to decide if you want to bake noise into your report or just ignore the data stream when it's too noisy.
Keep trying different filter values; maybe you need an even lower pass filter. From the comments, it sounds like your low pass filter was not good; there's tons of resources on filtering out there in the web. If you've got good visualization tools that will be the best way to test your algorithm.
You can try down-sampling the data, which will smooth it out. You might also want to discard samples which lie outside a valid range, either by discarding the value altogether, replacing it with the average of the previous and next sample, and/or by clamping it to some predetermined or calculated maximum.
My biggest beef with these sorts of applications is that hiccups are treated as real, live data. One of the bikes at my gym gives useless bpm readings because, every so often, it can't find my pulse and suddenly thinks my heart's going at 300 bpm. (Which it isn't; I've asked my doctor.) For a 20-minute session the average it has is useless. I think it's more useful to see the average of the (e.g.) last ten normal beats plus the anomaly rate rather than "I tried to cram the last 20 seconds into this algorithm and here's the garbage it spat out". If you can create a separate filter that indicates anomalies, I think you'll have a much more useful application.
The answer to this question is a little bit involved, as you need to do several things to process the signal and there is no single "right" way to do this. However, for your filter you want to use a band-pass filter. This type of filter allows you to specify a range of frequencies that are accepted both at the high and low ends. For a human heart beat, we know what these bounds should be (no less than 40 bpm and no higher than 250 bpm) so we can create a filter that removes frequencies outside of this range. The filter also moves the data to be centered at zero, so peak detection becomes much easier. This filter will give you a much more smooth signal, even if your users increases/decreases their finger pressure (to a certain degree). After that, additional smoothing and outlier removal will also need to happen.
A specific type of band-pass filter that I have used is a butterworth filter. This is a little involved to create by hand since the filter changes based on the frequency you are collecting your data at. Fortunately, there is a website that can help with this here. If you are collecting your data at 30 fps, then the frequency will be 30 hz.
I have created a project that wraps all of this together and detects a user's heart rate well enough to include it in my app on the iOS app store. I have made the heart rate detection code available on github.
I made a project that uses GPUImage filters, average color and exposure, to detect your pulse. The pulse is estimated based the running average of the green component of the filtered image.
Optical Pulse Reader
It sounds like you may already have another method, but one thing you could try is to use a small median filter. For example, using the median of, say, 3 to 7 input values for each output value will smooth out those peaks without destroying the overall shape of the non-anomylous data.