Moving RMS calculation - Page 1
Forum section: electronics / general

author: Psi
author_rank: Super Contributor
timestamp: February 12, 2019, 10:04:49 am
content: Does anyone know if it's possible to do a moving window type RMS calculation from ADC data without having to store all the values in memory?

author: ejeffrey
author_rank: Super Contributor
timestamp: February 12, 2019, 10:59:09 am
content: You can't do a moving window average without a memory buffer. Can you use an exponentially decaying average instead?

author: David Hess
author_rank: Super Contributor
timestamp: February 12, 2019, 11:14:45 am
content: It can be done with a FIFO type data structure which allows not recomputing from the entire list of values but this still requires storing every value.

author: Psi
author_rank: Super Contributor
timestamp: February 12, 2019, 11:21:53 am
content: Quote from: David Hess on February 12, 2019, 11:14:45 amyeah, ya can speed it up if you have all the data by subtracting (oldest value*oldest value) from the RMS sum.

author: Psi
author_rank: Super Contributor
timestamp: February 12, 2019, 11:22:53 am
content: Quote from: ejeffrey on February 12, 2019, 10:59:09 amThanks, that's what i needed to know.

author: RoGeorge
author_rank: Super Contributor
timestamp: February 12, 2019, 11:28:17 am
content: Depending on how much compromise can be made, if a FIFO must be avoided at all costs, I've seen the trick of remembering only the average, and subtracting Avg/N before adding each new value, where N is the number of the samples (the length) of the averaging window.

author: ebastler
author_rank: Super Contributor
timestamp: February 12, 2019, 11:39:09 am
content: Quote from: ejeffrey on February 12, 2019, 10:59:09 am@Psi, did you note this part of ejeffrey's reply? In many cases this will do the job, and is easy and efficient to implement:mean_square := p * mean_square + (1-p) * new_sample^2with a weight factor p, 0<p<1.

author: Psi
author_rank: Super Contributor
timestamp: February 12, 2019, 11:43:26 am
content: Yep, i will have a look into exponential decay tomorrow.It may work, just want to have a play with RMS first.

author: Jeroen3
author_rank: Super Contributor
timestamp: February 12, 2019, 11:52:22 am
content: Note that with exponential decay you still have to match the number of samples in the buffer with the period time. If you calculate RMS over 1.5 period, the result is off.A fifo is a easy way since you can also use it to decimate samples to match the period time.That is, if the frequency of the signal you measure is variable.

author: Kleinstein
author_rank: Super Contributor
timestamp: February 12, 2019, 12:31:10 pm
content: One can do the RMS calculation for short periods, like about 1 period at a time and store these values. For the final result one can than do moving average on these recalculated values (this could directly RMS, but maybe better the power and maybe DC contribution). So one would come close to moving average RMS with storing less data, though at a limited update rate (e.g. one period).

author: ebastler
author_rank: Super Contributor
timestamp: February 12, 2019, 12:35:01 pm
content: @Jeroen3, Kleinstein: It is not clear to me from the OP whether the intent is to deal with a periodic signal at all? I was thinking of RMS noise when I read the OP, where period duration is not a relevant parameter. But that was just me jumping to conclusions as well...

author: ogden
author_rank: Super Contributor
timestamp: February 12, 2019, 01:34:49 pm
content: Right. We shall not assume periodic (and bipolar) signal. Most likely mentioned moving average confused many. It is indeed possible to calculate RMS "on the fly", w/o data buffer, using just two global variables.samples = 0;sum = 0;while(1) {adc_data = ADC();samples = samples +1;sum = sum + adc_data*adc_data;RMS = sqrt(sum/samples);}Note that accumulator overflow/saturation shall be addressed, solution depends on application.

author: ali_asadzadeh
author_rank: Super Contributor
timestamp: February 12, 2019, 03:52:43 pm
content: QuoteThat's good solution, but the problem with this code is the overflow cases! and when samples roll over to zeroit can be corrected though!

author: Doctorandus_P
author_rank: Super Contributor
timestamp: February 12, 2019, 04:06:50 pm
content: The combination of RMS and moving average does not make much sens to me.RMS implies a periodic signal.Without a periodic signal you have to add some kind of windowing function to guestimate your RMS value, and that implies a full buffer to work with.If you have a periodic signal you can do some intermediate tricks.Just assume you're sampling a 50Hz signal @ 10ksps.You can then calculate a RMS value based on 10000 / 50 = 200 samples.You can then put the calculated RMS values of each set of 200 samples into a relatively small buffer, and do a moving average or exponential decaying on that.Depending on your sampling technique and doing AC only or AC+DC you ave to manage offsets carefully.Something else to think about:It is intuitive to start those 200 samples at a zero crossing, and continue untill the next zero crossing, and in a perfect world this is fine.However, in the real world this leads to relatively big errors, if the ratio does not fit perfectly.You may have upto one sample to many, or too less of your periodic signal without knowing it.That sample will be near the "zero" value of your RMS, which means that you effectively would have calculated a better RMS value if you divided by 199 or 201.However. If you start the sample period of those 200 samples near the (guestimated) RMS value of your signal, then one sample to few or too many does not matter much, because the "extra" sample has (almost) the same value as the RMS value and therefore does not add an error.You can safely calculate the RMS value from a 201 sample buffer if that 201-th sample is the same as the RMS value.But if that 201-th sample is (near to) 0, it will introcue an error of 0.5% in your RMS calculation.

