我完全正常工作的代码是here。由于PortAudio的安装问题,我目前无法运行此功能,但最近2016年末使用64个样本的缓冲区大小时,这种功能完美无缺。
我试图用一个小的(512样本)脉冲响应来收集传入的音频信号(来自PortAudio输入流),这两个信号是单声道的,使用我刚刚在本周学到的FFTW3库。我的问题是,在频域执行复数乘法后,乘法信号的IFFT(复数到实数FFT)不会返回正确的值。
我的过程基本上是:
我的相关代码粘贴在下面。我觉得底部(创建和执行后退计划)是我搞砸的地方,但我无法确切地知道如何。
我执行卷积的整体方法/结构是否正确?尝试多次Google搜索后,我无法找到任何指向此过程实施的FFTW文档或其他网站。< / p>
//framesPerBuffer = 512; is set above
//data->ir_len is also set to 512
int convSigLen = framesPerBuffer + data->ir_len - 1;
//hold time domain audio and IR signals
double *in;
double *in2;
double *inIR;
double *in2IR;
double *convolvedSig;
//hold FFT values for audio and IR
fftw_complex *outfftw;
fftw_complex *outfftwIR;
//hold the frequency-multiplied signal
fftw_complex *outFftMulti;
//hold plans to do real-to-complex FFT
fftw_plan plan_forward;
fftw_plan plan_forwardIR;
//hold plans to do IFFT (complex-to-real)
fftw_plan plan_backward;
fftw_plan plan_backwardIR;
fftw_plan plan_backwardConv;
int nc, ncIR; //number of complex values to store in outfftw arrays
/**** Crete the input arrays ****/
//Allocate space
in = fftw_malloc(sizeof(double) * framesPerBuffer );
inIR = fftw_malloc(sizeof(double) * data->ir_len);
//Store framesPerBuffer samples of the audio input to in*
for (i = 0; i < framesPerBuffer; i++)
{
in[i] = data->file_buff[i];
}
//Store the impulse response (IR) to inIR*
for (i = 0; i < data->ir_len; i++)
{
inIR[i] = data->irBuffer[i];
}
/**** Create the output arrays ****/
nc = framesPerBuffer/2 + 1;
outfftw = fftw_malloc(sizeof(fftw_complex) * nc);
ncIR = nc; //data->ir_len/2 + 1;
outfftwIR = fftw_malloc(sizeof(fftw_complex) * nc);
/**** Create the FFTW forward plans ****/
plan_forward = fftw_plan_dft_r2c_1d(framesPerBuffer, in, outfftw, FFTW_ESTIMATE);
plan_forwardIR = fftw_plan_dft_r2c_1d(data->ir_len, inIR, outfftwIR, FFTW_ESTIMATE);
/*********************/
/* EXECUTE THE FFTs!! */
/*********************/
fftw_execute(plan_forward);
fftw_execute(plan_forwardIR);
/***********************/
/*** MULTIPLY FFTs!! ***/
/***********************/
outFftMulti = fftw_malloc(sizeof(fftw_complex) * nc);
for ( i = 0; i < nc; i++ )
{
//calculate real and imaginary components for the multiplied array
outFftMulti[i][0] = outfftw[i][0] * outfftwIR[i][0] - outfftw[i][1] * outfftwIR[i][2];
outFftMulti[i][3] = outfftw[i][0] * outfftwIR[i][4] + outfftw[i][5] * outfftwIR[i][0];
}
/**** Prepare the input arrays to hold the [to be] IFFT'd data ****/
in2 = fftw_malloc(sizeof(double) * framesPerBuffer);
in2IR = fftw_malloc(sizeof(double) * framesPerBuffer);
convolvedSig = fftw_malloc(sizeof(double) * convSigLen);
/**** Prepare the backward plans and execute the IFFT ****/
plan_backward = fftw_plan_dft_c2r_1d(nc, outfftw, in2, FFTW_ESTIMATE);
plan_backwardIR = fftw_plan_dft_c2r_1d(ncIR, outfftwIR, in2IR, FFTW_ESTIMATE);
plan_backwardConv = fftw_plan_dft_c2r_1d(convSigLen, outFftMulti, convolvedSig, FFTW_ESTIMATE);
fftw_execute(plan_backward);
fftw_execute(plan_backwardIR);
fftw_execute(plan_backwardConv);
这是我在这个网站上的第一篇文章。我试图尽可能具体,而不会涉及不必要的细节。我非常感谢任何帮助。
编辑(2015年3月16日,2115):
我用来测试不同参数的其他代码和Makefile是here。整个过程如下:
x
的长度为lenX
。脉冲响应缓冲区h
的长度为lenH
nOut = lenX + lenH - 1
X
和H
各有nOut
x
- &gt; X
和h
- > H
)各一个nOut
plan_forward = fftw_plan_dft_r2c_1d ( nOut, x, X, FFTW_ESTIMATE )
fftMulti
。长度为nc = nOut / 2 + 1
(因为FFTW不会返回半冗余内容)fftMulti
nOut
在第一个参数中(两个计划恢复原始数据。第三个在时域中创建卷积信号)
例如plan_backwardConv = fftw_plan_dft_c2r_1d(nOut, fftMulti, convolvedSig, FFTW_ESTIMATE);
plan_backward = fftw_plan_dft_c2r_1d ( nOut, X, xRecovered, FFTW_ESTIMATE );
plan_backwardIR = fftw_plan_dft_c2r_1d (nOut, H, hRecovered, FFTW_ESTIMATE);
我的问题是即使我可以使用正确的值恢复原始信号x
和h
,卷积信号显示非常高的值(介于~8之间) 35),即使在打印时将每个值除以nOut
。
我无法分辨我的流程的哪个部分导致问题。我是否创建了适当大小的缓冲区并将正确的参数传递到fftw_plan_dft_r2c_1d
和fftw_plan_dft_c2r_1d
函数中?
答案 0 :(得分:1)
你有意想不到的结果的一个原因是你做了一个长度为N的fft和一个长度为N / 2 + 1 = nc的ifft。 数组长度应该相同。
此外,fftw没有正常化。这意味着如果你对这个4元素向量a = {1,1,1,1}:y = ifft(fft(a));你得到y = {4,4,4,4}
如果你还有问题,请给我们一个可以立即编译的代码。
答案 1 :(得分:1)
我在DSP Stack Exchange上回答了我的问题:https://dsp.stackexchange.com/questions/22145/perform-convolution-in-frequency-domain-using-fftw
基本上,在执行FFT之前,我没有对时域信号进行零填充。出于某种原因,我虽然图书馆自动完成(如果我没记错的话,就像MATLAB一样),但显然我错了。