RC filter
09 Feb 2017If we want to smooth unwanted noises or annoying fluctuations of an electric signal we read from an analog sensor we have to create a filter.
Now we want to consider different methods to create a filter, both software and hardware, and to do this we first need to prepare a simple circuit to use to test them.
We will use a photoresistor (or light-dependent resistor if you prefer) as the main element for our tests. By the way we’ve found this tutorial by Adafruit very interesting: it contains a lot of information about this electric component, definitely worth reading!
Our siple circuit is composed of a:
- photoresistor;
- resistor, used in pullup configuration.
Let’s start reading and plotting the voltage across the photoresistor. Here’s the code we are using:
#define PHOTO A0
void setup() {
Serial.begin(9600);
}
void loop() {
unsigned int value = analogRead( PHOTO );
Serial.println( value, DEC);
delay( 5 );
}
We use the Serial monitor to print the values from the analog input, and the Serial plotter tool to represent them in a more intuitive way.
As we see from the graph above, when we change the light headings towards the photoresistor, the graph registers big variations in ADC values: greater the quantity of light, the lower the resistance value, the same the voltage measured on analog pin 0.
On the other hand, when we let everything untouched, even if the readings from the photoresistor seems to be quite stable, they present a lot of noise.
From the serial monitor we read continuosly changing values (even if they only change a bit), the same we see from the serial plotter graph.
Even though this behaviour seems to be different according to the type of light, we would like to filter out this noise in some way.
The software way
Let’s try first to use software to smooth our analog readings. The first method we will see is the array method.
The array method
As we learn from Arduino Smoothing tutorial, we can use an array to store consecutive readings and calculate their mean. This way we will always have an output that will be smoother than the input.
Here’s the code we are using (the same shown in the tutorial):
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
#define PHOTO A0
void setup() {
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
int thisReading;
for (thisReading = 0; thisReading < numReadings; thisReading++) {
readings[ thisReading ] = 0;
}
}
void loop() {
// subtract the last reading:
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = analogRead( PHOTO );
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
}
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
Serial.println( average, DEC);
delay(5); // delay in between reads for stability
}
Below two screenshots for both a light changing and stable environment. As we see noise now seems to be more controlled.
Maybe changing the size of the array could improve the filter power but at the same time, as we read from the tutorial introduction, it will create a delay
The higher the number of samples to keep track of, the more the readings will be smoothed, but the slower the output will respond to the input.
The bit shift method
Another way could be that of usign a bit shift. In other words using this method we are reducing the bit depth of the ADC signal, loosing some of the least significant bits of the original 10 bit sampled signal.
This is a very rough method that is also responsible of reducing the dynamic range of the sampled signal because of a reduction of the number of quatization levels.
Here’s the code:
#define PHOTO A0
void setup() {
Serial.begin(9600);
}
void loop() {
unsigned char value = analogRead( PHOTO ) >> 3;
Serial.println( value, DEC);
delay( 5 );
}
And here the plotter images:
The scale of the graph has been reduced; due to the bit shift operation the maximum value that the value
variable could assume is lower than 1023 .
We can also test that the more bit we shift the readings to the left, the more squarewav-ish the graph will appear.
However if we take a look at the image above, it seems that the noise has been significantly reduced: this is because our graph now has a much lower resolution than before.
Because our noise is only responsible for little voltage variations, here we are no more able to see them.
The 1-sample delay method
Recently I’ve read about this method on Andy Farnell’s Designing Sound book. There’s a moment in chapter 10 when he describes this simple PureData patch:
This patch is a simple low pass filter that follows this filter equation:
The strenght of the filter is set by the ratio . Both and should be between and and add up to .
Let’s try this method in code with Arduino:
#define PHOTO A0
const float A = 0.1;
float B;
float currentValue, previousValue;
void setup() {
Serial.begin(9600);
B = 1.0 - A;
previousValue = 0.0;
}
void loop() {
currentValue = analogRead( PHOTO );
previousValue = currentValue * A + previousValue * B;
Serial.println( int(previousValue), DEC);
delay( 5 );
}
Here we have and , so the filter ratio is . Here the images from the serial plot for both a light changing environment and a static light one.
We also tried with different values for and : here and , for a filter ratio of
In both cases as we see, noise seems to be little, and we also note that the smaller is, more this code seems to graph a signal similar to a capacitor charge and discarge cycle.
The second one is much slower than the first one, meaning that a smaller and a smaller filter ratio creates a more powerful low pass filter behaviour.
If you want to go deeper into the theory behind this patch, please refer to this post!
The hardware way
But what about doing a filter using hardware components instead of code? We have to realize a simple circuit variation, adding the so called RC filter:
The theory tells us that if we accurately calibrate the value of R and C, we can precisely define , the cut frequency (where ) as:
In this way, all variations on the input signal will be attenuated according to their frequency. Voltage variations with a frequency will be attenuated and will not be transferred to the output signal. On the other hand, signals with a frequency lower than will be left untouched.
Let’s say we want to cancel all variations faster that , so we have to calculate the values for and accordingly.
For example, if we use and , we will obtain approximately an , as we wanted. Here’s our new circuit:
And here’s the Fritzing representation:
We highly reccomend you to read the chapter 2 of the “Practical Elctronics for inventors” by Paul Sherz if you want more information about filters.
Here’s the Arduino Serial plotter images for great variations:
and for no variation at all:
Despite our hopes, the noise is still present, as you can see in the last image. Even if this circuit would have completely cancelled the noise it actually seems to add more of it.
If you have a more clear understanding of this phenomenon, please feel free to leave a comment or contact us so we can improve this article adding new and significant clarification.
Maybe the solution it to use an hybrid approach and to create both an hardware RC and a software RC filter. We will let you know in our future experimentations.