Part 1.内容回顾
在《Polar SC的C语言实现之译码篇》中,我们讲解了使用二维数组对SC译码的方法,这种二维数组的方法与我们的编译码原理图相似,每个比特单元都有对应的二维坐标(数组),理解上很直观。但二维数组也有它的局限性:首先,它所消耗的内存明显比一维数组多;其次,当我们将SC程序改进为SCL译码程序时,就意味着要在数组本身的基础上再加一个维度,即二维数组要写成三维数组,而很多IDE会拒绝执行复杂度过高的程序片段,三维数组的使用正面临着这种风险,因此,我们需要将二维数组改写成更加轻便的一维数组。当然,改进也意味着算法会更加复杂,因此,我们要将这个译码图的理解从形象走向抽象。
Part 2.算法原理
我们以码长为4的SC为例,采用与SC译码方法做对比的方式进行讲解,如果对SC本身的译码方式不大了解,可以参考《Polar SC的C语言实现之译码篇》。
第一步,将
f
运算得到的LLR值存入一维数组的位置如下:
第二步,固定比特直接译为0,信息比特大于0译成0,小于0译成1,得到b值后进行
g
运算。
第三步,将一维数组得到的译码结果存入译码数组,然后计算用的数组进行异或运算得到内部LLR的b值。由于前两位的译码值已经得到并且存入了译码数组,因此,这两个计算单元已经可以空出来用于存储后面的b值。
第四步,
g
运算,然后
f
运算。注意,黄色部分的LLR在进行
g
运算后已无用处,因此可以放心利用它们的空间。值得注意的是,
f
运算得到的第三行LLR需要存入变量t中,然后用继续
f
运算、译码得到的译码值替代位置,之后的
g
运算则是以变量t与第四行的LLR为输入端、以第三位译码值为b值进行计算,计算结果按“固定比特直接译为0,信息比特大于0译成0,小于0译成1”的译码原则得到译码值(红色单元)。
同理,后面的计算也是以此类推的。
Part 3.代码实战
程序要求:写码长为16的SC译码,输入模拟信噪比(建议范围:1.5~3.5dB),程序按照比特的排列规则,随机生成一次码长为16的比特序列,模拟其经过编码、调制、受白噪声干扰,被接收后,将比特序列进行SC译码纠错,还原信息序列,返回给用户端。
输出显示:1.原码序列;2.译码序列; 3.比较原码与译码序列是否完全相同,完全相同,输出right;不完全相同,输出wrong。
除了算法原理所提到的LLR存储位置上的差别,其余程序算法与《Polar SC的C语言实现之译码篇》中相同,一维数组分为编码、译码两大类:编码数组包括原码数组与编码计算数组;译码数组包括浮点数、b值的计算数组,以及译码存储数组。出于数组种类比较多的缘故,我们将他们写入结构体当中,以便区分。完整程序如下:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>//种子随机数头文件
const int N=16;
const int n=5;
typedef struct Encode{
int code[N*2];//编码
}Encode;
typedef struct Decode{
float a[N*2];//浮点比特
int b[N];//b值
int LLR[N];//译码
}Decode;
Encode encode;
Encode *pE=&encode;
Decode decode;
Decode *pD=&decode;
float t;
int CBR[N]={0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1};
float add_gassrand(float EbNo);//加噪声函数
float gaussrand();//生成噪声函数
//译码函数声明************************************
float f(float Lin1,float Lin2);
float g(float Lin1,float Lin2,bool b);
inline void first_4(int i);
inline void function_back(int i,int v);
//************************************************
int main()
{
srand((unsigned)time(NULL));//设定种子随机数,使随机数随时间改变
int Vi,e,qq,ss,sum=0,s=0;
float EbNo;
printf("EbNo(dB):");
scanf("%f",&EbNo);
printf("\n");
for(Vi=0;Vi<N;Vi++)
{if(CBR[Vi])pE->code[Vi]=pE->code[Vi+N]=rand()%2;
//CBR数组中非0的元素是信息比特位,在对应行产生0或1的随机数
else pE->code[Vi]=pE->code[Vi+N]=0;
//固定比特位仍然为0
}
//编码部分
int h=N,y1,o;
for(y1=0;y1<n-1;y1++)
{
for(o=0;o<N;o=o+(2*N)/h)
{for(e=o;e<o+N/h;e++)
{pE->code[e+N]=pE->code[e+N]^pE->code[e+N+N/h]?1:0;}
}
h/=2;
}
//调制
for(y1=0;y1<N;y1++)
{pD->a[y1+N]=pE->code[y1+N]?-1.0:1.0;}
//加噪声
add_gassrand(EbNo);
//译码部分
int j,i,u=N,p=N;
for(j=n;j>0;j--)
{u/=2;
for(i=0;i<u;i++)
{pD->a[i+u]=f(pD->a[i+p],pD->a[i+u+p]);}
p/=2;
}
int password[7]={0,1,0,2,0,1,0};
int clue=0,clue0=0;
for(Vi=0;Vi<7;Vi++)
{
switch(password[Vi])
{
case 0:first_4(clue);clue+=4;break;
case 1:function_back(clue0,2);clue0+=8;break;
case 2:function_back(0,3);break;
}
}
//************************************************
//输出端
printf("原码序列:");
for(i=0;i<N;i++)printf("%d ",pE->code[i]);
printf("\n译码序列:");
for(i=0;i<N;i++)printf("%d ",pD->LLR[i]);
//判断正误
int w=0;
for(int i=0;i<N;i++)
{if(pE->code[i]^pD->LLR[i]){w++,s++;}
}
if(w)printf("\n结果:wrong\n");
else printf("\n结果:right\n");
return 0;
}
//译码函数****************************************
float f(float Lin1,float Lin2)
{float Lout,s,min;
int sign;
s=Lin1*Lin2;
if(s>0)sign=1;
else sign=-1;
min=fabs(Lin1)<=fabs(Lin2)?fabs(Lin1):fabs(Lin2);
Lout=sign*min;
return Lout;
}
float g(float Lin1,float Lin2,int b)
{float Lout;
Lout=pow((float)-1.0,b)*Lin1+Lin2;
return Lout;
}
inline void function_back(int i,int v)
{int u=(int)pow(2.0,v);
if(v==3){
for(int x=i;x<i+4;x++)
{pD->b[x]=pD->b[x]^pD->b[x+4]?1:0;}
}
for(int x=i;x<i+u;x++)
{pD->a[x+2*u]=g(pD->a[x+2*u],pD->a[x+3*u],pD->b[x]);
}
int p1=u,p2=0;
for(int j=v;j>0;j--)
{for(int x=i;x<i+p1/2;x++)
{pD->a[x+u+p1/2]=f(pD->a[x+2*p1+p2],pD->a[x+2*p1+p2+p1/2]);}
p2+=p1/2;
p1/=2;
}
}
inline void first_4(int i)
{if(!CBR[i])pD->b[i]=0;
else pD->b[i]=pD->a[i+1]>0.0?0:1;
pD->LLR[i]=pD->b[i];
pD->a[i+1]=g(pD->a[i+2],pD->a[i+3],pD->b[i]);
if(!CBR[i+1])pD->b[i+1]=0;
else pD->b[i+1]=pD->a[i+1]>0.0?0:1;
pD->LLR[i+1]=pD->b[i+1];
pD->b[i]=pD->b[i]^pD->b[i+1]?1:0;
t=pD->a[i+2]=g(pD->a[i+4],pD->a[i+6],pD->b[i]);
pD->a[i+3]=g(pD->a[i+5],pD->a[i+7],pD->b[i+1]);
pD->a[i+2]=f(pD->a[i+2],pD->a[i+3]);
if(!CBR[i+2])pD->b[i+2]=0;
else pD->b[i+2]=pD->a[i+2]>0.0?0:1;
pD->LLR[i+2]=pD->b[i+2];
pD->a[i+3]=g(t,pD->a[i+3],pD->b[i+2]);
if(!CBR[i+3])pD->b[i+3]=0;
else pD->b[i+3]=pD->a[i+3]>0.0?0:1;
pD->LLR[i+3]=pD->b[i+3];
pD->b[i+2]=pD->b[i+2]^pD->b[i+3]?1:0;
pD->b[i]=pD->b[i]^pD->b[i+2]?1:0;
pD->b[i+1]=pD->b[i+1]^pD->b[i+3]?1:0;
}
//噪声函数****************************************
float gaussrand()
{
static float V1,V2,S;
static int phase=0;
float X;
if (!phase)
{
do
{
float U1=(float)rand()/RAND_MAX;
float U2=(float)rand()/RAND_MAX;
V1=2*U1-1;
V2=2*U2-1;
S=V1*V1+V2*V2;
} while(S>=1||!S);
X=V1*sqrt(-2*log(S)/S);
}
else
X=V2*sqrt(-2*log(S)/S);
phase=1-phase;
return X;
}
float add_gassrand(float EbNo)
{
int i;
float Sigma2;//噪声方差
float Sigma;//噪声标准差
float Rate=(N/2)/(float)N;//数据的传输速率
Sigma2=(float)1/(2*Rate*pow(10,(EbNo / 10.0)));//白噪声的方差
Sigma=sqrtf(Sigma2);//白噪声的标准差
for(i=0;i<N;i++)
{
pD->a[i+N] = 2 * (pD->a[i+N] + gaussrand() * Sigma) / Sigma2;
}
return 0;
}
Part 4.运行结果
感谢耐心观看,如有错误,欢迎指正。