CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Noise reduction. Software or hardware?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

Re: Noise reduction. Software or hardware?
PostPosted: Fri Mar 28, 2003 1:52 pm     Reply with quote

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?
PostPosted: Fri Mar 28, 2003 2:02 pm     Reply with quote

:=
:=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

View user's profile Send private message

Re: Noise reduction. Software or hardware?
PostPosted: Fri Mar 28, 2003 2:27 pm     Reply with quote

:=
:=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?
PostPosted: Fri Mar 28, 2003 2:41 pm     Reply with quote

:=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?
PostPosted: Fri Mar 28, 2003 3:16 pm     Reply with quote

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.

View user's profile Send private message

PostPosted: Thu Nov 12, 2020 6:41 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 12, 2020 7:19 am     Reply with quote

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.

View user's profile Send private message

PostPosted: Thu Nov 12, 2020 7:20 am     Reply with quote

Thanks a lot!! I will try it at once!
_________________
George.
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Thu Nov 12, 2020 7:25 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 12, 2020 8:21 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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