author: RoGeorge
author_rank: Super Contributor
timestamp: February 12, 2019, 04:15:15 pm
content: Quote from: Doctorandus_P on February 12, 2019, 04:06:50 pmRMS does not imply a periodic signal.

author: ejeffrey
author_rank: Super Contributor
timestamp: February 12, 2019, 04:56:22 pm
content: Quote from: Doctorandus_P on February 12, 2019, 04:06:50 pmNo you don't have to do any of this.sqrt of the exponentially weighted moving average of the amplitude squared is perfectly fine by itself. No matter what you choose you have to make sure you are averaging over a time appropriate to your application. Yes, if your signal is at a known frequency and synchronous with your sampling rate you can get faster settling by using a square window filter synchronized to the period. But there is no reason you have to do that or assume anything like that is possible.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 12, 2019, 08:07:14 pm
content: Sorry if this is obvious to you - but just making sure what you meant by "store all the values in memory".A true moving average or moving RMS doesn't need to store "all values" (whatever that means) but only the last N values, N*Ts being your moving window's period (Ts being your sampling period).We don't know anything about your sample rate and moving window, but in a lot of cases, only a relatively small (circular) buffer is needed. For instance, @44100Hz, a 100ms moving RMS would only need a ~4K samples circular buffer.Now if this is too much for your intended target (but if it is, I'm not sure your target would be appropriate anyway, but again we don't know anything about your application as a whole...), you can use exponential decay filtering as already suggested for instance. That may fit your requirements. Keep in mind that exponential decay filtering is essentially an IIR filter, whereas a moving average/RMS is essentially an FIR.

author: snarkysparky
author_rank: Frequent Contributor
timestamp: February 14, 2019, 05:58:34 pm
content: at each sample point calculate the squared value of the signal.T = input^2;now exponential filter this stream of squared values.Ta = Ta + K*(T - Ta); // 0 < K < 1When the RMS is desired just square root this valueRMS = Ta^(1/2);

author: ebastler
author_rank: Super Contributor
timestamp: February 14, 2019, 07:02:21 pm
content: Quote from: snarkysparky on February 14, 2019, 05:58:34 pmYou had me wondering for a moment, but it's indeed the same as my formula in post #6.But I like mine better,since it makes the decay of the memory term more transparent (for me at least).

author: NorthGuy
author_rank: Super Contributor
timestamp: February 14, 2019, 07:36:06 pm
content: Quote from: ebastler on February 14, 2019, 07:02:21 pmDepending what you want to accomplish, the exponential smoothing may or may not replace the moving average.For example, if you have a 50 Hz periodic signal, you can choose the window of moving average to match the cycle, which is 20 ms for 50 Hz. In this case, your moving average will give you very nice flat estimate, which will also respond very fast to the changes.In the same situation, exponential smoothing will produce a periodic 50 Hz curve, and to suppress the periodicity you will have to make K very small. But the small K will make your exponential smoothing very slow to respond to changes.

author: Psi
author_rank: Super Contributor
timestamp: February 14, 2019, 10:19:59 pm
content: The signal is audio.I need to make a decision based on live data but also make a decision based on the RMS value at any given point.The RMS value will obviously be for a set period, likely 1-10 ms (TBD)The ADC will be running at max speed so 1-10ms is still a lot of samples to buffer in memory.I have the ram to buffer them, i was more just curious if it was possible to do an moving RMS calc without needing all the ram.

author: NorthGuy
author_rank: Super Contributor
timestamp: February 14, 2019, 10:27:46 pm
content: Quote from: Psi on February 14, 2019, 10:19:59 pmJust calculate the sum of squares for the burst, then move to the next burst etc. No need for memory.

author: Psi
author_rank: Super Contributor
timestamp: February 14, 2019, 10:31:17 pm
content: When RMS data is needed it needs to be for the last 1-10ms

author: ogden
author_rank: Super Contributor
timestamp: February 14, 2019, 10:43:15 pm
content: Quote from: Psi on February 14, 2019, 10:31:17 pmYou may calculate RMS for 1ms blocks and save results in circular buffer for last 10ms or even longer time. I believe that for many applications 1ms granularity may be ok.

author: Psi
author_rank: Super Contributor
timestamp: February 14, 2019, 11:30:17 pm
content: thanks, i will give it a try

author: ebastler
author_rank: Super Contributor
timestamp: February 15, 2019, 05:21:01 am
content: Quote from: Psi on February 14, 2019, 10:19:59 pmBut that's an RMS averaging time which is less than the period of many of your audio components?! I don't think that will give you meaningful results.I assume you have a mix of frequency components in your signal, hence can't average over exactly one period length. In that case you will need to average over "many" periods of the slowest signals to get a stable RMS readout. Or use the exponential decay approach, but again with a time constant that is significantly larger than the period of the slower signal components.