基于C/C++的PCM编码与解码简单实现

基于C/C++的PCM编码与解码简单实现

PCM原理:

将模拟信号变换成二进制信号的方法称为脉冲编码调制(PCM),目前,它不仅应用于通信领域,还广泛应用于计算机、遥控遥测、数字仪表等许多领域。在这些领域中,常将其称为模拟/数字(A/D)转换。PCM系统原理框图如下:

在这里插入图片描述
在发送端对输入的模拟信号m(t)进行抽样、量化、编码。编码后的PCM信号是一个二进制数字序列,其传输方式可以采用数字基带传输,也可以是对载波调制后的带通传输。在接收端,PCM信号经译码后还原为量化值序列,但是具有一定的误差,再经低通滤波器滤除高频分量,便可得到重建的模拟信号m(t)。
脉冲编码调制主要经过3个过程:抽样、量化和编码。抽样过程将连续时间模拟信号变为离散时间、连续幅度的抽样信号,量化过程将抽样信号变为离散时间、离散幅度的数字信号,编码过程将量化后的信号编码成为一个二进制码组输出。所谓量化,就是把经过抽样得到的瞬时值将其幅度离散,即用一组规定的电平,把瞬时抽样值用最接近的所谓编码,就是用一组二进制码组来表示每一个有固定电平的量化值。

编码的实现是由编码器完成的,PCM编码器有很多种类型,比较常用的是逐次比较型编码器,其原理方框图如下:在这里插入图片描述

该编码器的任务是把输入的每个样值脉冲编出相应的8位二进制码,除第一位极性码外,其余7位幅度码是通过逐次比较确定的。
(1)极性判决电路:用于确定样值信号的极性,编出极性码C1。
(2)整流器:将双极性的样值信号变成单极性信号。
(3)电路:使每个样值电流的幅度在7次比较编码中保持不变。
(4)比较器:通过对样值电流和标准电流的比较,实现对输入信号抽样值的非线性量化和编码。
(5)记忆电路:用来寄存前面编出的码。
(6)7/11变换电路:将7位非线性码转换成11位线性码。

编码、译码计算过程

