一种(2,1,3)卷积编码以及维特比解码程序

Pearl ·
更新时间:2024-11-10
· 548 次阅读

前言

原来做燃气项目,无线通讯,为了增加设备间的通讯距离,用到了一套编码解码方案,其中用了一种(2,1,3)卷积编码,卷积图以及要求如下图所示:
在这里插入图片描述

卷积编码和对应的维特比算法

卷积编码程序很简单,但是对应的维特比算法比较复杂,网上有很多算法都是不断循环试探路径,效率上会有一定的缺陷。本程序用了查表法,效率有所提高。但是查表法也只针对这种简单的卷积方法,若是再复杂一些,则制表会很困难。维特比算法参考了东南大学的教材。具体的设计思路参考教材。直接上代码,代码真实有效,可以下载下来测试。另外,本程序仅针对每字节高bit先输入的情况,如果每字节低bit先输入,则需要再重新制表,算法一样,具体可以下载本人上传的代码,不过需要积分。废话不多说,上代码:
//每个字节的高位先输入的卷码和解码
const INT8U status0[16][2]=
{
{0x00,0x00},
{0x03,0x08},
{0x0D,0x04},
{0x0E,0x0C},
{0x37,0x02},
{0x34,0x0A},
{0x3A,0x06},
{0x39,0x0E},
{0xDF,0x01},
{0xDC,0x09},
{0xD2,0x05},
{0xD1,0x0D},
{0xE8,0x03},
{0xEB,0x0B},
{0xE5,0x07},
{0xE6,0x0F},
};
const INT8U status1[16][2]=
{
{0x7C,0x00},
{0x7F,0x08},
{0x71,0x04},
{0x72,0x0C},
{0x4B,0x02},
{0x48,0x0A},
{0x46,0x06},
{0x45,0x0E},
{0xA3,0x01},
{0xA0,0x09},
{0xAE,0x05},
{0xAD,0x0D},
{0x94,0x03},
{0x97,0x0B},
{0x99,0x07},
{0x9A,0x0F},
};

const INT8U status2[16][2]=
{
{0xF0,0x00},
{0xF3,0x08},
{0xFD,0x04},
{0xFE,0x0C},
{0xC7,0x02},
{0xC4,0x0A},
{0xCA,0x06},
{0xC9,0x0E},
{0x2F,0x01},
{0x2C,0x09},
{0x22,0x05},
{0x21,0x0D},
{0x18,0x03},
{0x1B,0x0B},
{0x15,0x07},
{0x16,0x0F},
};
const INT8U status3[16][2]=
{
{0x8C,0x00},
{0x8F,0x08},
{0x81,0x04},
{0x82,0x0C},
{0xBB,0x02},
{0xB8,0x0A},
{0xB6,0x06},
{0xB5,0x0E},
{0x53,0x01},
{0x50,0x09},
{0x5E,0x05},
{0x5D,0x0D},
{0x64,0x03},
{0x67,0x0B},
{0x69,0x07},
{0x6A,0x0F},
};
const INT8U status4[16][2]=
{
{0xC0,0x00},
{0xC3,0x08},
{0xCD,0x04},
{0xCE,0x0C},
{0xF7,0x02},
{0xF4,0x0A},
{0xFA,0x06},
{0xF9,0x0E},
{0x1F,0x01},
{0x1C,0x09},
{0x12,0x05},
{0x11,0x0D},
{0x28,0x03},
{0x2B,0x0B},
{0x25,0x07},
{0x26,0x0F},
};
const INT8U status5[16][2]=
{
{0xBC,0x00},
{0xBF,0x08},
{0xB1,0x04},
{0xB2,0x0C},
{0x8B,0x02},
{0x88,0x0A},
{0x86,0x06},
{0x85,0x0E},
{0x63,0x01},
{0x60,0x09},
{0x6E,0x05},
{0x6D,0x0D},
{0x54,0x03},
{0x57,0x0B},
{0x59,0x07},
{0x5A,0x0F},
};
const INT8U status6[16][2]=
{
{0x30,0x00},
{0x33,0x08},
{0x3D,0x04},
{0x3E,0x0C},
{0x07,0x02},
{0x04,0x0A},
{0x0A,0x06},
{0x09,0x0E},
{0xEF,0x01},
{0xEC,0x09},
{0xE2,0x05},
{0xE1,0x0D},
{0xD8,0x03},
{0xDB,0x0B},
{0xD5,0x07},
{0xD6,0x0F},
};
const INT8U status7[16][2]=
{
{0x4C,0x00},
{0x4F,0x08},
{0x41,0x04},
{0x42,0x0C},
{0x7B,0x02},
{0x78,0x0A},
{0x76,0x06},
{0x75,0x0E},
{0x93,0x01},
{0x90,0x09},
{0x9E,0x05},
{0x9D,0x0D},
{0xA4,0x03},
{0xA7,0x0B},
{0xA9,0x07},
{0xAA,0x0F},
};

