ADC averaging question

Go To Last Post
33 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Guys,

I am trying to average out the ADC value (ADCH). I am using Mega48. I have a DC voltage of about 1.25V at the ADC input pin. This is giving me an ADCh value of about 62H.

I want to average the ADC values to filter the noisy input. Here is what I am using to do that:

#include 
#include 
#include 
#include 
//Using 1.25 as the reference
//I am getting 62 as the ADC value only ADCH which is about 1.215V

#define USART_BAUDRATE 230400
#define BAUD_PRESCALE (((7372800/ (USART_BAUDRATE * 16UL))) - 1) //value to load into UBRR
#define filter_strength 4

volatile unsigned char flag;
volatile  uint8_t sum = 0;
volatile  uint8_t filtered_value = 0;
volatile uint8_t i;

void USART0_init()
{


   UCSR0B |= (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry
   UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //Set to 8 bit no parity, 1 stop bit
   UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
   UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
//   stdout = &mystdout; //Required for printf init

}



void USART_putchar(unsigned char c)
   {

     while ((UCSR0A & (1 << UDRE0)) == 0) {};
   
     UDR0 = c;

}

void ADC_init()

  {
     ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADATE);
	 //using /8 prescalar
     ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0) | (1 << ADLAR); // Set ADC reference to AVCC,select channel 5; left shift ADC value to use only ADCH
     DIDR0 = (1 << ADC5D); //turn off the digital driver
    ADCSRA |= (1 << ADEN);  // Enable ADC
    ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt
    sei();   // Enable Global Interrupts
    ADCSRA |= (1 << ADSC);  // Start A2D Conversions
  }

void timer_init()
  {

   TCCR1B |= (1 << WGM12);
   TIMSK1  |= (1 << OCIE1A);

   sei();

   OCR1A = 2000;

   TCCR1B |= (1 << CS12) | (0 << CS11) | (0 << CS10);

  }

ISR(TIMER1_COMPA_vect)
 {

   PORTD ^= (1 <<PORTD7);//to indicate AVR is working
                  
 }

ISR(ADC_vect)
  {
                            
	for(i=0;i<16;i++)
	 {
						                 sum = sum + ADCH;
                      					   filtered_value = sum >> (filter_strength);
         }

	flag = 1;

  }
int main (void)
    {   

      DDRC = 0x0F;
      DDRD = 0xC0;
      USART0_init();
      ADC_init();
      timer_init();
   
            for(;;)
              {
                
          
                 ADCSRA |= (1 << ADSC);
                 if(flag==1)
          {
                                                                       USART_putchar(filtered_value);
                               flag = 0;
				sum =0;
                     }
               }
     } 

I am trying to average out the ADCH value in the interrupt and then transmit it to the UART in main. I have made all the variables volatile.

Without the averaging the UART shows me 62H which works fine.

However with the averaging, the UART is showing me this:

 0 15 0 0 14 0 0 0 0 13 0 0 15 15 0 0 0 0 1 0 15 0 0 14 0 1 0 0 0 1 1 15 0 3 0 0
 15 15 15 14 15 1 0 0 1 0 0 15 0 1 0 15 15 0 15 13 0 0 0 14 0 0 15 2 0 0 0 14 0 
0 0 0 15 15 0 15 0 2 0 0 0 1 1 1 15 15 0 0 0 1 15 0 0 0 0 0 2 14 0 0 0 0 0 0 0 0
 14 0 0 1 15 0 0 15 0 2 1 0 0 0 1 14 0 15 0 15 14 0 0 15 1 0 1 0 15 0 15 0 0 0 0
 0 0 0 1 0 0 0 15 14 0 0 0 0 1 0 14 15 0 0 1 15 15 0 0 15 15 14 0 0 12 0 14 15 0
 0 0 14 15 15 0 14 0 0 15 1 0 0 0 15 0 1 0 0 0 14 0 0 0 0 0 13 0 0 15 0 0 1 0 0 
