Calculating RMS using fixed point math (C)

1.5k views Asked by At

I am trying to calculate the RMS value of a waveform but am running into some problems.

I take samples every x microseconds which is triggered by an interrupt. The sample is stored in an array and each time a sample is taken it pushes the last value to the next point in the array and feeds a new value in. As i take the sample I square it and divide by 20 (number of sample per period, assume waveform fixed frequency) then put it into my array, i also add it to a sum value and when i reach 20 samples i subtract the first sample made and add the last sample made.

value 20 = value 19   //INT16 values
value 19 = value 18
...
value1 = (sample * sample)/20
sumvalue += value1
sumvalue -= value20

I then call an RMS function which takes that value, divides by the last calculated RMS value (or if not calculated yet then divide by 1) add the last RMS value then divide all that by 2.

CalcRMS(sumvalue)
INT32 tempsum
if(RMS)
tempsum = (sumvalue/RMS + RMS)/2
else
tempsum = (sumvalue + 1)/2
RMS = tempsum

I then output RMS to the screen. Only problem is that my RMS value keeps changing, even though the waveform is constant. If i run a dc value in there my RMS stays steady but shove in a sine wave and it goes crazy.

Hoping somebody can point me in the right direction. I don't want the answer straight up, just some nudges to get me back on track.

3

There are 3 answers

3
laloumen On

Aside from the fact that you're not calculating RMS (where is the sqrt?) and that your algorithm for calculating RMS doesn't seem correct, a sampled RMS value would be expected to oscillate within a range due to the sampling. You haven't specified what the frequency of the sine wave you are sampling, nor demonstrated that 20 values is sufficient to avoid aliasing. If you know the period of your sine wave and divide that by 20, then your RMS value won't oscillate.

In addition, your code is highly non-scalable - imagine the agony of your approach of value1, value2, ..., value20 when you realize you need to preserve 200 values (or 2000)!

Here is a sample Python script which you can play around with:

   i = 0
   x = 0
   values = []
   sampleSize = 20
   while True:
      y = math.sin(x)
      y = y*y/sampleSize
      values.append(y)
      if(len(values) > sampleSize):
         values.pop(0)
      val = sum(values)
      print(math.sqrt(val))
      x += 8*math.atan(1)/sampleSize
      i += 1
0
Dennis C Furlaneto On

Alrigth, this function doesn't really compute the RMS.

Did you take a look at how sumvalue changes overtime? sumvalue must be somewhat constant, in the dc and in the sign case. If it isn`t, something is wrong with the routine that does the sum. If the sumvalue is constant, then there is something wrong with your RMS procedure.

1
user3629249 On

if the code is sampling the data often enough, find min value, find max value, find median = (min+max)/2, find RMS = (max-median)*.707

if the code is not sampling the data often enough, then use a fast forier(spelling) transform to find the min/max values.