Я работал с 2D-БПФ в своем проекте и не смог получить правильные результаты, используя две разные библиотеки БПФ. Сначала я предположил, что использую их неправильно, но после сравнения с эталонными реализациями MATLAB и Linux GCC теперь кажется, что с моим компилятором происходит что-то зловещее (MSVC 2013 Express).
Мой тестовый пример выглядит следующим образом: комплекс 256x256 для реального IFFT, с одним бином на 255 (0,255 для обозначения X, Y), установленным на 10000.
Используя AMPFFT, я получаю следующее 2D-преобразование:
И с FFTW я получаю следующее 2D-преобразование:
Как видите, версия AMPFFT "почти" правильная, но в ней есть странная полоса каждого семпла, а версия FFTW просто повсюду и до обеда.
Я взял результаты двух разных тестовых версий и сравнил их с MATLAB (технически октавным, который использует FFTW под капотом). Я также провел тот же тест для FFTW под Linux с GCC. Вот фрагмент из этого набора тестов 127-й строки (номер строки технически не имеет значения, так как при моем выборе бинов все строки должны быть одинаковыми):
В этом примере реализации для октавы и Linux представляют правильный результат и следуют красной линии (октава была нанесена черным цветом, Linux — красным, и она полностью совпадала с октавой). FFTW в MSVC отображается синим цветом, а результат AMP FFT отображается пурпурным цветом. Как видите, снова версия AMPFFT кажется почти близкой, но в ней есть эта странная высокочастотная пульсация, а FFTW под MSVC — просто беспорядок с этим странным «пакетным» видом.
На данном этапе я могу только указать пальцем на Visual Studio, но понятия не имею, что происходит и как это исправить.
Вот две мои тестовые программы:
Тест FFTW:
//fftwtest.cpp
//2 dimensional complex-to-real inverse FFT test.
//Produces a 256 x 256 real-valued matrix that is loadable by octave/MATLAB
#include <fstream>
#include <iostream>
#include <complex>
#include <fftw3.h>
int main(int argc, char** argv)
{
int FFTSIZE = 256;
std::complex<double>* cpxArray;
std::complex<double>* fftOut;
// cpxArray = new std::complex<double>[FFTSIZE * FFTSIZE];
//fftOut = new double[FFTSIZE * FFTSIZE];
fftOut = (std::complex<double>*)fftw_alloc_complex(FFTSIZE*FFTSIZE);
cpxArray = (std::complex<double>*)fftw_alloc_complex(FFTSIZE * FFTSIZE);
for(int i = 0; i < FFTSIZE * FFTSIZE; i++) cpxArray[i] = 0;
cpxArray[255] = std::complex<double>(10000, 0);
fftw_plan p = fftw_plan_dft_2d(FFTSIZE, FFTSIZE, (fftw_complex*)cpxArray, (fftw_complex*)fftOut, FFTW_BACKWARD, FFTW_DESTROY_INPUT | FFTW_ESTIMATE);
fftw_execute(p);
std::ofstream debugDump("debugdumpFFTW.txt");
for(int j = 0; j < FFTSIZE; j++)
{
for(int i = 0; i < FFTSIZE; i++)
{
debugDump << " " << fftOut[j * FFTSIZE + i].real();
}
debugDump << std::endl;
}
debugDump.close();
}
Тест AMPFFT:
//ampffttest.cpp
//2 dimensional complex-to-real inverse FFT test.
//Produces a 256 x 256 real-valued matrix that is loadable by octave/MATLAB
#include <amp_fft.h>
#include <fstream>
#include <iostream>
int main(int argc, char** argv)
{
int FFTSIZE = 256;
std::complex<float>* cpxArray;
float* fftOut;
cpxArray = new std::complex<float>[FFTSIZE * FFTSIZE];
fftOut = new float[FFTSIZE * FFTSIZE];
for(size_t i = 0; i < FFTSIZE * FFTSIZE; i++) cpxArray[i] = 0;
cpxArray[255] = std::complex<float>(10000, 0);
concurrency::extent<2> e(FFTSIZE, FFTSIZE);
std::cout << "E[0]: " << e[0] << " E[1]: " << e[1] << std::endl;
fft<float, 2> m_fft(e);
concurrency::array<float, 2> outpArray(concurrency::extent<2>(FFTSIZE, FFTSIZE));
concurrency::array<std::complex<float>, 2> inpArray(concurrency::extent<2>(FFTSIZE, FFTSIZE), cpxArray);
m_fft.inverse_transform(inpArray, outpArray);
std::vector<float> outVec = outpArray;
std::copy(outVec.begin(), outVec.end(), fftOut);
std::ofstream debugDump("debugdump.txt");
for(int j = 0; j < FFTSIZE; j++)
{
for(int i = 0; i < FFTSIZE; i++)
{
debugDump << " " << fftOut[j * FFTSIZE + i];
}
debugDump << std::endl;
}
}
Оба они были скомпилированы со стандартными настройками MSVC 2013 для консольного приложения win32, а тест FFTW также выполнялся под Centos 6.4 с GCC 4.4.7. В обоих тестах FFTW используется версия FFTW 3.3.4, кроме того, были протестированы планы от сложного к реальному и от сложного к сложному (с идентичными результатами).
Есть ли у кого-нибудь хоть малейшее представление о настройках компилятора Visual Studio, я мог бы попытаться решить эту проблему?
fftw_complex
иstd::complex<double>
выглядит сомнительно. Вы не используете какие-либо функции std::complex. Лучше придерживайтесь родного типа вашей библиотеки. - person n. 1.8e9-where's-my-share m.   schedule 12.06.2014concurrency::array<std::complex<float>, 2> inpArray(concurrency::extent<2>(FFTSIZE, FFTSIZE), fftOut);
это приведет к неопределенному поведению, поскольку буфер fftOut не заполнен допустимыми значениями и его размер составляет только половину inpArray. Я думаю, что cpxArray следует использовать для инициализации inpArray. Можете ли вы попробовать это и посмотреть, решит ли это вашу проблему? - person Lukasz Mendakiewicz   schedule 12.06.2014