Jestem dość początkującym programistą, a zagadnienia związane z FFT są dla mnie po części abstrakcyjne, ale
staram się rozpoznać wys. dźwięku z użyciem FFT. Kod wygląda mniej więcej tak:
Jestem świadom ilości optymalizacji jakie można wykonać, ale nie to jest teraz ważne. Jak widać robię okno Hanning (a przynajmniej tak mi się wydaje), po czym obliczam FFT, szukam interpolowanego maksimum w otoczeniu największego prążka i obliczam jego częstotliwość. Wszystko byłoby ok, gdyby nie to, że dla sinusoidy 440Hz dostaję wynik 440.2Hz/440.3Hz. Biorąc ten sam plik, zaznaczając 4096 pierwszych sampli i okienko Hanning w Adobe Audition dokładność jest dużo większa (440.03Hz). Co zatem robię źle?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "kiss_fftr.h"
#include "spline2.c"
FILE *f;
double maxprazekhz, maxprazekval=0, sumhz=0;
long ilewczytano=0, maxprazek=0, i, maxinterp_i=0;
int ileprobekfft=0;
float *x, *y, *y2, *hann, wynik, maxinterp_pr=0, temp;
const double PI=3.141592653589793238462643383279502884197169399375105820974944;
const unsigned char ilefft=10;
#define N 16
#define NFFT 8192
#define ZASIEG 100
unsigned int iloscprobek;
signed short int buf=0;
kiss_fftr_cfg cfg;
kiss_fft_cfg cfg2;
kiss_fft_cpx *cx_out;
kiss_fft_scalar *cx_in;
x = malloc(sizeof(float)*N);
y = malloc(sizeof(float)*N);
y2 = malloc(sizeof(float)*N);
for (i=0; i<N; i++)
x[i] = i;
hann = malloc(sizeof(float)*NFFT);
for (i=0; i<NFFT; ++i)
{
hann[i] = sin((PI*i)/(NFFT-1));
hann[i] *= hann[i];
}
f = fopen("440.wav", "rb");
/*
OTWARCIE PLIKU, ominięcie nagłówka
*/
cfg = kiss_fftr_alloc(NFFT,0,NULL,NULL);
cx_in = (kiss_fft_scalar*) malloc(NFFT*sizeof(kiss_fft_scalar));
cx_out = (kiss_fft_cpx*) malloc((NFFT/2+1)*sizeof(kiss_fft_cpx));
while (ilewczytano = fread(&buf, sizeof(buf), 1, f))
{
if (ileprobekfft != NFFT)
{
cx_in[ileprobekfft] = buf * hann[ileprobekfft];
++ileprobekfft;
}
else
{
if (ilefft > ktorafft)
{
kiss_fftr( cfg , cx_in , cx_out );
ileprobekfft = 0;
maxprazekval = 0;
maxprazek = 0;
maxprazekhz = 0;
maxinterp_pr = 0;
for (i=0; i<NFFT/2+1; ++i) //szukanie maksimum
{
temp = hypot(cx_out[i].r, cx_out[i].i);
if (temp > maxprazekval)
{
maxprazekval = temp;
maxprazek = i;
}
}
for (i=0; i<N; i++) //wpisywanie wartości do tablicy interpolacji
y[i] = hypot(cx_out[i+maxprazek-(N/2)].r, cx_out[i+maxprazek-(N/2)].i);
spline(x, y, N, 0, 0, y2);
for (i=-ZASIEG; i<ZASIEG; ++i) //dość tandetne szukanie maksimum,
{ // ale przy dużej wartości ZASIEG i tak wyniki są podobne
splint(x, y, y2, N, (N/2)+((float)i/ZASIEG), &wynik);
if (wynik>maxinterp_pr)
{
maxinterp_pr = wynik;
maxinterp_i = i;
}
}
maxprazekhz = (double)samplerate / NFFT * ((double)maxprazek + ((double)maxinterp_i/ZASIEG));
printf(" %LfHz\n", (float)maxprazekhz);
}
else
break;
}
}
fclose(w);
}
fclose(f);
free(x);
free(y);
free(y2);Jestem świadom ilości optymalizacji jakie można wykonać, ale nie to jest teraz ważne. Jak widać robię okno Hanning (a przynajmniej tak mi się wydaje), po czym obliczam FFT, szukam interpolowanego maksimum w otoczeniu największego prążka i obliczam jego częstotliwość. Wszystko byłoby ok, gdyby nie to, że dla sinusoidy 440Hz dostaję wynik 440.2Hz/440.3Hz. Biorąc ten sam plik, zaznaczając 4096 pierwszych sampli i okienko Hanning w Adobe Audition dokładność jest dużo większa (440.03Hz). Co zatem robię źle?
przykładowy obrazek
