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
Post a Comment