java中如何在每次FFT计算中检索不同的原始频率,并且不存在任何频率泄漏

java中如何在每次FFT计算中检索不同的原始频率,并且不存在任何频率泄漏,java,audio,fft,frequency,javasound,Java,Audio,Fft,Frequency,Javasound,我在为这样的问题而斗争,比如从麦克风记录的音频数据中恢复原始频率 对不起,我的英语 让我更清楚地解释这个问题。我使用以下代码I生成了一些特定频率: void genTone() { numSamples = (int)(0.2 * sampleRate); //duration * sampleRate; sample = new double[numSamples]; generatedSnd = new byte[2 * numSamples]; //

我在为这样的问题而斗争,比如从麦克风记录的音频数据中恢复原始频率

对不起,我的英语

让我更清楚地解释这个问题。我使用以下代码I生成了一些特定频率:

void genTone() {
    numSamples = (int)(0.2 * sampleRate);   //duration * sampleRate;
    sample = new double[numSamples];
    generatedSnd = new byte[2 * numSamples];

    // fill out the array
    for (int i = 0; i < numSamples; ++i) {
        sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/freqOfTone));
    }

    // convert to 16 bit pcm sound array
    // assumes the sample buffer is normalised.
    int idx = 0;
    for (final double dVal : sample) {
        // scale to maximum amplitude
        final short val = (short) ((dVal * 32767));
        // in 16 bit wav PCM, first byte is the low order byte
        generatedSnd[idx++] = (byte) (val & 0x00ff);
        generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
    }
}
void genTone(){
numSamples=(int)(0.2*采样器);//持续时间*采样器;
样本=新的双精度[numSamples];
generatedSnd=新字节[2*numSamples];
//填写数组
对于(int i=0;i>>8);
}
}
我用下面的代码II记录了声音:

private void recordInBackground() {
    int read = 0;
    while (isRecording) {
        short data[] = new short[bufferSize];   // bufferSize = 4096

        read = audioRecorder.read(data, 0, bufferSize);
        if (read != AudioRecord.ERROR_INVALID_OPERATION) {
            try {
                float tempHammingRes[] = null;
                hamming(bufferSize);

                Complex[] complexs = new Complex[bufferSize];
                Complex[] results = new Complex[bufferSize];
                for (int i = 0; i < bufferSize; ++i) {
                    data[i] /= 32767; 
                    tempHammingRes[i] = tempHammingRes[i] * data[i];
                    complexs[i]= new Complex(tempHammingRes[i], 0);
                }

                results = FFT.fft(complexs);

                double highScore = 0.0;
                int freq = 1;

                for (int line = 1; line < bufferSize; ++line) {
                    double magnitude = Math.log(results[line].abs() + 1) / Math.log(10.0)*20.0;
                    if (magnitude > highScore) {
                        highScore = magnitude;
                        freq = line;
                    }
                }

                double currentFrequence = ComputeFrequency(freq, bufferSize);

                Log.d(TAG, "highScore = " + highScore + " freq = " + currentFrequence);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


}
private void recordInBackground(){
int read=0;
while(isRecording){
短数据[]=新的短数据[bufferSize];//bufferSize=4096
读取=录音机。读取(数据,0,缓冲区大小);
if(读取!=录音。错误\u无效\u操作){
试一试{
float temphamingres[]=null;
汉明(缓冲区大小);
Complex[]complexs=新的复合体[bufferSize];
复杂[]结果=新复杂[bufferSize];
对于(int i=0;i高分){
高分=量级;
频率=直线;
}
}
双电流频率=计算频率(频率、缓冲区大小);
Log.d(标记“highScore=“+highScore+”freq=“+currentFrequence”);
}捕获(例外e){
e、 printStackTrace();
}
}
}
}
现在,我有一个问题,在代码块II中,将在连续FFT计算间隔中获得相同的频率。例如,代码块II输出了一些日志:

高分=151.77662972416104频率=7999.5849609375//前8000

高分=146.330730294598455频率=7999.5849609375//秒8000

高分=146.44411729898255频率=9000.87890625

高分=144.43481176938155频率=9000.87890625

高分=142.7804662784702频率=10002.1728515625

高分=141.91874938214298频率=10002.1728515625

高分=136.4726991015098频率=11003.466796875

高分=136.6873278405228频率=11003.466796875

我只产生了一个8khz,但我得到了两个声音频率。我还减少了输出音的持续时间或增加了录音机的输入缓冲区大小。不幸的是,这无助于我想做的事

有没有人知道我是否错了,或者fft的输出本质上是这样的


非常感谢您的回复

我看到了一些潜在的问题。我可能误读了你的代码,但我会提到这些东西,因为它们看起来像是问题:

  • 尽管加窗,FFT总是有“旁瓣”。您选择了汉明窗,这可能是实现此目的的理想选择,但您可能会看到旁瓣。你不应该这样,但是如果genTone和recordInBackground之间发生了什么事情(例如,你正在通过扬声器播放声音并重新录制),这可能会产生足够的噪声和失真,偶尔会使旁瓣数据与主数据一样突出

  • 看起来您一直在读取FFT结果。只有FFT的前半部分包含相关结果,后半部分是前半部分的镜像。由于轻微的数值误差,您可能会发现下半部分的结果大于上半部分。这个问题也表明你可能计算错误的频率。我在这里(以及更多!)介绍了这一点:

  • 您可以将数据反向输出,但不输入。也许这取决于你在做什么,但从这么多代码来看,这是错误的。FFT可以“看穿”这一点,但实际上已经产生了大量的噪声


  • 我还注意到您正在尝试计算FFT结果绝对值的对数。这只会让你的计算耗时更长。出于您的目的,magnity=results[line].abs()是可以的。

    我在这里看到了一些潜在的问题。我可能误读了你的代码,但我会提到这些东西,因为它们看起来像是问题:

  • 尽管加窗,FFT总是有“旁瓣”。您选择了汉明窗,这可能是实现此目的的理想选择,但您可能会看到旁瓣。你不应该这样,但是如果genTone和recordInBackground之间发生了什么事情(例如,你正在通过扬声器播放声音并重新录制),这可能会产生足够的噪声和失真,偶尔会使旁瓣数据与主数据一样突出

  • 看起来您一直在读取FFT结果。只有FFT的前半部分将包含相关结果,后半部分将包含i