поцелуй амплитуда бина БПФ

Я потратил довольно много времени на изучение БПФ. Мне особенно интересно использовать KISSFFT, потому что это очень переносимая реализация C.

Мне все еще очень неясно, как превратить i[x] и r[x] в амплитуду частотного бина. Поэтому создал подписанную версию sin 16 int. У меня есть 512 образцов моей синусоидальной волны. Я ожидал увидеть один Bin с данными, а остальные — с нулями. Не так...

Вот мой код...

- (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)););
}

}

Я получаю результаты, которые выглядят так....


*****
*********************
****************************
*********************
************************
*********************
****************************
*********************
*****
*********************
****************************
*********************
*****************
*********************
****************************
*********************
*****
*********************
****************************
*********************
************************
*********************
****************************
*********************


person RW.    schedule 31.05.2011    source источник
comment
Я создал простой ascii-граф этого вывода и нашел закономерность. Я просто не понимаю схемы...   -  person RW.    schedule 31.05.2011
comment
Поскольку вы являетесь здесь старым участником, но никогда не голосовали и никогда не принимали ответы, позвольте мне напомнить три вещи, которые мы обычно делаем здесь: 1) Когда вы получаете помощь, старайтесь также отвечать на вопросы в своем область знаний 2) Read the FAQs 3) Если вы видите хорошие вопросы и ответы, проголосуйте за них using the gray triangles, так как доверие к системе основано на репутации, которую пользователи получают, делясь знаниями. Также не забудьте принять ответ, который лучше решает вашу проблему, by pressing the checkmark sign   -  person Dr. belisarius    schedule 02.06.2011


Ответы (2)


Пара программных изменений, прежде всего:

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*pi.

После того, как вы это сделаете, вернитесь к wantedH = 1000, что даст вам нецелое число циклов в буфере. Вы должны увидеть результат в форме широкой палатки, сосредоточенный вокруг ячеек 11 и 511-11. Вы должны умножить dataStream на оконную функцию (хорошо использовать Hann), чтобы уменьшить влияние этого эффекта.

person mtrw    schedule 31.05.2011

Я тоже боролся с этой библиотекой, и этот код может помочь вам протестировать. Это смешанный код, который я прочитал в Интернете, чтобы посмотреть, будет ли интересно включить его в проект. Работает отлично. Он записывает файл с формой волны и значениями исходного сигнала, БПФ и обратного БПФ тоже просто для проверки. Он был скомпилирован с помощью 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;

}

person Rodo    schedule 22.03.2013
comment
Пожалуйста, четко укажите, как решить проблему ОП в своем ответе. - person meyumer; 22.03.2013