Я пытаюсь рассчитать ДПФ синусоиды на 20 Гц.
Сначала я заполняю std :: vector 10 циклами функции синуса с частотой 20 Гц:
std::vector<double> sinx;
double samplerate = 1000.0;
double frequency = 20.0;
double num_cycles = 10.0;
for (int i=0; i<samplerate/frequency*num_cycles; i++){
sinx.push_back(sin(2.0*M_PI*((double)i)*frequency/samplerate));
}
double N = sinx.size();
Затем я запускаю входные и выходные массивы FFTW, а также план FFTW:
fftw_complex *in, *out;
fftw_plan p;
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)* N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
Затем я заполняю входной массив значениями синусоидальной функции:
for (int i=0; i<N; i++){
in[i][0] = sinx[i];
}
Затем я вычисляю БПФ:
fftw_execute(p);
После расчета БПФ я проверяю результаты и убираю.
double hz_per_index = samplerate/2.0/N*num_cycles;
for (int i=0; i<N/num_cycles; i++){
std::cout<<"hz: "<<hz_per_index*i<<" out: "<<fabs(out[i][0])<<" "<<out[i][1]<<" in: "<<in[i][0]<<std::endl;
}
Я ожидал бы всплеска около 20 Гц, однако никакого всплеска нет вообще. Все возвращаемые значения всегда равны нулю, бесконечности или отрицательной бесконечности. Моей первой мыслью было, что ввод перезаписывается сам, но после ввода проверьте правильность ввода. Я пытался запустить FFTW в разных режимах, FFTW_FORWARD, FFTW_BACKWARD, FFTW_ESTIMATE, FFTW_RELATIVE, ничего не помогает. Я пытался вычислить различные функции синуса на разных частотах, частоты дискретизации, количество циклов.
Грустная часть — то, что я смог заставить это работать однажды. Затем я продолжил работать, увидел, что он не работает, затем снова открыл файл, который работал, и теперь он больше не работает!
Кто-нибудь еще сталкивался с этим?
РЕДАКТИРОВАТЬ: НОВЫЙ КОД КАК ПРЕДЛОЖЕНИЯ
Это все еще не работает. Я попытался инициализировать мнимую часть комплексных чисел равной 0, и у меня все еще была та же проблема, поэтому вот код, использующий реальную функцию in / complex out библиотеки fftw.
Я в основном получаю 0 за все.
Вот полный вывод всех 5 циклов ввода, который показывает как вход, выход, так и значение hz:
https://gist.github.com/anonymous/ed419f4cfb43887c810e
double *in;
fftw_complex* out;
fftw_plan p;
std::vector<double> sinx;
double samplerate = 1000.0;
double frequency = 20.0;
double num_cycles = 5.0;
for (int i=0; i<samplerate/frequency*num_cycles; i++){
sinx.push_back(sin(2.0*M_PI*((double)i)*frequency/samplerate));
}
int N = sinx.size();
in = (double*) fftw_malloc(sizeof(double)* N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
p = fftw_plan_dft_r2c_1d(N, in, out, FFTW_ESTIMATE);
for (int i=0; i<N; i++){
in[i] = sinx[i];
}
fftw_execute(p);
double hz_per_index = samplerate/2.0/N*num_cycles;
for (int i=0; i<N; i++){
std::cout<<"hz: "<<hz_per_index * (i % (int)(N/num_cycles))<<" out: "<<out[i][0]<<" in: "<<in[i]<<std::endl;
}
fftw_destroy_plan(p);
fftw_free(in); fftw_free(out);
return 0;
}
Вы выделяете массив fftw_complex
es, которые состоят из двух элементов — реального и сложного компонентов — но вы только инициализируете реальный компонент каждого образца. Это, вероятно, оставляет сложные компоненты, содержащие случайные данные, вызывая неожиданные сумасшедшие результаты!
Если вам не нужно иметь дело со сложными образцами — что, вероятно, — вы можете использовать одна из функций DFT для реальных данных FFTW, который занимает double
массив в качестве ввода. В противном случае инициализируйте все сложные компоненты (in[i][1]
) к нулю.
Кроме того, вы не смотрите на сложную составляющую вывода. Там может быть что-то важное, что вы упускаете.
Ваш вклад — 10 периодов чистой синусоидальной волны. Это означает: