Basic FFT to identify frequency

If you need to know the relative strength of a series of nearby signals, then you will probably need a window.Good luck.In summary, the conversation discusses the use of a basic Java program to identify the frequency of a note captured by the microphone. The problem mentioned is that the frequencies do not seem accurate, and the poster provides advice on how to improve the accuracy, such as using a window function and testing with different input signals. The original poster later updates that their code is now accurately recognizing notes after making some adjustments.
  • #1
joseche
3
0
Hi there, I am using a basic java program to identify the frequency of a note captured by the microphone.

The problem is that frequencies don't seem accurate.

Code:
package com.overdrive.FreqFinder;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;

import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.transform.DftNormalization;
import org.apache.commons.math3.transform.FastFourierTransformer;
import org.apache.commons.math3.transform.TransformType;

public class AudioInput {
	
	TargetDataLine 	microphone;
	
	final int 		audioFrames= 2048;  //power ^ 2
	
	final float 	sampleRate= 8000.0f;
	final int 		bitsPerRecord= 16;
	final int 		channels= 1;
	final boolean 	bigEndian = true;
	final boolean 	signed= true;
	
	byte 			byteData[]; 	// length=audioFrames * 2
	double 			doubleData[];	// length=audioFrames only reals needed for apache lib.
	AudioFormat 	format;
	FastFourierTransformer transformer;
	
	double frequencyTable[][]= new double[12][8]; //12 notes, 8 octaves
	
	String notes[];
	
	public AudioInput () {
		byteData= new byte[audioFrames * 2];  //two bytes per audio frame, 16 bits
		
		//doubleData= new double[audioFrames * 2];  // real & imaginary
		doubleData= new double[audioFrames];  // only real for apache
		
		transformer = new FastFourierTransformer(DftNormalization.STANDARD);
		
		System.out.print("Microphone initialization\n");
		format = new AudioFormat(sampleRate, bitsPerRecord, channels, signed, bigEndian);
		DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); // format is an AudioFormat object
		
		if (!AudioSystem.isLineSupported(info)) {
			System.err.print("isLineSupported failed");
			System.exit(1);
		}
		
		try {
			 microphone = (TargetDataLine) AudioSystem.getLine(info);
		     microphone.open(format);
		     System.out.print("Microphone opened with format: "+format.toString()+"\n");
		     microphone.start();
		}catch(Exception ex){
			System.out.println("Microphone failed: "+ex.getMessage());
			System.exit(1);
		}
		
		notes= new String[12];
		notes[0]= "C";
		notes[1]= "C#";
		notes[2]= "D";
		notes[3]= "D#";
		notes[4]= "E";
		notes[5]= "F";
		notes[6]= "F#";
		notes[7]= "G";
		notes[8]= "G#";
		notes[9]= "A";
		notes[10]= "A#";
		notes[11]= "B";
		buildFreqTable();
		
		
	}
	
	public int readPcm(){
		int numBytesRead= 
				microphone.read(byteData, 0, byteData.length);
		if(numBytesRead!=byteData.length){
			System.out.println("Warning: read less bytes than buffer size");
			System.exit(1);
		}
		return numBytesRead;
	}
	
	
	public void byteToDouble(){
		ByteBuffer buf= ByteBuffer.wrap(byteData);
		buf.order(ByteOrder.BIG_ENDIAN);
		int i=0; 
		
		while(buf.remaining()>2){
			short s = buf.getShort();
			doubleData[ i ] = (new Short(s)).doubleValue();
			++i;
		}
	}
	
	public void buildFreqTable(){
		
		frequencyTable[0][0]= 32.7032;  // C
		frequencyTable[1][0]= 34.6478;  // C#
		frequencyTable[2][0]= 36.7081;  // D
		frequencyTable[3][0]= 38.8909;  // D#
		frequencyTable[4][0]= 41.2034;  // E
		frequencyTable[5][0]= 43.6535;  // F
		frequencyTable[6][0]= 46.2493;  // F#
		frequencyTable[7][0]= 48.9994;  // G
		frequencyTable[8][0]= 51.9131;  // G#
		frequencyTable[9][0]= 55.0000;  // A
		frequencyTable[10][0]= 58.2705;  // A#
		frequencyTable[11][0]= 61.7354;  // B
		
		for (int note=0; note<12; note++){
			for(int oct=1; oct<8; oct++){
				frequencyTable[note][oct]= frequencyTable[note][oct-1]*2;
			}
		}
	}
	
	public int findNearFreq(double freq){
		double dMin= Double.MAX_VALUE, dc;
		int curNote=0;
		
		for (int note=0; note<12; note++){
			for (int oct=0; oct<8; oct++){
				
				//calculate the distance
				if( frequencyTable[note][oct] > freq )
					dc= frequencyTable[note][oct] - freq;
				else dc= freq - frequencyTable[note][oct];
				
				// see if new closer distance
				if (dMin > dc){
					dMin= dc;
					curNote= note;
				}
					
			}
		}
		return curNote;
	}
	
	public String noteName(int n){
		return notes[n];
	}
	
	
	public void findFrequency(){
		double frequency;
		
		Complex[] cmplx= transformer.transform(doubleData, TransformType.FORWARD);
		double real;
		double im;
		double mag[] = new double[cmplx.length];
		
		for(int i = 0; i < cmplx.length; i++){
            real = cmplx[i].getReal();
            I am = cmplx[i].getImaginary();
            mag[i] = Math.sqrt((real * real) + (im*im));
        }
		
		double peak = -1.0;
		int index=-1;
        for(int i = 0; i < cmplx.length; i++){
            if(peak < mag[i]){
                index=i;
                peak= mag[i];
            }
        }
        
        frequency = (sampleRate * index) / audioFrames;
        
        System.out.print("Index: "+index+", Frequency: "+frequency+", Note: "+ noteName(findNearFreq(frequency)) +"\n");
   }
	
	/*
	 * Print the first frequency bins to know about the resolution we have
	 */
	public void printFreqs(){
		for (int i=0; i<audioFrames/4; i++){
			System.out.println("bin "+i+", freq: "+(sampleRate*i)/audioFrames);
		}
	}
	
	public static void main(String[] args) {
		AudioInput ai= new AudioInput();
		int turns=10000;
		while(turns-- > 0){
			ai.readPcm();
			ai.byteToDouble();
			ai.findFrequency();
		}
		//ai.printFreqs();
	}
}
 
