一、实验原理
MPEG-1音频编码器框架图
- 多相滤波器组:用来分割字带,将PCM样本变换到32个子带的频域信号。如果输入的采样频率为48kHz,那么子带的频率宽度为48/(2*32)=0.75Hz。
- 心理声学模型:计算信号中不可听觉感知的部分,计算噪声遮蔽效应。
分为生理(Physiological )感知极限(传感极限)和 心理 (Psychological )感知极限 (信号处理极限)
①将样本变换到频域
32个等分的子带信号并不能精确地反映人耳的听觉特性。引入FFT补偿频率分辨率不足的问题。
②确定声压级别
子带n中的声压级别Lsb计算如下:
③考虑安静时阈值
也即绝对阈值。在标准中有根据输入PCM信号的采样率编制的“频率、临界频带率和绝对阈值”表。此表为多位科学家经多次心理声学实验所得。
④将音频信号分解成“乐音(tones)” 和“非乐音/噪声”部分:因为两种信号的掩蔽能力不同。
⑤音调和非音调掩蔽成分的消除
利用标准中给出的绝对阈值消除被掩蔽成分;考虑在每个临界频带内,小于0.5Bark的距离中只保留最高功率的成分
⑥单个掩蔽阈值的计算
音调成分和非音调成分单个掩蔽阈值根据标准中给出的算法求得。
⑦全局掩蔽阈值的计算
还要考虑别的临界频带的影响。一个掩蔽信号会对其它频带上的信号产生掩蔽效应。这种掩蔽效应称为掩蔽扩散。
⑧每个子带的掩蔽阈值
- 选择出本子带中最小的阈值作为子带阈值。
- 对高频不正确——高频区的临界频带很宽,可能跨越多个子带,从而导致模型1将临界带宽内所有的非音调部分集中为一个代表频率,当一个子带在很宽的频带内却远离代表频率时,无法得到准确的非音调掩蔽值。但计算量低。
⑨计算每个子带信号掩蔽比
SMR = 信号能量 / 掩蔽阈值,并将SMR传递给编码单元。
- 比特分配器(Bit Allocator):根据心理声学模型的计算结果,为每个子带信号分配比特数。
- 在调整到固定的码率之前 先确定可用于样值编码的有效比特数这个数值取决于比例因子、比例因子选择信息、比特分配信息以及辅助数据所需比特数。
- 比特分配的过程:对每个子带计算掩蔽-噪声比MNR,信噪比SNR–信掩比SMR, 即:MNR = SNR–SMR。
使整个一帧和每个子带的总噪声-掩蔽比最小。这是一个循环过程,每一次循环使获益最大的子带的量化级别增加一级,当然所用比特数不能超过一帧所能提供的最大数目。第1层一帧用4比特给每个子带的比特分配信息编码;而第2层只在低频段用4比特,高频段则用2比特。
- 装帧(Frame Creation):产生MPEG-I兼容的比特流
- 层 I 每帧含384个样本数据。每帧由32个子带分别输出
的12个样本值组成。 - 层 II 每帧包含1152个样本。低、中、高频段对比特分
配不同,分别用4、3、2比特。比特流中增加了一个比
特因子选择信息域,解码器根据这个域的信息可知道
是否需要以及如何共享比例因子。
二、实验内容
- 实验要求(基本)
- 理解程序设计的整体框架
- 理解感知音频编码的设计思想
- 两条线
- 时-频分析的矛盾!
- 理解心理声学模型的实现过程
- 临界频带的概念
- 掩蔽值计算的思路
- 理解码率分配的实现思路
- 输出音频的采样率和目标码率
- 选择三个不同特性的音频文件
- 噪声(持续噪声、突发噪声)
- 某个数据帧,输出
- 该帧所分配的比特数
- 该帧的比例因子
- 该帧的比特分配结果
- 关键代码
采样率和目标码率:
①该帧所分配的比特数
int main (int argc, char **argv)
{
、、、
int i,j,k;
、、、
FILE* OUTFile;
OUTFile = fopen("outfile.txt","w");
、、、
if(frameNum==2)
{
fprintf(OUTFile, "第 %d 帧\n", frameNum);
fprintf(OUTFile,"可用比特数:%d\n",adb);
}
}
②该帧的比例因子
if(frameNum==2)
{
fprintf(OUTFile,"比例因子为:\n");
for(i=0;i < nch ; i++)
{
fprintf(OUTFile,"声道[%d]:\n",i+1);
for(j=0;j<frame.sblimit;j++)
{
fprintf(OUTFile,"子带[%d]: ",j+1);
for(k=0;k<3;k++)
{
fprintf(OUTFile,"%d\t",scalar[i][k][j]);
}
fprintf(OUTFile,"\n");
}
}
}
③输出比特分配结果
if(frameNum==2)
{
fprintf(OUTFile, "\n比特分配\n");
for (k = 0; k < nch; k++)//声道
{
fprintf(OUTFile, "声道[%d]:\n", k + 1);
for (i = 0; i < frame.sblimit; i++)//每个子带有一个比特分配结果
{
fprintf(OUTFile, "子带[%d]:\t", i+1);
fprintf(OUTFile, "%d\n", bit_alloc[k][i]);
}
}
}
三、实验结果