Is there any filter libraries for teensies out there?

Status
Not open for further replies.

frankzappa

Well-known member
I’m looking for a good filter library. Is there a library with bessel, chebyshev, butterworth etc. filters?

I need them to filter some sensor data.

I found this on github which seems to be what I need: https://github.com/vinniefalco/DSPFilters.git

However it’s not an arduino library and requires some skill to implement (which I don’t have), my programming knowledge is limited.

Thanks
 
The audio library has biquad filters. Maybe you could come up with biquad coefficients to give you those filter responses?
 
I’ve seen coefficients generators online, it’s a possibility I guess.

I was hoping there was an existing library I could mess around with and try different settings on the fly.

There are also code generators that generate a filter of your choice in a class I can just paste into my program.

However still I have to decide the cutoff frequency beforehand, go online, generate, paste the code, etc. It’s a painfully slow process if you need to experiment to find the best settings.
 
I was hoping there was an existing library I could mess around with and try different settings on the fly.

In the audio library tutorial, maybe take a look at part 2-7 starting on page 19.

https://www.pjrc.com/store/audio_tutorial_kit.html

If you haven't used the audio library at all, maybe look at the first few pages in section 1 and the first part of section 2, to learn how the design tool works.

From the tutorial:

The example program uses the 3 buttons to reconfigure the mixers, and the A3 pot to allow you to vary the filter frequency as the music plays. The serial monitor window will show the actual frequency setting as you turn the knob. On the low-pass and high-pass signals, the music will seem to get quieter as you filter away more of its spectrum.

There is also a full walkthrough video on that page. If you click to view it on YouTube, the video's description on YouTube has links to all the parts. So you can skip forward to part 2-7 and listen to a demo of the filter frequency changing.

In Arduino, you can access all the tutorial examples by clicking File > Examples > Audio > Tutorial. Please keep in mind the examples are meant for you to actually do the tutorial, which involves drawing stuff in the design tool and exporting code to add to those examples. If you want to skip that step, click File > Examples > Audio > Tutorial > Reference. But really, time actually doing the tutorial would probably be time well spent.

Admittedly that tutorial example is the state variable filter rather than biquad, but the concept is similar. Hopefully the tutorial can help you get up to speed quickly on how audio works on Teensy.
 
I maintain this Arduino-Filters library.
It supports Butterworth filters out of the box, as you can see in this example: Butterworth.ino
Ideally, this example is all you need to filter some sensor data.

If you want to delve into it a little deeper, you can find the derivation of the Butterworth filter coefficients here: Discretization of a Butterworth filter
Using these coefficients, you can use any library that supports BiQuad filters, like the Teensy Audio library, for example.
You can easily calculate the coefficients in your Arduino code, you don't need to use a filter design tool per se.
You don't have to go through all the mathematics of course, the only result you need are the coefficients (bₖ₀, bₖ₁, bₖ₂) and (aₖ₀, aₖ₁, aₖ₂), which are the coefficients of the k-th stage of the BiQuad filter, for k = 0..n/2-1, for n the order of the filter. If n is odd, you also need one first-order stage.
Many implementations expect aₖ₀ to be 1. You can just divide the other five coefficients by aₖ₀ in that case.

Other filter types like Chebyshev are similar, but I haven't had the time to implement them yet, and they have some additional design parameters like pass/stop band band ripple that you'd have to implement. Butterworth is simpler in that respect, you just have to select the order and the cut-off frequency.

Bessel functions aren't usually discretized because they lose some of their interesting properties in the process.

If you want to generate the filter beforehand and hard-code the coefficients in your code, you can use the SciPy “butter”, “cheby1” and “cheby2” functions. You can find an example included with the Arduino-Filters library: visualize-butterworth.py
By default, these functions return the coefficients of the entire transfer function polynomials, which is fine for low order filters, but prone to numerical errors for higher orders, so it's best to use a BiQuad implementation (each BiQuad filter is a second order filter, so implementing a filter using multiple BiQuads is referred to as “Second Order Sections” or SoS). You can pass the option output='sos' to the SciPy functions to get the BiQuad coefficients.

Pieter
 
I maintain this Arduino-Filters library.
It supports Butterworth filters out of the box, as you can see in this example: Butterworth.ino
Ideally, this example is all you need to filter some sensor data.

If you want to delve into it a little deeper, you can find the derivation of the Butterworth filter coefficients here: Discretization of a Butterworth filter
Using these coefficients, you can use any library that supports BiQuad filters, like the Teensy Audio library, for example.
You can easily calculate the coefficients in your Arduino code, you don't need to use a filter design tool per se.
You don't have to go through all the mathematics of course, the only result you need are the coefficients (bₖ₀, bₖ₁, bₖ₂) and (aₖ₀, aₖ₁, aₖ₂), which are the coefficients of the k-th stage of the BiQuad filter, for k = 0..n/2-1, for n the order of the filter. If n is odd, you also need one first-order stage.
Many implementations expect aₖ₀ to be 1. You can just divide the other five coefficients by aₖ₀ in that case.

Other filter types like Chebyshev are similar, but I haven't had the time to implement them yet, and they have some additional design parameters like pass/stop band band ripple that you'd have to implement. Butterworth is simpler in that respect, you just have to select the order and the cut-off frequency.

Bessel functions aren't usually discretized because they lose some of their interesting properties in the process.

