Вывод KissFFT из kiss_fftr
Я получаю данные PCM через сокет-соединение в пакетах, содержащих 320 образцов. Частота дискретизации звука составляет 8000 сэмплов в секунду. Я делаю с этим что-то вроде этого:
int size = 160 * 2;//160;
int isinverse = 1;
kiss_fft_scalar zero;
memset(&zero,0,sizeof(zero));
kiss_fft_cpx fft_in[size];
kiss_fft_cpx fft_out[size];
kiss_fft_cpx fft_reconstructed[size];
kiss_fftr_cfg fft = kiss_fftr_alloc(size*2 ,0 ,0,0);
kiss_fftr_cfg ifft = kiss_fftr_alloc(size*2,isinverse,0,0);
for (int i = 0; i < size; i++) {
fft_in[i].r = zero;
fft_in[i].i = zero;
fft_out[i].r = zero;
fft_out[i].i = zero;
fft_reconstructed[i].r = zero;
fft_reconstructed[i].i = zero;
}
// got my data through socket connection
for (int i = 0; i < size; i++) {
// samples are type of short
fft_in[i].r = samples[i];
fft_in[i].i = zero;
fft_out[i].r = zero;
fft_out[i].i = zero;
}
kiss_fftr(fft, (kiss_fft_scalar*) fft_in, fft_out);
kiss_fftri(ifft, fft_out, (kiss_fft_scalar*)fft_reconstructed);
// lets normalize samples
for (int i = 0; i < size; i++) {
short* samples = (short*) bufTmp1;
samples[i] = rint(fft_reconstructed[i].r/(size*2));
}
После этого я заполняю буферы OpenAL и играю их. Все работает отлично, но я хотел бы сделать некоторую фильтрацию аудио между kiss_fftr
а также kiss_fftri
, Начальная точка, как я думаю для этого, - преобразовать звук из временной области в частотную, но я не совсем понимаю, какие данные я получаю от kiss_fftr
функция. Какая информация хранится в каждом из этих комплексных чисел, какая ее действительная и мнимая часть может рассказать мне о частоте. И я не знаю, какие частоты покрыты (какой диапазон частот) в fft_out
- какие индексы соответствуют каким частотам.
Я новичок в области обработки сигналов и преобразований Фурье.
Любая помощь?
3 ответа
Я постараюсь ответить на ваши вопросы напрямую.
// a) the real and imaginary components of the output need to be combined to calculate the amplitude at each frequency.
float ar,ai,scaling;
scaling=1.0/(float)size;
// then for each output [i] from the FFT...
ar = fft_out[i].r;
ai = fft_out[i].i;
amplitude[i] = 2.0 * sqrtf( ar*ar + ai*ai ) * scaling ;
// b) which index refers to which frequency? This can be calculated as follows. Only the first half of the FFT results are needed (assuming your 8KHz sampling rate)
for(i=1;i<(size/2);i++) freq = (float)i / (1/8000) / (float)size ;
// c) phase (range +/- PI) for each frequency is calculated like this:
phase[i] = phase = atan2(fft_out[i].i / fft_out[i].r);
Прежде чем перейти обеими ногами к реализации C, ознакомьтесь с цифровыми фильтрами, особенно с фильтрами FIR.
Вы можете спроектировать FIR-фильтр, используя что-то вроде сигнальной панели инструментов GNU Octave. Посмотрите на команду fir1(самая простая), firls или Rememberz. Кроме того, вы можете разработать FIR-фильтр через веб-страницу. Быстрый веб-поиск "онлайн-дизайна фильтра пихты" обнаружил это (я не использовал его, но, похоже, он использует дизайн equiripple, используемый в команде revz или firpm)
Попробуйте сначала внедрить свой фильтр с прямым свертыванием (без БПФ) и посмотрите, приемлема ли скорость - это более простой путь. Если вам нужен подход, основанный на FFT, есть пример реализации overlap-save в файле kissfft/tools/kiss_fastfir.c.
Возможно, вы захотите исследовать быстрое свертывание FFT с использованием алгоритмов добавления с наложением или с перекрытием. Вам нужно будет увеличить длину каждого БПФ на длину импульса желаемого фильтра. Это связано с тем, что (1) свертка FFT/IFFT является круговой, и (2) каждый индекс в результате массива FFT соответствует почти всем частотам (отклик в форме Sinc), а не только одной (даже если в основном около одной), поэтому любой Модификация бина будет просачиваться по всей частотной характеристике (кроме определенных точных периодических частот).