0

it has been a week that I'm struggling with the arduino to measure the RMS Voltage value. By OSC I can see that the RMS voltage value changes around 3V. But I can't see it by serial port. I think my sampling or conversion has problem and I can't find it. I really appreciate it if anyone can take a look at my codes and suggest anything.

float readRMS_new(int pin, int vref) {
  int numReadings[100];
  const unsigned long samplingInterval = 2;  // Interval between RMS calculations in milliseconds
  unsigned int readingsSum = 0;   // Sum of squared readings
  unsigned int readingsCount = 0; // Number of readings taken
  unsigned long lastSamplingTime = 0;  // Time of the last RMS calculation
  float rmsVoltage = 0;
  float finalVoltage = 0;
  float circuitGain = 4.31;  // Gain of the circuit

  unsigned long currentTime = millis();  // Current time

  // Check if it's time to perform an RMS calculation
  if (currentTime - lastSamplingTime >= samplingInterval) {
    lastSamplingTime = currentTime;  // Update the last sampling time

    // Perform RMS calculation
    for (int i = 0; i < 100; i++) {
      numReadings[i] = analogRead(pin); 
      readingsSum += pow(numReadings[i] - vref, 2);
      readingsCount++;
    }


    // Calculate RMS voltage
    float rms = sqrt(readingsSum / readingsCount);
    rmsVoltage = rms * 0.0048;
    finalVoltage = rmsVoltage * circuitGain;

    if (finalVoltage > 0.0f) {
      // Print RMS voltage
      Serial.print("RMS Voltage: ");
      Serial.println(finalVoltage, 3);  // Print with 3 decimal places
    }

    // Reset variables for the next RMS calculation
    readingsSum = 0;
    readingsCount = 0;

    return finalVoltage;
  }

  return 0.0f;  // Return 0 if it's not time to perform an RMS calculation
}

Regards

Farzaneh

2
  • What calls readRMS_new() ? An Interrupt Service Routine or from the loop() ? But, whatever, it is going to be slow with all those maths functions.
    – 6v6gt
    Commented May 19, 2023 at 13:24
  • please describe the signal that is being sampled ... add the description to your question ... do not add a comment
    – jsotola
    Commented May 19, 2023 at 15:26

2 Answers 2

2

There are multiple issues with this piece of code:

  1. Local variables, i.e. variables defined inside functions or braced blocks, are created each time the execution enters the function or block, and destroyed when it leaves it. Thus, lastSamplingTime will always be zero when it is checked. If you want the variable to preserve its value across invocations of the function, you have to either make it global or qualify it as static.

  2. There is no point in storing the readings in an array, as you never read back any element of the array other than the one you just stored. The array is then eating memory for no good reason.

  3. The Arduino will not be able to take more than one reading every 112 µs, or 100 readings in 11.2 ms. There is no point in trying to ensure a 2 ms interval between RMS calculations.

  4. There is no point in counting the readings: you know you are taking 100 of them.

  5. You should avoid using pow() for squaring an integer: this is a floating-point function which is prone to rounding errors.

  6. Maybe the most serious issue: on the Mega, an unsigned int is 16-bits, and cannot store numbers larger than 65,535. readingsSum is very likely going to overflow and give you a meaningless result.

  7. Returning zero to mean “no data available” is probably not a very good choice, as zero is also a perfectly valid result. You should consider returning an impossible value, like -1 (an RMS reading cannot be negative).

Here is how I would write the computation of the RMS value:

long readingsSum = 0;
for (int i =0; i < 100; i++) {
    long reading = analogRead(pin) - vref;
    readingsSum += reading * reading;
}
float rms = sqrt(readingsSum / 100);

Note that reading is of type long in order to avoid the squaring to overflow.

0

Thank you all for your time dedication. Finally increasing the sampling and optimize the same codes I could achieve my goals. I will post the functioning code for those who might need it.

float readRMS(int pin, int vref) {

  int lecturas[200]; // declaring the matrix

  float suma = 0; // sum of the squares

  float rms = 0;  // squares mean

  float volt = 0;  // 

  float Volt_Final = 0;

  for (int cont = 0; cont < 200; cont++) { 

    lecturas[cont] = analogRead(pin);  

    delayMicroseconds(200);           
  }
  for (int j = 0; j < 200; j++) { 

    //Serial.println(lecturas[j]); 

    suma = suma + pow((lecturas[j] - vref), 2);
 
    //Serial.println(suma);
  }
  rms = sqrt((suma / 200));

  volt = (rms / 1024) * 5; 

  //Serial.println(volt);

  //suma=0;

  // Reset variables for the next RMS calculation

  rms = 0;

  lecturas[200] = 0;

  //Volt_Final = (volt * 4.31); //real voltage with circuit gain

  return volt;
}
1
  • lecturas[200] = 0; is out of bounds. Array indices are 0 to 199
    – SBF
    Commented May 29, 2023 at 12:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.