If you want to generate the filter beforehand and hard-code the coefficients in your code, you can use the SciPy “butter”, “cheby1” and “cheby2” functions. You can find an example included with the Arduino-Filters library: visualize-butterworth.py
By default, these functions return the coefficients of the entire transfer function polynomials, which is fine for low order filters, but prone to numerical errors for higher orders, so it's best to use a BiQuad implementation (each BiQuad filter is a second order filter, so implementing a filter using multiple BiQuads is referred to as “Second Order Sections” or SoS). You can pass the option output='sos' to the SciPy functions to get the BiQuad coefficients.

Pieter

I think the butterworth will be enough. Thanks.

I don’t know much about filters but I ran into something called denormalisation which I haven’t found much info about more than it’s something that can happen and can cause problems. Any chance you or paul know something about that?

The reason I’m asking this is because I’m using a filter in my project and on occasion I get weird noise problems when the sensors are idling around zero (ac signal). Only on some sensors and not always. I used a low pass ewma filter. Sample freq is 50000 samples per second and the alpha value is like 0.005 or so. I’m thinking maybe it’s some rounding errors because of some small numbers.
 
I'm not familiar with “denormalisation” in digital filters. In analog filter design, there seems to be a technique called denormalisation, but I'm not familiar with it.
In all floating point operations, you can end up with really small numbers that cannot be represented in the standard normalized form (1.mantissa × 2^exponent) because the exponent is too small. These numbers are referred to as “denormals” and are represented as 0.mantissa × 2^minimum exponent. Maybe that's what denormalisiation refers to? AFAIK, having denorms are not the cause of noisy outputs for filters, but they can increase the CPU load, as denorm computations are sometimes slower (I don't know if this is the case on the Teensy's FPU).

So I don't think that's the issue here. Can you post your code and maybe a data file with part of the signal that demonstrates the noise you talk about?
It matters how you implemented your filter, there are two ways to do the subtraction. Subtractions of numbers that are close to each other are always problematic from a numerical perspective.
 
I believe it was about the CPU load.

Anyway, here is the function for the filter, I store the previous value from 10 sensors in an array C_FILTERALPHA is a constant that is set to something like 0.005 or so.

Code:
float filterEWMA(float sensorValue, uint32_t i)
{
float filteredValue = C_FILTERALPHA * sensorValue  +  (1 - C_FILTERALPHA) * g_previousFilteredValue[i];
g_previousFilteredValue[i] = filteredValue;

return filteredValue;
}

The sensor signal is squeeky clean after filtering and is pretty much perfect but the problem occurs occasionally on some analog channels.

Not sure how I'll post the signal, it's an AC signal from a piezo sensor. It's 12 bit.

I should also add that I multiply the sensor reading by 100 because the values get small after filtering, also I reverse the phase (just 0 minus the sensor value).

Here is the sensor code part (it's the ADC library):

Code:
void setup() {
  
  ///// ADC0 ////
  adc->adc0->setAveraging(4);                                             // set number of averages
  adc->adc0->setResolution(12);                                           // set bits of resolution
  adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED );       // change the conversion speed
  adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED );           // change the sampling speed
  ////// ADC1 /////
  adc->adc1->setAveraging(4);                                             // set number of averages
  adc->adc1->setResolution(12);                                           // set bits of resolution
  adc->adc1->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED );       // change the conversion speed
  adc->adc1->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED );           // change the sampling speed
 }

And I read two sensors at a time and process between readings:

Code:
adc->startSynchronizedSingleRead(A2, A3);

//Work on previous sensor reading, filtering, peak tracking etc.

  while (adc->adc0->isConverting() || adc->adc1->isConverting());
  g_sensorValue[2] = 100.0f * (adc->adc0->readSingle());
  g_sensorValue[3] = 100.0f * (adc->adc1->readSingle());
  adc->startSynchronizedSingleRead(A4, A5); //start the next sensor reading 

//work on sensors A2/A3 etc.
 
Here is a comparison pic of two sensors idling after a peak. You can see one is oscillating a bit more when no vibrations are being detected, it happens when it's just eletrical noise. Two of 10 sensors do this and it happens on the inputs on the teensy, not the circuit it self as far as I can tell. https://www.dropbox.com/s/r35j117zv73z2m1/jig.jpg

It doesn't look that bad but occasionally it gets worse than this.
 
I don't have too much time to look into it right now, but here are a couple of things you could try:

- Try using doubles instead of floats. If it's a numerical issue, there should be a difference.
- Try implementing the filter as filtered = prev + alpha * (input - prev)
- Try using integers instead of floats. It'll have different numerical properties, and it might be faster if that's something you care about. The Arduino-Filters library has one for unsigned integers, and you can find one that works with signed integers as well here.

It's probably useful to compare the filter input with the output instead of just looking at the output.
 
I don't have too much time to look into it right now, but here are a couple of things you could try:

- Try using doubles instead of floats. If it's a numerical issue, there should be a difference.
- Try implementing the filter as filtered = prev + alpha * (input - prev)
- Try using integers instead of floats. It'll have different numerical properties, and it might be faster if that's something you care about. The Arduino-Filters library has one for unsigned integers, and you can find one that works with signed integers as well here.

It's probably useful to compare the filter input with the output instead of just looking at the output.

I tried your suggestion of implementing the filter as filtered = prev + alpha*(input-prev)

I think it works better. Will see if the problem occurs with time I guess. I also tried some cheby, bessel and butterworth filters Generated from this site: http://www.schwietering.com/jayduino/filtuino/index.php?

These are great, however not what I need at the moment but will come in handy with other stuff in the project.

Thanks.
 
Status
Not open for further replies.
Back
Top