0 15 4 0 0 15 0 0 15 15 1 1 0 0 15 0 0 0 0 14 0 0 2 0 15 0 0 15 0 0 0 0 0 14 0 0
 15 0 14 0 0 0 14 15 0 0 0 1 15 0 0 0 15 15 0 2 0 0 1 0 0 0 2 0 0 0 1 14 0 0 1 0
 0 2 0 0 0 0 1 1 0 0 0 0 1 15 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 2 0 0 0 0 0 0 1 0 
15 0 15 0 0 0 0 0 15 0 0 0 0 1 15 1 0 1 1 14 0 0 0 2 1 0 15 0 0 14 0 0 0 0 1 0 1
 1 0 1 13 13 0 0 0 15 15 14 15 1 0 15 15 2 0 14 0 0 0 0 14 0 0 14 15 0 14 0 0 0 
0 0 15 15 0 0 15 0 0 0 13 0 0 14 1 0 15 0 0 15 1 0 0 0 0 15 2 15 0 0 1 0 0 15 15
 1 0 0 15 1 0 0 14 1 14 0 0 1 2 14 0 14 0 0 1 0 0 14 0 15 0 15 0 0 1 0 15 0 0 0 
0 15 0 0 0 0 0 0 0 2 0 1 0 1 0 15 0 14 1 0 0 1 15 0 0 0 0 15 0 15 15 0 0 0 15 15
 0 1 0 2 0 1 0 15 15 0 0 0 1 2 0 1 0 1 0 1 0 1 0 1 0 1 14 15 1 1 0 1 0 1 0 15 0 
15 13 0 0 0 0 15 0 0 1 0 0 1 0 0 0 0 1 10 0 0 14 0 0 13 15 0 15 0 15 0 0 0 1 1 0
 0 0 2 15 14 0 15 1 0 0 15 0 0 0 14 2 0 15 0 0 0 1 0 0 4 0 14 0 0 0 0 0 0 0 15 1

I am summing 16 times and then dividing by 16 (with the right shift).
Could this be a float problem? filtered_value is defined as uint8_t. Do I have to convert the binary to decimal and then do the averaging? Wouldn't that slow down the ADC capture?

Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To take an average, you need to keep track of 16 values in an array. Maybe you are trying to use that decimation trick that gives you more a/d bits by adding up 16 samples then dividing by 8? I know how you could get from 8 bits to 10 bits real easy.... just read all 10 bits?. Anyway, the way I average 16 samples is: read sample, add it into total, subtract away sample from current slot in array (16 samples ago) from total, save current sample in current slot in the array, and the current avg is total >> 4.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are setting flag after every conversion. I would think that you would want to set it only after taking 16 readings.

Quote:
you need to keep track of 16 values in an array.

Only if you are keeping a running average. In this case, a simple sum is fine.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why are you adding the >>same<< conversion result 16 times?

As mentioned, you can get more resolution just by using all the bits. You can (as mentioned) simply add the results of n conversions (up to 64) and then divide by n or whatever to get your average value, or simply work with the total.

How are you seeing those apparent ASCII numbers & spaces when youa re only dumping a binary 8-bit value?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And since sum is 8 bit, you are going to overflow that pretty quickly (in fact, possibly on the very first add).

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

How are you seeing those apparent ASCII numbers & spaces when youa re only dumping a binary 8-bit value?

I am using realterm. It looks like a good program. So I am setting my capture format to uint8_t.That is how I was getting 62H without the averaging.

Quote:

I know how you could get from 8 bits to 10 bits real easy.... just read all 10 bits?.

The reason I am using only 8 bits (ADCH) is I want to try and exceed the 200 ksps ADC sampling frequency limitation.

Quote:

You are setting flag after every conversion. I would think that you would want to set it only after taking 16 readings.

Good point. Will try setting the flag when i > 15.

Quote:

And since sum is 8 bit, you are going to overflow that pretty quickly (in fact, possibly on the very first add).

So I will make sum as int and filtered_value as uint8_t and see what that gives me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've used something like this in some code I wrote. I've since expanded its functionality, but this is the basics.

