NAudio fft result gives intensity on all frequencies C#
我有NAudio的wasapi回送记录和数据FFT的有效实现。
我得到的大多数数据都是应有的值,但是每隔一段时间(间隔10秒到几分钟)就会显示几乎所有频率上的振幅。
基本上,图片从右到左滚动,时间和频率从底部的最低频率以对数标度递增。线是错误。据我所知,那些不应该在那里。
我得到音频缓冲区,并将样本发送到实现NAudio FFT的聚合器(应用Hamming窗口)。在以任何方式修改数据(FFT结果)之前,我已经检查了数据(图片不是来自原始FFT输出,而是按Desibel缩放比例),以确认FFT结果正在显示这些行。我还可以指出图片是使用LockBits修改的,所以我认为那里的逻辑有问题,但这就是为什么我检查了显示相同问题的FFT输出数据的原因。
好吧,我可能错了,问题可能出在我未曾说过的地方,但实际上它似乎起源于FFT或缓冲区数据(数据本身或样本的聚合)。我以某种方式怀疑缓冲区本身是否已损坏。
如果有人有什么想法会导致这种情况,我将不胜感激!
更新
因此,我决定绘制整个FFT结果范围,而不是一半。它显示出一些奇怪的东西。我不确定FFT是否有效,但我认为傅里叶变换应将结果反映在中间。这里肯定不是这种情况。
图片是线性比例的,因此图片的确切中间是FFT结果的中间点。底部是第一个,顶部是最后一个。
我正在播放10kHz正弦波,在那给出了两条水平线,但顶部不在我的范围内。似乎线条也被镜像在图片的底部四分之一周围,所以对我来说也很奇怪。
更新2
所以我将FFT大小从4096增加到8192,然后重试。这是我的输出与正弦频率混淆。
结果似乎被镜像了两次。一次在中间,然后再在上半部分和下半部分。巨大的线条现在消失了。.看起来这些线条现在仅出现在下半部分。
在使用不同的FFT长度进行了进一步测试之后,该行似乎完全是随机的。
更新3
我已经做了很多测试。我添加的最新内容是样本重叠,以便在下一个FFT的开头重用样本数组的后半部分。在汉明和汉恩的窗户上,它给了我很大的强度(非常像我发布的第二张照片),但是没有布莱克曼·哈里斯。禁用重叠功能可消除每个窗口功能上的最大错误。即使在BH窗口中,如顶部图片中的较小错误仍然保留。我仍然不知道为什么出现这些行。
我当前的形式允许控制使用哪个窗口功能(前面提到的三个),重叠(打开/关闭)以及多个不同的绘图选项。这使我可以比较更改时所有受影响方的影响。
我将作进一步调查(我很确定自己在某些时候犯了一个错误),但是很好的建议绝对值得欢迎!
问题出在我处理数据数组的方式上。 现在像魅力一样工作。
代码(删除了多余的代码,并可能添加了错误):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | // Other inputs are also usable. Just look through the NAudio library. private IWaveIn waveIn; private static int fftLength = 8192; // NAudio fft wants powers of two! // There might be a sample aggregator in NAudio somewhere but I made a variation for my needs private SampleAggregator sampleAggregator = new SampleAggregator(fftLength); public Main() { sampleAggregator.FftCalculated += new EventHandler<FftEventArgs>(FftCalculated); sampleAggregator.PerformFFT = true; // Here you decide what you want to use as the waveIn. // There are many options in NAudio and you can use other streams/files. // Note that the code varies for each different source. waveIn = new WasapiLoopbackCapture(); waveIn.DataAvailable += OnDataAvailable; waveIn.StartRecording(); } void OnDataAvailable(object sender, WaveInEventArgs e) { if (this.InvokeRequired) { this.BeginInvoke(new EventHandler<WaveInEventArgs>(OnDataAvailable), sender, e); } else { byte[] buffer = e.Buffer; int bytesRecorded = e.BytesRecorded; int bufferIncrement = waveIn.WaveFormat.BlockAlign; for (int index = 0; index < bytesRecorded; index += bufferIncrement) { float sample32 = BitConverter.ToSingle(buffer, index); sampleAggregator.Add(sample32); } } } void FftCalculated(object sender, FftEventArgs e) { // Do something with e.result! } |
和Sample Aggregator类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | using NAudio.Dsp; // The Complex and FFT are here! class SampleAggregator { // FFT public event EventHandler<FftEventArgs> FftCalculated; public bool PerformFFT { get; set; } // This Complex is NAudio's own! private Complex[] fftBuffer; private FftEventArgs fftArgs; private int fftPos; private int fftLength; private int m; public SampleAggregator(int fftLength) { if (!IsPowerOfTwo(fftLength)) { throw new ArgumentException("FFT Length must be a power of two"); } this.m = (int)Math.Log(fftLength, 2.0); this.fftLength = fftLength; this.fftBuffer = new Complex[fftLength]; this.fftArgs = new FftEventArgs(fftBuffer); } bool IsPowerOfTwo(int x) { return (x & (x - 1)) == 0; } public void Add(float value) { if (PerformFFT && FftCalculated != null) { // Remember the window function! There are many others as well. fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HammingWindow(fftPos, fftLength)); fftBuffer[fftPos].Y = 0; // This is always zero with audio. fftPos++; if (fftPos >= fftLength) { fftPos = 0; FastFourierTransform.FFT(true, m, fftBuffer); FftCalculated(this, fftArgs); } } } } public class FftEventArgs : EventArgs { [DebuggerStepThrough] public FftEventArgs(Complex[] result) { this.Result = result; } public Complex[] Result { get; private set; } } |
我就是这样。 我可能已经错过了一些东西。
希望这可以帮助!