Нормализация величины спектра БПФ до 0dB

Я использую FFT для извлечения амплитуды каждой частотной компоненты из аудиофайла. На самом деле в Audacity уже есть функция, называемая Plot Spectrum, которая может помочь решить проблему. Принимая это пример аудио файлом которое составлено синуса 3khz и синуса 6kHz, результат спектра как следующее изображение. Вы можете видеть, что пики находятся на 3KHz и 6kHz, без дополнительной частоты.

enter image description here

теперь мне нужно реализовать та же функция и построить аналогичный результат в Python. Я близок к результату Audacity с помощью rfft но я все еще есть проблемы после получения этого результата.

enter image description here

  1. что такое физический смысл амплитуды во второй картине?
  2. Как нормализовать амплитуду до 0dB, как в Audacity?
  3. почему частота над 6kHz имеет такую высокую амплитуду (≥90)? Могу я их масштабировать? частота к относительному низкому уровню?

код:

import numpy as np
from pylab import plot, show
from scipy.io import wavfile

sample_rate, x = wavfile.read('sine3k6k.wav')
fs = 44100.0

rfft = np.abs(np.fft.rfft(x))
p = 20*np.log10(rfft)
f = np.linspace(0, fs/2, len(p))

plot(f, p)
show()

обновление

я умножил окно Ханнинга на сигнал всей длины (это правильно?) и вот что. Большая часть амплитуды юбок ниже 40.

enter image description here

и масштабируйте ось y до децибела как @Mateen Ulhaq сказал. Результат ближе к дерзости. Могу я обработать амплитуду ниже-90dB настолько низко, что его можно игнорировать?

обновленный код:

fs, x = wavfile.read('input/sine3k6k.wav')
x = x * np.hanning(len(x))

rfft = np.abs(np.fft.rfft(x))
rfft_max = max(rfft)
p = 20*np.log10(rfft/rfft_max)
f = np.linspace(0, fs/2, len(p))

enter image description here


о награде

С кодом в обновлении выше я могу измерить частотные компоненты в децибелах. Максимально возможное значение будет 0dB. Но метод работает только для определенного аудиофайла, потому что он использует rfft_max этого звука. Я хочу измерить частотные компоненты нескольких аудиофайлов в одном стандартное правило, как и дерзость.

Я тоже началась дискуссия в форуме Audacity, но мне все еще не было ясно, как реализовать мою цель.

1 ответов


после выполнения некоторого обратного проектирования исходного кода Audacity здесь некоторые ответы. Во-первых, они используют алгоритм Уэлча для оценки PSD. Короче говоря, он разбивает сигнал на перекрывающиеся сегменты, применяет некоторую оконную функцию, применяет FFT и усредняет результат. В основном это помогает получить лучшие результаты, когда присутствует шум. Во всяком случае, после извлечения необходимых параметров вот решение, которое аппроксимирует спектрограмму Audacity:

import numpy as np
from scipy.io import wavfile
from scipy import signal
from matplotlib import pyplot as plt

segment_size = 512

fs, x = wavfile.read('sine3k6k.wav')
x = x / 32768.0  # scale signal to [-1.0 .. 1.0]

noverlap = segment_size / 2
f, Pxx = signal.welch(x,                        # signal
                      fs=fs,                    # sample rate
                      nperseg=segment_size,     # segment size
                      window='hanning',         # window type to use
                      nfft=segment_size,        # num. of samples in FFT
                      detrend=False,            # remove DC part
                      scaling='spectrum',       # return power spectrum [V^2]
                      noverlap=noverlap)        # overlap between segments

# set 0 dB to energy of sine wave with maximum amplitude
ref = (1/np.sqrt(2)**2)   # simply 0.5 ;)
p = 10 * np.log10(Pxx/ref)

fill_to = -150 * (np.ones_like(p))  # anything below -150dB is irrelevant
plt.fill_between(f, p, fill_to )
plt.xlim([f[2], f[-1]])
plt.ylim([-90, 6])
# plt.xscale('log')   # uncomment if you want log scale on x-axis
plt.xlabel('f, Hz')
plt.ylabel('Power spectrum, dB')
plt.grid(True)
plt.show()

некоторые необходимые пояснения по параметрам:

  • волновой файл читается как 16-битный PCM, чтобы быть совместимым с Audacity, он должен быть масштабирован до |A /
  • segment_size соответствует Size в GUI Audacity.
  • тип окна по умолчанию- "Hanning", вы можете изменить его, если хотите.
  • наложение segment_size/2 как в коде Audacity.
  • окно вывода оформлено в соответствии со стилем Audacity. Они выбрасывают первые низкочастотные ящики и вырезать все ниже-90dB

enter image description here

что такое физический смысл амплитуды во второй картине?

это в основном количество энергии в частотном ОГРН.

Как нормализовать амплитуду до 0dB, как в Audacity?

вам нужно выбрать какой-нибудь ориентир. Графики в децибелах всегда к чему-то относятся. При выборе максимальной энергии bin в качестве ссылки ваша точка 0db является максимальной энергией (очевидно). Допустимо устанавливать в качестве опорной энергии синусоидальную волну с максимальной амплитудой. См.ref переменной. Мощность в синусоидальном сигнале - это просто квадрат RMS, а чтобы получить RMS, вам просто нужно разделить амплитуду на sqrt (2). Таким образом, коэффициент масштабирования просто 0,5. Обратите внимание, что фактор перед log10 это 10, а не 20, это потому, что мы имеем дело с мощностью сигнала, а не амплитудой.

могу я обработать амплитуда ниже-90dB настолько низкая, что ее можно игнорировать?

Да, все что ниже -40дб, как правило, считается negligeble