Поцелуй FFT бин амплитуда
Я потратил довольно много времени на изучение БПФ. Я особенно заинтересован в использовании KISSFFT, потому что это очень переносимая реализация языка Си.
Мне все еще очень непонятно, как превратить i[x] и r[x] в амплитуду частотного бина. Так что создали подписанную в 16 версии греха. У меня есть 512 образцов моей волны греха. Я ожидал увидеть одну корзину с данными, а остальные на нуле. Не так...
Вот мой код...
- (IBAction)testFFT:(id)sender{
NSLog(@"testFFT");
static double xAxis = 0;
static int sampleCount = 0;
static double pieSteps;
static double fullSinWave = 3.14159265*2;
static double sampleRate = 44100;
static double wantedHz = 0;
int octiveOffset;
char * globalString = stringToSend;
SInt16 dataStream[512];
// Notes: ioData contains buffers (may be more than one!)
// Fill them up as much as you can. Remember to set the size value in each buffer to match how
// much data is in the buffer.
for (int j = 0; j < 512; j++) {
wantedHz = 1000;
pieSteps = fullSinWave/(sampleRate/wantedHz);
xAxis += pieSteps;
dataStream[j] = (SInt16)(sin(xAxis) * 32768.0);
NSLog(@"%d) %d", j, dataStream[j]);
}
kiss_fft_cfg mycfg = kiss_fft_alloc(512,0,NULL,NULL);
kiss_fft_cpx* in_buf = malloc(sizeof(kiss_fft_cpx)*512);
kiss_fft_cpx* out_buf = malloc(sizeof(kiss_fft_cpx)*512);
for (int i = 0;i < 512;i++){
in_buf[i].r = dataStream[i];
in_buf[i].i = dataStream[i];
}
kiss_fft(mycfg,in_buf, out_buf);
for (int i = 0;i < 256;i++){
ix = out_buf[i].i;
rx = out_buf[i].r;
printfbar(sqrt(ix*ix+rx*rx)););
}
}
Я получаю результаты, которые выглядят так...
***** ********************* **************************** ********************* ************************ ********************* **************************** ********************* ***** ********************* **************************** ********************* ***************** ********************* **************************** ********************* ***** ********************* **************************** ********************* ************************ ********************* **************************** *********************
2 ответа
Я тоже боролся с этой библиотекой, и этот код мог бы помочь вам протестировать. Это смешивание кода, который я читаю в Интернете, чтобы увидеть, было бы интересно включить его в проект. Работает отлично. Он записывает файл с осциллограммой и значениями исходного сигнала, БПФ и обратного БПФ для проверки. Был скомпилирован с VS2010
#include "kiss_fft.h"
#include "tools\kiss_fftr.h"
#include <stdio.h>
#include <conio.h>
#define numberOfSamples 1024
int main(void)
{
struct KissFFT
{
kiss_fftr_cfg forwardConfig;
kiss_fftr_cfg inverseConfig;
kiss_fft_cpx* spectrum;
int numSamples;
int spectrumSize;
} fft;
static double dospi = 3.14159265*2;
static double sampleRate = 44100;
static double wantedHz = 0;
int j,i,k;
float dataStream[numberOfSamples];
float dataStream2[numberOfSamples];
float mags[numberOfSamples];
FILE * pFile;
//Frequency to achive
wantedHz = 9517;
fft.forwardConfig = kiss_fftr_alloc(numberOfSamples,0,NULL,NULL);
fft.inverseConfig = kiss_fftr_alloc(numberOfSamples,1,NULL,NULL);
fft.spectrum = (kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx) * numberOfSamples);
fft.numSamples = numberOfSamples;
fft.spectrumSize = numberOfSamples/2+1;
pFile = fopen ("c:\\testfft.txt","w");
//filling the buffer data with a senoidal wave of frequency -wantedHz- and printing to testing it
for (j = 0; j < numberOfSamples; j++) {
dataStream[j] = 32768*(sin(wantedHz*dospi*j/sampleRate));
//Draw the wave form
for (k=-64;k<(int)(dataStream[j]/512);k++) fprintf(pFile," ");
fprintf(pFile,"*\n");
}
//spectrum
kiss_fftr(fft.forwardConfig, dataStream, fft.spectrum);
//inverse just to testing
kiss_fftri( fft.inverseConfig, fft.spectrum, dataStream2 );
for(i=0;i<fft.spectrumSize;i++) {
mags[i] = hypotf(fft.spectrum[i].r,fft.spectrum[i].i);
fprintf(pFile,"[Sample %3d] ORIGINAL[%6.0f] -SPECTRUM[%5dHz][%11.0f]",i,dataStream[i],i*(int)sampleRate/numberOfSamples,mags[i]);
dataStream2[i] = dataStream2[i] / (float)fft.numSamples;
fprintf(pFile," -INVERSE[%6.0f]\n",dataStream2[i]);
}
//end
//free and close
fclose (pFile);
kiss_fft_cleanup();
free(fft.forwardConfig);
free(fft.inverseConfig);
free(fft.spectrum);
getch();
return 0;
}
Пара изменений в программировании, прежде всего:
xAxis += pieSteps;
if (xAxis >= fullSinWave)
xAxis -= fullSinWave; //wrap x back into 0-2pi period
поможет уменьшить числовую ошибку.
in_buf[i].r = dataStream[i];
in_buf[i].i = 0;
установит входной буфер в sin(x)
ранее он был установлен на sin(x) + j*sin(x)
, где j = sqrt(-1)
,
перемещение wantedHz = 1000;
из цикла выглядит лучше.
И более фундаментальная проблема: вы устанавливаете wantedHz = 1000
, При частоте дискретизации 44,1 кГц это соответствует 44100 points/sec * (1/1000) sec/cycle = 44.1 points/cycle
, С буфером в 512 точек, вы получите 11,6 циклов синусоиды в буфере. Нецелые циклы приводят к утечке.
Однако прежде чем приступить к этому, попробуйте установить wantedHz = 12*44100.0/512
дать ровно 12 циклов в буфере. Вы должны увидеть два пика в преобразовании: один с индексом 12 и один с индексом 511-12.
Причина, по которой вы увидите два всплеска, состоит в том, что преобразование sin(w_0*x)
является j*{-delta(w-w_0) - delta(w+w_0)}
, То есть, вы получаете импульсную функцию в w_0 и -w_0 в мнимой части преобразования. Причина, по которой они находятся в тех местах, где они находятся, заключается в том, что преобразование идет от 0 до 2* пи.
После этого вернитесь к wantedH = 1000
, давая вам не целое число циклов в буфере. Вы должны увидеть широкий результат в форме палатки, сосредоточенный вокруг контейнеров 11 и 511-11. Вы должны умножить dataStream
с помощью оконной функции ( Ханн хорош), чтобы уменьшить влияние этого эффекта.