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 support@ccsinfo.com

Radical olympic++ ADC averaging , de-noising routine
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

Radical olympic++ ADC averaging , de-noising routine
PostPosted: Sat Apr 20, 2013 2:19 pm     Reply with quote

I've had very good luck with this HL adc averaging routine that i wrote some time ago, for use under high noise ADC reading conditions.

Was particularly good for a high power AC heater system with hashy/trashy EMI TRIAC modulators.

a typical use was to call it 4 times /second and use a circular buffer for the results of this routine at a higher level ( main() )
Then to average sets of 16 of the values this returns for process decison making.

that yielded 256 ADC readings , summarized to very low noise,
and time weighted as well.

I am always grateful for tips on how to do this better.

Code:

// olympic++  adc de-noising routine for 10 or 12 bit ADC values
// NOTE: you must have selected the desired ADC channel before calling
// reads 16x , sorts and tosses low4 && high 4 readings
// then averages the middle 8

unsigned int16 adchlx(void){  // read 16 - sort, keep middle 8 average

 unsigned int8 i;  unsigned int16 accum=0; 
 unsigned int16 s, b[16]; int1 didswap=1;

   for ( i = 0 ; i < 16;  i++ ) {
           b[i]= read_adc(ADC_start_and_read); // ADC set for 10 or 12 bits
           delay_us(8); 
     } //    end of for loop for multi sample
   while(didswap){  // bubble sort
     didswap=0;
     for (i=0; i<15; i++){ // i 0-15
      if(b[(i)]>b[(i+1)]){ // if low element greater than next  -do  swap
           s=b[i]; // hold upper
           b[i]=b[(1+i)];
           b[(1+i)]=s;
           didswap=1;
      } // ~if
     } // ~for
    } // ~while
   // now sort and keep middle 8 values
   for (i=4; i<12; i++){  accum +=b[i];  }
   return(accum>>3);
}


Last edited by asmboy on Mon Apr 22, 2013 1:39 pm; edited 1 time in total
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Mon Apr 22, 2013 8:35 am     Reply with quote

Awesome work man...
Thanks for sharing.
_________________
CCS PCM 5.078 & CCS PCH 5.093
a_abdoli



Joined: 18 Dec 2010
Posts: 1

View user's profile Send private message

PostPosted: Tue Oct 22, 2013 9:01 am     Reply with quote

Thank you, It was great.
muratmert4



Joined: 19 May 2011
Posts: 3

View user's profile Send private message

PostPosted: Wed Oct 23, 2013 11:17 am     Reply with quote

asmboy
this code very nice thankyou
dorinm



Joined: 07 Jan 2006
Posts: 38

View user's profile Send private message

PostPosted: Thu Oct 24, 2013 7:11 pm     Reply with quote

Yes it is a good idea indeed ... I've also used a similar method for slow changing variations where "almost" realtime was not necessary;

....just for completeness sake, I would add that if anyone need that "almost" realtime reading, even if not that accurate, I would use some sort of predictive filtering (a simple Kalman would do that Smile )
andrewg



Joined: 17 Aug 2005
Posts: 316
Location: Perth, Western Australia

View user's profile Send private message Visit poster's website

PostPosted: Fri Oct 25, 2013 10:04 pm     Reply with quote

Just a comment that if I was going to do this, then I would use an insertion sort where the delay_us is (for a somewhat random delay), and change the array size to 12 to save a bit of RAM. The extreme min or max values would just drop off (it doesn't matter which), then take the average of 8 values left after the other 4 extreme values are ignored.
_________________
Andrew
andrewg



Joined: 17 Aug 2005
Posts: 316
Location: Perth, Western Australia

View user's profile Send private message Visit poster's website

PostPosted: Tue Oct 29, 2013 9:33 am     Reply with quote

To clarify "somewhat random", the time taken to perform the insertion sort will depend on the data it is sorting - the ADC readings. It will vary slightly, but probably not too much. Given there are just a few readings it will be quite quick, but almost certainly longer than 8us.
_________________
Andrew
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Oct 29, 2013 5:43 pm     Reply with quote

to be clear: -
the 8uS delay is not part of the sorting algorithm at all -
It is inserted only in the acquisition phase of the function as an arbitrary delay to space out the individual ADC readings so as to better allow for trending changes in the string of averaged values returned
( as in when the true value really is slowly increasing or decreasing
over the course of the raw reading set)

It is a delay that can be:
1) eliminated
2) made longer
3) made shorter

The example code is based on the experimentally determined integral T.C. of the readings being taken in my particular application, from whence it was excerpted. It is up to the user who borrows this code to find a delay value which works optimally in their own application of this concept.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Sun Dec 15, 2013 8:19 pm     Reply with quote

I used this routine today for a project i have ongoing.
It worked perfectly...

Thank you Asmboy.

G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
jeremiah



Joined: 20 Jul 2010
Posts: 1341

View user's profile Send private message

PostPosted: Wed Mar 19, 2014 10:12 am     Reply with quote

I made use of it as well! Thanks!

I did change the sorting algorithm to an insertion sort, which ended up being a bit quicker for the data sets I typically get.

Code:

