Reputation: 959
I need to cut out frequencies outside the 0.667 - 3.833 Hz range (heart rate range: 40 to 230 bpm). I looked at the Apple documentation, but I only see the AVFoundation Butterworth filter. Apparently, "The valid range of values is 20 Hz through (SampleRate/2)." The filter comes from the AVAudioUnitEQ so it's understandable... I can't seem to find any filters that work within the frequency range I'm working with.
Will I have to implement my own Butterworth filter or is there something I am missing?
EDIT: So I've dug into the documentation a bit more and I found an IIR filter and FIR filter, but it's not really what I expected... The IIR filter is a "cascaded biquad IIR filter", not a Butterworth filter (which is what I would prefer). I did a little reading and I have no idea how this filter is supposed to work. Can I achieve a similar function as a Butterworth filter if I play around with the coefficients? If so, how do I go about doing that? The goal is to have a flat pass-band with no ripples.
Blog post I'm loosely following: http://www.ignaciomellado.es/blog/Measuring-heart-rate-with-a-smartphone-camera
Blog post with some biquad filter advice: http://www.ignaciomellado.es/blog/Measuring-heart-rate-with-a-smartphone-camera
Upvotes: 0
Views: 1701
Reputation: 16748
The implementation of an IIR filter is pretty strait forward and simple in any language. The design of an IIR is the challenge and fun part. There are lots of trade-offs that can be made. Biquad IIR filters are pretty good second order filters (which can be configured with Butterworth coefficients) and for many applications one would be sufficient, however you can also cascade them to make even higher order filters if you need to.
The first thing is to figure out what you really need, which generally means you need to understand what the noise you want to filter looks like in the frequency domain, then design a filter that suppresses the noise.
There are lots of tools around that will give you a view of what the frequency response of the a given set of IIR coefficients will look like.
Here is one of many from a quick google search.
A key parameter is how often you are sampling the source of your data (the sample rate)
Once you have the coefficient the implementation is very simple, its just a function of the current input sample and a number of previous inputs and outputs.
You can find some details here, but here is a function.
y[n] = b0* x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a2 * y[n-2]
where x[n] is your current sample, x[n-1], is the previous sample, etc. and y[n] is your current output value, while y[n-1], y[n-2] are previous outputs.
If you really want to get into the details of the filter design, one of the best resources I have found is to use SciPy, again there are many tutorials on how to do this as well.
I have not looked at it but here is a youtube video describing how to design a Butterworth filter in Python.
And as I said earlier, once you have the coefficients, the implementation in any language is pretty simple. For example here is a very simple Biquad I did in c++ to filter data in an Arduino project. This could easily be converted to swift or any other language.
class BiQuad {
public:
BiQuad(double b0, double b1, double b2, double a1, double a2)
: b0_(b0), b1_(b1), b2_(b2), a1_(a1), a2_(a2) {}
double processSample(double xn) {
xn_ = xn;
yn_ = b0_ * xn_ + b1_ * xnm1_ + b2_ * xnm2_ - a1_ * ynm1_ - a2_ * ynm2_;
ynm2_ = ynm1_;
ynm1_ = yn_;
xnm2_ = xnm1_;
xnm1_ = xn_;
return yn_;
}
double getCurrentY() { return yn_; }
void prime(double value) {
xn_ = xnm1_ = xnm2_ = yn_ = ynm1_ = ynm2_ = value;
}
private:
double b0_;
double b1_;
double b2_;
double a1_;
double a2_;
double xn_;
double xnm1_ = 0.0;
double xnm2_ = 0.0;
double yn_ = 0.0;
double ynm1_ = 0.0;
double ynm2_ = 0.0;
};
Hope this helps.
Upvotes: 3