音频能量计算:RMS和dB
admin
2023-06-20 08:01:41
0

麦克风采集时,界面上经常有个麦克风能量条,用来实时显示采集的音频能量大小。

而一般采集到的音频数据都是PCM格式,也就是说我们需要将PCM的赋值转换成 dB。

##################

1. RMS:均方根(Root Mean Square)

即:将N个项的平方和除以N后开平方的结果,即均方根的结果。


##################

2. dB:分贝

定义:为两个数值的对数比率,这两个数值分别是测量值和参考值(也称为基准值)。存在两种定义情况。


一种为功率之比:

dB = 10lg(Wn/W0)


一种为幅值之比:

dB = 10lg(Xn/X0)^2 = 20lg(Xn/X0)


PS:下标为0的数值均为幅值和功率的参考值。

功率量的例子如:声功率(W),声强(W/m^2),电功率,电强等。

幅值量的例子如:声压(Pa),电压(V),加速度(m/s^2),温度等。

但有一点要注意对于场量的幅值应该是 RMS 值,如声压场


因为分贝值完全依赖于测量值与参考值之比,因此,计算时选择合适的参考值尤为关键。

当测量结果相互比较时,这一点非常重要,选择的参考值不同,计算结果肯定不一样。


##################

3. PCM的幅值转dB

n个样本:x1、x2、...、xn
参考值:x0 (一般是幅值范围的极限值:比如 s16_LE 的参考值就是 32768.0 = 2^15)

理解一:
RMS = { (x1^2+x2^2+...+xn^2)/(n * x0^2) }^0.5
(除 x0^2 原因:Normalize by the max level.归一化)
dB = 20lg(RMS) = 10lg{(x1^2+x2^2+...+xn^2)/(n * x0^2)}

理解二:
RMS = { (x1^2+x2^2+...+xn^2)/n }^0.5
dB = 20lg(RMS/x0) = 10lg{(x1^2+x2^2+...+xn^2)/(n * x0^2)}


##################

4. dB转界面上麦克风能量条数值

映射
dB ——————————> power
[-127,0] [0~31] (或 [0,100])

dB: 前面第3步计算出的响度
power: 能量条数值

power = A + B*dB
(一把采用线性映射,且保证二者是正相关关系,即 dB越大,power就越大)

dB取值范围一般限制为[-127,0],而能量条的取值范围是[0~31] (或 [0,100])

因此需要一个映射关系将 dB 映射成 能量条数值


例如下面的映射关系:

u32 DBtoPower(double dB)
{
if (dB > 0)
{
dB = 0;
}
else if (dB < -127)
{
dB = -127;
}

u32 dwRmsPower = static_cast(dB + 0.5);

s32 dwPower = 42 - (dwRmsPower * 2 / 3); //此处的 42 和 2/3 就是映射参数
if(dwPower > 31)
{
dwPower = 31;
}
else if(dwPower < 0)
{
dwPower = 0;
}
return dwPower;
}

##################

5. 如果采集声音过小,可以增加一个固定的线性增益来放大声音

比如说,麦克风采集的声音过小,那么就增加一个固定的线性增益值 GaindB

raw-dB = 20lg(Xn/X0) //原始采集样本的响度:raw-dB

GaindB = 20lg(Gain) //用户设置的已知固定增益值:GaindB

根据上面两个公式,推导出:

new-dB = GaindB + raw-dB = 20lg{(Gain*Xn)/X0}

所以我们只要将 采集样本的幅值 Xn 放大 Gain 倍,就能实现增益 GaindB

所以我们需要根据固定增益值 GaindB 计算出样本幅值放大倍数 Gain

Gain = 10^( GaindB / 20 )

/** 固定增益处理(输入输出buf可以相同)(适用 S16_LE)
* 参数1:增益值 dB
* 参数2:样点数
* 参数3:输入buf
* 参数4:输出buf
* 返回值:错误码
*/
int LinearGain(float GaindB, int FrameLen, short *InFrameData, short *OutFrameData)
{
int j;
float Gain;
float Data;

GaindB = (GaindB < 0 ? 0 : (GaindB > 50? 50 : GaindB)); //限制设置的固定增益值范围[0,50]
Gain = powf(10.0, (GaindB / 20.0)); //将固定增益GaindB 转换成样本幅值的放大倍数Gain

for (j = 0; j < FrameLen; j++)
{
Data = InFrameData[j] * Gain; // 通过放大幅值来实现 固定线性增益
Data = (Data < -32767.5f ? -32768 : (Data > 32766.5f ? 32767 : Data));
OutFrameData[j] = (short)Data;
}

return 0;
}

相关内容