文章目录
前言
很多博客中经常会把声音的能量和分贝说成是一个东西,这种说法是错误的。在实际生活中,想要形容声音大小按照之前博客中的介绍,其实就是音频模拟信号的振幅,而在实际的数字信号也就是PCM中,这种振幅被量化成了分贝。
本篇博客会介绍音频能量和分贝的关系,并且给出以16k 双通 short类型的数据进行计算分贝的算法。
|版本声明:山河君,未经博主允许,禁止转载
一、能量与分贝
音频能量和分贝 (dB) 都用于描述声音的强度,但它们的概念和计算方式有所不同。
1.音频能量
音频能量是声音信号中携带的实际物理能量,它通常与声音的振幅(Amplitude)相关。它代表声音的功率或强度,直接反映了声音信号在某个时刻或时间段内的物理表现。
- 能量与振幅的关系:音频信号的能量与振幅的平方成正比。也就是说,如果音频信号的振幅增大,能量会以平方的速度增长。例如,振幅为2的音频信号,其能量是振幅为1信号的4倍。
数学上,音频信号的能量通常表示为信号样本的平方和,例如:
E = ∑ i = 0 n x i 2 E = \sum_{i = 0}^{n}x^{2}_{i} E=i=0∑nxi2
其中, x i 2 x^{2}_{i} xi2是每个音频样本的振幅,N 是样本数.
- 能量的单位:音频能量的单位取决于它的具体表示方式。它可以用功率单位(如瓦特,W)来度量,或者仅作为信号强度的无量纲值表示。
2.分贝
分贝是一种对数单位,用于表示两种能量或强度之间的相对差异。分贝表示相对变化,而不是绝对的物理量,因此它是音频能量的对数缩放形式。分贝用于更方便地表示非常大或非常小的数字,并用于描述信号的强度变化。
- 分贝与能量的关系:分贝是基于音频信号的能量或振幅的相对值,通过对数计算得出:
d B = 10 × log 10 ( E s i g n a l E r e f e r e n c e ) dB = 10 \times \log_{10}\Bigg( \frac{E_{signal}}{E_{reference}} \Bigg) dB=10×log10(EreferenceEsignal)
如果把能量换做为振幅:
d B = 20 × log 10 ( A s i g n a l A r e f e r e n c e ) dB = 20 \times \log_{10}\Bigg( \frac{A_{signal}}{A_{reference}} \Bigg) dB=20×log10(AreferenceAsignal)
其中 E s i g n a l E_{signal} Esignal是信号能量, E r e f e r e n c e E_{reference} Ereference是参考能量, A s i g n a l A_{signal} Asignal是信号振幅, A r e f e r e n c e A_{reference} Areference是参考振幅。
3.两者的区别
-
本质区别:音频能量是一个物理量,表示声音信号中实际携带的功率或强度;分贝则是一个相对量,用对数方式表示音频能量与某个参考值的比值。
-
单位不同:音频能量可能有具体的物理单位(如瓦特、焦耳),而分贝没有单位,它是两种能量之间的对数比例。
-
线性 vs 对数:音频能量是线性变化的(能量值可以直接累加),而分贝是对数变化的(增减6 dB表示能量变化一倍)。
4. 应用场景
音频能量:在实际计算音频信号的物理功率或存储、传输音频信号时,直接使用音频能量。它可以用于描述音频信号的功率输出、能量消耗等。
分贝:用于方便地表示音频信号的相对强度,特别是在处理范围非常广的信号时(如从微弱信号到非常强的信号)。分贝广泛应用于音频工程和声音的感知描述中,如声压级、信号增益等。
二、分贝的计算方式
1.具体数学公式
在实际数字信号中,计算声音的dB往往计算的不是某一个具体的时间点上样本的dB,而是一段时间上所有样本的均值。
而这个均值很多博主写的完全就是错误的,所以往往有很大误差:
- 错误做法:把一段时间的采样点值相加取平均
- 正确做法:通过计算信号各个样本平方的平均值,然后取平方根,得出信号的平均有效值
具体的数学公式为:
d B = 20 × l o g 10 ( R e f e r e n c e R M S R M S o f t h e s i g n a l ) dB=20×log_{10} \Bigg( \frac {Reference RMS} {RMS of the signal} \Bigg) dB=20×log10(RMSofthesignalReferenceRMS)
其中 R e f e r e n c e R M S R M S o f t h e s i g n a l 叫做 R M S ,信号强度的一个度量 \frac {Reference RMS} {RMS of the signal} 叫做 RMS,信号强度的一个度量 RMSofthesignalReferenceRMS叫做RMS,信号强度的一个度量计算方式为:
R M S = 1 N ∑ i = 1 N x i 2 RMS= \sqrt{ \frac{1}{N}\sum_{i=1}^{N}x_i^2} RMS=N1i=1∑Nxi2
2.具体算法示例
假设现在PCM为16k short 单通的:
cpp
#include <stdint.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
int pcm_db_count(const unsigned char* ptr, size_t size) {
if (size == 0 || ptr == NULL) {
return -96; // Handle empty or invalid input
}
int16_t value;
double sum_squares = 0.0;
for (size_t i = 0; i < size; i += 2) {
// Read 16-bit PCM value from the byte array
memcpy(&value, ptr + i, sizeof(value));
// Handle endianess if needed
// value = (int16_t)ntohs((uint16_t)value); // Convert from network to host byte order
sum_squares += value * value;
}
// Calculate RMS
size_t num_samples = size / 2;
double rms = sqrt(sum_squares / num_samples);
// Convert RMS to dB
int ndb;
if (rms > 0) {
ndb = (int)(20.0 * log10(rms / 32768.0)); // 32768.0 for 16-bit PCM
} else {
ndb = -96; // Define a suitable low value for silence or very low levels
}
return ndb;
}
3.对于算法的释义
大小端
这里value = (int16_t)ntohs((uint16_t)value);
如果使用的是pcm是大端排列,需要进行大小端转换。
为什么通过计算得到的是负值
在分贝公式中,log10 函数会计算信号与参考值的比例。如果信号的幅度 小于参考值,结果就是负数。这是因为:
- 当振幅较小时,信号强度 rms 远小于最大值 32768,例如信号振幅为 1000 时:
d B = 20 × log 10 ( 1000 37268 ) ≈ 30 d B dB= 20 \times \log_{10} \big( \frac{1000}{37268} \big) \approx 30dB dB=20×log10(372681000)≈30dB
- 当信号振幅很低时,例如靠近零(接近静音),dB 值会更小,甚至接近负无穷,所以我们用 − 96 d B -96dB −96dB来表示
范围
在实际医学中,分贝当然是越大才表示声音越大
- 人正常说话的声音,一般是在40-60分贝。
- 在低声细语地说话时,一般处于30分贝左右
- 在大声说话或者吵架的时候,会高达60-70分贝
- 若在过于嘈杂的环境中,可能会达到100分贝左右。
而在我们算法中
- 人声的正常分贝范围:通常在 -30 dB 到 -10 dB 之间。
- 正常对话:约 -25 dB 到 -15 dB。
- 轻声或远距离人声:约 -35 dB 到 -20 dB。
- 大声说话或近距离录音:约 -10 dB 到 -5 dB。
实际结果
下图是每10ms打印
总结
- RMS 是计算信号强度的基础,表示信号的均方根值,是一种 绝对强度 的度量。
- 信号振幅与参考振幅的比值 是用来计算分贝的,它衡量信号相对于参考值的强度,并通过对数缩放表示为分贝(dB)。
- 音频能量:描述声音信号的实际强度,通常与振幅平方相关,表示声音信号中的物理功率。
- 分贝:是一种对数单位,用于表示相对音频强度或能量,便于描述信号的增减和相对变化。
如果对您有帮助,请帮忙点个赞吧