【问题标题】:audioop.rms() - why does it differ from normal RMS?audioop.rms() - 为什么它与正常的 RMS 不同?
【发布时间】:2012-03-19 00:05:56
【问题描述】:

我正在编写一个 python 函数来返回 .wav 文件的响度。 RMS 似乎是最好的指标,Detect and record a sound with pythonaudioop.rms() 可以解决问题,但我想避免将 audioop 作为依赖项,并且我已经导入了 numpy.但我没有得到相同的 RMS 值,希望能帮助我理解正在发生的事情。

来自audioop page,它表示rms 计算正是您所期望的,即sqrt(sum(S_i^2)/n),其中S_ii-th 声音样本。似乎它不是火箭科学。

要使用 numpy,我首先将声音转换为 numpy 数组,并且总是看到相同的最小值/最大值和相同的数据长度(因此转换看起来很好)。

>>> d = np.frombuffer(data, np.int16)
>>> print (min(d), max(d)), audioop.minmax(data,2)
(-2593, 2749) (-2593, 2749)

但我得到非常不同的 RMS 值,甚至没有接近球场:

>>> numpy_rms = np.sqrt(sum(d*d)/len(d))
>>> print numpy_rms, audioop.rms(data, 2)
41.708703254716383, 120

它们之间的区别是可变的,我看不到明显的模式,例如,我也得到:

63.786714248938772, 402
62.779300661773405, 148

我的 numpy RMS 代码给出了与此处相同的输出:Numpy Root-Mean-Squared (RMS) smoothing of a signal

我看不出哪里出错了,但有些不对劲。非常感谢任何帮助。


编辑/更新:

如果它有用,这是我最终得到的代码。它没有audioop那么快,但仍然足够快,足以满足我的目的。值得注意的是,使用 np.mean() 比我使用 python sum() 的版本快得多(~100 倍)。

def np_audioop_rms(data, width):
    """audioop.rms() using numpy; avoids another dependency for app"""
    #_checkParameters(data, width)
    if len(data) == 0: return None
    fromType = (np.int8, np.int16, np.int32)[width//2]
    d = np.frombuffer(data, fromType).astype(np.float)
    rms = np.sqrt( np.mean(d**2) )
    return int( rms )

【问题讨论】:

  • 谢谢,但不行。使用: "d = np.frombuffer(data, np.short)" 给出完全相同的行为。
  • 对不起,我在看到回复之前已经删除了评论。顺便说一句,如果您使用double 来计算np.power(a, 2),例如,将其更改为np.power(a, 2.),则可以使用window_rms()
  • 为什么不能使用audioop?数据有多大?可以使用 C 扩展吗?
  • 我可以使用 audioop,但这样做意味着为应用程序打包另一个依赖项(= 更大的下载量,并且在构建版本时更麻烦)。我们已经包含了 numpy,并且不需要每一微秒。可能只有很短的声音片段。
  • audioop 在 stdlib 中还是我遗漏了什么?您可以使用np.power(np.frombuffer(data, dtype=fromType), 2.0).mean()**.5 来避免使用.astype() 进行复制(这里power 创建浮点数组)。

标签: python numpy


【解决方案1】:

使用double 执行计算,如audioop.rms() code

d = np.frombuffer(data, np.int16).astype(np.float)

示例

>>> import audioop, numpy as np
>>> data = 'abcdefgh'
>>> audioop.rms(data, 2)
25962
>>> d = np.frombuffer(data, np.int16)
>>> np.sqrt((d*d).sum()/(1.*len(d)))
80.131142510262507
>>> d = np.frombuffer(data, np.int16).astype(np.float)
>>> np.sqrt((d*d).sum()/len(d))
25962.360851817772

【讨论】:

  • 谢谢!完美的。我投了“赞成票”,但还没有 15 个声望点。
【解决方案2】:

来自 matplotlib.mlab:

def rms_flat(a):
    """
    Return the root mean square of all the elements of *a*, flattened out.
    """
    return np.sqrt(np.mean(np.absolute(a)**2))

【讨论】:

  • 不错。对我来说,在 rms 之前转换为 np.float 是个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-06
  • 1970-01-01
  • 2019-11-21
相关资源
最近更新 更多