我有一个肌电图数据的信号,我应该(科学论文的明确推荐)平滑地使用RMS。
我有以下工作代码,生成所需的输出,但它比我认为可能的速度要慢得多。
#!/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我已经看到了一些关于移动窗口循环优化的deque和itertools建议,还有来自numpy的convolve,但我不知道如何使用它们来实现我想要的。
此外,我不再关心避免边界问题,因为我最终拥有大型数组和相对较小的滑动窗口。
感谢您的阅读
发布于 2011-11-25 00:49:16
使用卷积来执行你所指的操作是可能的()。为了处理脑电信号,我也做了几次。
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'))分解后,np.power(a, 2)部分生成一个与a维度相同的新数组,但每个值都是平方的。np.ones(window_size)/float(window_size)生成一个数组或长度window_size,其中每个元素都是1/window_size。因此,卷积实际上产生了一个新的数组,其中每个元素i等于
(a[i]^2 + a[i+1]^2 + … + a[i+window_size]^2)/window_size其是移动窗口内的阵列元素的RMS值。通过这种方式,它应该表现得非常好。
但是请注意,np.power(a, 2)会生成一个相同维数的新数组。如果a真的很大,我的意思是足够大,以至于它不能在内存中放两次,你可能需要一个策略,在适当的地方修改每个元素。此外,'valid'参数指定放弃边框效果,从而产生由np.convolve()生成的较小数组。您可以通过指定'same' (参见documentation)来保留所有内容。
发布于 2019-07-16 13:34:03
我发现我的机器正在纠结卷积,所以我提出了以下解决方案:
计算移动均方根窗口快速
假设我们有模拟电压样本a0 ...a99 (100个样本),我们需要10个样本的移动均方根通过它们。
该窗口将首先从元素a0扫描到a9 (十个样本),以获得rms0。
# rms = [rms0, rms1, ... rms99-9] (total of 91 elements in list):
(rms0)^2 = (1/10) (a0^2 + ... + a9^2) # --- (note 1)
(rms1)^2 = (1/10) (... a1^2 + ... + a9^2 + a10^2) # window moved a step, a0 falls out, a10 comes in
(rms2)^2 = (1/10) ( a2^2 + ... + a10^2 + a11^2) # window moved another step, a1 falls out, a11 comes in
...简化它:我们有a = [a0, ... a99]来创建10个样本的移动均方根,我们可以取10个a^2的加法的sqrt并乘以1/10。
换句话说,如果我们有
p = (1/10) * a^2 = 1/10 * [a0^2, ... a99^2]要获得rms^2,只需添加一组10个p。
让我们有一个acummulator acu:
acu = p0 + ... p8 # (as in note 1 above)然后我们就可以
rms0^2 = p0 + ... p8 + p9
= acu + p9
rms1^2 = acu + p9 + p10 - p0
rms2^2 = acu + p9 + p10 + p11 - p0 - p1
...我们可以创建:
V0 = [acu, 0, 0, ... 0]
V1 = [ p9, p10, p11, .... p99] -- len=91
V2 = [ 0, -p0, -p1, ... -p89] -- len=91
V3 = V0 + V1 + V2如果我们运行itertools.accumulate(V3),我们将得到rms数组
代码:
import numpy as np
from itertools import accumulate
a2 = np.power(in_ch, 2) / tm_w # create array of p, in_ch is samples, tm_w is window length
v1 = np.array(a2[tm_w - 1 : ]) # v1 = [p9, p10, ...]
v2 = np.append([0], a2[0 : len(a2) - tm_w]) # v2 = [0, p0, ...]
acu = list(accumulate(a2[0 : tm_w - 1])) # get initial accumulation (acu) of the window - 1
v1[0] = v1[0] + acu[-1] # rms element #1 will be at end of window and contains the accumulation
rmspw2 = list(accumulate(v1 - v2))
rms = np.power(rmspw2, 0.5)我可以在不到1分钟的时间内计算出128兆样本的数组。
发布于 2011-11-24 05:11:41
因为这不是线性变换,所以我不相信可以使用np.convolve()。
这是一个可以做你想做的事情的函数。注意,返回数组的第一个元素是第一个完整窗口的均方根;即,对于示例中的数组a,返回数组是子窗口[1,2],[2,3],[3,4],[4,5]的均方根,并且不包括部分窗口[1]和[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])https://stackoverflow.com/questions/8245687
复制相似问题