#define DEV_ADC_SAMPLES       16

   //insertion sort the values.  This is usually a fast enough sort for small
   //sets of values.  This algorithm divides the array into a sorted section
   //on the left side and an unsorted section on the right side.  Elements
   //are placed one at a time into the sorted section, which scoots over
   //existing sorted elements as needed to make space for the new element
   //     5 | 4 3 2 1 0
   //       Pull 4 out
   //     5 | X 3 2 1 0
   //       Shift values higher than 4 one space to the right
   //     X 5 | 3 2 1 0
   //       Place 4 in left over space
   //     4 5 | 3 2 1 0
   //     4 5 | X 2 1 0
   //     4 X 5 | 2 1 0
   //     X 4 5 | 2 1 0
   //     3 4 5 | 2 1 0
   //       Continue until all are sorted
   for(i=1; i<DEV_ADC_SAMPLES; i++){
      s = b[i];  //Get current sample to place in the sorted section
     
      //Move left down the array, scooting all values higher than 's' one
      //place to the right.  This loop always stops after j=1, so that j=0
      //doesn't cause j-1 to give an out of bounds index in the array
      for(j=i; j && (b[j-1] > temp); j--){
         b[j] = b[j-1];  //shift to the right one location
      }
      //At this point, no values left of current position are larger than
      //'s', so place 's' here
      b[j] = s;
     
     
   }
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Mar 19, 2014 7:49 pm     Reply with quote

i considered the use of the insertion sort when i created the routine,
BUT in my case there is a very special consideration!
i did choose the bubble on purpose based on the histogram of collected data
during development of the precision heater it was used in.

when the noise is low in a given block of readings - frequently there are multiple identical ADC values in the array. I leave it to the reader to apprehend the implications of that - though i believe
"res ipsa loquitur" in this instance
Very Happy Very Happy Very Happy
jeremiah



Joined: 20 Jul 2010
Posts: 1341

View user's profile Send private message

PostPosted: Thu Mar 20, 2014 5:37 pm     Reply with quote

Curiosity question:

In this part:
Code:

for ( i = 0 ; i < 16;  i++ ) {
   b[i]= read_adc(ADC_start_and_read); // ADC set for 10 or 12 bits
   delay_us(8);
} //    end of for loop for multi sample


What purpose does the delay serve exactly? I assume to allow for some part of the process to charge/settle, but up till recently, I have (probably naively) assumed that read_adc(ADC_start_and_read) blocked appropriately. I am familiar with adding a delay between selecting a port and doing a reading, but was wondering about the delay inbetween (in this case, the 8us delay). I have yet to run into any problems not having delays between successive readings, but I understand that doesn't mean that it will always work that way.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri Mar 21, 2014 11:57 am     Reply with quote

the above question is answered a few posts earlier in this thread ......
Very Happy Very Happy Very Happy Very Happy Very Happy
akay



Joined: 29 Sep 2020
Posts: 17

View user's profile Send private message

Re: Radical olympic++ ADC averaging , de-noising routine
PostPosted: Tue Sep 29, 2020 1:04 pm     Reply with quote

The value we need to print on the LCD is int B?
asmboy wrote:
I've had very good luck with this HL adc averaging routine that i wrote some time ago, for use under high noise ADC reading conditions.

Was particularly good for a high power AC heater system with hashy/trashy EMI TRIAC modulators.

a typical use was to call it 4 times /second and use a circular buffer for the results of this routine at a higher level ( main() )
Then to average sets of 16 of the values this returns for process decison making.

that yielded 256 ADC readings , summarized to very low noise,
and time weighted as well.

I am always grateful for tips on how to do this better.

Code:

// olympic++  adc de-noising routine for 10 or 12 bit ADC values
// NOTE: you must have selected the desired ADC channel before calling
// reads 16x , sorts and tosses low4 && high 4 readings
// then averages the middle 8

unsigned int16 adchlx(void){  // read 16 - sort, keep middle 8 average

 unsigned int8 i;  unsigned int16 accum=0; 
 unsigned int16 s, b[16]; int1 didswap=1;

   for ( i = 0 ; i < 16;  i++ ) {
           b[i]= read_adc(ADC_start_and_read); // ADC set for 10 or 12 bits
           delay_us(8); 
     } //    end of for loop for multi sample
   while(didswap){  // bubble sort
     didswap=0;
     for (i=0; i<15; i++){ // i 0-15
      if(b[(i)]>b[(i+1)]){ // if low element greater than next  -do  swap
           s=b[i]; // hold upper
           b[i]=b[(1+i)];
           b[(1+i)]=s;
           didswap=1;
      } // ~if
     } // ~for
    } // ~while
   // now sort and keep middle 8 values
   for (i=4; i<12; i++){  accum +=b[i];  }
   return(accum>>3);
}
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Sep 29, 2020 1:23 pm     Reply with quote

Not sure what you are getting at.

The result is implied in the function call.
I did not mention an LCD display -

unsigned int16 adchlx(void)
It returns an unsigned int16 on exit as in
Code:

unsigned int16 myanswer,

myanswer=adchlx(); // myanswer has the function result

Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Goto page 1, 2, 3  Next
Page 1 of 3

 
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