Java .wav 文件频率分析 - 不正确的频率
Java .wav file frequency analysis - incorrect frequency
我正在做一个项目,我必须分析 .wav
文件,这对我来说基本上归结为能够显示所述文件中存在的频率。
我正在使用 WavFile
class to read the file, and then I FFT them using the JTransforms
class (I actually do a realForward
因为我只给它输入实数)。
一切似乎都工作正常,直到我将数据输入 Excel:我在第一列中添加了行编号(我正在测试的文件为 1-8000),然后我添加了FFT 的输出到下一列。我输入的文件是一个简单的单频声音,频率为 440Hz,持续时间为 1 秒。
看到图表后,有一个问题:我有一个频率峰值,这正是我所期望的,但峰值位于 880 位置,是实际频率的两倍。有人可以向我解释这是为什么吗?
额外问题:为什么我得到的值在 e-16
附近?除了峰值之外的所有内容都应该为 0,对吗? (每次我得到的数据是 <= 1
时,我都会通过向文件写入 0 来解决此问题 - 请参阅下面的代码)。也许是 "noise"?
代码:
有两个 类。第一个 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");
}
}
}
您没有说明如何解释使用上述代码生成的 Excel 中的结果。然而,一个可能的错误是误解了 FFTfft.realForward()
的输出——它是一个复数数组,其实部和虚部占据连续的元素,如记录 here。如果您只是使用出现峰值的数组的索引,您的结果将偏离两倍。请注意,此 FFT 实现仅计算 Nyqvist 速率(超出此范围仅产生 'alias')。
其他注意事项:
- 您正在将 rectangular window function 应用于样本。坦率地说,我很惊讶其他垃圾箱中的流血量小到
10e-16
。您的应用程序有更好的选择。
- window 似乎是文件的全长,可能导致巨大的 FFT。作为一般规则,2 的幂 FFTS 效率要高得多。您通常会看到在固定长度 windows 上执行的频率分析。
- FFT 实际上是一系列带通滤波器,它们是输入样本的加权和。您看到的非零值的一个贡献是简单的浮点舍入误差。事实上,您将整个文件放在 window 中,这意味着有很多操作对此有贡献。
我正在做一个项目,我必须分析 .wav
文件,这对我来说基本上归结为能够显示所述文件中存在的频率。
我正在使用 WavFile
class to read the file, and then I FFT them using the JTransforms
class (I actually do a realForward
因为我只给它输入实数)。
一切似乎都工作正常,直到我将数据输入 Excel:我在第一列中添加了行编号(我正在测试的文件为 1-8000),然后我添加了FFT 的输出到下一列。我输入的文件是一个简单的单频声音,频率为 440Hz,持续时间为 1 秒。
看到图表后,有一个问题:我有一个频率峰值,这正是我所期望的,但峰值位于 880 位置,是实际频率的两倍。有人可以向我解释这是为什么吗?
额外问题:为什么我得到的值在 e-16
附近?除了峰值之外的所有内容都应该为 0,对吗? (每次我得到的数据是 <= 1
时,我都会通过向文件写入 0 来解决此问题 - 请参阅下面的代码)。也许是 "noise"?
代码:
有两个 类。第一个 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");
}
}
}
您没有说明如何解释使用上述代码生成的 Excel 中的结果。然而,一个可能的错误是误解了 FFTfft.realForward()
的输出——它是一个复数数组,其实部和虚部占据连续的元素,如记录 here。如果您只是使用出现峰值的数组的索引,您的结果将偏离两倍。请注意,此 FFT 实现仅计算 Nyqvist 速率(超出此范围仅产生 'alias')。
其他注意事项:
- 您正在将 rectangular window function 应用于样本。坦率地说,我很惊讶其他垃圾箱中的流血量小到
10e-16
。您的应用程序有更好的选择。 - window 似乎是文件的全长,可能导致巨大的 FFT。作为一般规则,2 的幂 FFTS 效率要高得多。您通常会看到在固定长度 windows 上执行的频率分析。
- FFT 实际上是一系列带通滤波器,它们是输入样本的加权和。您看到的非零值的一个贡献是简单的浮点舍入误差。事实上,您将整个文件放在 window 中,这意味着有很多操作对此有贡献。