Save analogRead() values in array fast enough for signal frequency

Hi all! I’m not Arduino programmer and I’m looking for a way to improve my code performance.

I have an ESP32 with an AC voltage signal in an ADC input, from a current clamp transformer.
I want to get the points of the AC wave and get the signal RMS value out of them.

For this test I’ve configured the ADC with 10 bits and 0 dB of attenuation. If I read the analog input directly in the “void loop()” I can get enough measurments to plot the wave like the figure “wave1”. Here the code:

void setup() {
  analogReadResolution(10);
  analogSetAttenuation(ADC_0db);
  Serial.begin(115200);
}

void loop() {
  Serial.println(analogRead(34));
}

However, I want to save these points in an array to process them and get the RMS value. When I save them in an array the points I can get are the ones shown in the figure “wave2” because of the slower sample rate. Here there’s the code I use to save the readings to an array:

#define samplesLenght 750

void setup() {
  analogReadResolution(10);
  analogSetAttenuation(ADC_0db);
  Serial.begin(115200);
}

void loop() { 
  float measures[samplesLenght];
  int i = 0;
  while (i <= samplesLenght) {
    measures[i++] = analogRead(34);
  }
}

How could I increase the performance of the iteration where I save the analogRead() value to an array?

Thank you for you attention!
Marc C.

There is nothing in your code that changes the ADC sample rate, which is fixed at about 10,000 samples/second, unless your program does something else.

However, it takes time to print the value of each sample (one character printed every 10/115200 seconds). So, in the first example the act of printing determines when each sample is collected, and the time difference between samples is not constant.

Don’t print while collecting data.

When I save them in an array the points I can get are the ones shown in the figure "wave2" because of the slower sample rate.

What detail tells you that the sampling rate is lower?
BTW, wave2.png is definitely not generated by the second code sample because it doesn't print anything to the serial interface.

float measures[samplesLenght];

Please explain why you chose "float" for the array base type!

To improve the performance of the ESP32 and thing do's start with using freeRTOS FreeRTOS API categories. I, also, suggest using the ESP32 A:D API Analog to Digital Converter - ESP32 - — ESP-IDF Programming Guide latest documentation.

Also, core assignment of tasks will do wonders for the performance:

xTaskCreatePinnedToCore( fDo_AudioReadFreq, "fDo_ AudioReadFreq", TaskStack40K, NULL, Priority4, NULL, TaskCore1 ); //assigned to core
  xTaskCreatePinnedToCore( fDo_LEDs, "fDo_ LEDs", TaskStack40K, NULL, Priority4, NULL, TaskCore0 ); //assigned to core

. 2 tasks, with each task assigned to its own core.

Your input signal is an alternating sinusoidal wave of only 50 Hz (European mains). Is the ADC of ESP is bipolar? If not, use an external 16-bit bipolar ADC of type ADS7805P (or equivalent I2C Bus driven); sample your signal at 2050 samples/sec (theoretically 250 is good enough to retain the maximum information of the wave); feed the samples into a 16-bit DAC and observe the output. What you have done in the loop() function (taking thousands of samples/sec) does not make any sense!!!

Thanks for your help. I see that the question was not well raised so I will try again using your feedback:

GolamMostafa:
Your input signal is an alternating sinusoidal wave of only 50 Hz (European mains). Is the ADC of ESP is bipolar?

The reference of the AC signal is 0,5V from a resistors voltage divider and the maximum peak of the wave can be 0.5V. Therefore the total input range can be from 0 to 1V.

jremington:
There is nothing in your code that changes the ADC sample rate, which is fixed at about 10,000 samples/second, unless your program does something else.

However, it takes time to print the value of each sample (one character printed every 10/115200 seconds). So, in the first example the act of printing determines when each sample is collected, and the time difference between samples is not constant.

Exactly! So, modifying the following code with a baud rate of 9600, 115200 or 1000000 I get the results shown in “wave_9600.jpg”, “wave_115200.jpg” and “wave_1000000.jpg” correspondingly. See that with a higher rate I get more readings for the same time period.

void setup() {
  analogReadResolution(10);
  analogSetAttenuation(ADC_0db);
  Serial.begin(115200);
}

void loop() {
  Serial.println(analogRead(34));
}

These results show me that the sample rate of the ADC integrated in ESP32 is more than enough for sampling the 50 Hz AC wave.
What I want to do is to save the readings in a sample rate of 115200 to get the wave shown in “wave_115200.jpg” in an array. The question is: how can i do it?

Without defining a sample rate and saving the analog readings in a “while()” loop i get the points shown in the figure “wave2.png” of the original post.

pylon:
BTW, wave2.png is definitely not generated by the second code sample because it doesn’t print anything to the serial interface.

Sorry about it, now I put the full code to print the wave 750 values stored in the array every 10 seconds:

#define samplesLenght 750

void setup() {
  analogReadResolution(10);
  analogSetAttenuation(ADC_0db);
  Serial.begin(9600);
}

void loop() {
  int measures[samplesLenght];
  int i = 0;
  while (i <= samplesLenght) {
    measures[i++] = analogRead(34);
  }
  for(int i = 0; i <= samplesLenght; i++) {
    Serial.println(measures[i]);
  }
  delay(10000);
}

In summary: I want to save the readings into an array in a higher rate than I can do it with a while() loop.

Thanks again!

wave_115200.jpg

wave_1000000.jpg

jremington:
There is nothing in your code that changes the ADC sample rate, which is fixed at about 10,000 samples/second, unless your program does something else.

That's the number for the ATmega processors - OP is using the ESP32, apparently able to sample at 6 ksps

mcanigueral:
In summary: I want to save the readings into an array in a higher rate than I can do it with a while() loop.

Looking at the wave2.png I think your problem is quite the opposite. You're sampling WAY too fast. That plot looks like a small part of the wave, suggesting those 750 samples were taken within a few ms, which is quite feasible considering this reference mentioning much higher sample speeds (up to 1 Msps), as well as the comment by @ESP_Sprite in the first link that I gave:

You can sample way faster than that, but we don't guarantee all frequencies will make it unattenuated into the digital samples.

.
The other images (the 115k2 and 1M baud plots) are perfectly consistent with this. The print statements slow you down enough to get a reasonable sampling rate. For a 50/60 Hz signal a 6k sps sampling rate is more than enough.

Wow, you are right... it was too fast! I was sampling during 6.8 ms which means only a 3% of a 50Hz period.
Now in the interative loop I've introduced a "delayMicroseconds()" in order to set the number of samples per period.

Thank you very much @wvmarle!