时间序列 dBFS 图输出修改 - 当前输出图不符合预期 (matplotlib)

2024-06-03

我正在尝试绘制Amplitude (dBFS) vs. Time (s)音频图(.wav)文件使用matplotlib。我设法用以下代码做到了这一点:

def convert_to_decibel(sample):
    ref = 32768                    # Using a signed 16-bit PCM format wav file. So, 2^16 is the max. value.
    if sample!=0:
        return 20 * np.log10(abs(sample) / ref)

    else:
        return 20 * np.log10(0.000001)


from scipy.io.wavfile import read as readWav
from scipy.fftpack import fft

import matplotlib.pyplot as gplot1
import matplotlib.pyplot as gplot2
import numpy as np
import struct
import gc

wavfile1 = '/home/user01/audio/speech.wav'

wavsamplerate1, wavdata1 = readWav(wavfile1)
wavdlen1 = wavdata1.size
wavdtype1 = wavdata1.dtype

gplot1.rcParams['figure.figsize'] = [15, 5]
pltaxis1 = gplot1.gca()
gplot1.axhline(y=0, c="black")
gplot1.xticks(np.arange(0, 10, 0.5))
gplot1.yticks(np.arange(-200, 200, 5))
gplot1.grid(linestyle = '--')
wavdata3 = np.array([convert_to_decibel(i) for i in wavdata1], dtype=np.int16)
yvals3 = wavdata3
t3 = wavdata3.size / wavsamplerate1
xvals3 = np.linspace(0, t3, wavdata3.size)
pltaxis1.set_xlim([0, t3 + 2])
pltaxis1.set_title('Amplitude (dBFS) vs Time(s)')
pltaxis1.plot(xvals3, yvals3, '-')

给出以下输出:

我还绘制了Power Spectral Density (PSD, in dBm)使用下面的代码:

from scipy.signal import welch as psd            # Computes PSD using Welch's method.

fpsd, wPSD = psd(wavdata1, wavsamplerate1, nperseg=1024)

gplot2.rcParams['figure.figsize'] = [15, 5]

pltpsdm = gplot2.gca()
gplot2.axhline(y=0, c="black")
pltpsdm.plot(fpsd, 20*np.log10(wPSD))
gplot2.xticks(np.arange(0, 4000, 400))
gplot2.yticks(np.arange(-150, 160, 10))
pltpsdm.set_xlim([0, 4000])
pltpsdm.set_ylim([-150, 150])
gplot2.grid(linestyle = '--')

输出如下:

上面的第二个输出使用韦尔奇方法绘制了更美观的输出。 dBFS 图虽然信息丰富,但在我看来并不是很美观。这是因为:

  1. 域中的差异(第一个输出的时间与第二个输出的频率)?
  2. pyplot中plot函数的实现方式?

另外,有没有办法可以绘制我的dBFS输出为峰峰式的情节就像在我的PSD (dBm)情节而不是密集茎图?

将会很有帮助,并且会感谢这里专家的任何指示、答案或建议,因为我只是一个初学者matplotlib和情节python一般来说。


TLNR

  • 这与pyplot.
  • 频域与时域不同,但这并不是您没有得到想要的结果的原因。
  • 您的代码中 dbFS 的计算是错误的。

你应该构建数据,计算每帧的 RMS 或峰值,然后将该值转换为 dbFS而不是将这种变换应用于每个样本点。


当我们谈论振幅时,我们谈论的是周期信号。当我们从声音文件中读取一系列数据时,我们读取了一系列样本点信号的(可以是或不是周期性的)。每个采样点的值代表在特定时间采样的电压值或声压值。

We assume在很短的时间间隔内,例如 10 毫秒,信号是静止的。每个这样的区间称为frame.

通常会对每一帧应用一些特定的函数,以减少该帧边缘的突变,这些函数称为窗函数。如果您对每个帧不执行任何操作,则会向它们添加矩形窗口。

举个例子:当你的声音采样频率是44100Hz时,在10ms长的帧中,有44100*0.01=441样本点。这就是nperseg争论意味着在你的psd功能,但与 dbFS 无关。

