【问题标题】:convolution of audio signal音频信号的卷积
【发布时间】:2014-08-30 09:29:39
【问题描述】:

我正在使用录音机来录制声音并在安卓手机上进行一些伪实时处理。 我面临着 FFT 和音频信号卷积之间的问题: 我对已知信号(正弦波形)执行 FFT,通过使用 FFT,我总是正确地找到其中包含的单音。

现在我想通过使用卷积来做同样的事情(这是一个练习):我使用 5000 个过滤器对该信号执行 5000 次卷积。每个滤波器都是 0 到 5000 Hz 之间不同频率的正弦波形。 然后,我搜索每个卷积输出的峰值。通过这种方式,当我使用信号中包含相同音调的滤波器时,我应该找到最大峰值。

事实上,对于 2kHz 的音调,我可以使用 2kHz 滤波器找到最大值。

问题是,当我收到 4kHz 音调时,我发现使用 4200Hz 滤波器的卷积最大(而 FFT 总是可以正常工作) 物质上可能吗? 我的卷积有什么问题?

这是我写的卷积函数:

 //i do the convolution and return the max
 //IN is the array with the signal
 //DATASIZE is the size of the array IN
 //KERNEL is the filter containing the sine at the selected frequency

 int convolveAndGetPeak(short[] in,int dataSize, double[] kernel) {
        //per non rischiare l'overflow, il kernel deve avere un ampiezza massima pari a 1/10 del max
        int i, j, k;
        int kernelSize=kernel.length;
        int tmpSignalAfterFilter=0;
        double out;

        // convolution from out[0] to out[kernelSize-2]
        //iniziamo 
        for(i=0; i < kernelSize - 1; ++i)
        {
            out = 0; // init to 0 before sum

            for(j = i, k = 0; j >= 0; --j, ++k)
                out += in[j] * kernel[k];

            if (Math.abs((int) out)>tmpSignalAfterFilter ){
                tmpSignalAfterFilter=Math.abs((int) out);   
            }
        }

        // start convolution from out[kernelSize-1] to out[dataSize-1] (last)
        //iniziamo da dove eravamo arrivati
        for( ; i < dataSize; ++i)
        {
            out = 0;  // initialize to 0 before accumulate

            for(j = i, k = 0; k < kernelSize; --j, ++k)
                out += in[j] * kernel[k];

            if (Math.abs((int) out)>tmpSignalAfterFilter ){
                tmpSignalAfterFilter=Math.abs((int) out);   
            }

        }


        return tmpSignalAfterFilter;
    }

用作过滤器的内核是这样生成的:

 //curFreq is the frequency of the filter in Hz
 //kernelSamplesSize is the desired length of the filter (number of samples), for time precision reasons i'm using 20 samples length.
 //sampleRate is the sampling frequency

 double[] generateKernel(int curFreq,int kernelSamplesSize,int sampleRate){
    double[] curKernel= new double[kernelSamplesSize] ;

    for (int kernelIndex=0;kernelIndex<curKernel.length;kernelIndex++){
        curKernel[kernelIndex]=Math.sin( (double)kernelIndex * ((double)(2*Math.PI) * (double)curFreq / (double)sampleRate));    //the part that makes this a sine wave....
    }
    return curKernel;

 }

如果要尝试卷积,IN数组中包含的数据如下: http://www.tr3ma.com/Dati/signal.txt

注1:采样频率为44100Hz

注意 2:信号中包含的音调是单个 4kHz 音调(即使卷积具有 4200Hz 滤波器的最大峰值。

编辑:我还在 Excel 表上重复了测试。结果是相同的(当然,我使用的是相同的算法)并且算法在我看来是正确的...... 这是我准备的 excel 表,如果您喜欢使用 excel:http://www.tr3ma.com/Dati/convolutions.xlsm

【问题讨论】:

    标签: android processing audio-recording convolution


    【解决方案1】:

    您通过两个因素改变带宽:

    a) 内核的长度(例如,5ms 的长度 t 产生 f >= 200Hz 的粗略带宽,估计为 1/0.005,因为 Δt·Δf >= 1,请参阅“Heisenberg”),以及

    b) 窗口函数(您绝对应该实现它以使您的算法在实际应用中工作,否则在某些情况下,某些滤波器输出的旁瓣可能会产生比预期滤波器输出的主瓣更多的能量)。

    但是您还有另一个问题:您需要与由余弦波组成的第二个内核进行卷积(这意味着您需要与第一个内核中相同的波,但偏移了 90 度)。这是为什么?因为只有正弦内核,您会得到滤波器输出的相位相关调制(例如,如果输入信号与具有相同频率的内核波之间的相位差为 90 度,则幅度为 0)。

    最后,您将两个内核的输出与毕达哥拉斯相结合。

    【讨论】:

    • 真的很有趣。感谢您的贡献,我将继续学习。我找到了如何在发布问题后几天计算带宽以及解决方案。我不太了解余弦的第二个内核。我会再次学习。谢谢你
    • 现在我明白了为什么你会谈论带有余弦的第二次卷积,但在我的情况下,我只需要确定卷积输出的第一个峰值,我不需要连续输出。
    • 此外,第二次卷积将过多地增加处理时间。考虑到到目前为止,我处理信号所花费的时间比接收样本的时间还要多。所以为了卷积所有的流,我不得不跳过一些信号片段,降低我的时间精度
    • 您走在正确的道路上,但您需要了解,如果没有第二个过滤器内核,您只会偶然获得正确的结果。第二种正确的方法是执行真正的卷积,即将滤波器内核的所有样本与相应的输入信号相乘,将结果写入新信号的一个样本,并将输入信号移动一个样本以用于下一个样本的新信号。最后,对新信号进行整流和平滑,你就得到了增益。
    【解决方案2】:

    除了内核(过滤器)的样本数量之外,这似乎都是正确的。 增加过滤器的大小,结果更准确。 我不知道如何计算这个滤波器的带宽,但我似乎很清楚这是滤波器带宽的问题。因此,滤波器带宽还取决于卷积中使用的滤波器的样本数,参考采样频率(也可能参考音调频率)。不幸的是,我不能过多地增加过滤器的样本数量,否则手机无法实时执行过滤。 注意:我需要卷积,因为我需要确定触发音调的精确时刻。

    编辑:我对 20 个样本的过滤器和 40 个样本的过滤器进行了比较。 我不知道获得 fitler 带宽的公式,但在下图中很清楚 2 个滤波器之间的区别。

    EDIT2:发布解决方案几天后,我发现了如何计算此类过滤器的带宽:这只是过滤器持续时间的倒数。因此,在示例中,40 个样本的内核在 44100KhZ 的持续时间约为 907uS,然后滤波器带宽,使用此内核和相同长度的窗口为 1/907uS=1,1KhZ
    (来源:tr3ma.com

    【讨论】:

      猜你喜欢
      • 2013-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-17
      • 2014-03-08
      • 2018-11-24
      • 2020-12-02
      相关资源
      最近更新 更多