2016-02-04 124 views
0

我正在研究一個項目,我必須分析.wav文件,這對我來說基本上是能夠顯示出現在所述文件中的頻率。我使用WavFile類來讀取文件,然後我使用JTransforms類(我實際上做了realForward,因爲我只餵它實數)對它們進行FFT。Java .wav文件頻率分析 - 不正確的頻率

一切似乎工作正常,直到我將數據輸入到Excel中:我在第一列(我正在測試的文件爲1-8000)中輸出一個行計數,然後將FFT的輸出下一列。我饋送的文件是一個簡單的單頻聲音,頻率爲440Hz,持續時間爲1秒。

看到圖表後,出現了一個問題:我有一個單一的頻率峯值,這正是我所期望的,但峯值位於880的位置,這是實際頻率的兩倍。有人可以向我解釋爲什麼?

獎勵問題:爲什麼我會得到e-16左右的值?除峯值以外的其他值都應爲0,對嗎? (我通過在每次獲得的數據是<= 1時寫入0來解決此問題 - 請參閱下面的代碼)。也許這是「噪音」?


代碼:

有兩個類。第一個,readWav用於讀取.wav文件。第二個,wavFFT,是實際上FFT數據的人。

代碼readWav.java

import WavFile.*; 
import java.io.*; 

public class readWav { 

    // getter methods 
    public static long getWavFrames(File file) 
    { 
     // try loop to catch any exception 
     try { 
      // open the wav file 
      WavFile wavFile = WavFile.openWavFile(file); 

      // return the number of frames 
      return wavFile.getNumFrames(); 

     } catch (Exception e) { 
      System.err.println(e); 

      // error value 
      return -1; 
     } 

    } 

    public static int getWavChannels(File file) 
    { 
     // try loop to catch any exception 
     try { 
      WavFile wavFile = WavFile.openWavFile(file); 

      return wavFile.getNumChannels(); 

     } catch (Exception e) { 
      System.err.println(e); 

      // error value 
      return -1; 
     } 
    } 

    public static double[] getWavData(File file) 
    { 
     // try loop to catch any exception 
     try { 
      // open the file 
      WavFile wavFile = WavFile.openWavFile(file); 

      // use the getter method to get the channel number (should be mono) 
      int numChannels = getWavChannels(file); 

      // same, but with the frame getter method 
      int numFrames = (int) getWavFrames(file); // possible data loss 

      // create a buffer the size of the number of frames 
      double[] buffer = new double[numFrames * numChannels]; 

      // Read frames into buffer 
      wavFile.readFrames(buffer, numFrames); 

      // Close the wavFile 
      wavFile.close(); 

      return buffer; 

     } catch (Exception e) { 
      System.err.println(e); 

      // throw an error, if this runs something went wrong in reading the .wav file 
      throw new RuntimeException("[could not read wav file " + file + "]"); 
     } 
    } 


    // main method, solely for testing purposes 
    public static void main(String[] args) 
    { 
     // test, everything seems to be working 
     File fichier_son = new File("son/freq1.wav"); 
     double[] test = getWavData(fichier_son); 
     for(int i = 0; i<test.length; i++){ 
      System.out.println(test[i]); 
     } 
    } 

} 

代碼wavFFT.java

import org.jtransforms.fft.DoubleFFT_1D; 
import java.io.File; 
import java.io.PrintWriter; 
import java.io.IOException; 

public class wavFFT { 

    public static double[] realFFT(File file) 
    { 
     // Get the .wav data using the readWav class 
     double[] data_to_fft = readWav.getWavData(file); 

     /* Get the length of the array. 
     Since we are feeding real numbers into the fft, 
     the length of the array should be equal to the 
     number of frames, which we get using the readWav class. */ 
     int n = (int) readWav.getWavFrames(file); 

     // Make a new fft object 
     DoubleFFT_1D fft = new DoubleFFT_1D(n); 

     // Perform the realForward fft 
     fft.realForward(data_to_fft); 

     // Return the final data 
     return data_to_fft; 
    } 


    public static void writeToFile(File in, File out) throws IOException 
    { 
     PrintWriter print_out = new PrintWriter(out); 
     int i; 
     double[] data_to_file = realFFT(in); 

     for(i=0; i<data_to_file.length; i++){ 
      if(data_to_file[i] > 1){ 
       print_out.println(data_to_file[i]); 
      } else { 
       print_out.println(0); 
      } 

     } 
     print_out.close(); 
    } 

    // main method, solely for testing purposes 
    public static void main(String[] args) { 
     File fichier_son = new File("son/freq1.wav"); 
     double[] test = realFFT(fichier_son); 
     int i; 

     for(i=0; i<test.length; i++){ 
      System.out.println(test[i]); 
     } 


     try{ 
      writeToFile(fichier_son, new File("datafiles/output.txt")); 
     } catch (IOException e){ 
      System.out.println("error"); 
     } 
    } 

} 
+0

嗨。當我運行你的代碼時,我會出現一個'WavFile包不存在'的錯誤。這是爲什麼?如何克服它? – Learner

+0

@VibhavChaddha您尚未在項目中導入WavFile類。我在我的答案中鏈接到它。 – jimkokko5

+0

@VibhavChaddha取決於你使用的IDE。我會建議谷歌搜索。 – jimkokko5

回答

2

你不說你如何解釋在Excel中,你與上面的代碼生成的結果。然而,一個可能的錯誤是誤解FFT fft.realForward()的輸出 - 這是一個複數的數組,其實部和虛部佔據連續的元素,如記錄here。如果您只是簡單地使用出現峯值的陣列的索引,則結果會偏差兩倍。請注意,此FFT實現僅計算Nyqvist速率(超出此範圍僅產生一個「別名」)。

其他注意事項:

  • 你所申請的rectangular window function的樣本。我很坦然地驚訝其他垃圾桶的流血量只有10e-16。您的應用程序有更好的選擇。
  • 該窗口看起來是文件的全長,可能會導致巨大的FFT。作爲一般規則,2 FFTS的功率更有效率。您通常會看到在固定長度窗口上執行的頻率分析。
  • FFT實際上是一系列帶通濾波器,它們是輸入採樣的加權和。對您看到的非零值的貢獻僅僅是浮點四捨五入錯誤。您將整個文件放在窗口中的事實意味着有很多操作對此有所貢獻。
+0

謝謝。你能提出一種解決這個問題的方法嗎?你在談論什麼是「更好的選擇」? (旁邊的問題:垂直軸上的單位是多少?它是分貝嗎?現在數組輸出是固定的,我在水平位置獲得位置440的峯值,在垂直軸上獲得1355的峯值)。 – jimkokko5

+0

FFT的輸入是幅度,所以這也是FFT的輸出。 dB刻度通常是信號功率,所以您需要自己計算。 至於更好的窗口函數,這是一個應用程序的問題。我想這將是漢明的窗口。 – marko

+0

在第二節課中,我將代碼改爲「Hamming.hamming(data_to_fft);」 (http://marf.sourceforge.net/api/marf/math/Algorithms.Hamming.html),但我仍然得到不需要的值。這裏有什麼問題? – jimkokko5