От амплитуды или БПФ до дБ - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть код Python, который выполняет БПФ для файла WAV и строит графики зависимости амплитуды от времени / амплитуды от частоты.Я хочу рассчитать дБ из этих графиков (это длинные массивы).Я не хочу рассчитывать точные дБА, я просто хочу видеть линейные отношения после моих расчетов.У меня дБ метр, буду сравнивать.Вот мой код:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function
import scipy.io.wavfile as wavfile
import scipy
import scipy.fftpack
import numpy as np
from matplotlib import pyplot as plt

fs_rate, signal = wavfile.read("output.wav")
print ("Frequency sampling", fs_rate)
l_audio = len(signal.shape)
print ("Channels", l_audio)
if l_audio == 2:
    signal = signal.sum(axis=1) / 2
N = signal.shape[0]
print ("Complete Samplings N", N)
secs = N / float(fs_rate)
print ("secs", secs)
Ts = 1.0/fs_rate # sampling interval in time
print ("Timestep between samples Ts", Ts)
t = scipy.arange(0, secs, Ts) # time vector as scipy arange field / numpy.ndarray
FFT = abs(scipy.fft(signal))
FFT_side = FFT[range(N//4)] # one side FFT range
freqs = scipy.fftpack.fftfreq(signal.size, t[1]-t[0])
fft_freqs = np.array(freqs)
freqs_side = freqs[range(N//4)] # one side frequency range
fft_freqs_side = np.array(freqs_side)

makespositive = signal[44100:]*(-1)
logal = np.log10(makespositive)

sn1 = np.mean(logal[1:44100])
sn2 = np.mean(logal[44100:88200])
sn3 = np.mean(logal[88200:132300])
sn4 = np.mean(logal[132300:176400])

print(sn1)
print(sn2)
print(sn3)
print(sn4)

abs(FFT_side)
for a in range(500):
    FFT_side[a] = 0

plt.subplot(311)
p1 = plt.plot(t[44100:], signal[44100:], "g") # plotting the signal
plt.xlabel('Time')
plt.ylabel('Amplitude')

plt.subplot(312)
p1 = plt.plot(t[44100:], logal, "r") # plotting the signal
plt.xlabel('Time')
plt.ylabel('Amplitude')

plt.subplot(313)
p3 = plt.plot(freqs_side, abs(FFT_side), "b") # plotting the positive fft spectrum
plt.xlabel('Frequency (Hz)')
plt.ylabel('Count single-sided')
plt.show()

Первый график - это амплитуда в зависимости от времени, второй - логарифм предыдущего графика, а последний - БПФ.В части sn1, sn2 я пытался вычислить дБ по сигналу.Сначала я взял журнал, а затем рассчитал среднее значение для каждой секунды.Это не дало мне четких отношений.Я также попробовал это и не сработало.

import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wf

fs, signal = wf.read('output.wav')  # Load the file
ref = 32768  # 0 dBFS is 32678 with an int16 signal

N = 8192
win = np.hamming(N)                                                       
x = signal[0:N] * win                             # Take a slice and multiply by a window
sp = np.fft.rfft(x)                               # Calculate real FFT
s_mag = np.abs(sp) * 2 / np.sum(win)              # Scale the magnitude of FFT by window and factor of 2,
                                                  # because we are using half of FFT spectrum
s_dbfs = 20 * np.log10(s_mag / ref)               # Convert to dBFS
freq = np.arange((N / 2) + 1) / (float(N) / fs)   # Frequency axis
plt.plot(freq, s_dbfs)
plt.grid(True)

Итак, какие шаги я должен выполнить?(Суммируйте / обозначьте все амплитуды частот, затем возьмите логарифм или реверс или выполните его для сигнала и т. Д.)

import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wf

fs, signal = wf.read('db1.wav') 

signal2 = signal[44100:]
chunk_size = 44100
num_chunk  = len(signal2) // chunk_size
sn = []
for chunk in range(0, num_chunk):
    sn.append(np.mean(signal2[chunk*chunk_size:(chunk+1)*chunk_size].astype(float)**2))

print(sn)

logsn = 20*np.log10(sn)

print(logsn)

Выход:

[4.6057844427695475e+17, 5.0025315250895744e+17, 5.028593412665193e+17, 4.910948397471887e+17]
[353.26607217 353.98379668 354.02893044 353.82330741]

revised plot

1 Ответ

0 голосов
/ 13 декабря 2018

Децибеллометр измеряет среднюю мощность сигнала.Таким образом, из вашей записи сигнала времени вы можете рассчитать среднюю мощность сигнала с помощью:

chunk_size = 44100
num_chunk  = len(signal) // chunk_size
sn = []
for chunk in range(0, num_chunk):
  sn.append(np.mean(signal[chunk*chunk_size:(chunk+1)*chunk_size]**2))

Тогда соответствующая средняя мощность сигнала в децибелах просто определяется как:

logsn = 10*np.log10(sn)

Эквивалентное соотношение можеттакже можно получить для сигнала частотной области с использованием теоремы Парсеваля , но в вашем случае потребуются ненужные вычисления БПФ (это соотношение в основном полезно, когда вам уже приходится вычислять БПФ для других целей).

Обратите внимание, что в зависимости от того, что вы сравниваете, могут быть некоторые (надеюсь, небольшие) расхождения.Например, использование нелинейного усилителя и колонок может повлиять на отношения.Точно так же окружающие шумы добавили бы к измеренной мощности измерителем децибел.

...