问题描述
我工作的一个项目,我就来分析 .WAV
文件,这基本上是我归结为能够显示是$ P $频率psent在上述文件中。
我使用的是类(其实我做一个因为我喂养它的实数只)。
一切似乎都做工精细,直到我养活的数据导入到Excel:我扔(对于我与测试文件1-8000)在第一列行记数,我扔FFT的输出入下一列。我喂养的文件是一个简单的频率的声音,在440Hz的,1秒的持续时间。
看到图后,虽然有一个问题:我有一个单一的频率峰值,这正是我期待,但峰值位于880位,这是双倍的实际频率。这是为什么有人能解释一下吗?
奖金的问题:为什么我让周围值E-16
?比峰值其他一切都应该是0,对不对? (我通过每一次我得到的数据是&LT写0到该文件解决这个问题= 1
- 见下code)。也许这是噪音?
code:
有两大类。第一个, readWav
来,好了,阅读 .WAV
文件。第二个, wavFFT
,是究竟是谁的FFT的数据之一。
code为 readWav.java
:
进口WavFile *。
进口java.io. *;公共类readWav { // getter方法
公共静态长getWavFrames(档案文件)
{
//尝试循环捕捉任何异常
尝试{
//打开wav文件
WavFile wavFile = WavFile.openWavFile(文件); //返回帧数
返回wavFile.getNumFrames(); }赶上(例外五){
通信System.err.println(E); //错误值
返回-1;
} } 公共静态INT getWavChannels(档案文件)
{
//尝试循环捕捉任何异常
尝试{
WavFile wavFile = WavFile.openWavFile(文件); 返回wavFile.getNumChannels(); }赶上(例外五){
通信System.err.println(E); //错误值
返回-1;
}
} 公共静态双重[] getWavData(档案文件)
{
//尝试循环捕捉任何异常
尝试{
//打开文件
WavFile wavFile = WavFile.openWavFile(文件); //使用getter方法得到的通道号(应该是单声道)
INT numChannels = getWavChannels(文件); //相同,但与框架getter方法
INT numFrames =(int)的getWavFrames(文件); //可能的数据丢失 //创建一个缓冲帧的数量的大小
双[] =缓冲新的双[numFrames * numChannels]。 //读取到帧缓冲
wavFile.readFrames(缓冲,numFrames); //关闭wavFile
wavFile.close(); 返回缓冲区; }赶上(例外五){
通信System.err.println(E); //抛出一个错误,如果这个东西运行在读.wav文件出错
抛出新的RuntimeException([无法读取wav文件+文件+]);
}
}
//主要方法,但仅限用于测试目的
公共静态无效的主要(字串[] args)
{
//测试,一切似乎是工作
文件fichier_son =新的文件(儿子/ freq1.wav);
双[] =测试getWavData(fichier_son);
的for(int i = 0; I< test.length;我++){
的System.out.println(试验[Ⅰ]);
}
}}
code为 wavFFT.java
:
进口org.jtransforms.fft.DoubleFFT_1D;
进口的java.io.File;
进口的java.io.PrintWriter;
进口java.io.IOException异常;公共类wavFFT { 公共静态双重[] realFFT(档案文件)
{
//使用readWav类获取数据的.wav
双[] = data_to_fft readWav.getWavData(文件); / *获取阵列的长度。
由于我们是喂养实数到FFT,
阵列的长度应等于
帧,这是我们开始使用readWav类的数量。 * /
INT N =(INT)readWav.getWavFrames(文件); //创建一个新的FFT对象
DoubleFFT_1D FFT =新DoubleFFT_1D(N); //执行realForward FFT
fft.realForward(data_to_fft); //返回最终数据
返回data_to_fft;
}
公共静态无效将writeToFile(文件,文件输出)抛出IOException异常
{
PrintWriter的print_out =的新PrintWriter(出);
INT I;
双[] = data_to_file realFFT(中); 对于(i = 0; I< data_to_file.length;我++){
如果(data_to_file [I]→1){
print_out.println(data_to_file [I]);
}其他{
print_out.println(0);
} }
print_out.close();
} //主要方法,但仅限用于测试目的
公共静态无效的主要(字串[] args){
文件fichier_son =新的文件(儿子/ freq1.wav);
双[] =测试realFFT(fichier_son);
INT I; 对于(i = 0; I< test.length;我++){
的System.out.println(试验[Ⅰ]);
}
尝试{
将writeToFile(fichier_son,新的文件(数据文件/ output.txt中));
}赶上(IOException异常五){
的System.out.println(错误);
}
}}
你不说你怎么际preT你与上面的code产生的结果在Excel中。然而,一个可能的错误是误解了FFT fft.realForward()
的输出 - 这是复数,其部和虚部占用连续元素的数组,如记录此处。如果你只是使用其中的峰值发生的数组的索引,你的结果会由两个因素关闭。请注意,这个FFT实现只计算到Nyqvist率(超出了仅仅是产生一个别名)。
其他的事情需要注意:
- 您所申请的以样本。我坦率地惊讶于其他段的出血是小如
10E-16
。有更好的选择的应用程序。 - 的窗口似乎是文件的完整长度,可能造成巨大的FFT。一般来说,功率为2的FFTS是更为有效。您通常会看到在固定长度窗口进行频率分析。
- FFT是有效的一系列带通滤波器,其被输入样本的加权和。到非零值的贡献,你看到的是简单的浮点舍入误差。即你把整个文件窗口中的事实,意味着有有助于这极大许多操作。
I'm working on a project where I have to analyze .wav
files, which basically for me comes down to being able to display the frequencies that are present in said file.I'm using the WavFile
class to read the file, and then I FFT them using the JTransforms
class (I actually do a realForward
since I'm feeding it real numbers only).
Everything seems to work fine, until I feed the data into Excel: I throw a line numeration in the first column (1-8000 for the file that I'm testing with) and I throw the output of the FFT into the next column. The file I'm feeding is a simple one-frequency sound, at 440Hz, with a duration of 1 second.
After seeing the graph, though, there's a problem: I have a single frequency peak, which is exactly what I'm expecting, but the peak is situated at position 880, which is double the actual frequency. Can somebody explain to me why is that?
Bonus question: Why am I getting values around e-16
? Everything other than the peak should be 0, right? (I fix this by writing a 0 to the file each time the data I get is <= 1
- see code below). Maybe it's "noise"?
Code:
There's two classes. The first one, readWav
is used to, well, read the .wav
file. The second one, wavFFT
, is the one who actually FFTs the data.
Code for 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]);
}
}
}
Code for 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");
}
}
}
You don't say how you interpret the results in Excel that you generate with the code above. However, a likely error is misunderstanding the output of the FFTfft.realForward()
- which is an array of complex numbers, whose real and imaginary parts occupy consecutive elements, as documented here. If you simply use the index of the array in which the peak occurs, your result would be off by a factor of two. Note that this FFT implementation only calculates up to the Nyqvist rate (beyond this merely yields an 'alias').
Other things to note:
- You are applying the rectangular window function to the samples. I'm frankly surprised the bleed in other bins is as small as
10e-16
. There are better choices the your application. - The window appears to be the full length of the file, probably resulting in a huge FFT. As a general rule, power-of-2 FFTS are far more efficient. You would typically see frequency analysis performed on fixed length windows.
- The FFT is in effect a series of band-pass filters, which are the weighted sum of input samples. A contribution to the non-zero values you see is simply floating point round-off errors. The fact that you're putting the whole file in the window, means that there are a great many operations that contribute to this.
这篇关于Java的.wav文件的频率分析 - 不正确的频率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!