我正在使用audiorecorder录制声音并在Android手机上进行伪时间处理。 我在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答案 0 :(得分:1)
您可以通过两个因素更改带宽:
a)内核的长度(例如,长度t为5ms产生f> = 200Hz的粗带宽,估计为1 / 0.005,因为Δt·Δf> = 1,参见“Heisenberg”),和< / p> b)窗口函数(你必须实现它才能使你的算法在实际应用程序中工作,否则在某些情况下,某些滤波器输出的旁瓣会产生比预期滤波器输出的主瓣更多的能量)。 / p>
但是你有另一个问题:你需要与由余弦波组成的第二个内核进行卷积(这意味着你需要与第一个内核相同的波,但是需要移动90度)。这是为什么?因为只有正弦内核,你会得到滤波器输出的相位相关调制(例如,如果输入信号和具有相同频率的内核波之间的相位差为90度,则得到幅度为0)。
最后,将两个内核的输出与毕达哥拉斯结合起来。
答案 1 :(得分:0)
除了内核(过滤器)的样本数量外,它似乎都是正确的。 增加过滤器的大小会使结果更准确。 我不知道如何计算此过滤器的带宽,但我觉得这是过滤器带宽的问题。因此,滤波器带宽还取决于卷积中使用的滤波器的样本数量,参考采样频率(并且还可以参考音调频率)。不幸的是,我无法增加过滤器样本的数量,因为否则手机无法实时进行过滤。 注意:我需要卷积,因为我需要确定音调被发射时的精确时刻。
编辑:我对20个样本的过滤器和40个样本的过滤器进行了比较。 我不知道获得fitler带宽的公式,但在下图中,两个过滤器之间的区别很清楚。
EDIT2:发布解决方案后的几天我发现如何计算这种过滤器的带宽:它只是过滤器持续时间的逆转。例如,在44100KhZ的40个样本的核心持续时间大约为907uS,然后滤波器带宽,这个内核和相同长度的窗口是1 / 907uS = 1,1KhZ http://www.tr3ma.com/Dati/convolution.JPG