Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More precise frequency from FFT with EZAudio? #371

Open
audiokit16 opened this issue Jan 3, 2018 · 2 comments
Open

More precise frequency from FFT with EZAudio? #371

audiokit16 opened this issue Jan 3, 2018 · 2 comments

Comments

@audiokit16
Copy link

I've generated a few pure sine tones with Audacity at different frequencies to test with. The issue I'm seeing is that the code is returning the same frequency for two different sine tones that are relatively close in value.

For example: A sine tone generated at 19255Hz will show up from FFT as 19293.750000Hz. So will a sine tone generated at 19330Hz. Something must be off in the calculations.

Any assistance in how I can modify the above code to get a more precise FFT frequency reading for pure sine tones is greatly appreciated. Thank you!

//
// Initialize FFT
//
float maximumBufferSizeBytes = self.maximumBufferSize * sizeof(float);
self.info = (EZAudioFFTInfo *)calloc(1, sizeof(EZAudioFFTInfo));
vDSP_Length log2n = log2f(self.maximumBufferSize);
self.info->fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);
long nOver2 = maximumBufferSizeBytes / 2;
size_t maximumSizePerComponentBytes = nOver2 * sizeof(float);
self.info->complexA.realp = (float *)malloc(maximumSizePerComponentBytes);
self.info->complexA.imagp = (float *)malloc(maximumSizePerComponentBytes);
self.info->outFFTData = (float *)malloc(maximumSizePerComponentBytes);
memset(self.info->outFFTData, 0, maximumSizePerComponentBytes);
self.info->inversedFFTData = (float *)malloc(maximumSizePerComponentBytes);

//
// Calculate real + imaginary components and normalize
//
vDSP_Length log2n = log2f(bufferSize);
long nOver2 = bufferSize / 2;
float mFFTNormFactor = 10.0 / (2 * bufferSize);
vDSP_ctoz((COMPLEX*)buffer, 2, &(self.info->complexA), 1, nOver2);
vDSP_fft_zrip(self.info->fftSetup, &(self.info->complexA), 1, log2n, FFT_FORWARD);
vDSP_vsmul(self.info->complexA.realp, 1, &mFFTNormFactor, self.info->complexA.realp, 1, nOver2);
vDSP_vsmul(self.info->complexA.imagp, 1, &mFFTNormFactor, self.info->complexA.imagp, 1, nOver2);
vDSP_zvmags(&(self.info->complexA), 1, self.info->outFFTData, 1, nOver2);
vDSP_fft_zrip(self.info->fftSetup, &(self.info->complexA), 1, log2n, FFT_INVERSE);
vDSP_ztoc(&(self.info->complexA), 1, (COMPLEX *) self.info->inversedFFTData , 2, nOver2);
self.info->outFFTDataLength = nOver2;

//
// Calculate max freq
//
if (self.sampleRate > 0.0f)
{
vDSP_maxvi(self.info->outFFTData, 1, &self.info->maxFrequencyMangitude, &self.info->maxFrequencyIndex, nOver2);
self.info->maxFrequency = [self frequencyAtIndex:self.info->maxFrequencyIndex];

float nyquistMaxFreq = self.sampleRate / 2.0;
NSLog(@"FREQ: %f", (((float)self.info->maxFrequencyIndex / (float)self.info->outFFTDataLength) * nyquistMaxFreq));

}
EZAudio code here: https://github.com/syedhali/EZAudio/blob/master/EZAudio/EZAudioFFT.m

@heyaibek
Copy link

Any suggestions for this question? I'm interested too on this topic 🤓

@JanX2
Copy link

JanX2 commented Jan 27, 2020

I would guess that this issue is a result of the use of FFT. It quantizes the frequencies into bins (log2n is effectively the number of bins in the example). If you need more frequency resolution, you can try weighing the bins around the loudest bin according to their energies or use another algorithm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants