mpeg音频编码实验

MPEG音频编码实验

MPEG标准主要有以下五个,MPEG-1、MPEG-2、MPEG-4、MPEG-7及MPEG-21等。该专家组建于1988年,专门负责为CD建立视频和音频标准,而成员都是为视频、音频及系统领域的技术专家。及后,他们成功将声音和影像的记录脱离了传统的模拟方式,建立了ISO/IEC11172压缩编码标准,并制定出MPEG-格式,令视听传播方面进入了数码化时代。因此,大家现时泛指的MPEG-X版本,就是由ISO (InternationalOrganization for Standardization) 所制定而发布的视频、音频、数据的压缩标准。
下面介绍详细原理:

MPEG-1 Audio LayerII编码器原理

流程框图如下:
在这里插入图片描述

多相滤波器组

多相滤波器组(Polyphase Filter Bank),可以将PCM样本变换到32个自子带的频域信号。如果输入的采样频率为48kHz,子带的频带宽度就是48/2×32=0.75kHz
如图:
在这里插入图片描述
但其存在一定缺点:

  1. 等带宽的滤波器组与人类听觉系统的临界频带不对应。在低频区域,单个子带会覆盖多个临界频带。
  2. 滤波器组与其逆过程不是无失真的。
  3. 子带间频率有混叠

时-频分析的矛盾

32个子带样本在时域上的分析较为清晰,不能精确地反映人耳的听觉特性,且如果频域进行32点FFT,分辨率不高;而FFT也仍然存在问题,其只能说明哪些频率成分存在,不能说明这些频率成分在什么时间出现。

心理声学模型(Psychoacoustic Model)

通过子带分析滤波器组使信号具有高的时间分辨率,确保在短暂冲击信号情况下,编码的声音信号具有足够高的质量。又可以使信号通过FFT运算具有高的频率分辨率,因为掩蔽阈值是从功率谱密度推出来的。在低频子带中,为了保护音调和共振峰的结构,就要求用较小的量化阶、较多的量化级数,即分配较多的位数来表示样本值。而话音中的摩擦音和类似噪声的声音,通常出现在高频子带中,对它分配较少的位数。而如何实现这一分配方式,就需要参考心理声学模型和比特预算。
MPEG-1标准定义了两个模型:

  1. 心理声学模型1:计算复杂度低,对于假设用户听不到的部分压缩太严重。
  2. 心理声学模型2:提供了适合Layer III编码的更多特征

但实际实现的模型复杂度取决所需要的压缩因子。如大的压缩因子不重要,则可以完全不用心理声学模型。此时位分配算法不使用SMR(Signal Mask Ratio),而是使用SNR。

临界频带的概念

临界频带是指当某个纯音被以它为中心频率、且具有一定带宽的连续噪声所掩蔽时,如果该纯音刚好被听到时的功率等于这一频带内的噪声功率,这个带宽为临界频带宽度。

掩蔽值计算的思路

音频信号可以分解为乐音和噪声,两者共有四种掩蔽组合,即“乐音-乐音”、“乐音-噪声”、“噪声-乐音”、“噪声-噪声”。另有安静时的阈值为绝对阈值。

某一频率点i的总掩蔽阈值可通过该点的绝对掩蔽阈值与单独掩蔽阈值相加获得。

第一项为绝对阈值、第二项为乐音掩蔽、第三项为噪音掩蔽。

码率分配的思路

多相滤波器组用来分割子带
对各子带每12个样点进行一次比例因子计算,定出12个样点中绝对值的最大值。查比例因子表中比这个最大值大的最小值作为比例因子,用6bit表示。
确定可用于样值编码的有效比特数,对每个子带计算掩蔽-噪声比MNR。比特分配应使整个一帧和每个子带的总噪声-掩蔽比最小。

实验内容

在main函数中添加以下代码:

printf("采样频率为 %d kHz.\n 目标码率为 %d kbps. \n", header.sampling_frequency, bitrate[header.version][header.bitrate_index]);

可以看到输出音频的采样率和目标码率:
在这里插入图片描述

然后在main函数中添加以下代码:

 printf("输出的为第 %d 帧\n", frameNum); //输出数据帧
  printf("分配的比特数为 %d\n", adb);
  printf("比例因子为:\n");  //输出比例因子
  for (ch = 0; ch < nch; ch++) {
	  printf("通道%d\n", ch + 1);
	  for (int i = 0; i < frame.sblimit; i++) {
		  printf("子带%d:", i + 1);
		  for (int j = 0; j < 3; j++)
		  {
			  printf("%d\t", scalar[ch][j][i]);
		  }
		  printf("\n");
	  }
  }

	  if (frameNum == 10) {
		  printf("\n分配的bit数:\n");
		  for (int i = 0; i < nch; i++) {
			  printf("通道%d:\n", i + 1);
			  for (int j = 0; j < frame.sblimit; j++) {
				  printf("子带%d:%d\n", j, bit_alloc[i][j]);
			  }
		  }
	  }

可以看到输出某一帧分配的比特数、比例因子和比特分配结果
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考资料:

https://blog.csdn.net/weixin_45671402/article/details/125032289
https://blog.csdn.net/weixin_48930931/article/details/125426437

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值