• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Basic FFT to identify frequency

 
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
For some reason my code seams to work but with the frequencies off.




This is how I cast from byte[2] => double:



And this is the format I use:



What am I doing wrong ?

 
Bartender
Posts: 1166
17
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jose Hidalgo wrote:For some reason my code seams to work but with the frequencies off.



Define 'work' and 'off' in this context. Is your frequency a factor of N out always or is it a random value that seems to have nothing to do with the input ?

I do a lot of work with the FFT and before using real data I always create test data with exactly known characteristics and use it to test my code.

Points to note -
1) Your byteToDouble() method aught really to return the number of points placed in the doubleData array since this is the number of points to transform and not necessarily the array length.
2) Using 44100 Hz sampling rate with 1024 samples means you can only resolve to about 43 Hz. Whether or not this matters depends on the frequency you are trying to measure.
3) I suspect you should be using a 'window' . Hamming is normally adequate for this type of application. Google is your friend here.
4) The creation of the 'transformer' only needs to be done once and can be made an instance variable initialized in the constructor of the enclosing class.
5) The zero frequency term is usually of little use and probably should be ignored when scanning for the peak magnitude.
6) I would expect your findFrequency() method to return the estimated frequency.
 
Jose Hidalgo
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks Richard, you are totally right about the bad parameters I am using.

Richard Tookey wrote:
2) Using 44100 Hz sampling rate with 1024 samples means you can only resolve to about 43 Hz. Whether or not this matters depends on the frequency you are trying to measure.



I think the problem I am having is that the frequency bins I am using are not accurate enough. I am trying to identify what note of a piano has been played, but seems like my code is good identifying it, but since the exact bin is not there it resolves to a harmonic that is closer. I think this because there are some frequencies that it can identify easily while others are always matched with high values ( harmonics )

I changed it to 8000 Hz and 8196 samples which should give a 1:1 resolution, but seems like it didn't help

Is there a way to have more accuracy than what the frequency bins offer ?, because if I am always limited to those bins I can only increase the number of samples I read, but that adds more noise making it worst !

Attached is a test program you can use to change parameters, it reads audio from the microphone. I use my cellphone with a free guitar tuner to check frequencies, and an guitar to generate the sound !

 
Richard Tookey
Bartender
Posts: 1166
17
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jose Hidalgo wrote:Thanks Richard, you are totally right about the bad parameters I am using.

Richard Tookey wrote:
2) Using 44100 Hz sampling rate with 1024 samples means you can only resolve to about 43 Hz. Whether or not this matters depends on the frequency you are trying to measure.



I think the problem I am having is that the frequency bins I am using are not accurate enough. I am trying to identify what note of a piano has been played, but seems like my code is good identifying it, but since the exact bin is not there it resolves to a harmonic that is closer. I think this because there are some frequencies that it can identify easily while others are always matched with high values ( harmonics )

I changed it to 8000 Hz and 8196 samples which should give a 1:1 resolution, but seems like it didn't help

Is there a way to have more accuracy than what the frequency bins offer ?, because if I am always limited to those bins I can only increase the number of samples I read, but that adds more noise making it worst !



The best one can resolve to is 1/sample_period (equivalent to the sample_frequency/number_of_samples) so you must either decrease the sample frequency or increase the number of samples. This resolution constraint is fundamental to the physics of the process. In my music player I sample for about 0.1 second (a resolution of about 10 Hz) and adjust the FFT order as a function of the sample rate (frame rate) to keep the 0.1 second. I use my own mixed radix (2,3 and 5) FFT so don't have the power of 2 limitation you have with the Commons library.

I can't see harmonics being the problem though in the spectral density plot of my music player I do see the harmonics being significant relative to the fundamental. Maybe you should scale the DFT modulus values prior to looking for the maximum; say something along the lines of 1/f or 1/sqrt(f) .

I still think you should apply a Window to reduce the energy collecting side lobes. I have this as an option on my music player and it does make some difference. Unfortunately using a window will reduce the resolution by an amount that is dependent on the Window but typically by about 40%.

One significant effect can be due to very low frequencies which over the sample period can look like a ramp. A way to reduce the effect of these is to remove the best straight line from the samples before performing the DFT.

You can reduce the effect of noise by averaging the spectral density estimates taken over a number of periods. For orchestral music this is not a good ideal but for a single note on a Piano it might be worth looking at.

Finally - instead of taking the frequency of the maximum power spectral density you should maybe take the weighted average over the maximum and the two values either side. A Radar project I was involved in many many years ago used this technique to get a better speed estimate. This gives one a better estimate of frequency in the mean (less systematic bias) but worse in STD.
 
After some pecan pie, you might want to cleanse your palatte with this tiny ad:
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic