在Python中为一个gammatone滤波器组实现窗口化音频信号

时间:2014-08-11 21:35:41

标签: python audio window

我是编程新手,尤其是python。我正在尝试使用4阶gammatone滤镜实现听觉模型。我需要将信号分解为39个通道。当我使用较小的信号(大约884726位)时,代码运行良好,但我认为缓冲区已满,所以我必须重新启动shell以便第二次运行代码。尝试使用flush()但没有成功。 因此,我决定使用Hanning窗口来显示信号,但也无法成功。要非常清楚,我需要将音频信号分解为39个通道,对其进行整流(半波),然后将其传递到第二组4阶滤波器,这次是10个通道。我想在发送到第二组滤波器之前对信号进行下采样。这是通过使用由另一个函数生成的系数来实现滤波器组的代码片段。 b的尺寸为39x4096。

def filterbank_application(input, b, verbose = False):
"""
A function to run the input through a bandpass filter bank with parameters defined by the b and a coefficients.

Parameters:
    * input (type: array-like matrix of floats) - input signal. (Required)
    * b (type: array-like matrix of floats) - the b coefficients of each filter in shape b[numOfFilters][numOfCoeffs]. (Required)

Returns:
* y (type: numpy array of floats) - an array with inner dimensions equal to that of the input and outer dimension equal to
    the length of fc (i.e. the number of bandpass filters in the bank) containing the outputs to each filter. The output 
    signal of the nth filter can be accessed using y[n].
"""

input = np.array(input)
bshape = np.shape(b)
nFilters = bshape[0]
lengthFilter = bshape[1]   

shape = (nFilters,) + (np.shape(input))
shape = np.array(shape[0:])
shape[-1] = shape[-1] + lengthFilter -1
y = np.zeros((shape))    

for i in range(nFilters):
    if(verbose):
        sys.stdout.write("\r" + str(int(np.round(100.0*i/nFilters))) + "% complete.")
        sys.stdout.flush()
    x = np.array(input)
    y[i] = signal.fftconvolve(x,b[i]) 
if(verbose): sys.stdout.write("\n")
return y

samplefreq,input = wavfile.read('sine_sweep.wav')


input = input.transpose()
input = (input[0] + input[1])/2

b_coeff1 = gammatone_filterbank(samplefreq, 39)
Output = filterbank_application(input, b_coeff1)

Rect_Output = half_rectification(Output)

我想将音频分成20秒长的块。如果您能让我知道一种有效的窗口信号窗口,我将不胜感激,因为整个音频将比我使用的信号大6倍。提前谢谢。

1 个答案:

答案 0 :(得分:1)

如果运行32位Python,则可能存在内存消耗问题。您的代码每个样本消耗大约320个八位字节(字节)(40个缓冲区,每个样本8个八位字节)。可用的最大内存为2 GB,这意味着信号的绝对最大大小约为600万个样本。如果您的文件大约100秒,那么您可能会遇到问题。

这个问题有两种解决方法(如果这确实是问题,但我看不出任何明显的原因,否则你的代码会崩溃)。要么获得64位Python,要么重写代码以更实际的方式使用内存。

如果我已正确理解您的问题,您需要:

  1. 通过39个FIR滤波器(每个4096点)运行信号
  2. 对结果信号进行半整顿
  3. 下采样得到的半整流信号
  4. 通过10个FIR滤波器(或IIR?)
  5. 过滤每个下采样整流信号

    这将为您提供39 x 10信号,为您提供传入听觉信号的攻击和频率响应。

    我将如何做到这一点:

    1. 取出原始信号并将其保存在内存中(如果它不合适,可以通过一个名为memmap的技巧修复,但如果你的信号不是很长就适合了)
    2. 取第一个gammatone过滤器并运行卷积(scipy.signal.fftconvolve
    3. 进行半波整流(sig = np.clip(sig, 0, None, out=sig)
    4. 对信号进行下采样(例如scipy.signal.decimate
    5. 运行10个过滤器(例如scipy.signal.fftconvolve
    6. 对所有其他gammatones重复步骤2-5
    7. 这样,如果您只需要最终结果,则无需将已过滤信号的39份副本保留在内存中。

      如果没有看到完整的应用程序并且对环境有更多了解,很难说你是否确实遇到了内存问题。


      只是一个愚蠢的信号处理问题:为什么要进行半波整流?为什么不进行全波整流:sig = np.abs(sig)?全波整流信号的低通滤波更容易,音频信号应该相当对称。


      您可能希望在代码中更改一些内容:

      • 您将input转换为数组作为函数中的第一项内容 - 无需在循环中再次执行此操作(只需使用input而不是x在运行fftconvolve

      • 创建一个空的y可以由y = np.empty((b.shape[0], input.shape[0] + b.shape[1] - 1))完成;这将更具可读性并摆脱许多不必要的变量

      • input.transpose()需要一些时间和记忆,不是必需的。您可以这样做:input = np.average(input, axis=1)这将平均数组中的每一行(即平均通道)。

      您的sys.stdout.write等没有任何问题。使用了flush,因为否则文本会被写入缓冲区,并且只有在缓冲区已满时才显示在屏幕上。