signal processing - Real FFT output -


i have implemented fft at32ucb series ucontroller using kiss fft library , struggling output of fft. intention analyse sound coming piezo speaker. currently, frequency of sounder 420hz got fft output (cross checked oscilloscope). however, output frequency half of expected if put function generator waveform system. suspect frequency bin calculation formula got wrong; using, fft_peak_magnitude_index*sampling frequency / fft_size. input real , doing real fft. (output samples = n/2) , doing iir filtering , windowing before fft. suggestion great help!

            // iir filter calculation, n = 256 fft points                (ctr=0; ctr<n; ctr++)         {                    // filter calculation             y[ctr] = num_coef[0]*x[ctr];             y[ctr] += (num_coef[1]*x[ctr-1]) - (den_coef[1]*y[ctr-1]);             y[ctr] += (num_coef[2]*x[ctr-2]) - (den_coef[2]*y[ctr-2]);             y1[ctr] = y[ctr] - 510; //eliminate dc offset              // hamming window             hamming[ctr] = (0.54-((0.46) * cos(2*m_pi*ctr/n)));             window[ctr] = hamming[ctr]*y1[ctr];              fft_input[ctr].r = window[ctr];             fft_input[ctr].i = 0;             fft_output[ctr].r = 0;             fft_output[ctr].i = 0;         }           kiss_fftr_cfg fftconfig = kiss_fftr_alloc(n,0,null,null);         kiss_fftr(fftconfig, (kiss_fft_scalar * )fft_input, fft_output);          peak = 0;         freq_bin = 0;                (ctr=0; ctr<n1; ctr++)             {                    fft_mag[ctr] = 10*(sqrt((fft_output[ctr].r * fft_output[ctr].r) + (fft_output[ctr].i * fft_output[ctr].i)))/(0.5*n);                  if(fft_mag[ctr] > peak)                 {                     peak = fft_mag[ctr];                     freq_bin = ctr;                 }              frequency = (freq_bin*(10989/n)); // 10989 sampling freq                 //************************************                 //usart write                 char filtresult[10];                 //sprintf(filtresult, "%04d %04d %04d\n", (int)peak, (int)freq_bin, (int)frequency);                 sprintf(filtresult, "%04d  %04d  %04d\n", (int)x[ctr], (int)fft_mag[ctr], (int)frequency);                 char c;                 char *ptr = &filtresult[0];                                 {                     c = *ptr;                     ptr++;                     usart_bw_write_char(&avr32_usart2, (int)c);                     // sendbyte(c);                  } while (c != '\n');             } 

the main problem how declared fft_input. based on your previous question, allocating fft_input array of kiss_fft_cpx. function kiss_fftr on other hand expect array of scalar. casting input array kiss_fft_scalar with:

kiss_fftr(fftconfig, (kiss_fft_scalar * )fft_input, fft_output); 

kissfft sees array of real-valued data contains zeros every second sample (what filled in imaginary parts). upsampled version (although without interpolation) of original signal, i.e. signal twice sampling rate (which not accounted in freq_bin frequency conversion). fix this, suggest pack data kiss_fft_scalar array:

kiss_fft_scalar fft_input[n]; ... (ctr=0; ctr<n; ctr++) {            ...     fft_input[ctr] = window[ctr];     ... } kiss_fftr_cfg fftconfig = kiss_fftr_alloc(n,0,null,null); kiss_fftr(fftconfig, fft_input, fft_output); 

note while looking peak magnitude, interested in final largest peak, instead of running maximum. such, limit loop computing peak (using freq_bin instead of ctr array index in following sprintf statements if needed):

for (ctr=0; ctr<n1; ctr++) {      fft_mag[ctr] = 10*(sqrt((fft_output[ctr].r * fft_output[ctr].r) + (fft_output[ctr].i * fft_output[ctr].i)))/(0.5*n);    if(fft_mag[ctr] > peak)   {     peak = fft_mag[ctr];     freq_bin = ctr;   } } // close loop here before computing "frequency" 

finally, when computing frequency associated bin largest magnitude, need ensure computation done using floating point arithmetic. if suspect n integer, formula performing 10989/n factor using integer arithmetic resulting in truncation. can remedied with:

frequency = (freq_bin*(10989.0/n)); // 10989 sampling freq 

Comments