|
|
View previous topic :: View next topic |
Author |
Message |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: Noise reduction. Software or hardware? |
Posted: Fri Mar 28, 2003 1:52 pm |
|
|
My question are there any other methods of software filtering that you
can recomend, That do not bog the cpu down?
--------------------------------------------------------------
Here are two filter routines. The first one is a median
filter, which is also called a "spike filter". It's useful
because it removes the occasional bad sample ("flyers").
You don't want to include obviously bad data in your average.
The 2nd one is an averaging filter.
With both filters, you just feed it the latest element (ie.,
from an A/D sample, or a CCP sample). It keeps track of the
previous several elements in a static array. So essentially,
these filters can work with streaming data. You give it the
latest reading, and it will return the latest filtered result.
Both filters will automatically adapt for the initial situation,
where they don't have the normal number of elements yet.
I used these in a tachometer project.
Code: | // filters.h
//------------------------------------------
// DEFINES
#define MEDIAN_FILTER_WIDTH 7
#define MEAN_FILTER_WIDTH 6
//------------------------------------------
// FUNCTION PROTOTYPES
int16 median_filter(int16 latest_element);
void Insertion_Sort_16(int16 *data, char array_size);
int16 mean_filter(int16 latest_element); |
Code: | // filters.c
//-------------------
// median_filter:
// This function sorts an array of longs so it's in
// ascending order. It then returns the middle element.
// ie., If the array has 7 elements (0-6), it returns
// the element at index 3. The user should ensure that
// the array has an odd number of elements.
// This function stores data from prior calls in a static
// buffer.
// The output of this function will always be N/2 +1
// elements behind the input data, where N is the filter width.
int16 median_filter(int16 latest_element)
{
static int16 input_buffer[MEDIAN_FILTER_WIDTH];
static char inbuf_index = 0;
static char num_elements = 0;
int16 sorted_data[MEDIAN_FILTER_WIDTH];
int16 median;
// Insert incoming data element into circular input buffer.
input_buffer[inbuf_index] = latest_element;
inbuf_index++;
if(inbuf_index >= MEDIAN_FILTER_WIDTH) // If index went past buffer end
inbuf_index = 0; // then reset it to start of buffer
if(num_elements < MEDIAN_FILTER_WIDTH)
num_elements++;
// THIS LINE MAY NOT BE NEEDED IF SORTED DATA IS STATIC.
memset(sorted_data, 0, MEDIAN_FILTER_WIDTH * 2);
// Copy input data buffer to the (to be) sorted data array.
memcpy(sorted_data, input_buffer, num_elements * 2); // memcpy works on bytes
// Then sort the data.
Insertion_Sort_16(sorted_data, MEDIAN_FILTER_WIDTH);
// During the first few calls to this function, we have fewer
// elements in the sorted data array than the filter width.
// So to compensate for that, we pick the median from the number
// of elements that are available. ie, if we have 3 elements,
// we pick the middle one of those as the median.
// Also, because the sort function sorts the data from low to high,
// we have to calculate the index from the high end of the array.
median = sorted_data[MEDIAN_FILTER_WIDTH - 1 - num_elements/2];
return(median);
}
//-------------------------------------------------------------
// This function calculates the Mean (average).
int16 mean_filter(int16 latest_element)
{
static int16 input_buffer[MEAN_FILTER_WIDTH];
static char inbuf_index = 0;
static char num_elements = 0;
int32 mean;
int32 sum;
char i;
// Insert incoming data element into circular input buffer.
input_buffer[inbuf_index] = latest_element;
inbuf_index++;
if(inbuf_index >= MEAN_FILTER_WIDTH) // If index went past buffer end
inbuf_index = 0; // then reset it to start of buffer
if(num_elements < MEAN_FILTER_WIDTH)
num_elements++;
// Calculate the mean. This is done by summing up the
// values and dividing by the number of elements.
sum = 0;
for(i = 0; i < num_elements; i++)
sum += input_buffer[i];
// Round-off the result by adding half the divisor to
// the numerator.
mean = (sum + (int32)(num_elements >> 1)) / num_elements;
return((int16)mean);
}
//-----------------------------------------------------
void Insertion_Sort_16(int16 *data, char array_size)
{
char i, j;
int16 index;
for(i = 1; i < array_size; i++)
{
index = data[i];
j = i;
while ((j > 0) && (data[j-1] > index))
{
data[j] = data[j-1];
j = j - 1;
}
data[j] = index;
}
} |
Edited on Feb. 20, 2005 to remove double-spacing from the code.
The double-spacing happened when this post was ported from the
old CCS board to this board. Also, the code was put into a Code
format block.
___________________________
This message was ported from CCS's old forum
Original Post ID: 13211
Last edited by PCM programmer on Sun Feb 20, 2005 4:34 pm; edited 1 time in total |
|
|
Sherpa Doug Guest
|
Re: Noise reduction. Software or hardware? |
Posted: Fri Mar 28, 2003 2:02 pm |
|
|
:=
:=Listed below I've got a sub that adds 16 AD values strips of the last bits. It seems to work well enough as a crude averaging method and doesn't require too much cpu. I also have a .1 uf cap as a hardware filter. This is because there is a 3 phase motor controlled by a VFD in the same encloser and I'm trying to reduce the amount of noise. My question are there any other methods of software filtering that you can recomend, That do not bog the cpu down?
:=
:=
:=Update_turret_position()
:={
:=
:=(long)valve_position_accumulator+=Read_ADC; valve_position_accumulator_counter+=1;
:=
:=if(valve_position_accumulator_counter==15)
:= {
:= valve_position.L = (long)valve_position_accumulator>>4;
:= valve_position_accumulator_counter=0;
:= (long)valve_position_accumulator=0;
:= }
:=}
A lot depends on the nature of the noise. If you just get occasional bad readings but most readings are fine then averaging just lets the bad reading spoil the whole lot.
Instead you could try what we call "Olimpic scoring". You take a few readings, as few as 3. You keep track of the maximum, the minimum, and the sum. When you are done subtract the minimum and maximum from the sum and average the rest. If there was one spurious high or low reading it is eliminated and most of the "good" data is averaged. It is a simplified version of what is called a "median filter." If you know all your bad readings will be high (or low) you can simplify further.
Something else to try is to synchronize your A/D readings with the motor power. With a VFD that could be hard though.
___________________________
This message was ported from CCS's old forum
Original Post ID: 13212 |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Noise reduction. Software or hardware? |
Posted: Fri Mar 28, 2003 2:27 pm |
|
|
:=
:=Listed below I've got a sub that adds 16 AD values strips of the last bits. It seems to work well enough as a crude averaging method and doesn't require too much cpu. I also have a .1 uf cap as a hardware filter. This is because there is a 3 phase motor controlled by a VFD in the same encloser and I'm trying to reduce the amount of noise. My question are there any other methods of software filtering that you can recomend, That do not bog the cpu down?
:=
:=
:=Update_turret_position()
:={
:=
:=(long)valve_position_accumulator+=Read_ADC; valve_position_accumulator_counter+=1;
:=
:=if(valve_position_accumulator_counter==15)
:= {
:= valve_position.L = (long)valve_position_accumulator>>4;
:= valve_position_accumulator_counter=0;
:= (long)valve_position_accumulator=0;
:= }
:=}
This takes advantage of bit shift divide and a simple multiply.
Current_reading = Read_ADC;
Filtered_reading = (Current_reading + (Filtered_reading * 15)) /16;
___________________________
This message was ported from CCS's old forum
Original Post ID: 13214 |
|
|
Eugene Onishi Guest
|
Re: Noise reduction. Software or hardware? |
Posted: Fri Mar 28, 2003 2:41 pm |
|
|
:=This takes advantage of bit shift divide and a simple multiply.
:=
:=Current_reading = Read_ADC;
:=Filtered_reading = (Current_reading + (Filtered_reading * 15)) /16;
I didn't know that it would
___________________________
This message was ported from CCS's old forum
Original Post ID: 13215 |
|
|
Hans Wedemeyer Guest
|
Re: Noise reduction. Software or hardware? |
Posted: Fri Mar 28, 2003 3:16 pm |
|
|
You did not
I read the replies and no one asked the few important questions.
1) How often do you need to sample the analog data ?
2) Similar to question 1) what is the highest frequency you need to sample or is it a DC level ?
3) You mention a 0.1uF Cap. is it on the input to the ADC, if Yes, is there a resistor in series with the signal before the 0.1uF ? what is the value ?
4) what is the source impedance of the signal ?
Answer these questions and then we can decide what is the best solution.
Some other points to note about assembly.
It is important to make sure the Analog and digital circuits have a common ground at ONE POINT, and not ground loops. In a high noise situation (as you describe) it is possible to inject noise through "poor wiring" and "poor wiring layout".
If it is electromagnetic induced noise, you can do a lot by laying your cables away for other power cables, simple sheilding helps. Using a differential connection to the source of the signal would be best, however that means circuit changes.
___________________________
This message was ported from CCS's old forum
Original Post ID: 13217 |
|
|
georpo
Joined: 18 Nov 2008 Posts: 281 Location: Athens, Greece.
|
|
Posted: Thu Nov 12, 2020 6:41 am |
|
|
Can you please give an example of how to work with the filter?
What is the filter Filter_Index? Should I keep track of it?
Thanks!!! _________________ George. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 12, 2020 7:19 am |
|
|
You question is about the filter routines posted earlier in this thread.
This is how they are used:
Code: |
int16 current_rpm;
int16 median_rpm;
int16 filtered_rpm;
current_rpm = read_rpm(); // Get rpm from tachometer
median_rpm = median_filter(current_rpm); // Remove spikes
filtered_rpm = mean_filter(median_rpm); // Average it
printf("rpm = %lu \n\r", filtered_rpm); // Display rpm
|
Note that the int16's are all unsigned for PCM and PCH.
If you're using the PCD compiler, then make them be "unsigned int16".
All the indexing is internal to the routines. You don't have to do anything about it. |
|
|
georpo
Joined: 18 Nov 2008 Posts: 281 Location: Athens, Greece.
|
|
Posted: Thu Nov 12, 2020 7:20 am |
|
|
Thanks a lot!! I will try it at once! _________________ George. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Thu Nov 12, 2020 7:25 am |
|
|
Some more comments:
First it is always better to reduce noise 'earlier'. So hardware filtering
is preferred to software. Ideally probably do both.
As others have said a lot does depend on the nature of the noise. So
for instance, if there is an 'occasional' spike on just one reading, the favoured
filtering method would probably be Olympic averaging.
Basically exactly the same as the original posted filter, but before the
filter load a value called 'max' with 0, and one called 'min' with 65535.
Then instead of adding 16 values, add 18, and at each loop test the new
value against min, and max. If it is above max, load max with the value
if it is below min, load min with the value. Then at the end of the 18
samples, subtract min and max, from the sum, and generate sum/16.
The result is you get an average of sixteen values out of eighteen without
the highest and lowest. This rejects any single value spike much better. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Thu Nov 12, 2020 8:21 am |
|
|
As Mr. T. says hardware FIRST, then software.
What's unknown, at least to me, is Which PIC and what ADC selection ? There's a HUGE difference in capturing 10, 12 or 16 bit values compared to 8 bit data.
Anything over 8 bits needs real good, no, GREAT! pcb layout, selection of components, grounding, shielding, etc. I designed 16 BIT ADC systems to work INSIDE optical emissions spectrometers (think of a 20KV spark, several 100s of ma), so I have an idea about 'noise'. I got solld 14-15 bits on all 32 channels of data back in late 70s.
Is this just one ADC channel ? Are the others terminated and disabled? A simple R-C front end filter on the channel ? Might need a 3-4 section filter depending on the 'noise'.
If you get the hardware right (within 2 bits, all the time), then software can smooth out the numbers.
I use the 'Olympic average' method.
Take 10 readings ( 12 bit in my case),toss out the max and the min readings which leaves 8 'good' readings. A simple divide by 8 gives the result.
Jay |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|