//==========================================================================
// 函数名称:ham_ming_distance
// 函数功能:一个字节输入,4bit输出,四次状态转移的汉明码距计算
// 入口参数:
// 出口参数:无
// 程序版本:1.0
// 编写日期:2016-08-02
// 程序作者:
// 修改次数:
// 修改作者:
// 修改日期:
// 修改内容:
// 版本升级:
//==========================================================================
INT8U ham_ming_distance(INT8U a, const INT8U *status)
{
INT8U i,m,n,k,out,j=0xff;
for(i=0;i<16;i++)
{
k=status[i<<1]^a; //位异或
n=0;
for(m=0;m<8;m++) //求汉明码距,1个字节中1的个数
{
n += (k & 0x01);
k = (k >> 1);
}
if(j>=n)
{
j=n;
out=status[(i<<1)+1];//记录汉明码距小的对应的输出,循环完毕,保存的就是最小的输出
}
}
return out; //返回每8个bit汉明码距为最小的对应的四个bit输出
}

//状态转移
INT8U state_transition(INT8U a)
{
INT8U i=0;
switch(a)
{
case 0x00:
case 0x01: i=0;break;
case 0x08:
case 0x09: i=1;break;
case 0x04:
case 0x05: i=2;break;
case 0x0C:
case 0x0D: i=3;break;
case 0x02:
case 0x03: i=4;break;
case 0x0A:
case 0x0B: i=5;break;
case 0x06:
case 0x07: i=6;break;
case 0x0E:
case 0x0F: i=7;break;
default: break;
}
return i;
}

//==========================================================================
// 函数名称:Viterbi
// 函数功能: 维特比解码,2n字节输入, n字节输出
// 入口参数:
// 出口参数:无
// 程序版本:1.0
// 编写日期:2016-08-02
// 程序作者:
// 修改次数:
// 修改作者:
// 修改日期:
// 修改内容:
// 版本升级:
//==========================================================================
void Viterbi(INT8U *input,INT8U *output,INT8U len)
{
INT8U i,j,k,status=0;
INT8U data;
if(len%2) //如果输入的字节是奇数,那么在输入字节的最后补一个字节的0x00,这样输出的就是完整的字节
{
input[len]=0x00;
len++;
}
k=len>>1;
for(i=0;i<k;i++) //清空输出
{
*output++=0;
}
for(i=0;i<k;i++)
{
*output–;
}

k=len>>1; //输入数组奇偶顺序变换 for(i=0;i<k;i++) { data=input[i<<1]; input[i<<1]=input[(i<<1)+1]; input[(i<<1)+1]=data; } for(i=0;i<len;i++) { switch(status) { case 0: j=ham_ming_distance(*input,&status0[0][0]); // status=state_transition(j); *output|=(j<<((i&0x01)<<2)); break; case 1: j=ham_ming_distance(*input,&status1[0][0]); status=state_transition(j); *output|=(j<<((i&0x01)<<2)); break; case 2: j=ham_ming_distance(*input,&status2[0][0]); status=state_transition(j); *output|=(j<<((i&0x01)<<2)); break; case 3: j=ham_ming_distance(*input,&status3[0][0]); status=state_transition(j); *output|=(j<<((i&0x01)<<2)); break; case 4: j=ham_ming_distance(*input,&status4[0][0]); status=state_transition(j); *output|=(j<<((i&0x01)<<2)); break; case 5: j=ham_ming_distance(*input,&status5[0][0]); status=state_transition(j); *output|=(j<<((i&0x01)<<2)); break; case 6: j=ham_ming_distance(*input,&status6[0][0]); status=state_transition(j); *output|=(j<<((i&0x01)<<2)); break; case 7: j=ham_ming_distance(*input,&status7[0][0]); status=state_transition(j); *output|=(j<<((i&0x01)<>1; for(i=0;i<k;i++) { *output--; } for(i=0;i<k;i++) //输出数据高低bit移位处理 { data=0; for(j=0;j>j)&0x01)<<(7-j); } output[i]=data; }

}

//卷码
const INT8U fecEncodeTable[]={
0,3,1,2,
3,0,2,1,
3,0,2,1,
0,3,1,2
};
void Fec213(INT8U *input,INT8U *fec,INT8U len)
{
INT16U fecReg=0;
INT16U fecOutput;
INT8U i,j;
for(i=0;i<len;i++)
{
fecReg=(fecReg&0x700)|(*input & 0xFF);
input++;
fecOutput=0;
for(j=0;j<8;j++)
{
fecOutput=(fecOutput<>7];
fecReg=(fecReg<<1)&0x7FF;
}
*fec++=fecOutput&0xFF;
*fec++=fecOutput>>8;
}
}

验证方法

可以通过发送一段字节型的数据,经过Fec213()卷积函数,变成2倍长度的字节,然后对这些字节中数据做一些0、1变换(注意先不要过多改变),然后经过Viterbi()函数,验证是否变化出来的数据跟原始的数据一样,一样就代表算法ok.


作者:李启爸爸



维特 编码 解码 程序 卷积

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章