NAudio FFT возвращает малые и одинаковые значения амплитуды для всех частот

Я работаю над проектом с NAudio 1.9 и хочу вычислить fft для всей песни, т.е. разделить песню на фрагменты одинакового размера и вычислить fft для каждого фрагмента. Проблема в том, что функция NAudio FFT возвращает очень маленькие и одинаковые значения для любой частоты в частотном спектре.

Я искал предыдущие связанные сообщения, но ни один из них, похоже, не помог мне.

Код, который вычисляет БПФ с помощью 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);
        }
    }
}

для файла, содержащего синусоиду 440 Гц

ожидаемый результат: такие значения, как 0,5 для частоты = 440 и 0 для остальных

фактический вывод: такие значения, как 0,000168153987f для любой частоты в спектре

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
687
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Кажется, я сделал 4 ошибки:

1) Здесь я предполагаю, что частота дискретизации равна 44100. Однако это не было причиной того, что мой код не работал.

return new FrequencySpectrum(timeDomain, 44100);

2) Всегда сделать визуальное представление ваших выходных данных! Я должен усвоить этот урок... Кажется, что для файла, содержащего синусоиду 440 Гц, я получаю правильный результат, но...

3) Частотный спектр немного смещен от того, что я ожидал из-за этого:

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

timeDomain представляет собой массив размером 44100, потому что это значение windowSize (я вызвал метод с windowSize = 44100), но метод БПФ ожидает размер окна со степенью двойки. Я говорю: «Вот, NAudio, вычисли мне fft этого массива, состоящего из 44100 элементов, но учитываем только первые 32768". Я не понимал, что это будет иметь серьезные последствия для результата:

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

Здесь this.FftWindowSize — это свойство, основанное на размере массива, а не на мм>. Итак, визуализировав результат, я обнаружил, что величина частоты 440 Гц на самом деле соответствует вызову:

spectrum[371]

вместо

spectrum[440]

Итак, моя ошибка заключалась в том, что размер окна fft (мм>) не соответствовал фактической длине массива (FrequencySpectrum.FftWindowSize).

4) Небольшие значения, которые я получал для величин, были связаны с тем, что аудиофайл, на котором я тестировал свой код, не был записан с достаточным усилением.

Другие вопросы по теме