NAudio FFT返回所有频率的小且相等的幅值 [英] NAudio FFT returns small and equal magnitude values for all frequencies

查看:169
本文介绍了NAudio FFT返回所有频率的小且相等的幅值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用NAudio 1.9开发一个项目,我想为整首歌曲计算fft,即将歌曲分成大小相等的块,并为每个块计算fft.问题在于,NAudio FFT函数对于频率频谱中的任何频率都返回非常小的且相等的值.

I'm working on a project with NAudio 1.9 and I want to compute an fft for an entire song, i.e split the song in chunks of equal size and compute fft for each chunk. The problem is that NAudio FFT function returns really small and equal values for any freq in the freq spectrum.

我搜索了以前的相关帖子,但似乎没有一个帮助我.

I searched for previous related posts but none seemed to help me.

使用NAudio计算FFT的代码:

The code that computes FFT using NAudio:

public IList<FrequencySpectrum> Fft(uint windowSize) {
        IList<Complex[]> timeDomainChunks = this.SplitInChunks(this.audioContent, windowSize);
        return timeDomainChunks.Select(this.ToFrequencySpectrum).ToList();
}


private IList<Complex[]> SplitInChunks(float[] audioContent, uint chunkSize) {
        IList<Complex[]> splittedContent = new List<Complex[]>();

        for (uint k = 0; k < audioContent.Length; k += chunkSize) {
            long size = k + chunkSize < audioContent.Length ? chunkSize : audioContent.Length - k;
            Complex[] chunk = new Complex[size];

            for (int i = 0; i < chunk.Length; i++) {
                //i've tried windowing here but didn't seem to help me
                chunk[i].X = audioContent[k + i];
                chunk[i].Y = 0;
            }

            splittedContent.Add(chunk);
        }
        return splittedContent;
}


private FrequencySpectrum ToFrequencySpectrum(Complex[] timeDomain) {
        int m = (int) Math.Log(timeDomain.Length, 2);
        //true = forward fft
        FastFourierTransform.FFT(true, m, timeDomain);
        return new FrequencySpectrum(timeDomain, 44100);
}

频率频谱:

public struct FrequencySpectrum {

    private readonly Complex[] frequencyDomain;

    private readonly uint samplingFrequency;


     public FrequencySpectrum(Complex[] frequencyDomain, uint samplingFrequency) {
        if (frequencyDomain.Length == 0) {
            throw new ArgumentException("Argument value must be greater than 0", nameof(frequencyDomain));
        }
        if (samplingFrequency == 0) {
            throw new ArgumentException("Argument value must be greater than 0", nameof(samplingFrequency));
        }

        this.frequencyDomain = frequencyDomain;
        this.samplingFrequency = samplingFrequency;
    }


    //returns magnitude for freq
    public float this[uint freq] {
        get {
            if (freq >= this.samplingFrequency) {
                throw new IndexOutOfRangeException();
            }

            //find corresponding bin
            float k = freq / ((float) this.samplingFrequency / this.FftWindowSize);
            Complex c = this.frequencyDomain[checked((uint) k)];
            return (float) Math.Sqrt(c.X * c.X + c.Y * c.Y);
        }
    }
}

对于包含440Hz正弦波的文件

for a file that contains a sine wave of 440Hz

预期输出:freq = 440的值为0.5,其他值为0

expected output: values like 0.5 for freq=440 and 0 for the others

实际输出:频谱中任何频率的值都类似于0.000168153987f

actual output: values like 0.000168153987f for any freq in the spectrum

推荐答案

似乎我犯了4个错误:

1)在这里,我假设采样频率为44100.这不是我的代码无法正常工作的原因,

1) Here I'm asumming that sampling freq is 44100. This was not the reason my code wasn't working, though

return new FrequencySpectrum(timeDomain, 44100);

2)始终以可视方式表示您的输出数据!我必须学习这一课...似乎对于包含440Hz正弦波的文件,我得到了正确的结果,但是...

2) Always make a visual representation of your output data! I must learn this lesson... It seems that for a file containing a 440Hz sine wave I'm getting the right result but...

3)由于这个原因,频谱与我的预期有所不同:

3) The frequency spectrum is a little shifted from what I was expecting because of this:

int m = (int) Math.Log(timeDomain.Length, 2);
FastFourierTransform.FFT(true, m, timeDomain);

timeDomain是一个大小为44100的数组,因为这是windowSize的值(我用windowSize = 44100调用了该方法),但是FFT方法期望窗口大小的值为2的幂.计算此数组的fft,该数组具有44100个元素,但仅考虑前32768.我没有意识到这会对结果产生严重影响:

timeDomain is an array of size 44100 becaused that's the value of windowSize (I called the method with windowSize = 44100), but FFT method expects a window size with a value power of 2. I'm saying "Here, NAudio, compute me the fft of this array that has 44100 elements, but take into account only the first 32768". I didn't realize that this was going to have serious implications on the result:

float k = freq / ((float) this.samplingFrequency / this.FftWindowSize);

这里.FftWindowSize是基于数组大小的属性,而不是基于 m 的属性.因此,在可视化结果之后,我发现440Hz频率的幅度实际上与该呼叫相对应:

Here this.FftWindowSize is a property based on the size of the array, not on m. So, after visualizing the result I found out that magnitude of 440Hz freq was actually corresponding to the call:

spectrum[371]

代替

spectrum[440]

所以,我的错误是fft( m )的窗口大小与数组的实际长度( FrequencySpectrum.FftWindowSize )不对应.

So, my mistake was that the window size of fft (m) was not corresponding to the actual length of the array (FrequencySpectrum.FftWindowSize).

4)我收到的幅度值很小,是因为我测试代码的音频文件未获得足够的增益记录.

4) The small values that I was receiving for the magnitudes came from the fact that the audio file on which I was testing my code wasn't recorded with enough gain.

这篇关于NAudio FFT返回所有频率的小且相等的幅值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