True RMS - Audio

Hello,

I am working on a project which calculates true RMS of an audio signal. I am using Arduino UNO+Seven segment display to achieve this.
I have defined prescalar to be 32 to achieve sampling frequency of 38.5kHz, and used fast read analog input ADCH instead of analogRead().
The results are not as desired when tested with sine wave and square wave of 10kHz(offset applied). It works fine for DC voltage input.
The code is as follows:

#include <DigitShield.h>  // Includes header file for digit shield display

long x=0;              // For calculating number of samples read
float RMS = 0 ;       // Variable to store final result
float inputRead = 0 ; // Variable to read and store input samples
float sum = 0 ;       // Variable to store and manipulate the samples
float voltage = 0 ;

void setup() 

{
  
  //clear ADCSRA and ADCSRB registers
  ADCSRA = 0;
  ADCSRB = 0;
  
  ADMUX |= (1 << REFS0); //set reference voltage
  ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only
  
  ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500kHz
  ADCSRA |= (1 << ADATE); //enabble auto trigger
  ADCSRA |= (1 << ADEN); //enable ADC
  ADCSRA |= (1 << ADSC); //start ADC measurements    
  interrupts();//enable interrupts
  
  DigitShield.begin();         // Initiate digit shield for displaying output value
  Serial.begin(9600);          // Initialize serial monitor
            
}

/*ISR(ADC_vect) 
  {//when new ADC value ready
    inputRead = ADCH ;     
  }*/
  
void loop() 
{                                     
while(millis()<=10000) 
{ 
inputRead = ADCH ; 
voltage = inputRead * (5.0/255.0);
x++; 
sum = sum + ((voltage*voltage)); 
}

RMS = sqrt(sum/x);

Serial.println(inputRead);
Serial.println(voltage);                  // Displays number of samples in serial monitor
Serial.println(sum);    
Serial.println(x);
Serial.println(RMS);                              // Displays final result in serial monitor
Serial.println("\n");

if(RMS)
    {      
      DigitShield.setValue(RMS);                 // Display the final RMS value
      DigitShield.setPrecision(3);    
    }  
}

Please look at attachments for test wave and serial monitor results.

Please help…

The results are not as desired

What were you expecting?

Pete

the true RMS value.

I am getting wrong output for my code. Please see attachments.

What should the numbers be?

Pete

I have applied sine wave and square wave of 5V. for square wave, it should show the average value i.e 2.5V. for sine wave, some where around 3.5V.
Note that I have limited my input to 10sec so that after 10 seconds, the samples should stop and RMS should be displayed for samples collected between 0 - 10 seconds.

The first thing you need to do is correct for the offset of the input values. They are going to be values from zero to 255. To calculate RMS properly you need to subtract 128 from each one so that they vary from -128 to +127.

Input the square wave and check the output. You can estimate what the program's output should be because you know how many samples were taken (x) over ten seconds and you know the frequency of the input square wave. If the output and your calculations don't match, you need to figure out what you're doing wrong.

Pete

could you please give me example calculation for 0-5V sine wave with offset ?

Like I said, for now stick to the square wave because it is easier to calculate what the program should be producing. The RMS value of a square wave with amplitude A is just A. The ADC values for the square wave should be either 0 or 255. Correcting this for the offset (subtracting 128 from every ADC value) means the inputs should be -128 for the negative half of the wave and 127 for the positive half. Therefore the final value for RMS should be about 127 which you can then convert to voltage.
For now, try this code:

while(millis()<=10000) 
{ 
voltage = ADCH - 128; 
x++; 
sum = sum + voltage*voltage; 
}

RMS = sqrt(sum/x);

This does not convert to voltage. That can be done once the thing is producing numbers that look right.
The value printed for RMS should be about 127 if your square wave is 0-5V at the ADC.

Pete

Thank you so much el_supremo. It helps me a lot. I will try this method and share results with you :slight_smile:
Just now, I learned how to calculate RMS of sine n square wave with DC offset(http://masteringelectronicsdesign.com/how-to-derive-the-rms-value-of-a-sine-wave-with-a-dc-offset/)
Also, I should have made wrong settings in my signal generator even though the output waveform looks alright. I ll recheck the settings too.