有了上面的知识,现在我们可以讨论振幅了。

有两种方法可以获取每帧的幅度值:

  • 最直接的方法是获取每一帧中的最大值(峰值)。
  • 另一种是计算每一帧的RMS(均方根)。

之后,峰值或RMS值可以转换为dbFS值。

让我们开始编码:

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

# Determine full scall(maximum possible amplitude) by bit depth
bit_depth = 16
full_scale = 2 ** bit_depth

# dbFS function
to_dbFS = lambda x: 20 * np.log10(x / full_scale)

# Read in the wave file
fname = "01.wav"
fs,data = wavfile.read(fname)

# Determine frame length(number of sample points in a frame) and total frame numbers by window length(how long is a frame in seconds)
window_length = 0.01 
signal_length = data.shape[0]
frame_length = int(window_length * fs)
nframes = signal_length // frame_length

# Get frames by broadcast. No overlaps are used.
idx = frame_length * np.arange(nframes)[:,None] + np.arange(frame_length)
frames = data[idx].astype("int64") # Convert to in 64 to avoid integer overflow

# Get RMS and peaks
rms = ((frames**2).sum(axis=1)/frame_length)**.5
peaks = np.abs(frames).max(axis=1)

# Convert them to dbfs
dbfs_rms = to_dbFS(rms)
dbfs_peak = to_dbFS(peaks)

# Let's start to plot

# Get time arrays of every sample point and ever frame
frame_time = np.arange(nframes) * window_length
data_time = np.linspace(0,signal_length/fs,signal_length)

# Plot
f,ax = plt.subplots()
ax.plot(data_time,data,color="k",alpha=.3)

# Plot the dbfs values on a twin x Axes since the y limits are not comparable between data values and dbfs
tax = ax.twinx()
tax.plot(frame_time,dbfs_rms,label="RMS")
tax.plot(frame_time,dbfs_peak,label="Peak")
tax.legend()
f.tight_layout()

# Save serval details
f.savefig("whole.png",dpi=300)
ax.set_xlim(1,2)
f.savefig("1-2sec.png",dpi=300)
ax.set_xlim(1.295,1.325)
f.savefig("1.2-1.3sec.png",dpi=300)

整个时间跨度看起来像(右轴单位为dbFS):

Whole time span And the voiced part looks like:

您可以看到 dbFS 值变大,而元音起点处的振幅变大:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

