БПФ волнового файла не соответствует спектру сюжета Audacity

#c# #wpf #audio #fft #scottplot

Вопрос:

Я пытаюсь воспроизвести спектр сюжета в Audacity, но мои результаты не совпадают с результатами Audacity.

Я использую NAudio для преобразования WAV в образцы PCM, а затем БПФ последовательных блоков и усреднения БПФ блоков вместе. Наконец, я использую график Скотта для визуализации спектра графика. Ниже приведен мой код. Пожалуйста, дайте мне знать, где я допустил ошибку.

НАудио:

 double[] ReadWav(string filePath)
        {
            using (AudioFileReader afr = new AudioFileReader(filePath))
            {             
                sampleRate = afr.WaveFormat.SampleRate;
                var bitsPerSample = afr.WaveFormat.BitsPerSample;
                var sampleCount = (int)(afr.Length * 8 / bitsPerSample);
                int channelCount = afr.WaveFormat.Channels;
                audio = new List<double>(sampleCount);
                var buffer = new float[sampleRate * channelCount];
                int samplesRead = 0;
                while ((samplesRead = afr.Read(buffer, 0, buffer.Length)) > 0)
                {
                    audio.AddRange(buffer.Take(samplesRead).Select(x => (double)x));
                }

                double[] fft = new double[bufferSize];
                counter = 0;
                while (counter   bufferSize <= audio.Count())
                {
                    double[] pcm = audio.Skip(counter).Take(bufferSize).ToArray();
                    fft = fft.Zip(WindowedFFT(pcm), (x, y) => x   y).ToArray();
                    counter  = bufferSize;
                }
                fft = fft.Select(x => 10 * Math.Log10(x * bufferSize / counter)).ToArray();
          
                fftReal = new double[bufferSize / 2];
                Array.Copy(fft, fftReal, fftReal.Length);

                fftPointSpacingHz = (double)sampleRate / (2 * bufferSize);

                return audio.ToArray();
            }
        }
 

БПФ:

 public double[] WindowedFFT(double[] data)
        {
            double[] wdata = new double[data.Length];
            double[] hann = MathNet.Numerics.Window.Hamming(data.Length);
            for (int i = 0; i < data.Length; i  )
            {
                wdata[i] = hann[i] * data[i];
            }

            double[] fft = new double[data.Length];
            System.Numerics.Complex[] fftComplex = new System.Numerics.Complex[data.Length];
            for (int i = 0; i < data.Length; i  )
            {
                fftComplex[i] = new System.Numerics.Complex(wdata[i], 0.0);
            }
                
            Accord.Math.FourierTransform.FFT(fftComplex, Accord.Math.FourierTransform.Direction.Forward);
            for (int i = 0; i < data.Length; i  )
            {
                fft[i] = fftComplex[i].Magnitude;
            }              
            return fft;
        }
 

Сюжет Скотта:

         void Btn_Load_Click(object sender, RoutedEventArgs e)
        {
            s_graph.Plot.Clear();
            s_graph.Plot.AddSignal(music_data, sampleRate);
            s_graph.Plot.Title("Time Domain");
            s_graph.Plot.XLabel("Time (seconds)");
            s_graph.Plot.YLabel("Amplitude");
            s_graph.Plot.AxisAuto(0);
            s_graph.Configuration.LockVerticalAxis = true;
            s_graph.Configuration.LockHorizontalAxis = true;
            s_graph.Refresh();

            s_graph_fft.Plot.Clear();
            s_graph_fft.Plot.AddSignal(fftReal, fftPointSpacingHz);
            s_graph_fft.Plot.Title("Frequency Domain");
            s_graph_fft.Plot.XLabel("Frequency (Hz)");
            s_graph_fft.Plot.YLabel("Amplitude");
            s_graph_fft.Plot.AxisAuto(0);
            s_graph_fft.Configuration.LockVerticalAxis = true;
            s_graph_fft.Configuration.LockHorizontalAxis = true;
            s_graph_fft.Refresh();
        }