Missing measured values of the ADC

Oleum

Active member
I have made measurements with the built-in ADC. When I displayed the data graphically, I noticed that certain values are missing or are displayed as "0". Interestingly these values are in the binary-typical distance of 64 to 65. Possibly it is a quantization problem. The following measured values are missing:
318 + 319
382 + 383
446 + 447
510 + 511
575
639
I have run measurements for some time, and summed up the measurement results. Normally the measured values are between 0 and 1024 (2^10) for a 10 bit measurement. I have now counted how often certain measured values were measured.
for example the measurement value 637 was measured 7679 times. The measurement value 638 was measured 599 times (which is also unusual), the measurement value 639 was not measured at all, while the next measurement value 640 was measured 7483 times. This is purely from the measurement technology not possible that there could be dropouts here. I assume that a certain bit in the converter does not work. Now I used another input pin and it is the same values that do not exist.
These were measurements, on my project. In the meantime, I put a noise generator on the analog input pin, and observed the noise. In fact, I see white lines in the graphical representation.

Then, because I wanted to rule out that it was due to serial reception, I caused an output of the values I mentioned earlier.
In fact, these values are not output, but the ones right next to them are output. I made this last test with the attached program.

On the attached screenshot you can clearly see the horizontal lines in the noise


Code:
#include "TeensyTimerTool.h"
#include <ADC.h>

ADC *adc;

using namespace TeensyTimerTool;


int Val_u = 0;

void setup() {

  //Serial.begin(115200);
  Serial.begin(230400);
  // Serial.begin(38400);

  adc = new ADC();

  analogReadAveraging(1);

  // Methode 2
  adc->adc0->setReference(ADC_REFERENCE::REF_3V3);  // internal 3.3V ref
  adc->adc0->setAveraging(1);                       // samples per reading
  adc->adc0->setResolution(10);                     // bits of resolution
  adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED);
  adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED);
}


void loop() {  // Whole array send to SerialPort
  // read;

  Val_u = adc->adc0->analogRead(A17);

  if (Val_u == 319 || Val_u == 320 || Val_u == 446 || Val_u == 447 || Val_u == 448 || Val_u == 510 || Val_u == 511 || Val_u == 512) {

    Serial.println(Val_u);
  }
}
 

Attachments

  • noise.jpg
    noise.jpg
    243.7 KB · Views: 64
Did you use a low impedance source to drive the ADC - many ADC only reach their published performance for low impedance drive. ADCs built in to microcontroller chips are usually a poor compromise in performance since the process used for high performance digital chips is not tuned for analog requirements.

You've not indicated which chip is involved BTW.
 
The noise generator should have an impedance of 50 ohms.

I would accept a non-linearity of the ADC, because this could be corrected. Also a somewhat slow calculation could be compensated by waiting. But that certain bits (2^6) are out is a more serious problem.

Would you please check the program, since I am a beginner in C++ it could be that I had built in a bug somewhere myself.

I use a Teensy 4.1
 
Interesting observation.
Did you perhaps change the amplitude of your (digitally-generated-noise?) generator to make sure it's not the generator causing this?
And what do you measure when using the generic analogRead(A17); without using the ADC library?

Paul
 
I noticed the thing during my spectrometer tests, because I create a point cloud so far.
Over the whole width of the representation these interruptions were to be seen. Afterwards I looked at these data statistically, and found out that these lines are always in the distance of about ? 64 units. Because my spectrogram does not cover the whole area all the time, I connected my function generator. And to get a nice graph I switched on the noise generator. On the picture you can see that now. So I used two different signal sources. So the error can not come from there.
I actually also used analogRead(Ax) without using these special specifications. However, the library was loaded at that time. Therefore I do not know whether this would possibly disturb the measurement.
Anyway, it would be good if someone else would check this whole thing, since it can't be ruled out that it's just my Teensy.
 
I'm playing right now with your exact code and a noise generator.
What tool did you use to display the point cloud? I'm now using TyCommander to save the serial data, import that data into Excel and then display the data by a Scatter chart...not ideal.
From the serial data I've captured sofar (20K points): I did not see values 447 & 511. The distribution is weird though.

NPP.png

Paul
 
I had written my own VB program to display the point cloud, which I plan to use to display the spectrometer data. However, I then had the data entered in a list box, from which I then imported the data into Excel via C&P.
There I then looked at the distribution.

That means you are also missing various data?
 
Well, changed the test strategy from using noise to using a slow ramping signal (0V > 3V3 in 1 sec).
That did not help; still missing values.
Then I changed the code to
Code:
int Val_u = 0;

void setup() {
  Serial.begin(230400);
}

void loop() {  
  Val_u = analogRead(A17);
  Serial.println(Val_u);
  delayMicroseconds(50);
}

Result: no missing values.

Paul
 
That's interesting, of course. However, it would then be the case that my ADC measurement is interrupted prematurely,
and therefore the decisive bit was not read.
However, I would not like to use delay. Is this a hardware problem, or a kind of library problem?
 
I am just wondering if that noise waveform is ever going below -0.3V or above 3.6V, that cause input protection diodes to conduct and inject charge into the supply rails for the ADC.

As for the speed of ramping and the delay, I'm not sure - normally the sample/hold window would occur at the start of conversion, so delays between conversions ought not to matter.
 
Well, my reason for diverting from a noise signal to a ramp was to rule out a potential issue with the digitally-generated noise.
However it appears to be something with the ADC routines. But I don't know enough about that library to come with a useful answer.
Did you perhaps try to change the setConversionSpeed and setSamplingSpeed?
The delayMicroseconds(50) in my last sketch was only added by me to not overflood the serial monitor with too fast data.

Paul
 
It is true:

I ran two tests again. Once with the ADC library and once without it.
The ADC library omits some values.
Without the library all values come through.

Who is responsible for this library, is there a
error reporting web page?
Or a newer version?


These are the missing values:
63
127
191
255
319
383
447
511
575
639
703
767
831
895
 
If you print the values in hex you'll see they have lots of low-order 1 bits, typically 6 or 7 low-order bits are 1. Some kinds of ADC have missing codes like this.
 
Who is responsible for this library, is there a error reporting web page?
The ADC library is written by @Pedvide and to be found here: https://github.com/pedvide/ADC.
As far as I can tell, the version on Github is included in Teensyduino 1.58.
One thing Pedvide stated at a certain commit: change pin mode to INPUT_DISABLE for best performance.
You may want to add pinMode(A17, INPUT_DISABLE); to your setup() code and check whether that makes a difference.

Paul
 
Back
Top