Technology news on Phys.org
  • #2
Can you give a specific example that doesn't seem to produce good results?
 
  • #3
I am producing a sound freq. with my phone and freqs don't match.
 
  • #4
Two common possibilities.

1. missing a scaling factor, often of a rational times Pi.

2. input frequency is not an exact multiple of your fft sampling frequency and you are not windowing your data. Check Window function - Wikipedia, the free encyclopedia and Spectral leakage - Wikipedia, the free encyclopedia Try a nice clean single frequency for input, plot the the entire output from the fft and see if you get a nice clean single peak or if you get a broad range of results. If the latter then see if a good windowing function or sampling at an exact multiple of your possible input frequencies will help.
 
Last edited:
  • #5
Hi Bill,

I did a few things, first I plotted the output of FFT and found a few things:
1) the peak was always in the second part of the output, which is the mirrored value?, so I only scan for the peak mag in the first halt
2) I divided the casted double from 'short' by 32768, because double works better in that range

Those two things seem to have fixed my code as it is recognizing notes very accurately.

I didn't use a window function although it seems I should ?, if that is the case, which one should I use ?

Thanks
 
  • #6
joseche said:
I didn't use a window function although it seems I should ?, if that is the case, which one should I use ?

I'm glad you were able to able to get your code working.

There are many more windowing functions now than when I used to do this.

I'd try Hann or Hamming, give your code input signals that are nice clean simple multiples of your sampling frequency and in phase with the sampling, and compare the result with and without the window, see the maximum and plot the whole output. Then I'd progressively try less nice input signals, shift away from the sampling frequency, shift away the phase and repeat the process.

Depending on what your real input signals are going to be, you may or may not need a window if all you are trying to do is get the peak.
 

1. What is a basic FFT (Fast Fourier Transform)?

The Fast Fourier Transform (FFT) is an efficient algorithm for computing the discrete Fourier transform (DFT) of a sequence, or its inverse. Essentially, it is a mathematical technique for converting a signal from its original domain (often time or space) to a representation in the frequency domain and vice versa.

2. How does the FFT identify frequency in a signal?

The FFT works by breaking down a signal into its component frequencies and their amplitudes. It does this by representing the signal as a sum of sinusoids of varying frequencies and amplitudes. The resulting spectrum shows the strength of each frequency present in the signal.

3. What are the applications of using FFT to identify frequency?

The FFT is commonly used in signal processing, image processing, and data analysis. It can be used to analyze audio signals, identify periodic patterns in time series data, and filter out noise from a signal. It is also used in various engineering fields, such as telecommunications, to analyze and improve signal quality.

4. Are there any limitations to using FFT to identify frequency?

While the FFT is a powerful tool for identifying frequencies in a signal, it does have some limitations. It assumes that the signal is periodic and stationary, meaning that the frequencies present in the signal do not change over time. It also has a trade-off between time and frequency resolution, meaning that it may not be suitable for analyzing signals with both low and high frequencies.

5. Can the FFT be used to identify multiple frequencies in a signal?

Yes, the FFT can identify multiple frequencies in a signal. It is able to do this by breaking down the signal into its individual frequencies and their amplitudes. The resulting spectrum will show all the frequencies present in the signal, allowing for the identification of multiple frequencies at once.

Similar threads

  • Programming and Computer Science
Replies
8
Views
1K
  • Programming and Computer Science
Replies
7
Views
2K
  • Programming and Computer Science
Replies
1
Views
2K
  • Programming and Computer Science
Replies
1
Views
2K
  • Programming and Computer Science
Replies
4
Views
2K
  • Programming and Computer Science
Replies
1
Views
1K
  • Programming and Computer Science
Replies
9
Views
1K
  • Programming and Computer Science
Replies
1
Views
1K
  • Programming and Computer Science
Replies
1
Views
1K
  • Programming and Computer Science
Replies
1
Views
2K
Back
Top