[DONE] Experimenting with hardware Low-pass RC filter into Arduino analog input

i have been fiddling about with the raw data from a MMA 7361 accelerometer and it really is noisy.

i had previously been experimenting with various calculations in the code to ‘smooth it out’ by using moving average and have seen in threads, the mention of a “low pass filter”.

now i have discovered it’s actually an electronic circuit concept, and have learned what it is and what it does.

i now intend to use this actual hardware circuit to filter the MMA 7361 output before it goes into the Arduino input.

the circuit would then be like this;

before i proceed, i would like to make sure i have understood it fully asf:

  1. R should not be too high or else it starts to eat into the 10-bit resolution of the analog input.

  2. a cut-off of 1Hz is obvously silly, but i just wanted to confirm my understanding of it in code-form; i would like to try it out and compare the resulting data w/- the hardware filter, and then with the software method, at several different frequencies. (ie. 2 Hz is equivalent to delay(500);

would appreciate any comments or feedback to above statements and pointing out any misunderstandings.

Thanks.

R=10k and C=100uF gives a one-second time constant.

I’m surprised you don’t find a moving average useful - how are you doing this?

Allan

I have a couple of thoughts:

You should add a resistor between the capacitor and the analog pin. Reason, If the capacitor is charged to some voltage and power is removed from the arduino, the capacitor will discharge through the analog input pin and possibly cause damage.

You should change your R and C values. Increase the R and decrease the C. You want to have the C value in the range of ceramic or film capacitors. Reason: High value electrolytics have leakage which looks like a resistor in parallel with the capacitor.

As allanhurst suggested an digital / mathematical filter might also help. However I’ve found a mathematical filter alone often inadequate. I think a less aggressive RC filter (i.e. maybe a cutoff at 100Hz) coupled with some averaging might give you the best results.

Good luck.

  1. R should not be too high or else it starts to eat into the 10-bit resolution of the analog input.

That is nonsense.

now i have discovered it's actually an electronic circuit concept,

No it is a signal processing concept which can be implemented in hardware or software.

a cut-off of 1Hz is obvously silly

The cut off frequency is probbly not what you think it is. It is the frequency where the output is half the input, nothing else. Often people think it is the point where no frequencies get through.

What you have there is a simple "first order" filter that drops off at 6 dB per octave, Where an octave is a doubling of frequency.

all good comments which are helpful to my understanding.

allanhurst:
I'm surprised you don't find a moving average useful - how are you doing this?

i do find it useful, i was just curious to see the differences between HW and SW approaches.
i understand that one drawback of a moving average is it can miss 'sudden high peaks' ?

JohnRob:
I have a couple of thoughts:

You should add a resistor between the capacitor and the analog pin. Reason, If the capacitor is charged to some voltage and power is removed from the arduino, the capacitor will discharge through the analog input pin and possibly cause damage.

ahh yes, Arduino protection concerns - i had a feeling i had to have some, but wasn't sure where or how it would be done.

Thanks for pointing that out - so the resistor would go between the RC filter and the Arduino pin.

JohnRob:
You should change your R and C values. Increase the R and decrease the C. You want to have the C value in the range of ceramic or film capacitors. Reason: High value electrolytics have leakage which looks like a resistor in parallel with the capacitor.

As allanhurst suggested an digital / mathematical filter might also help. However I've found a mathematical filter alone often inadequate. I think a less aggressive RC filter (i.e. maybe a cutoff at 100Hz) coupled with some averaging might give you the best results.

Good luck.

thanks for the tips - will keep those in mind.

Grumpy_Mike:
No it is a signal processing concept which can be implemented in hardware or software.
The cut off frequency is probbly not what you think it is. It is the frequency where the output is half the input, nothing else. Often people think it is the point where no frequencies get through.

What you have there is a simple "first order" filter that drops off at 6 dB per octave, Where an octave is a doubling of frequency.

i see.
yes, i learned of this "low pass RC filter" from a tutorial from an audio perspective, so that made sense - i'm not quite sure how that looks from a DC perspective - the "noise" from the sensor can still be considered a sort of wave, right ?

Grumpy_Mike:
That is nonsense.

maybe i'm using the terminology wrong ?

this is how my thinking went;

without the filter, the input is "0-5V", meaning analogRead() gets 0-1023 over that range.
but; if a resistor is too big, there is a larger voltage drop, leaving less range for analogRead() ie. 0-1023 is over a smaller voltage range, meaning "less resolution" - or sensitivity ?

am i getting something fundamentally wrong there ?

without the filter, the input is "0-5V", meaning analogRead() gets 0-1023 over that range.
but; if a resistor is too big, there is a larger voltage drop, leaving less range for analogRead() ie. 0-1023 is over a smaller voltage range, meaning "less resolution" - or sensitivity ?

Practically speaking, no because the Arduino has "almost infinite" resistance (~100 Meghoms). As long as the resistor is "reasonable" (say, less than 1M) you should be fine. (Electrolytic capacitors also have leakage resistance, in the Meghoms, and that can mess you up with very-high resistances too.)

  1. a cut-off of 1Hz is obvously silly

It depends on how fast your measurement is changing... With an accelerometer you're probably right... that's too slow... Unless you are measuring the G-force of gravity and in that case you can take all day...

DVDdoug:
Practically speaking, no because the Arduino has "almost infinite" resistance (~100 Meghoms). As long as the resistor is "reasonable" (say, less than 1M) you should be fine. (Electrolytic capacitors also have leakage resistance, in the Meghoms, and that can mess you up with very-high resistances too.)

ahh yes, it's that "high impedance thing" again - i need to keep thinking of the Arduino as part of the circuit instead of "just some magic box" !

Thanks !

DVDdoug:
It depends on how fast your measurement is changing... With an accelerometer you're probably right... that's too slow... Unless you are measuring the G-force of gravity and in that case you can take all day...

ha ha, yes - it's all "relative", huh ! :smiley:

i understand that one drawback of a moving average is it can miss 'sudden high peaks'

Yes that is the whole point of a low pass filter to suppress or reject rapid changes. A low pass filter that let through sudden high peaks would be not much of a filter.

i'm not quite sure how that looks from a DC perspective - the "noise" from the sensor can still be considered a sort of wave, right ?

Yes it is a wave. However, “DC perspective “ are the wrong words, if it is DC then their is no wave. It is the AC component of your circuit that is noise. An AC circuit does not mean audio, it is any variation of voltage over time.

but; if a resistor is too big, there is a larger voltage drop, leaving less range for analogRead() ie. 0-1023 is over a smaller voltage range, meaning "less resolution" - or sensitivity ?

It is what Bob said, but also the words are wrong, resolution means how many bits the reading is in, the more bits the more resoloution. Sensitivity is how big the smallest of those bits are. None of those change no matter what you put on the input.

Grumpy_Mike:
Yes that is the whole point of a low pass filter to suppress or reject rapid changes. A low pass filter that let through sudden high peaks would be not much of a filter.

i see, it's about what you want and what a chosen method delivers - and whether this is acceptable to your requirements.

Grumpy_Mike:
It is what Bob said, but also the words are wrong, resolution means how many bits the reading is in, the more bits the more resoloution. Sensitivity is how big the smallest of those bits are. None of those change no matter what you put on the input.

okay, thanks for the correction - will absorb and comprehend that.

Grumpy_Mike:
Yes it is a wave. However, “DC perspective “ are the wrong words, if it is DC then their is no wave. It is the AC component of your circuit that is noise. An AC circuit does not mean audio, it is any variation of voltage over time.

what would a PWM (square wave ?) be called - that's technically "DC", right ?

what would a PWM (square wave ?) be called - that’s technically “DC”, right ?

No that is an AC signal because it is changing. It doesn’t have to change polarity to be AC. Anyway change polarity is just a relative term. A 5V PWM signal does change polarity with respect to 2.5V

i see, it’s about what you want and what a chosen method delivers

No any requirement can be delivered with any method, a running avrage is just one way of implementing what is known as a digital filter. The same results can be obtained with physical components or an other sort of digital filter algorithm. Digital filters come in two types, recursive and non recursive. With a recursive filter some fraction of the output is fed back into the input chain. With a non recursive filter it is not. A running avrage is just one way of implementing a non recursive filter.

Grumpy_Mike:
No that is an AC signal because it is changing. It doesn’t have to change polarity to be AC. Anyway change polarity is just a relative term. A 5V PWM signal does change polarity with respect to 2.5V

i see, a PWM does alternate between 5V and 0V.

Grumpy_Mike:
No any requirement can be delivered with any method, a running avrage is just one way of implementing what is known as a digital filter. The same results can be obtained with physical components or an other sort of digital filter algorithm. Digital filters come in two types, recursive and non recursive. With a recursive filter some fraction of the output is fed back into the input chain. With a non recursive filter it is not. A running avrage is just one way of implementing a non recursive filter.

okay, i'm slowly getting it.
an example of a recursive filter would be like that used in PID controls.
and an example of a physical component that has the feedback would be an op-amp ?

...

so anyway, thanks guys for all the responses - here is the circuit that i ended up using;

and the resulting data plot - the graph shows hand-held movement of the sensor, first pitching up and down, the rolling left and right - the X plot is raw analogRead() through the low-pass RC filter, and the Y plot is raw analogRead() fed direct from the MMA7361 module.

i also made a plot with software filtering, using a moving average (with weighting as well) and you can see that it lags behind the raw data - even against the HW-filtered one, so i'd say the HW-version proves to be a better input.

here's the code i used;

const int axisX=A1;  // roll
const int axisY=A2;  // pitch

float avgX , avgY ;
const float setcount = 20;

#define DEBUG 1

void setup() {
  Serial.begin(9600);
}


void loop()
{
    // read the input on analog pin 1 on a moving average + added weighting on most recent reading:
    avgX = ( (avgX * ( (setcount-2) / setcount) ) 
      + (analogRead(axisX) * ( 2/(setcount)) ) );

    // read the input on analog pin 2 on a moving average:
    avgY = ( (avgY * ( (setcount-1) / setcount) ) 
      + (analogRead(axisY) * ( 1/(setcount)) ) );

#ifdef DEBUG
    Serial.print(avgX);
    Serial.print("\t");
    Serial.print(analogRead(axisX));
    Serial.print("\t");
    Serial.print(avgY);
    Serial.print("\t");
    Serial.print(analogRead(axisY));
    Serial.println("\t");
#endif

}

granted that software filter is rather basic, i'm aware using an array would be more accurate in dropping the oldest value - but was wondering what the program speed consideration would be -would it be slower using an array ?

BabyGeezer:
i also made a plot with software filtering, using a moving average (with weighting as well) and you can see that it lags behind the raw data - even against the HW-filtered one, so i'd say the HW-version proves to be a better input.

The HW filtered input is delayed relative to the raw accelerometer output as well. One could see this by collecting analog data from both the accelerometer output and the RC filter simultaneously.

DVDdoug:
Practically speaking, no because the Arduino has "almost infinite" resistance (~100 Meghoms).

This in NOT true generally speaking. Arduino ADC uses sample and hold circuit. It means at start of a conversion a "low impedance" path to the internal sampling cap opens and lets it charge. It does not matter here but it does matter in other applications. If you are reading a high impedance source (i.e. voltage divider made of MOhm resistors to save current) you may run into trouble if you don't use a "reservoir" cap. The problem is made much worse when you switch channels (analogRead different pins) - the S&H cap is common for all pins. The datasheet states "The ADC is optimized for analog signals with an output impedance of approximately 10 kOhm or less." In fact OP is right high input impedance may degrade resolution of the ADC but for other reasons than he thinks.

As stated by MrMark, the R-C will delay the accel signal, the delay is a function of frequency.

If you look at Bode Plot in the figure titled "Frequency Response of a 1st-order Low Pass Filter" you can see the delay, represented as a phase at (each) frequency.

When looking at how the A/D works, it takes a "snapshot" of the input pin and holds it in a 14 pF capacitor. This is akin to taking a "flash" photo of someone in motion, often the resulting photo is shows the subject in some awkward position. The same goes for the arduino A/D. If a noise spike occurs at the time the analog multiplexer disconnects from the sampling capacitor, your conversion reflects that noise spike as a real value.

In the past, I've had the best luck (accuracy) with a combination of analog filter and average calculation. The analog filter removed (reduces) the high frequency noise, the average calculation helps with lower frequency variations.

Hope this helps.

PS If you want to be philosophical, there is not such thing as DC voltage. The universe has only been around for 13.772 billion years. So the lowest frequency one could see is 1/13.772 billion years (converted to Hz).

BabyGeezer:
i also made a plot with software filtering, using a moving average (with weighting as well)

If you want to compare your RC filter with a simple software filter, have a look at:

                                    // Exponential Moving Average filter...
#define FILTER_TIME_CONST   10.0    // time constant: time in samples to reach ~ 63% of a steady value from zero
                                    // the rise time of a signal to > 90% is approx 2.5 times this value
                                    // time to >99% is approx 30 times this value
#define FILTER_WEIGHT (FILTER_TIME_CONST/(FILTER_TIME_CONST +1.0))

// add new value to filtered value
// - returns new filtered value
//
float filter( float filteredValue, int newValue )
{
  return (FILTER_WEIGHT * filteredValue) + (1.0-FILTER_WEIGHT) * (float)newValue;  
}

e.g.
  avgX= filter( avgX, analogRead(axisX) );

With your RC filter you can calculate the Time Constant.
To simulate the same time constant in software, you calculate the number of sample times.

So, with your 1k/10uF, RC = 10mS
If you do an analogRead() once per millisecond, 10 x 1mS sample period = 10mS 'Time Constant'

It is important to note that the speed at which you sample the signal affects the 'software time constant' but, of course, does not affect the hardware RC time constant.

Yours,
TonyWilk

MrMark:
The HW filtered input is delayed relative to the raw accelerometer output as well. One could see this by collecting analog data from both the accelerometer output and the RC filter simultaneously.

you mean like this ?

Smajdalf:
This in NOT true generally speaking. Arduino ADC uses sample and hold circuit.

thanks for your comments, i will look up to learn about "sample and hold circuit."

JohnRob:
Hope this helps.

it does indeed - thanks for that very informative website link - it looks like just the right level of complexity for my current level of knowledge.

JohnRob:
As stated by MrMark, the R-C will delay the accel signal, the delay is a function of frequency.

If you look at Bode Plot in the figure titled "Frequency Response of a 1st-order Low Pass Filter" you can see the delay, represented as a phase at (each) frequency.

i'll have to study that more closely, am not quite sure what i'm looking at and where the delay is occuring in

JohnRob:
When looking at how the A/D works, it takes a "snapshot" of the input pin and holds it in a 14 pF capacitor. This is akin to taking a "flash" photo of someone in motion, often the resulting photo is shows the subject in some awkward position. The same goes for the arduino A/D. If a noise spike occurs at the time the analog multiplexer disconnects from the sampling capacitor, your conversion reflects that noise spike as a real value.

That is expanding in more detail on what Smajdalf was mentioning, right ?
His mention of "ADC" and your "A/D" are one and the same thing.

JohnRob:
PS If you want to be philosophical, there is not such thing as DC voltage. The universe has only been around for 13.772 billion years. So the lowest frequency one could see is 1/13.772 billion years (converted to Hz).

interesting point - will have to mull that over !!

TonyWilk:
If you want to compare your RC filter with a simple software filter, have a look at:
[ code ]

thanks a lot, i will certainly try that out.

TonyWilk:
With your RC filter you can calculate the Time Constant.
To simulate the same time constant in software, you calculate the number of sample times.

So, with your 1k/10uF, RC = 10mS
If you do an analogRead() once per millisecond, 10 x 1mS sample period = 10mS 'Time Constant'

It is important to note that the speed at which you sample the signal affects the 'software time constant' but, of course, does not affect the hardware RC time constant.

ahh, this gets to what i was trying to grasp earlier with the "delay(1000);" - of course in a non-blocking method with millis().

so the sampling or reading of the signal is every "n-th" period (of the time constant) - instead of once every loop() execution.

this would mean ignoring some readings in between - it doesn't seem that the HW version would do the same ? (or is that 'phase delay' doing exactly the same thing.)

thanks everyone for the insightful comments.
(it's very helpful for my learning while doing" approach - which probably is not as efficient as a formal approach from learning in an organised instructional way)

Way to go folks how to confuse a beginner with irrelevant details and getting him more mixed up than he was at the beginning.

Grumpy_Mike:
Way to go folks how to confuse a beginner with irrelevant details and getting him more mixed up than he was at the beginning.

to be fair, i am appreciating the extra details to further the knowledge from what i am currently at.

i don’t think i’m too confused - i just have to learn more about the ‘phase delay’ to understand how that functions, the HW and SW comparisons should be straight-forward as alternative methods which is, after all, what i am investigating.

i’m guessing ADC vs. A/D is probably just various common short-forms of the same thing, but i just wanted to confirm, no confusion there i would think, but i get made aware of alternative terminologies used.

guessing ADC vs. A/D is probably just various common short-forms of the same thing,

Yes.

Phase delay is something that is not relevant to your question. In fact it is not relevant to 98% of filter implementations.

Well done with coping. The problem with a lot of electronics engineers is that they don’t know when to stop with exceptions and fine detail and I know this sometimes puts off beginners in to making it seem it is a lot more complex than it need be.

Grumpy_Mike:
Phase delay is something that is not relevant to your question. In fact it is not relevant to 98% of filter implementations.

i see - even the wikipedia page doesn't delve too much into it, and just lumps it into a page with "group delay".

okay then, i'll just concentrate on the Time Constant part with relevance to a delay.

Grumpy_Mike:
Well done with coping. The problem with a lot of electronics engineers is that they don’t know when to stop with exceptions and fine detail and I know this sometimes puts off beginners in to making it seem it is a lot more complex than it need be.

Thanks, i suppose it's good to at least be aware of such exceptions, even if we don't understand it, knowing that "an issue exists" can help in trouble-shooting problems.

i would agree that grasping the fundamental concepts first is more important.

...

i'll assume that my last diagram has understood MrMark's statement of "by collecting analog data from both the accelerometer output and the RC filter simultaneously."