Величина результата БПФ зависит от частоты волны? - PullRequest
6 голосов
/ 25 декабря 2009

Я сбит с толку результатами, полученными от FFT, и был бы признателен за любую помощь.

Я использую FFTW 3.2.2, но получил аналогичные результаты с другими реализациями FFT (на Java). Когда я беру БПФ синусоидальной волны, масштабирование результата зависит от частоты (Гц) волны - в частности, от того, близка она к целому числу или нет. Результирующие значения масштабируются очень мало, когда частота приближается к целому числу, и они на порядки больше, когда частота находится между целыми числами. Этот график показывает величину пика в результате БПФ, соответствующего частоте волны, для разных частот. Это правильно??

Я проверил, что обратное БПФ БПФ равно исходной синусоиде, умноженному на число выборок, и оно есть. Форма БПФ также кажется правильной.

Было бы не так плохо, если бы я анализировал отдельные синусоидальные волны, потому что я мог просто искать шип в БПФ независимо от его высоты. Проблема в том, что я хочу проанализировать суммы синусоидальных волн. Если я анализирую сумму синусоидальных волн, скажем, в 440 Гц и 523,25 Гц, то обнаруживается только пик для 523,25 Гц. Всплеск для другого настолько мал, что выглядит как шум. Должен быть какой-то способ заставить это работать, потому что в Matlab это работает - я получаю шипы одинакового размера на обеих частотах. Как я могу изменить код ниже, чтобы выровнять масштабирование для разных частот?

#include <cstdlib>
#include <cstring>
#include <cmath> 
#include <fftw3.h>
#include <cstdio>
using namespace std; 

const double PI = 3.141592;

/* Samples from 1-second sine wave with given frequency (Hz) */
void sineWave(double a[], double frequency, int samplesPerSecond, double ampFactor); 

int main(int argc, char** argv) {

 /* Args: frequency (Hz), samplesPerSecond, ampFactor */
 if (argc != 4)  return -1; 
 double frequency  = atof(argv[1]); 
 int samplesPerSecond = atoi(argv[2]); 
 double ampFactor  = atof(argv[3]); 

 /* Init FFT input and output arrays. */
 double * wave = new double[samplesPerSecond]; 
 sineWave(wave, frequency, samplesPerSecond, ampFactor); 
 double * fftHalfComplex = new double[samplesPerSecond]; 
 int fftLen = samplesPerSecond/2 + 1; 
 double * fft = new double[fftLen]; 
 double * ifft = new double[samplesPerSecond]; 

 /* Do the FFT. */
 fftw_plan plan = fftw_plan_r2r_1d(samplesPerSecond, wave, fftHalfComplex, FFTW_R2HC, FFTW_ESTIMATE);
 fftw_execute(plan); 
 memcpy(fft, fftHalfComplex, sizeof(double) * fftLen); 
 fftw_destroy_plan(plan);

 /* Do the IFFT. */
 fftw_plan iplan = fftw_plan_r2r_1d(samplesPerSecond, fftHalfComplex, ifft, FFTW_HC2R, FFTW_ESTIMATE); 
 fftw_execute(iplan); 
 fftw_destroy_plan(iplan);

 printf("%s,%s,%s", argv[1], argv[2], argv[3]); 
 for (int i = 0; i < samplesPerSecond; i++) {
  printf("\t%.6f", wave[i]); 
 }
 printf("\n"); 
 printf("%s,%s,%s", argv[1], argv[2], argv[3]); 
 for (int i = 0; i < fftLen; i++) {
  printf("\t%.9f", fft[i]); 
 }
 printf("\n"); 
 printf("\n"); 
 printf("%s,%s,%s", argv[1], argv[2], argv[3]); 
 for (int i = 0; i < samplesPerSecond; i++) {
  printf("\t%.6f (%.6f)", ifft[i], samplesPerSecond * wave[i]);  // actual and expected result
 }

 delete[] wave; 
 delete[] fftHalfComplex; 
 delete[] fft; 
 delete[] ifft; 
}

void sineWave(double a[], double frequency, int samplesPerSecond, double ampFactor) {
 for (int i = 0; i < samplesPerSecond; i++) {
  double time = i / (double) samplesPerSecond; 
  a[i] = ampFactor * sin(2 * PI * frequency * time); 
 }
}

Ответы [ 2 ]

10 голосов
/ 25 декабря 2009

Результирующие значения масштабируются очень мало, когда частота приближается к целому числу, и они на порядки больше, когда частота находится между целыми числами.

Это потому, что быстрое преобразование Фурье предполагает, что ввод периодический и повторяется бесконечно. Если у вас есть неинтегральное число синусоидальных волн, и вы повторяете эту форму волны, это не идеальная синусоида. Это приводит к результату БПФ, который страдает от "спектральной утечки"

Просмотр оконных функций . Они ослабляют вход в начале и в конце, так что спектральная утечка уменьшается.

p.s .: если вы хотите получить точный частотный контент вокруг основной частоты, запишите много циклов волны, и вам не нужно захватывать слишком много точек за цикл (32 или 64 точки за цикл, вероятно, достаточно). Если вы хотите получить точное частотное содержание на высших гармониках, запишите меньшее количество циклов и больше точек за цикл.

0 голосов
/ 25 декабря 2009

Я могу только порекомендовать вам посмотреть код радио GNU. Файл, который может представлять для вас особый интерес, - usrp_fft.py.

...