时间序列 dBFS 图输出修改 - 当前输出图不符合预期 (matplotlib) 的相关文章

  • 如何显示 pymongo.errors.OperationFailure 详细信息?

    写入 MongoDB 时 我在 python 中遇到 pymongo OperationsFailure 除了回溯之外 还有没有办法打印出详细信息或代码属性 另请参阅 http api mongodb org python current
  • 将鼠标悬停在 Folium 的弹出窗口中

    用这样一个简单的例子 import folium map 1 folium Map location 45 372 121 6972 zoom start 12 tiles Stamen Terrain folium Marker 45 3
  • 来自 yahoo 的 python lxml etree 小程序信息

    雅虎财经更新了他们的网站 我有一个 lxml etree 脚本 用于提取分析师建议 然而现在 分析师的建议已经存在 但只是以图表的形式出现 你可以看到一个例子这一页 https finance yahoo com quote CSX ana
  • 如何在 Pandas 中用多个唯一字符串替换重复值?

    import pandas as pd import numpy as np data Name Tom Tom Jack Terry Age 20 21 19 18 df pd DataFrame data 假设我有一个如下所示的数据框
  • Python + Selenium:驱动程序路径

    是否有可能在不输入路径的情况下运行 Python Selenium 脚本exePython 行中每个脚本中的文件 driver webdriver Chrome 同样的问题也适用于 IE 驱动程序 Edge 驱动程序 和 Gecko 驱动程
  • 从两个列表中查找总和等于 x 的 2 个数字的最快方法

    我的代码 n 3 a1 0 b1 10 a2 2 b2 2 if b1 gt n b1 n if b2 gt n b2 n diap1 x for x in range a1 b1 1 diap2 x for x in range a2 b
  • 对训练和测试数据帧使用相同的标签编码器

    我有 2 个不同的 csv 其中包含训练数据和测试数据 我从这些 train features df 和 test features df 创建了两个不同的数据帧 请注意 测试和训练数据有多个分类列 因此我需要对它们应用 labelEnco
  • 如何使用 BeautifulSoup 排除表中的某些行?

    我已经从表格中获得了所需的数据 但不想要各个玩家统计数据之间的缩写 Rk Pos Name 等 如何在保留所需数据的同时排除这些数据 包含缩写的行被归类为 thead 但我不知道如何使用该信息来跳过它 我知道玩家的数据都被压缩在一起 但现在
  • Pygame - 两个圆圈的碰撞检测

    我正在制作一个碰撞检测程序 其中我的光标是一个半径为 20 的圆 当它碰到另一个圆时应该将值更改为 TRUE 出于测试目的 我在屏幕中心有一个半径为 50 的固定圆 我可以测试光标圆是否击中固定圆 但它不能正常工作 因为它实际上是在测试它是
  • Python条件运算符“if else”不等于“and or”[重复]

    这个问题在这里已经有答案了 我认为下面两个函数的结果会相同 但事实并非如此 def fib2 n return n and n lt 2 or fib2 n 1 fib2 n 2 def fib3 m return m if m lt 2
  • 如何使用 Python 从 URL 中删除查询字符串

    Example http example com a text q2 text2 q3 text3 q2 text4 删除后 q2 它将返回 http example com q text q3 text3 在这种情况下 出现了多个 q2
  • 如何向 Iron Python 添加模块?

    我一直在尝试使用 C Visual Studio 执行以下 Python 代码 graphcreater py 我通过 NuGet 包管理器添加了 IronPyton 2 7 7 和 IronPython StdLib 2 7 7 一旦我运
  • 使用 Python for PyQt WebEngine 授予对 Cam & Mic 的访问权限

    我正在构建一个从 Python 调用的简单 Web 应用程序 我正在使用下面的代码 加载此页面时 以编程方式授予对摄像头和麦克风的访问权限的最简单方法是什么 我只在网上找到了 C 示例 无法找到在 Python 代码中执行此操作的方法 fr
  • 从线程队列中获取所有项目

    我有一个线程将结果写入队列 在另一个线程 GUI 中 我定期 在 IDLE 事件中 检查队列中是否有结果 如下所示 def queue get all q items while 1 try items append q get nowai
  • pandas 数据帧和聚合中的行明智排序

    我在 pandas dataframe df 中有一个表 col1 col2 count 12 15 3 13 17 5 1 36 4 15 12 7 36 1 4 等等 我想要的是将 12 和 15 和 15 和 12 等计算值视为相同
  • 如何在 python setup.py 中 chmod 文件?

    我使用 setup py 创建了一个 python 包安装 我希望它复制文件夹 为临时创建的 did 中的数据文件 问题是我必须使用 sudo 权限调用 setup py 因为它写入 usr local 因此 当我的数据文件复制到 did
  • 如何在(最好是纯)Python 中解码 QR 码图像?

    TL DR 我需要一种使用 最好是纯 Python 从图像文件中解码 QR 码的方法 我有一个带有 QR 码的 jpg 文件 我想使用 Python 对其进行解码 我发现有几个库声称可以做到这一点 PyQRCode 网站在这里 http p
  • 在 QThread.exit() 上立即停止处理事件队列

    我正在构建一个 Qt GUI 应用程序 它使用 QThread QObject 组合充当在主线程之外执行操作的工作人员 Via moveToThread QObject 被移动到 QThread 中 这样 我的工作线程就可以拥有在事件循环
  • Python:正则表达式 findall

    我使用 python 正则表达式从给定字符串中提取某些值 这是我的字符串 mystring txt sometext somemore text here some other text course course1 Id Name mar
  • python chaco轴标签时间格式

    在 Enthought 的 Chaco 中 TimeFormatter类用于格式化刻度的时间字符串 标签 有没有办法指定时间格式 类似于time strftime 源代码现在将显示月份和日期时的格式硬编码为美国风格 MMDD 我想添加一些灵

随机推荐