Electronic – arduino – Specific noise while using arduino ADC in free running mode

adcaliasingarduinonoisesampling

To make an oscilloscope in matlab environment, for data acquisition on arduino side, when inbuilt analogRead() is used, it's working fine, but with very low sampling rate, that aliasing is clearly observed. That too, non-uniform sampling. Thus listing out the drawbacks:

  1. Very slow data rate, even if, sent with 115200 baudrate,
  2. Aliasing
  3. Non-uniform sampling

Observed waveform, analogRead()

Thus, to overcome above, ADC in free running mode was used, with 16 as prescaling factor, thus 76.9KHz sampling rate (counting each ADC as 13 clock cycles). Thus, data is uniformly sampled now. Also it is quite fast, because of sampling, and is observed. The only problem now exists is, output has a specific noise. The data being sampled is 50Hz sinusoidal current waveform by current sensor ACS712. It overlays instantaneous current waveform over a bias of 2.5V. Thus, when signal is not present, a constant voltage of 2.5V is observed, thus, 512, because of mapping to 255 range.. 127. But in the case of free running mode, along with 127, 191, 63 only are observed. And it can also be seen that nearly 127 = 63*2, and 191 = 63*3. And when current waveform exists, it's highly distorted, but perceptible that it's not the previous signal of just 127, 191, 63. In the below plot, current is passed since 33.5sec.
Observed waveform, free running mode

I am unable to understand this observed structured noise. What may be the reason ? I have once read, last two MSB bits get noisy at this sampling rate, but then how would 127, jump to 191. Why is 63 getting added, subtracted at each instant ?
I understand the reason for non-uniform sampling now is because of Serial.print(), whose interrupts are obstructing the ADC interrupts, but don't understand the reason behind the noise observed.

Following is the code uploaded in arduino. Serial data is read from matlab by fread() function.

long t1=0,ts1=0,ts2=0;
int aval=0, val=0;

void setup() {

 TIMSK0 = 0x00;           // disable timer (causes anoying interrupts)
 DIDR0 = 0x3F;            // digital inputs disabled
 ADMUX = 0x40;            // measuring on ADC0, right adjust, AREF reference
 ADCSRA = 0xAC;           // AD-converter on, interrupt enabled, prescaler = 16
 ADCSRB = 0x00;           // AD channels MUX on, free running mode
 bitWrite(ADCSRA, 6, 1);  // Start the conversion by setting bit 6 (=ADSC) in ADCSRA
 sei(); 
 Serial.begin(115200); 
 t1=millis(); 
 }

ISR(ADC_vect)
{
 aval = ADCL;    
 aval += ADCH << 8; 
} 

void loop() {
val = map(aval, 0, 1023, 0, 255);
Serial.write(val);
delay(10);
}

Best Answer

Sounds like you have several things going on. Aliasing is highly likely. First, you are sending data at 115200 baud. That is in bits per second, so with 10 bits per byte, it takes about 200uS to send a 2 byte int. That is about 5K bandwidth. You say that you are sampling at 76.9K, samples per second.

Then you are doing some reasonably complicated math (map()), for an 8 bit micro, on the data which may have an impact on the sampling response. And you have a delay. All of that will have an impact on the sampling rate.

On top of that, and probably more importantly, you are updating the variable 'aval' in your ADC interrupt. 'aval' is a two byte int, so, in an 8 bit processor, it takes two memory moves to save the value. How do you guarantee that you don't get an interrupt between byte moves and have 'aval' be half of one reading and half of a different reading?

Then you are performing the map() function on that data. Is the map() function re-entrant? If the map function retrieves the 'aval' data several times in side the function, it is likely that the data will be updated by the interrupt during that time.

I would try to synchronize the interrupt to your main loop so the 'aval' value is not changed while you are operating on it. I would create another int and, at the beginning of your main loop, disable interrupts, copy 'aval' to that new variable, re-enable interrupts, then operate on the new variable.

That may clean things up some, but I think you will still have a bandwidth issue between the sampling and communications.