Numpy Root-Mean-Squared (RMS) smoothing of a signal

匿名 (未验证) 提交于 2019-12-03 01:48:02

问题:

I have a signal of electromyographical data that I am supposed (scientific papers' explicit recommendation) to smooth using RMS.

I have the following working code, producing the desired output, but it is way slower than I think it's possible.

#!/usr/bin/python import numpy def rms(interval, halfwindow):     """ performs the moving-window smoothing of a signal using RMS """     n = len(interval)     rms_signal = numpy.zeros(n)     for i in range(n):         small_index = max(0, i - halfwindow)  # intended to avoid boundary effect         big_index = min(n, i + halfwindow)    # intended to avoid boundary effect         window_samples = interval[small_index:big_index]          # here is the RMS of the window, being attributed to rms_signal 'i'th sample:         rms_signal[i] = sqrt(sum([s**2 for s in window_samples])/len(window_samples))      return rms_signal 

I have seen some deque and itertools suggestions regarding optimization of moving window loops, and also convolve from numpy, but I couldn't figure it out how to accomplish what I want using them.

Also, I do not care to avoid boundary problems anymore, because I end up having large arrays and relatively small sliding windows.

Thanks for reading

回答1:

It is possible to use convolution to perform the operation you are referring to. I did it a few times for processing EEG signals as well.

import numpy as np def window_rms(a, window_size):   a2 = np.power(a,2)   window = np.ones(window_size)/float(window_size)   return np.sqrt(np.convolve(a2, window, 'valid')) 

Breaking it down, the np.power(a, 2) part makes a new array with the same dimension as a, but where each value is squared. np.ones(window_size)/float(window_size) produces an array or length window_size where each element is 1/window_size. So the convolution effectively produces a new array where each element i is equal to

(a[i]^2 + a[i+1]^2 + … + a[i+window_size]^2)/window_size 

which is the RMS value of the array elements within the moving window. It should perform really well this way.

Note, though, that np.power(a, 2) produces a new array of same dimension. If a is really large, I mean sufficiently large that it cannot fit twice in memory, you might need a strategy where each element are modified in place. Also, the 'valid' argument specifies to discard border effects, resulting in a smaller array produced by np.convolve(). You could keep it all by specifying 'same' instead (see documentation).



回答2:

Since this is not a linear transformation, I don't believe it is possible to use np.convolve().

Here's a function which should do what you want. Note that the first element of the returned array is the rms of the first full window; i.e. for the array a in the example, the return array is the rms of the subwindows [1,2],[2,3],[3,4],[4,5] and does not include the partial windows [1] and [5].

>>> def window_rms(a, window_size=2): >>>     return np.sqrt(sum([a[window_size-i-1:len(a)-i]**2 for i in range(window_size-1)])/window_size) >>> a = np.array([1,2,3,4,5]) >>> window_rms(a) array([ 1.41421356,  2.44948974,  3.46410162,  4.47213595]) 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!