NAudio fft результат дает интенсивность на всех частотах C#
У меня есть рабочая реализация записи WASAPI loopback NAudio и FFT данных.
Большинство данных, которые я получаю, такие же, как и должны быть, но время от времени (с интервалом от 10 секунд до нескольких минут) они показывают амплитуду почти на всех частотах.
В основном картина катится справа налево со временем и частотами, идущими по логарифмической шкале от самых низких частот внизу. Линии - это ошибки. Насколько я могу судить, это не так. должен был быть там.
Я получаю звуковой буфер и отправляю образцы в агрегатор (применяет окно Хэмминга), который реализует NAudio FFT. Я проверил данные (результат БПФ), прежде чем изменить его каким-либо образом (изображение не является результатом необработанного вывода БПФ, но масштабируется десибелем), подтверждая, что результат БПФ дает эти строки. Я также мог бы указать, что изображение модифицировано с помощью Локбитов, поэтому я подумал, что у меня что-то не так с логикой, но именно поэтому я проверил выходные данные FFT что показывает ту же проблему.
Ну, я могу ошибаться, и проблема может быть где-то, где я сказал, что это не так, но на самом деле кажется, что это происходит из БПФ или буферных данных (сами данные или агрегация выборок). Почему-то я сомневаюсь, что сам буфер поврежден подобным образом.
Если у кого-нибудь есть хоть малейшее представление о том, что могло бы вызвать это, я буду очень признателен!
Обновить
Поэтому я решил нарисовать весь диапазон результатов FFT, а не половину его. Это было заметно что-то странное. Я не уверен в FFT, но я думал, что преобразование Фурье должно дать результат, который отражается примерно посередине. Здесь, конечно, дело обстоит иначе.
Изображение имеет линейный масштаб, поэтому точная середина изображения является средней точкой результата БПФ. Низ-первый, а верх-последний.
Я играл синусоидальную волну 10 кГц, которая дает две горизонтальные линии, но верхняя часть находится за пределами меня. Это также кажется, что линии зеркально отражаются в нижней части рисунка, так что мне это тоже кажется странным.
Обновление 2
Поэтому я увеличил размер БПФ с 4096 до 8192 и попробовал снова. Это выход с моей возней с синусоидальной частотой.
Казалось бы, результат повторяется дважды. Один раз в середине, а затем снова на верхней и нижней половинках. И огромные линии теперь исчезли.. И казалось бы, линии появляются только на экране. теперь нижняя половина.
После некоторого дальнейшего тестирования с различными длинами FFT кажется, что линии полностью случайны в этом счете.
Обновление 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; } }И это все, что я думаю. Хотя, возможно, я что-то упустил. Надеюсь, это поможет!



Comments