编码:
首先判断极性码,正取1,为负则取0;然后写一个函数用来判断段落码,通过二分法逐步与各个标准电平比较,比标准电平大则取1,反之取0;然后再写一个函数确定段内码,同样是利用二分法。
译码:
输入要译码的PCM码组后,通过第一位确定电平的极性,C1=1则为正,C1=0则为负;然后通过C2C3C4确定所处段落以确定起始电平和量化间隔;最后通过C5C6C7确定所处的段内量化间隔级数。得到的结果再加上二分一量化间隔就得到最终的译码电平。
#include
#include
using namespace std;
int parCode[7] = { 16,32,64,128,256,512,1024 };//通过数组,用来确定段落码
int parInsideCode[8] = { 1,1,2,4,8,16,32,64 }; //段内量化间隔
int parInsideSart[8] = { 0,16,32,64,128,256,512,1024 }; //段落起始电平
int flag;
void parJudge(string &result, int testNum) { //确定段落码,&表示引用实参
int low = 0, high = 7, mid;
for (int i = 0; i < 3; i++) {
mid = (low + high) / 2; //逐次比较,判断段落码为1或者0
if (testNum >= parCode[mid]) {
result = result + ‘1’;
low = mid + 1;
flag = mid;
} else {
result = result + ‘0’;
high = mid - 1;
flag = mid - 1;
}
}
}
void parInsideJudge(string &result, int testNum, int parStart, int parSpace) { //确定段内码
int low = 0, high = 17, mid = 8;
for (int i = 0; i < 4; i++) {
int cost = parStart + parSpace * mid; //段落起始电平+量化间隔*序列号
if (cost > testNum) {
result = result + ‘0’;
high = mid;
mid = (low + high) / 2;
} else {
result = result + ‘1’;
low = mid;
mid = (low + high) / 2;
}
}
cout<<“所处的量化级为:”<<mid<<endl;
}
void change(int x) {
//程序功能:将十进制整数转换为二进制数,输出11位线性码
int n = 0; //x为输入的整数
int i = 10; //n为每次x%2取得的余数
int j = 0; //i为整型数组长度减一
int a[11];
for (int i = 0; i < 11; i++) {
a[i] = 0; //数组初始值为0
}
if (x < 0) {
x = -x;
j = 1;
}
while (x > 0.5) { // 除二取余
n = x % 2;
x = (x - n) / 2;
a[i] = n;
i = i - 1;
}
for (int k = 0; k < 11;) {
for (int l = 0; l < 11; l++) { //输出11位线性码
cout << a[k];
k++;
}
if (k != 11) {
cout << " “;
}
}
cout << ‘\n’;
}
int main()
{
int testNum,xuanz;
while (1) {
cout << “1.pcm编码\n”;
cout << “2.pcm解码\n”;
cout << “请输入你的选择:”;
cin >> xuanz;
if (xuanz == 2) {
int i, j, m, n = 16, k, y;//n表示段落起始电平
int a[8] = { 0 };
for (i = 0; i < 8; i++) {
cout << “请输入PCM编码a[” << i << “]:”;
cin >> a[i];
}
m = a[1] * 4 + a[2] * 2 + a[3];//段落序列号
i = m;
if (m == 0)
n = 0;
else {
while (–i)
n = n * 2;
}
k = a[4] * 8 + a[5] * 4 + a[6] * 2 + a[7];
if (m <= 1)
y = n + k * 2 + 1;
else
y = n + k * n / 16 + n / 32;
if (a[0] == 0)
y = -y;
if(m>=1)
cout<<“该编码处于第”<<m+1<<“段,段落起始电平为”<<parCode[m-1]<<”,段内量化间隔为:"<<parInsideCode[m]<<endl;
if(m=0)
cout<<“该编码处于第”<<m+1<<“段,段落起始电平为”<<0<<",段内量化间隔为:"<<parInsideCode[m]<<endl;
cout<<“所处量化级序号为第”<<k<<“级”<<endl;
cout << “输入编码译码后的值:” << y << endl;
} else if(xuanz == 1) {
cout << "请输入编码的值: ";
cin >> testNum;
string result; //字节用来存储编码出来的pcm码
if (testNum < 0) //判断极性码
result = result + ‘0’;
else
result = result + ‘1’;
testNum = fabs(testNum);//去符号
parJudge(result, testNum);//确定段落码
int parSeq = flag + 1; //量化间隔级数
int parStart = parInsideSart[parSeq];//段落起始电平
int parSpace = parInsideCode[parSeq];//量化间隔
parInsideJudge(result, testNum, parStart, parSpace);
cout << "编译出来的pcm码组: ";
cout << result << endl;
int sum = 0;
int j, cvb, jyc, bmh;
for (j = 4; j < 8; j++)
if (result[j] == ‘1’)
sum = sum + pow(2, 7 - j);//确定量化级的序列号
cvb = fabs(parStart + sum * parSpace + parSpace / 2);//为了使量化误差小于量化间隔的一半,译码后的值应该加上量化间隔的一半
jyc = fabs(cvb - parSpace / 2); //7位非线性码编译的电平(除去极性码)
cout << “编码电平:” << jyc << endl;
bmh = fabs(testNum - jyc); //编码后的量化误差
cout << “编码后的量化误差:” << bmh << endl;
cout << “11线性码(pcm):”;
change(jyc);
int errorNum = fabs(cvb - testNum);//确保量化误差的值为正数
cout << “译码出来的值:” << cvb << endl;
cout << "译码后的量化误差: " << errorNum << endl;
cout << endl;
} else {
cout << “输入有误,请重新输入!\n”;
}
}
return 0;
}

运行结果