uint16_t setreadADC(uint8_t newadmux)
{
	uint8_t i; // Loop increment.
	uint16_t adcsum = 0; // Sum of converted ADC readings

	ADMUX = newadmux;

	for (i = 0; i < 16; i++)
	{
		ADCSRA |= _BV(ADSC); // Start 
		while(ADCSRA & _BV(ADSC)); // Wait

		adcsum += ADCW; 
	}

	return(adcsum >> 4); // Average results
}

Jim M., Rank amateur AVR guy.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I tried this:


volatile unsigned char flag;
volatile  uint16_t sum = 0;
volatile  uint8_t filtered_value = 0;
volatile uint8_t i;
volatile unsigned char count_1 = 0;

ISR(ADC_vect)
  {
                            
	for(i=0;i<16;i++)
	  {
	     sum = sum + ADCH;
       	   filtered_value = sum >> (filter_strength);
	   count_1++;
           }
                if(count_1 > 15)
	          {
			flag = 1;
	          }

  }

int main (void)
    {   

	  DDRC = 0x0F;
      DDRD = 0xC0;
      USART0_init();
      ADC_init();
      timer_init();
   
            for(;;)
              {
                
          
                 ADCSRA |= (1 << ADSC);
                 if(flag==1)
          {
                          
                          USART_putchar(filtered_value);
                          

                flag = 0;
				sum =0;
				count_1 = 0;
                     }
               }
     } 


With this, I am still getting:


0 0 0 2 1 1 1 0 0 1 0 3 4 1 0 1 1 0 0 1 3 1 1 3 1 1 0 1 0 3 2 1 2 1 1 0 0 0 0 5 
0 0 1 0 1 9 0 1 0 2 5 0 0 3 0 0 0 0 0 0 3 0 0 0 0 2 0 0 1 2 3 1 0 0 2 2 0 1 1 1 
4 1 0 0 3 1 0 2 1 0 0 1 3 2 1 0 3 2 1 1 1 1 2 0 2 0 0 3 2 0 2 0 1 0 9 1 0 0 1 1 
2 0 0 0 0 2 0 0 0 0 2 0 0 9 1 0 0 0 1 0 0 1 0 0 0 0 0 0 1 1 1 1 0 2 1 0 1 1 0 0 
7 0 0 0 0 2 0 3 1 2 0 0 2 1 2 3 1 2 1 1 0 1 0 3 0 0 3 6 3 0 0 0 0 0 0 0 4 0 0 0 
2 6 4 4 8 0 1 0 0 0 2 1 0 0 0 0 1 0 0 0 2 1 6 15 1 0 0 1 2 1 0 3 3 1 1 0 1 0 1 1
 0 3 0 2 4 0 2 1 0 2 0 1 0 1 1 0 0 1 0 2 0 1 1 0 1 0 13 0 3 0 0 1 3 0 0 0 9 0 0 
