Java .wav文件频率分析 - 频率不正确

时间:2016-02-04 10:16:42

标签: java audio wav frequency

我正在开展一个项目,我必须分析.wav个文件,这对我来说基本上可以显示所述文件中存在的频率。 我使用WavFile类来读取文件,然后使用JTransforms类对它们进行FFT计算(我实际上是realForward,因为我正在将它提供给它只有数字。)

一切似乎工作正常,直到我将数据输入Excel:我在第一列中抛出一个行数(我测试的文件为1-8000)并抛出FFT的输出进入下一栏。我输入的文件是一个简单的单频声音,频率为440Hz,持续时间为1秒。

看到图表之后,出现了一个问题:我有一个频率峰值,这正是我所期待的,但峰值位于880位置,这是实际频率的两倍。有人可以向我解释为什么会这样吗?

奖金问题:为什么我会在e-16附近获得价值?除了峰值之外的所有东西都应该是0,对吧? (我通过在每次获得的数据<= 1时向文件写入0来解决此问题 - 请参阅下面的代码)。也许是&#34;噪音&#34;?

<小时/> 代码:

有两个班级。第一个,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");
        }
    }

}

1 个答案:

答案 0 :(得分:2)

您没有说明如何解释使用上述代码生成的Excel中的结果。然而,可能的错误是误解FFT fft.realForward()的输出 - 这是一个复数数组,其实部和虚部占据连续元素,如文献here所述。如果您只是使用出现峰值的数组的索引,则结果将偏离两倍。请注意,此FFT实现仅计算Nyqvist速率(超出此范围仅产生'别名')。

其他注意事项:

  • 您正在将rectangular window function应用于示例。我坦率地感到惊讶,其他箱子的流血量只有10e-16。您的应用程序有更好的选择。
  • 窗口似乎是文件的全长,可能导致巨大的FFT。作为一般规则,2-power-of FFTS效率更高。您通常会在固定长度的窗口上看到频率分析。
  • FFT实际上是一系列带通滤波器,它们是输入样本的加权和。您看到的非零值的贡献只是浮点舍入误差。您将整个文件放在窗口中的事实意味着有很多操作可以促成这一点。