基于c++的通信系统仿真--pcm编码与解码

版权声明:转载请标明链接, https://blog.csdn.net/qq_43433255/article/details/88138627

本次是基于c++的通信系统,系统实现的是能对输入的将要编码的值,采用A律13折线进行pcm编码与解码。

Pcm的编码与解码采用的是A律13折线,正负各有8段,每段内有16个量化级,共有2816=2^8=256个量化级,因此所需编码位数N=8,这8位编码的安排如下:
C1 C2C3C4 C5C6C7C8
极性码 段落码 段内码
极性码C1表示样值的极性。规定正极性为“1”,负极性为“0”。
段落码C2C3C4表示样值幅度所处的段落。3位端落码的8种可能状态对应8个不同的段落,如表10-5所示:
在这里插入图片描述

段内码C5C6C7C8的16种可能状态对应各段内的16个量化级,见表10-6。编码器将根据样值幅度所在的段落和量化级,编出相应的幅度码。
在这里插入图片描述

为了确定样值的幅度所在的段落和量化级,必须知道每个段落的起始电平和各段内的量化间隔。在A律13折线中,由于各段长度不等,因此各段内的量化间隔也是不同的。第一段、第二段最短,只有归一化值的1/128,再将它等分16级,每个量化级间隔为
^=1/128*(1/16)=1/2048
式中,^
表示最小的量化间隔,称为一个量化单位,它仅有输入信号归一化值的1/2048。第八段最长,它的每个量化级间隔为(1-1/2)*(1/16)=1/32=64^
即包含64个最小量化间隔。若以^
为单位,则各段的起始电平Ii和各段内的量化间隔^Vi如表10-7所示:
在这里插入图片描述

以上是非均匀量化的情况。若以^
为量化间隔进行均匀量化,则13折线正极性所包含的均匀量化级数分别为16、16、32、64、128、 256、 512、 1024,共计2048=2^11个量化级或量化电平,需要进行11位(线性)编码。而非均匀量化只有128个量化电平,只要编7位(非线码)。由此可见,在保证小信号量化间隔相同条件下,非均匀量化的编码位数少,所需传输系统宽带减小。

总体代码的思路:

第一,输入幅度,确定pcm码组的极性码C1;文本result写入1或者0;去掉符号。
第二,因为段落码有3位,采用逐次比较的方法,确定每一位码的值,文本result在第一步的基础上继续写入1或者0,通过循环实现(C2C3C4)。
第三,通过第二步骤得到相应量化级数,用来确定对应的段落起始电平与量化间隔。
第四,将输入的值与Iw4、 Iw5、Iw6、Iw7依次比较,通过循环得到相应的码值(C5C6C7C8),而result在第二步骤上的基础继续添加1或者0;此步骤结束后,就可以得到相应pcm码组。
第五,计算相对于的编码后的误差,通过除二取余得到11位线性码,译码的值,以及译码后的误差。
总之,这五个步骤在主函数中,通过调用函数实现上述功能。

定义数组,用来存放相关的内容,以便通过比较确定对应的pcm码值:

#define N 7
int parCode[N] = { 16,32,64,128,256,512,1024 };//通过数组,用来确定段落码
int parInsideCode[N + 1] = { 1,1,2,4,8,16,32,64 };   //段内量化间隔
int parInsideSart[N + 1] = { 0,16,32,64,128,256,512,1024 };    //段落起始电平

parJudge函数用来确定段落码,通过逐次比较得到

void parJudge(string &result, int testNum)//确定段落码
{
int low = 0, high = N, mid;
for (int i = 0; i < 3; i++)
{
mid = (low + high) / 2;     //逐次比较,判断段落码为1或者0
//cout << mid;
if (testNum >= parCode[mid])
{
result = result + '1';
low = mid + 1;
flag = mid;
}
else
{
result = result + '0';
high = mid - 1;
flag = mid - 1;
}
}
}

parInsideJudge函数用来确定段内码,通过逐次比较得到

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;
}
}
}

change函数用来确定11线性码,通过除二取余得到,考虑到除二取余方法的特殊性,这里用了两个数组,第一个数组是依次写入,而第二个数组只需要将第一个数组的顺序颠倒一下,就能得到11位线性码。

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';
}

Main函数编码部分通过调用不同的函数,实现不同的功能。解码通过数组来实现。

int main()

{
int testNum,xuanz;
while (1) {
cout << "欢迎来到pcm编码与解码程序\n";
cout << "1、pcm编码码程序\n";
cout << "2、pcm解码程序\n";
cout << "\n";
cout << "请输入你的选择:";
cin >> xuanz;
if (xuanz == 2)
{
int i, j, m, n = 16, k, y;
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;
cout << "输入编码的值:" << y << endl;
}
else if(xuanz == 1)
{
cout << "请输入编码的值: ";
cin >> testNum;   // 死循环实现




string result;        //字节用来得到编码出来的pcm码组

cout << "信号的采集值: " << testNum << endl;

if (testNum < 0)

result = result + '0';

else

result = result + '1';

testNum = fabs(testNum);//去符号
//cout << "去符号后: " << testNum;

parJudge(result, testNum);//判断段内码

//处理段内码

int parSeq = flag + 1;       //量化间隔级数
//cout << parSeq;

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 < N + 1; 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;
}

在代码运行过程中,最开先能编码出来,之后添加各种功能(比如:11位线性码)的时候就会出现一些问题,通过断点以及在关键代码出输出相关的内容,来确定问题的出现之处。

实验的结果:
在这里插入图片描述在这里插入图片描述

再次验证:
在这里插入图片描述

在pcm编码与解码的设计实验中,首先,要读懂A律13折线pcm编码的原理,
解决了相关原理后,就是代码的设计,按照原理的理解,以及将要实现功能,来设计相应的代码。按照课程设计的要求,只要能做出相应的解码与编码就可以了。

猜你喜欢

转载自blog.csdn.net/qq_43433255/article/details/88138627