0 0 0 0 0 0 0 2 0 0 1 1 1 0 0 2 0 0 0 0 0 1 1 0 3 1 0 0 1 1 0 1 2 0 0 4 5 2 1 0 
2 1 1 3 2 1 1 1 1 0 1 0 2 0 2 1 0 2 0 2 0 0 0 0 0 2 0 0 5 0 1 6 0 0 0 0 0 0 5 1 
4 3 0 0 2 0 0 2 0 1 1 3 0 0 9 0 0 1 1 0 2 0 1 1 2 2 0 0 1 1 1 0 0 0 2 0 1 2 1 1 
0 1 0 2 1 0 2 1 0 2 1 1 3                                                       
1 4 0 1 1 0 0 0 9 0 0 0 9 0 2 0 0 2 1 3 0 0 0 0 0 0 2 5 2 0 0 1 2 1 1 2 0 1 2 0 
1 0 0 0 1 1 1 1 0 0 1 1 1 0 3 2 0 2 2 0 1 2 0 1 2 1 9 6 0 0 0 2 0 0 0 0 2 1 2 0 
1 1 0 0 0 0 1 0 0 2 0 0 0 0 0 0 1 0 0 0 0 0 2 0 0 0 1 1 1 1 0 0 4 2 0 6 3 1 0 1 
1 1 0 1 0 1 0 0 2 2 2 3 1 0 0 1 1 1 0 0 3 1 0 0 0 2 0 3 0 0 1 10 0 0 3 4 0 4 0 1
 0 0 1 0 0 0 3 6 0 0 0 0 1 0 9 0 2 0 0 0 0 0 1 2 5 1 1 1 0 1 2 0 0 4 1 0 2 1 0 1
 0 1 0 1 4 1 1 0 0 0 2 0 0 3 0 0 0 1 2 6 0 0 2 0 0 0 0 0 1 7 6 0 0 8 0 0 0 0 2 3
 0 0 0 0 0 7 0 3 0 3 2 0 5 0 1 2 1 1 1 0 0 1 1 0 0 2 2 2 1 1 0 0 1 2 1 1 1 1 1 2
 1 2 2 0 1 2 0 1 2 1 0 2 4 3 1 0 0 7 0 0 1 2 8 0 0 9 0 0 0 1 0 0 2 2 1 0 0 1 0 0
 0 4 3 0 0 1 1 0 0 0 0 0 0 0 0 2 4 1 1 0 0 1 0 1 1 1 1 2 1 0 0 1 1 1 1 0 2 1 2 0
 1 2 3 2 1 0 1 1 0 2 3 0 0 0 0 4 1 15 0 0 3 0 2 3 0 2 0 10 0 0 0 0 0 0 35 1 0 3 
0 0 0 2 1 3 0 1 2 0 0 1 5 1 1 1 1 0 0 1 3 2 1 0 1 2 2 0 2 1 1 0 3 4 1 0 1 0 0 1 
1 1 2 3 0 2 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 1 0 3 2 12 1 0 0 2 0 1 5 0
 0 10 0 1 16 0 6 2 1 0 0 0 2 1 2 0 5 1 1 0 1 3 2 2 1 0 0 1 1 2 0 1 1 2 1 3 0 0 0
 0 1 4 2 1 6 2 1 0 0 0 1 0 1 7 0 0 0 0 1 0 0 3 0 0 0 0 0 2 3 2 0 1 2 0 0 0 0 0 1
 6 0 0 0 1 0 1 0 2 1 2 1 0 1 2 1 1 0 1 1 4 1 0 0 3 2 0 2 0 0 2 1 0 0 0 2 0 3 2 0
 0 0 1 1 0 0 4 0 0 0 1 0 0 0 3 8 0 2 0 0 0 1 2 0 2 3 0 0 1 0 4 1 0 0 2 0 0 0 1 1

What is missing here? Also I know I am reducing my sample rate by 16 because of the averaging too.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try this...

uint8_t readADC()
{
	uint8_t adcvalue;
	uint8_t adcsum = 0;

	for (uint8_t i = 0; i < 16; i++)
	{
		ADCSRA |= _BV(ADSC);
		while(ADCSRA & _BV(ADSC));

		adcvalue = ADCH; 

		adcsum += adcvalue;
	}

	return(adcsum >> 4);
}

int main (void)
{   

   DDRC = 0x0F;
   DDRD = 0xC0;
   USART0_init();
   ADC_init();
   timer_init();
   
   for(;;)
   {
                      
      USART_putchar( readADC() );
                         
   }
}

Jim M., Rank amateur AVR guy.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So let me get this straight. You need faster readings, so you exceed the maximum rate by approximately 5 times, but give up accuracy doing so. In order to make up for that missing accuracy, you take 16 readings and sum them, making the effective reading slower than if you had just done the conversion at the maximum rate. And then you throw away any accuracy that you might have gotten by taking the value back down to 8 bit.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the OP is trying to average out noise.

Jim M., Rank amateur AVR guy.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wonder if he is trying to reduce the worst-case measurement (output) latency, and the latency's variation.

- John

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, Jim. I will try that.

@Steve,
I completely understand your point and it is a valid one. I am only trying to get rid of the noise at a minimum loss of accuracy while still trying to exceed the 200 ksps ADC sampling. I know there is a HUGE trade off here (and this may be like an asymptote i.e. hitting the wall) but I am trying to find the optimum solution that will meet my needs.