对1270进行编码:其PCM码组为11110011,量化电平(编码电平)为1216,量化误差为1270-1216=54,译码电平为1216+32=1248,译码后的量化误差为1270-1248=22,运行结果如下:
在这里插入图片描述
对01110011进行译码:极性码为0,代表该数值为负数,段落码为111,代表处于第8段,段落起始电平为1024,段内码为0011,表示处于序号为3的量化间隔内,所以1024+3*64=1216,再加上一半的量化间隔,所以译码电平为1216+32=1248,再把极性加上,最终的译码电平为-1248,运行结果如下:
在这里插入图片描述
这个实验只是PCM的一个简单实现编码和译码的过程,具体有些功能并没有实现,代码还有待完善。

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 实现基于Qt/C的音频转换程序可以使用Qt的多媒体框架和音频处理库。具体步骤如下: 1. 首先,选择Qt的多媒体框架,以便处理音频文件。可以在Qt Creator中创建一个基于Qt的桌面应用程序项目。 2. 在Qt的项目中引入Qt Multimedia库,该库提供了对音频的处理功能。可以通过在.pro文件中添加`QT += multimedia`来引入该库。 3. 在Qt的项目中创建一个界面,用于用户选择待转换的音频文件和转换参数。可以使用Qt的UI设计器来创建用户界面,例如添加文件选择按钮和转换按钮。 4. 当用户点击转换按钮时,程序将执行音频转换的操作。在转换操作中,首先需要读取待转换的音频文件。 5. 若要实现PCM到WAV的转换,需要将PCM音频数据封装为WAV文件格式。使用Qt的QAudioFormat类来设置WAV格式的音频参数,例如采样率、位深度等。 6. 创建一个QFile对象并打开一个.wave文件,在文件中写入WAV文件头部信息。 7. 读取PCM音频数据,并根据WAV的音频参数将数据写入.wave文件。 8. 如果需要实现WAV到PCM的转换,可以使用Qt的QAudioDecoder类来解码WAV文件,提取出PCM数据。 9. 在PCM互转WAV和位数转换的情况下,可以使用Qt的QAudioConverter类来实现。 10. 最后,将转换后的音频文件保存到指定位置。 以上就是基于Qt/C的音频转换程序的实现步骤。通过以上方法,可以轻松地实现PCM和WAV文件的互相转换和位数的转换。 ### 回答2: 基于QT/C的音频转换程序可以实现PCM格式音频文件与WAV格式音频文件的互相转换和位数转换。 PCM(脉冲编码调制)是一种无压缩的音频编码格式,它将模拟音频信号数字化,采样率和位深度可以自定义。WAV是一种开放的音频文件格式,常用于存储无压缩的音频数据。PCM转换为WAV格式可以使音频文件能够在各种播放器和设备中播放。 首先,程序需要读取PCM格式音频文件,并解析其采样率、位深度等参数。这些参数将在转换过程中用于重构WAV文件头。 接下来,程序根据WAV格式的规范,创建一个新的WAV文件,并将PCM音频数据写入。同时,需要根据PCM音频数据的位深度,进行相应的位数转换。例如,将16位的PCM音频数据转换为8位的WAV音频数据。 转换完成后,程序会保存新生成的WAV文件,该文件可以被各种音频播放器或设备直接播放。 同样地,该音频转换程序也可以将WAV格式音频文件转换为PCM格式。程序会读取WAV文件的文件头信息,并解析其中的采样率、位深度等参数。然后,程序将WAV文件中的音频数据进行位数转换,并写入一个新的PCM文件。 通过该基于QT/C的音频转换程序,我们可以方便地将PCM格式音频文件与WAV格式音频文件进行互相转换,同时实现位数转换。这样,我们就可以根据实际需求,对音频文件进行灵活的处理和使用。 ### 回答3: 基于Qt/C的音频转换程序可以实现PCM到WAV的互转,以及位数转换。PCM是一种原始的音频格式,而WAV是一种常用的音频文件格式。 PCM到WAV的转换可以通过读取PCM文件的原始数据,然后添加WAV文件头部信息的方式实现。WAV文件头部包含了音频的采样率、位数、通道数等信息。程序可以根据用户选择的参数生成WAV文件头部,并将PCM数据和WAV头部写入新的WAV文件。 位数转换可以将16位的PCM数据转换为8位的PCM数据,或者将8位的PCM数据转换为16位的PCM数据。转换过程中,将每个采样数据的位数进行缩放或扩展即可。程序可以根据用户选择的目标位数对PCM数据进行相应的位数转换,并将转换后的数据写入新的PCM文件或WAV文件。 在实现这个音频转换程序时,可以使用Qt的音频相关类库,如QAudioFormat和QAudioOutput来处理音频数据的读取和写入,以及音频文件格式的解析和生成。同时,还可以利用Qt提供的界面框架来设计一个简洁易用的用户界面,让用户可以方便地选择要转换的文件和转换参数。 总的来说,基于Qt/C的音频转换程序可以实现PCM到WAV的互转和位数转换功能,通过读取和处理音频数据,生成相应的音频文件。该程序可以提供一个用户友好的界面,让用户可以方便地操作和选择转换参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值