**声压级(Sound Pressure Level, SPL)**定义为:
SPL (dB)=20⋅log10(pp0) \text{SPL (dB)} = 20 \cdot \log_{10}\left(\frac{p}{p_0}\right) SPL (dB)=20⋅log10(p0p)
麦克风采集的数字音频是归一化浮点数,范围通常是 [-1.0, 1.0]
。我们不能直接将它用于 SPL 计算,必须先通过校准:
RMS=1N∑i=1Nxi2 \text{RMS} = \sqrt{\frac{1}{N} \sum_{i=1}^{N} x_i^2} RMS=N1i=1∑Nxi2
p=RMS×K p = \text{RMS} \times K p=RMS×K
其中 KKK 是单位 RMS 对应的帕斯卡值(来自校准)。
SPL=20⋅log10(p2×10−5) \text{SPL} = 20 \cdot \log_{10} \left( \frac{p}{2 \times 10^{-5}} \right) SPL=20⋅log10(2×10−5p)
你需要一组参考数据:
计算换算因子:
K=p参考RMS参考其中p参考=2×10−5⋅10SPL参考/20 K = \frac{p_{\text{参考}}}{\text{RMS}_{\text{参考}}} \quad \text{其中} \quad p_{\text{参考}} = 2 \times 10^{-5} \cdot 10^{\text{SPL}_{\text{参考}} / 20} K=RMS参考p参考其中p参考=2×10−5⋅10SPL参考/20
pip install sounddevice numpy
import sounddevice as sd
import numpy as np
# ==== 校准参数 ====
# 假设你测得 RMS=0.05 时对应 94 dB SPL(可以通过实际测量获得)
ref_rms = 0.05
ref_db_spl = 94.0
# ==== 计算换算因子 ====
p0 = 2e-5 # 参考声压(Pa)
p_ref = p0 * 10**(ref_db_spl / 20) # 计算参考声压(Pa)
pa_per_rms = p_ref / ref_rms # 每单位 RMS 对应多少 Pa
# ==== 音频回调函数 ====
def audio_callback(indata, frames, time, status):
if status:
print("状态:", status)
# 计算当前音频帧的 RMS
rms = np.sqrt(np.mean(indata**2))
# 转换为实际声压(Pa)
p = rms * pa_per_rms
# 转换为 dB SPL(加入极小值避免 log(0))
db_spl = 20 * np.log10(p / p0 + 1e-10)
print(f"当前声压级: {db_spl:.2f} dB SPL")
# ==== 打开麦克风输入流 ====
print("实时声压级监测中(Ctrl+C 停止)")
with sd.InputStream(callback=audio_callback, channels=1, samplerate=44100, blocksize=1024):
try:
while True:
sd.sleep(100)
except KeyboardInterrupt:
print("已停止")
你可以估算校准值:
+1e-10
?为了避免在 RMS = 0 时出现 log(0)
错误。这个小数不会影响实际 SPL 计算。
当然!可以使用 matplotlib
、tkinter
或 streamlit
实现实时图表显示和日志保存。如果你需要,我可以帮你扩展为可视化工具。
步骤 | 内容 |
---|---|
获取音频 | 使用 sounddevice 采集 |
计算 RMS | np.sqrt(np.mean(indata**2)) |
校准换算 | RMS → 声压(Pa)→ SPL(dB) |
显示/存储 | 终端打印,或图形化界面 |