Maybe I should try the noise cancellation in the ADC? The other option probably is to use a low pass/antialiasing hardware filter as suggested in another post.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you can get 8 bit conversions at 30 or 40K samples per sec... here's how to test what you're getting.... fill up a big ram buffer with samples at full speed, then graph it out the serial port and see if it is a nice smooth sine wave or is all jerky and discontinuous. To graph the data, I just print sample/4 spaces and a "*\n" for every sample. The fine print says they roll off the amp above 4k, so I bet you aint gettin nuthin at 200k.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Silly idea but why not add an external ADC to the AVR that can sample much faster than the AVR's 15.3kHz ADC?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

200ks/s. Eeek. External ADC via SPI.
I don't know much, but I know enough to listen to clawson.

Jim M., Rank amateur AVR guy.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

The reason I am using only 8 bits (ADCH) is I want to try and exceed the 200 ksps ADC sampling frequency limitation.

Did you not pay ANY attention in your other thread where the sps was discussed?

https://www.avrfreaks.net/index.p...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

He must have meant 200 kHz sampling rate.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

He must have meant 200 kHz sampling rate.

No he actually means 200kHz ADC clock which, because of 13 clocks per sample conversion leads to a 15.3kHz sample rate.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's what I meant. :P
Back to lurk mode...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I am only trying to get rid of the noise at a minimum loss of accuracy

But where is this noise coming from? Is the input signal really that noisy, or is the noise coming from the way that you are sampling it?

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are reading a sin wave from a signal generator, get it set up to acquire samples, graph them in a loop. Should work great at 9khz. Factory spec. I claim you can get 30 or so khz at 8 bits. Turn up the freq, see what you get. At some point, you'll just start grabbing a random sample somewhere in the middle of whatever freq wave you have, and it will look EXACTLY LIKE YOUR PRINTOUT that you posted.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
The other option probably is to use a low pass/antialiasing hardware filter as suggested in another post.

