Результат NAudio fft дает интенсивность на всех частотах C#

У меня есть рабочая реализация записи цикла WASAPI Наудио и БПФ данных. Большинство данных, которые я получаю, так же, как и должно быть, но время от времени (от 10 секунд до минут) он показывает амплитуду почти на всех частотах.

The error image

в основном изображение катится справа налево со временем и частотами, идущими по логарифмической шкале от самых низких частот внизу. Линии ошибки. Насколько я могу скажи, что их там не должно быть.

Я получаю звуковой буфер и отправляю образцы в агрегатор (применяет окно Хэмминга), который реализует NAudio FFT. Я проверил данные (результат FFT), прежде чем я изменю его каким-либо образом (изображение не из необработанного вывода FFT, а масштабируется desibel), подтверждая, что результат FFT дает эти строки. Я также мог бы указать, что картина модифицирована LockBits, поэтому я думал, что у меня что-то не так с логикой, но именно поэтому я проверил выходные данные FFT, которые показывают ту же проблему.

Ну, я могу ошибаться, и проблема может быть где-то, я сказал, что это не так, но на самом деле кажется, что она исходит из БПФ или буферных данных (сами данные или агрегация образцов). Почему-то я сомневаюсь, что сам буфер поврежден таким образом.

Если кто-нибудь знает, что может вызвать это, я был бы очень признателен!

обновление

поэтому я решил нарисовать весь диапазон результатов FFT, а не половина его. В нем было что-то странное. Я не уверен в FFT, но я думал, что преобразование Фурье должно дать результат, который отражается вокруг середины. В данном случае это, конечно, не так.

изображение находится в линейном масштабе, поэтому точная середина изображения является средней точкой результата FFT. Низ первого и верх последние.

wholefft

Я играл синусоидальную волну 10 кГц, которая дает две горизонтальные линии там, но верхняя часть за пределами меня. Также кажется, что линии отражаются вокруг нижней четверти изображения, так что мне это тоже кажется странным.

обновление 2

поэтому я увеличил размер БПФ с 4096 до 8192 и попробовал еще раз. Это выход, когда я возился с синусоидальной частотой.

picture3

казалось бы, результат отражается дважды. Один раз посередине, а потом ... снова на верхней и нижней половинках. И огромные линии теперь исчезли.. И казалось бы, ЛИНИИ теперь появляются только на нижней половине.

после некоторого дальнейшего тестирования с различными длинами БПФ кажется, что линии полностью случайны в этой учетной записи.

обновление 3

Я сделал некоторые тесты со многими вещами. Последнее, что я добавил, Было перекрытие образцов, так что я повторно использую последнюю половину массива образцов в начале следующий БПФ. На окнах Хэмминга и Ханна это дает мне огромную интенсивность (совсем как на второй картинке, которую я опубликовал), но не с BlackmannHarris. Отключение перекрытия удаляет самые большие ошибки в каждой функции окна. Меньшие ошибки, как на верхнем рисунке, по-прежнему остаются даже с окном BH. Я до сих пор не понимаю, почему появляются эти линии.

моя текущая форма позволяет контролировать, какую функцию окна использовать (из трех ранее упомянутых), перекрывать (ВКЛ / ВЫКЛ) и несколько различные варианты рисования. Это позволяет мне сравнить все затрагивающие стороны воздействия при изменении.

Я буду исследовать дальше (я уверен, что я ошибся в какой-то момент), но хорошие предложения, более чем приветствуется!

1 ответов


проблема заключалась в том, как я обрабатывал массивы данных. Работает как по маслу.

код (удален избыток и, возможно, добавлены ошибки):

// 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!
}

и класс агрегатора выборки:

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; }
}

и это все, что я думаю. Возможно, я что-то упустил. Надеюсь, это поможет!