1

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.

  • I am not sure about the averaging between the last two RMS values because that adds an extra "mean" calculation between frames. Since you are dealing with fixed point numbers, perhaps you would like to test if you get overflow errors. For this purpose, try feeding your algorithm with a lower amplitude sinusoid. Finally, this might help: http://stackoverflow.com/questions/1058813/on-line-iterator-algorithms-for-estimating-statistical-median-mode-skewnes as well as this: http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance – A_A Jun 10 '15 at 13:06
  • this kind of code: 'value 20 = value 19 //INT16 values value 19 = value 18 ...' is a massive CPU cycle waster. Instead, use a circular queue. – user3629249 Jun 10 '15 at 13:18
  • Perhaps it is taking too long and the interrupt is getting called again part way through the shift. I will try putting the values into a buffer and use pointers to index the values. – user2585465 Jun 10 '15 at 13:25
  • 20 samples won't be nearly enough to get an accurate reading, your description is exactly what I'd expect. You're basically getting random parts of a waveform. Unless your readings are timed to precisely cover a single wave of AC. – Mark Ransom Jun 10 '15 at 13:49
  • If you think about what it means to converge to a steady value, it means that your value1 = value20. Given x[i] = sin(t[i]), and value=x*x/20, this places very specific requirement on the sampling rate with respect to the period of your harmonic function. In other words, t[1] and t[20] must fall in the same place relative to the sine curve. Does that make sense? – laloumen Jun 10 '15 at 16:32

3 Answers3

0

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.

0

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.

user3629249
  • 16,402
  • 1
  • 16
  • 17
  • The code samples a full waveform, but since the MCU doesnt have an FPU I cannot use decimal values as it costs too much in execution time. – user2585465 Jun 11 '15 at 02:58
0

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
laloumen
  • 1,229
  • 2
  • 14
  • 15
  • The calculations give a close approximation of RMS after a couple of cycles the value should be constant. I cant use floating point numbers because of no FPU and the high overhead it introduces. – user2585465 Jun 10 '15 at 13:47
  • That depends on the period of the sine wave and the sample rate. If the 20 samples only cover a small part of the period - the RMS value will constantly change. – laloumen Jun 10 '15 at 13:49
  • Correct. I should have put that in the original post, the 20 samples covers a full period of the waveform. – user2585465 Jun 11 '15 at 01:50