You MUST have a low pass filter on the input to your signal. This should be a real, hardware filter on the input. (Disclaimer: A couple of threads have mentioned a software filter on the front end... "I" don't know how you do that, as the software filter is still a sampled signal which, AFAIK still requires a band limited input signal. Otherwise you have alias noise.)

You need to know the frequency spectrum of the input signal. Only if you have a clean signal, bandlimited by whatever created it, can you think about ignoring the front end LPF.

The Xmega spec's up to 1 MSps conversion rate, 12 bits, although I know there are some issues with the analog components, and it is worth looking at the errata sheets before committing to them.

Pick the right tool for the job, and the job becomes soooo much easier.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Cliff,

I will be looking at an external ADC. What are some good chips I could use for this? Will the ADC interface to the AVR (SPI,I2C,etc.) slow down my overall sample rate?

@Bob,

That is exactly what I am doing. I am using a sine wave through a signal generator. I could get a decent 10kHz sine wave. When I bumped the frequency up to 18 kHz, I start getting "random" sampling.

@JC,
I understand. I will be using an LPF. I wanted to use the XMega but that has an entire new learning curve for me.

My only doubt was if averaging could help with the random sampling and smooth out the captured sine wave.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bump the prescaler down a notch and run it again.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

That is exactly what I am doing. I am using a sine wave through a signal generator. I could get a decent 10kHz sine wave. When I bumped the frequency up to 18 kHz, I start getting "random" sampling.

To resolve an 18kHz signal you need to sample at 36kHz though to truly resolve sine the rate probably really needs to be more like 5 or 10 times the sampled frequency. Meanwhile the AVR can sample at a maximum 15.3kHz (for 10bits in datasheet spec). Sure you can drop to 8 bits and sure you can pump it up a bit and see if you can get away with it. But can you really take 15.3kHz to 90kHz with such "tweaks"? (and you cannot then make a silk purse out of a sow's ear by any amount of averaging or whatever)

Admit it, the AVR ADC is NOT the tool for this job.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

npat_avr wrote:

My only doubt was if averaging could help with the random sampling and smooth out the captured sine wave.

Since the wave is changing significantly over time (as it should, it's a sine wave) you can't really average much to reduce noise. Average enough, and it will be a flat line. You really need an external ADC and a good filter for the input. If your expected measured frequency is within a certain range, you can build high and low pass filters to allow a notch of frequencies through. At the very least you want to use a low pass filter whose cutoff is just slightly above your highest expected input frequency. If you exceed 8-bits in your ADC you will need 2-bytes of data over SPI. If you use 2 bytes of SPI per sample, that means you "could" use up to a 16-bit ADC, but that's a bit much. you can find a lot of 12-bit ADCs with an SPI interface.

A simple low pass filter is an inductor in series with the ADC input, with a cap connected from the input to ground. Of course you'll need to know the input impedance of the ADC to calculate values.

Jim M., Rank amateur AVR guy.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's some MATLAB code of how to fit a sine curve to noisy data (that has sinusoidal characteristics). It's from my 2nd year engineering, so it only works for well-distributed (Gaussian, white, whatever else they're called) noise. We were learning regression...

function [A phi B] = sinefit(w,t,y);

% function [A phi B] = sinefit(w,t,y);
%
%   Lab 5, Part III:
% Fits a sinusoid to a noisy set of data known to have constant maximum 
% amplitude wave (no/slow attenuation) characteristics using SSE.
%
% Inputs:
%   w       Angular frequency
%   t       Time values (abscissa)
%   y       Values
%
% Outputs:
%   A       Amplitude of wave
%   phi     Phase shift
%   B       DC offset
%
% GPL; ie: No guarantees!

t = t(:); y = y(:);
m = length(y); n = length(t);
if m ~= n, error('y and t must be of equal length'); end

Z = [cos(w*t),sin(w*t),ones(n,1)];
a = Z\y;

A = sqrt((a(1)^2+a(2)^2));
phi = acos(a(1)/A);
B = a(3);

This still requires that you fulfill Nyquist's rule!
ie: sample rate > 2x max signal frequency

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes. Good old Nyquist.. :)

One of the reasons to use only the AVR was to minimize components and improve reliability.

Quote:

If you use 2 bytes of SPI per sample, that means you "could" use up to a 16-bit ADC, but that's a bit much. you can find a lot of 12-bit ADCs with an SPI interface.

I agree but will the SPI transfer to the AVR "slow" down my data capture?

What are some good audio (DC - 22kHz) ADC IC's with a SPI interface? Are there ADC's with on chip antialiasing filters and gain control?

As Bob had suggested, maybe it makes more sense to write to a RAM or dataflash.

The only plus point about the SPI is I will get "real" time data (of course with some delay)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I agree but will the SPI transfer to the AVR "slow" down my data capture.

Do the sums. SPI can run at what? 1/4 F_CPU? So if you run at 16Mhz you could run the SPI clock at 4MHz so get bytes at 0.5MHz. I have a strong feeling that the ADC will be the bandwidth limiting factor - not the SPI link to it.

Of course even if you were getting samples at 100kHz (say) then the next question to arise is how fast you can process the data and where are you going to put it. In the 1/2/4K of RAM of an AVR you will fill it pretty quickly at 100kHz so I guess the next question is exactly how quick you can write to Dataflash. As long as it's erased before you start I guess the writes can be quite fast but if you have to erase pages on the fly it could have a big hit on the write-bandwidth.

Quote:
I will get "real" time data (of course with some delay)

where does this "some delay" come from? Do you mean the conversion time of the ADC or the time to clock 8 bits across SPI (at 2MHz that is not a very long delay at all)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tell me the avr clock speed and a/d prescaler settings you are using, I'll give you the sample rate I think it gives using 8 bit mode.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff,
I mean the delay to transfer from ADC to AVR through SPI. But as you mentioned I agree that this won't be a problem.

Bob,

I am using a 14.746MHz crystal with a prescalar of 32 and 8 bits.

To test this, I used a 1kHz sine wave as the input. I got about 28 samples in one cycle of the wave.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bob,

I think it is using 1kHz * 28 = 28ksps as the sample rate. Does that make sense?