Is there a filter function? If not, help to create one please.

Hello

Still learning the Arduino.

Is there a built in filter function? I'm using a hx711 sensor to capture the weight of a keg. I would like to smooth out the read value. I'm not familiar at all with average technique. I did learn some basic tips while I was studying electronics back in 1980.

My idea, take 12 reading, removed the highest and lowest value. Then do an average of the 10 left reading.

Does it make sens?

If yes, how can I do that? Don't have a single idea on how to start this...

Martin

Sure: https://github.com/tttapa/Arduino-Filters

But do know that just averaging the data, while simple conceptually, is not a great filter.

Pieter

Yes, that makes sense and it should be quite simple to implement - there are a lot of examples, working code and so on in the forum for you to find.

function GetAverage returns integer
  variables: lowest = 1024, highest = 0, all = 0, readings = 12, current
  while readings > 0 do
    current = readSensorValue()
    if current > highest then highest = current
    if current < lowest then lowest = current
    all += current
    readings -= 1
  end
  return (all - lowest - highest) divided by 10
end

In a series of consecutive readings, I have found that the first few readings are most likely to be off, and take a few dummy readings before I start recording the value returned by analogRead()

DrAzzy: In a series of consecutive readings, I have found that the first few readings are most likely to be off, and take a few dummy readings before I start recording the value returned by analogRead()

I usually use one dummy reading if I switch the mux channel, more than one never seems to do any better.

Were you reading high-impedance outputs that you needed multiple readings? IIRC, the ATmega328P's ADC can handle up to 5 kΩ, if you go higher, it takes too long to charge the sample-and-hold capacitor, so you need multiple readings.

I have have great success with the Simple Kalman filter GitHub - denyssene/SimpleKalmanFilter: A basic implementation of Kalman Filter for single variable models.. Getting a good time lapse, using some form of millis or micros, helps improve the filters operation.

PieterP: Sure: https://github.com/tttapa/Arduino-Filters

But do know that just averaging the data, while simple conceptually, is not a great filter.

Pieter

Thanks, I haven't seen that version of the filter library before. Other versions of that are much less flexible.

The moving average is a GREAT filter. See this filter comparison

My idea, take 12 reading, removed the highest and lowest value. Then do an average of the 10 left reading.

This should work well.

If there are large outliers in the data, the median filter works much better than any moving or simple average. Several examples appear in a search for "arduino median filter".

MorganS: The moving average is a GREAT filter. See this filter comparison

I would disagree with the conclusion of that comparison. An EMA (single-pole recursive filter) can be implemented much more efficiently if the pole lies a negative power of 2 away from one, and requires just one word of memory. The SMA on the other hand requires N words of memory, and requires expensive integer divisions if N is not a power of 2. Even when N is a power of 2, it's still slightly slower than the EMA. I do not get his point about development time, the EMA algorithm is trivial, it's just a straightforward implementation of the difference equation, and the SMA requires a bit of fiddling with circular buffers, but it's pretty straightforward as well.

Here are the speed differences between some of the different filters mentioned here, as tested on an Arduino Leonardo:

[color=#000000]EMA[/color] [color=#000000]([/color][color=#000000]K[/color] [color=#434f54]=[/color] [color=#000000]4[/color][color=#000000])[/color]
[color=#000000]358731.53[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

[color=#000000]EMA[/color] [color=#000000]([/color][color=#000000]K[/color] [color=#434f54]=[/color] [color=#000000]6[/color][color=#000000])[/color]
[color=#000000]297867.28[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

[color=#000000]EMA[/color] [color=#000000]([/color][color=#000000]K[/color] [color=#434f54]=[/color] [color=#000000]8[/color][color=#000000])[/color]
[color=#000000]657375.75[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

[color=#000000]SMA[/color] [color=#000000]([/color][color=#000000]N[/color] [color=#434f54]=[/color] [color=#000000]16[/color][color=#000000])[/color]
[color=#000000]162951.37[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

[color=#000000]SMA[/color] [color=#000000]([/color][color=#000000]N[/color] [color=#434f54]=[/color] [color=#000000]10[/color][color=#000000])[/color]
[color=#000000]51198.03[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

[color=#000000]SMA[/color] [color=#000000]([/color][color=#000000]N[/color] [color=#434f54]=[/color] [color=#000000]100[/color][color=#000000])[/color]
[color=#000000]53278.78[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

[color=#000000]Median[/color] [color=#000000]even[/color] [color=#000000]([/color][color=#000000]N[/color] [color=#434f54]=[/color] [color=#000000]10[/color][color=#000000])[/color]
[color=#000000]16338.37[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

[color=#000000]Median[/color] [color=#000000]odd[/color] [color=#000000]([/color][color=#000000]N[/color] [color=#434f54]=[/color] [color=#000000]11[/color][color=#000000])[/color]
[color=#000000]17778.92[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

[color=#000000]Median[/color] [color=#000000]even[/color] [color=#000000]([/color][color=#000000]N[/color] [color=#434f54]=[/color] [color=#000000]100[/color][color=#000000])[/color]
[color=#000000]2162.23[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

[color=#000000]Median[/color] [color=#000000]odd[/color] [color=#000000]([/color][color=#000000]N[/color] [color=#434f54]=[/color] [color=#000000]101[/color][color=#000000])[/color]
[color=#000000]2658.79[/color] [color=#000000]filter[/color] [color=#000000]operations[/color] [color=#000000]per[/color] [color=#000000]second[/color]

Observations:

The EMA is much faster than the EMA, even if N is a power of two.

If K = 4, the EMA is very fast, because the AVR instruction set has an instruction to swap nibbles in a byte. If K = 8, the EMA is even faster, because this just corresponds to removing the least significant byte. Otherwise, multiple bit shift instructions are used, which is slower.

The SMA with N a power of two is significantly faster than SMA with N not a power of two, because the division by N can then be implemented as a series of bit shifts. (It should be noted that the library uses special code for signed integers, otherwise the compiler can't optimize it.) Making N 10 times larger doesn't really impact the performance.

The median filter is a bit slower, because each step involves copying and partially sorting the ring buffer. As N increases, the performance drops, because the sorting algorithm used has an average complexity of O(N). Odd N is faster, as the median requires only one middle element, when N is even, you have to find the two middle elements, which requires N/2 extra comparisons.

Filters used: EMA Filter SMA Filter Median Filter

For filtering most sensor readings, all you need is a simple low-pass filter:

float smoothedValue += ((rawValue - smoothedValue) * coeff;

rawValue is the new reading smoothedValue is the smoothed (filtered) reading coeff is the filter coefficient, between 0 and 1.0. The smaller the value, the more aggressively it gets smoothfiltered, and the longer it takes to reach the final value after a large change. Typical values, using Arduino floats, would be between 0.005 and 0.20.

Regards, Ray L.