Нормализация величины спектра БПФ до 0 дБ - PullRequest
0 голосов
/ 27 июня 2018

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

enter image description here

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

enter image description here

  1. Какое физическое значение амплитуды на втором рисунке?
  2. Как нормализовать амплитуду до 0 дБ, как в Audacity?
  3. Почему частота более 6 кГц имеет такую ​​высокую амплитуду (≥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 . Результат ближе к Audacity. Можно ли считать амплитуду ниже -90 дБ настолько низкой, чтобы ее можно было игнорировать?

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

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


О награде

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

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

1 Ответ

0 голосов
/ 09 июля 2018

После некоторого реверс-инжиниринга исходного кода Audacity вот несколько ответов. Во-первых, они используют алгоритм Уэлча для оценки PSD. Короче говоря, он разделяет сигнал на перекрывающиеся сегменты, применяет некоторую оконную функцию, применяет БПФ и усредняет результат. Главным образом, поскольку это помогает получить лучшие результаты при наличии шума. В любом случае, после извлечения необходимых параметров вот решение, которое приближает спектрограмму 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 | <1.0 </li>
  • segment_size соответствует Size в графическом интерфейсе Audacity.
  • тип окна по умолчанию - Hanning, вы можете изменить его, если хотите.
  • перекрытие segment_size/2 как в коде Audacity.
  • окно вывода оформлено в соответствии со стилем Audacity. Они выбрасывают первые низкочастотные контейнеры и режут все ниже -90 дБ

enter image description here

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

Это в основном количество энергии в частотном бине.

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

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

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

Да, все, что ниже -40 дБ, обычно считается незначительным

...