📄 decode_4_21.c
字号:
#include <stdio.h>
#include "config.h"
extern unsigned short int received[size_rcpc];//引用在main函数中写入的接收端接收到的序列。
extern unsigned short int a[3][period];//引用一个选取的删除图形
void decode()
{
unsigned short int code[64][3]={{0,0,0},{1,1,1},{1,1,0},{0,0,1},{1,1,1},{0,0,0},{0,0,1},{1,1,0},{1,0,1},{0,1,0},{0,1,1},
{1,0,0},{0,1,0},{1,0,1},{1,0,0},{0,1,1},{0,1,0},{1,0,1},{1,0,0},{0,1,1},{1,0,1},{0,1,0},{0,1,1},{1,0,0},{1,1,1},{0,0,0},
{0,0,1},{1,1,0},{0,0,0},{1,1,1},{1,1,0},{0,0,1},{0,0,1},{1,1,0},{1,1,1},{0,0,0},{1,1,0},{0,0,1},{0,0,0},{1,1,1},{1,0,0},
{0,1,1},{0,1,0},{1,0,1},{0,1,1},{1,0,0},{1,0,1},{0,1,0},{0,1,1},{1,0,0},{1,0,1},{0,1,0},{1,0,0},{0,1,1},{0,1,0},{1,0,1},
{1,1,0},{0,0,1},{0,0,0},{1,1,1},{0,0,1},{1,1,0},{1,1,1},{0,0,0}};
//用于存放从状态0->状态1->状态2->状态3->状态4------>状态63时,所产生的编码表,具体见本函数最后的注释
unsigned short int mettab[2][2]={0,1,1,0};
//这个表是为了计算度量的方便,
//mettab[0][0]=0, mettab[0][1]=1,
//mettab[1][0]=1, mettab[1][1]=0
unsigned short int branch_metric[2]={0};
//计算在当前状态下,输入为0或1时,理论输出的码字与接收到的码字之间的汉明距离
unsigned short int path_metric[64]={0};//保存每条路径的汉明距离总和,最多有效的路径为64条。
unsigned short int temp[64]={0};//暂时保存路径度量
unsigned long int path[64]={0};//记录下进入当前状态的路径。路径长度为32个比特,即可保存32级译码,以便回溯,译码输出。
unsigned long int temp_path[64]={0};//暂时保存路径
unsigned short int min_metric=0;//最终输出的所有路径中最小的汉明距离
unsigned short int i,j,k;//循环变量i,j。k为回溯时暂存数值j
unsigned short int *p,*q;
unsigned short int decode[length]={0};//译码输出,以每个数组元素对应received中相应的数组元素。
unsigned short int out0,out1,out2;//在译码时判断接收到的码字,哪几个是由同一个信息码编码而成的。
unsigned short int weight1=0,weight2=0;
p=decode;//将指针初始化,指向输出的最终译码序列
q=received;//初始化指针
printf("this is the RCPC decode:\n");
/************************************************************************************************************
以下这个循环主要是实现由状态0开始的最初的6级译码。
这个时候状态数呈2的指数形式递增,即状态数为2,4,8,16,32,64
而且此时每个状态都只有一个支路进入,而有两个支路出去
*************************************************************************************************************/
for(i=0;i<6;i++)//记录前六级的路径
{
/*=====================================这个部分是将接收到的比特流分组=============================*/
weight1=a[1][i%period];//i%period体现了RCPC删除图形的周期性,记录第二个加法器的权重
weight2=a[2][i%period];//记录第三个加法器的权重
out0=*q;q++;//根据RCPC的删除图形,我们可以知道第一个加法器的输出是全部保留的。
if(weight1==1)//判断编码时对第二加法器的编码是否进行删除
{out1=*q;q++;}
if(weight2==1)//判断编码时对第三加法器的编码是否进行删除
{out2=*q;q++;}
/*================================================================================================*/
for(j=0;(j<(2<<i));j++)
{
branch_metric[j%2]=mettab[code[j][0]][out0]+weight1*mettab[code[j][1]][out1]+weight2*mettab[code[j][2]][out2];
//计算当前状态下0或1支路的度量。j%2表示了0或1支路;code[j][*]表示了从状态j/2--->状态j的编码。
//对mettab查表后的值乘以权重a[*][i%period]。
//例如:假如当a[1][i%period]=0时,对应的第2个加法器的度量就不做计算;若a[1][i%period]=1时,对应的第2个加法器的度量就需算作计算,
temp[j]=path_metric[j];//暂存需要改变的度量值
path_metric[j]=temp[j/2]+branch_metric[j%2];//使用蝶形算法计算度量。
path[j]=j;//记录支路的路径,前6级的路径和当前状态密切相关。
}
}
/********************************************************************************************************************
蝶形算法的介绍
(1) 编码器共有64 种状态,分成状态i (0 <=i<=31,下面均做此假设) 和状态i+32的上下两部分。
(2) 编码器当前状态为i或i+32时,输入为0 时,下一状态均为2*i 。
(3) 编码器当前状态为i 或i+32 时,输入为1 时,下一状态均为2*i+1 。
(4) 编码器当前状态为i ,输入为0 时,若输出为out0 ,则编码器当前状态为i+32 ,输入为0 时,输出为7^out0 。
(5) 编码器当前状态为i ,输入为1 时,若输出为out1 ,则编码器当前状态为i + 32 ,输入为1 时,输出为7^out1 。
*******************************************************************************************************************/
/*******************************************************************************************************************
以下这个循环是实现从第7级开始译码,这个时候,状态保持在64个,每个状态都有两个支路进入,也有两个支路出去。
每次译码时都要进行加-比-选的操作。
同时在这个循环中还考虑到了,path[]路径记录是否已满的情况:
如果满了,则译一个码,就回溯路径输出1个码字至decode[];
未满,就继续记录路径
********************************************************************************************************************/
for(i=6;i<length-6;i++)//减6是因为接收到的序列有6个码字为填充位,这些填充位是已知的,假定为0
{
if(i>=32)//判断路径记录是否已满。若已满,则回溯路径
{
/*下述两步是假定path_metric[0]最小时,输出path[0]最早记录的1位至decode*/
min_metric=path_metric[0];
*p=(path[0]&0x80000000)>>31;
/*以下这个循环是查找在path_metric中是否还有更小的度量值,如果有赋值给min_metric*/
for(j=0;j<64;j++)
{if(min_metric>path_metric[j])
{ min_metric=path_metric[j];
k=j;//暂存数值j
}
*p=(path[k]&0x80000000)>>31;//输出最后找到的最小度量所对应路径中最早记录的1位至decode
}
p++;
}
/*=====================================这个部分是将接收到的比特流分组=============================*/
weight1=a[1][i%period];//i%period体现了RCPC删除图形的周期性,记录第二个加法器的权重
weight2=a[2][i%period];//记录第三个加法器的权重
out0=*q;q++;//根据RCPC的删除图形,我们可以知道第一个加法器的输出是全部保留的。
if(weight1==1)//i%period体现了RCPC删除图形的周期性,判断编码时对第二个加法器的编码是否进行删除
{out1=*q;q++;}
if(weight2==1)//判断编码时对第三个加法器的编码是否进行删除
{out2=*q;q++;}
/*================================================================================================*/
/*===============以下这个循环是viterbi译码中的核心单元,加—比—选,记录路径========================*/
for(j=0;j<64;j++)
{branch_metric[0]=mettab[code[j][0]][out0]+weight1*mettab[code[j][1]][out1]+weight2*mettab[code[j][2]][out2];//记为支路0的度量
branch_metric[1]=mettab[code[j][0]][out0]^1+weight1*(mettab[code[j][1]][out1]^1)+weight2*(mettab[code[j][2]][out2]^1);//记为支路1的度量
temp[j]=path_metric[j];
temp_path[j]=path[j];
if(branch_metric[0]<branch_metric[1])//如果支路0度量小于支路1度量,即从0-31状态过来的理论译码与接收到序列的汉明距离更小
{path_metric[j]=temp[j/2]+branch_metric[0];//进入状态j的路径度量
path[j]=(temp_path[j/2]<<1)+j%2;//进入状态j的路径,这个路径是包括前6级输入的
}
else//如果支路1度量小于支路0度量,即从32-63状态过来的理论译码与接收到序列的汉明距离更小
{k=j/2+32;
temp[k]=path_metric[k];
temp_path[k]=path[k];
path_metric[j]=temp[k]+branch_metric[1];
path[j]=(temp_path[k]<<1)+j%2;
}
}
}
/***************************************************************************************************************
以下这个部分是当接收到的序列已读取完毕,只剩下最后补上的已知的6个0 bits序列时,通过加-比-选法则来最后将路径
收敛的过程。
收敛如下:
i=0时: i=1时:
状态0,状态32--->状态0, 状态0,状态32--->状态0,
状态1,状态33--->状态2, 状态2,状态34--->状态4,
状态2,状态34--->状态4, 状态4,状态36--->状态8,
…… ……
状态32,状态63--->状态62, 状态30,状态62--->状态60,
依此类推得到最后收敛至状态0。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -