连载:有限状态机以及维特比(Viterbi)译码器(三)
来源:互联网 发布:mrtg windows下载 编辑:程序博客网 时间:2024/04/29 12:08
现在,我们有了一个通用的状态机编译码器,还有针对前向码、反馈码的具体状态生成器。测试一下。
就一个文件,main.cpp
先是为了弥合C++不同的编译器,弄些辅助代码。
- #include <stdio.h>
- #include <memory>
- #include "lsm_viterbi.h"
- #include "front_conv_lsmaker.h"
- #include "feedback_conv_lsmaker.h"
- #include <time.h>
- #include <stdlib.h>
- using namespace LSMVIT;
- using namespace std;
- #if defined (_MSC_VER)
- #if _MSC_VER <=1600
- using namespace std::tr1::placeholders;
- #else
- using namespace std::placeholders;
- #endif
- #else
- using namespace std::placeholders;
- #endif
- int bitweight[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
- //打印输出的工具函数
- void outputArray(const char * name,int array[], int nLen,int nMaxBytes);
这个程序可在VS2010及以上,或者GCC 4.6以上(要开C++0x 或 C++11开关)编译运行.
为了一次性的适合不同形式的演示,写一个模板函数来演示。
- /** \brief 用来演示的通用函数
- * 可以方便的演示各类码
- * \param pName const char* 演示的名称
- * \param pins[][n] int 前馈(输出)抽头,k*n
- * \param errRate double 误码率, 0~1
- * \param const int * nDelMask = nullptr 删除图案,某比特为1表示本比特被删除,共codelen长度
- * \param const int (* nFeedbackPins)[k] = nullptr 反馈抽头描述,k*k, 为nullptr 表示为前向码
- * \return void
- *
- */
- template <int n, int k, int m, int L /*约束长度*/ , int codelen /*测试数据长度*/ >
- void demo(
- const char * pName,
- const int pins[/*k*/][n],
- double errRate,
- bool outputViz = false,
- const int * nDelMask = nullptr,/*数组长度必须是codelen*/
- const int (* nFeedbackPins)[k] = nullptr/*反馈码反馈引脚*/
- )
- {
- puts ("------------------------");
- puts (pName);
- puts ("------------------------");
- putchar ('\n');
- //编码译码器
- const int nRegStatus = (1<<(m*k)),nInStatus = 1<<k;
- typedef lsm_codec<nRegStatus,nInStatus,n,L> t_lcm_codec;
- //建立有限状态机编译码器
- shared_ptr<t_lcm_codec> pcodec (new t_lcm_codec);
- //用状态机填写器填写译码器的状态参数
- if (nFeedbackPins==nullptr)
- {
- //前向卷积码状态机填写器
- typedef fconv_lsmaker<n,k,m> t_fcmaker;
- t_fcmaker fc_maker(pins);
- pcodec->init_status(bind(&t_fcmaker::cb_status,&fc_maker,_1,_2,_3,_4));
- }
- else
- {
- //反馈卷积码状态机填写器
- typedef feedback_lsmaker<n,k,m> t_bcmaker;
- t_bcmaker bc_maker(pins,nFeedbackPins);
- pcodec->init_status(bind(&t_bcmaker::cb_status,&bc_maker,_1,_2,_3,_4));
- }
- if (outputViz==true)
- {
- //把状态图输出到文件,好用GraphviZ来查看跳转图
- string filename = pName;
- filename += ".txt";
- string strGraph = pcodec->make_graph();
- FILE * file = fopen(filename.c_str(),"wb");
- if (file)
- {
- fwrite(strGraph.c_str(),strGraph.size(),1,file);
- fclose(file);
- }
- }
- //开始演示
- const int buflen = codelen;
- int nInputData[buflen], nOutputCode[buflen], nErrorBit[buflen];
- int nRecievedCode[buflen], nDecodedData[buflen],nErrGraph[buflen];
- //产生输入,最后几个比特是全0冲洗
- for (int i=0;i<buflen;i++)
- nInputData[i] = (i<buflen-m)?rand() % (1<<k):0;
- outputArray("信息",nInputData,buflen,1);
- //编码
- int nInitStatus = rand() % (nRegStatus);
- printf ("初态 = %d\n",nInitStatus);
- pcodec->encode(nInputData,buflen,nOutputCode,nInitStatus);
- outputArray("卷积码",nOutputCode,buflen,n/4 + n%4==0?0:1);
- //产生错误比特, 按照给定的误码率产生。
- int rawerr = 0;
- for (int i=0;i<buflen;i++)
- {
- nErrorBit[i] = 0;
- for (int j = 0;j<n;j++)
- nErrorBit[i] |=(i>=m && i<=buflen - m)? (rand() % 100 / 100.0 < errRate ? (1<<j):0):0;
- for(int j=0;j<n/4+1;j++)
- rawerr += bitweight[(nErrorBit[i]>>(j*4))&0x0f];
- }
- outputArray("错误图案",nErrorBit,buflen,n/4 + n%4==0?0:1);
- printf("\n让 %d 比特中,有 %d bit 发生错误\n",n*buflen,rawerr);
- printf("\n");
- //污染码字,直接进行XOR
- for (int i=0;i<buflen;i++)
- nRecievedCode[i] = nOutputCode[i] ^ nErrorBit[i];
- outputArray("被污染的卷积码",nRecievedCode,buflen,n/4 + n%4==0?0:1);
- //如果有删除码,则需要在原始码的高位进行删除图样叠加
- if (nDelMask != nullptr)
- {
- for (int i=0;i<buflen;i++)
- nRecievedCode[i] += (nDelMask[i] << n);
- outputArray("输入译码器的删除图样和码",nRecievedCode,buflen,(2*n/4 + (2*n)%4==0?0:1));
- }
- //译码
- pcodec->decode(nRecievedCode, buflen, true);
- int nPoped = pcodec->pop_data(nDecodedData,buflen);
- outputArray("译码结果",nDecodedData,nPoped,n/4 + n%4==0?0:1);
- int err = 0;
- for (int i=0;i<nPoped;i++)
- {
- nErrGraph[i] = (nDecodedData[i]^nInputData[i]);
- for(int j=0;j<n/4+1;j++)
- err += bitweight[(nErrGraph[i]>>(j*4))&0x0f];
- }
- printf("纠错后错了 %d bit\n",err);
- if (err)
- outputArray("错误分布",nErrGraph,nPoped,n/4 + n%4==0?0:1);
- putchar('\n');
- putchar('\n');
- }
这样,我们的Main 就简单了
- int main (int argc, char * argv[])
- {
- srand((unsigned int)time(0));
- const int datalen = 256;
- /*
- 2,1,3 码
- -[]-[]-[]-+
- 1 0 1 1
- 1 1 1 1
- */
- int nPins213 [1][2] = {{13,17}};
- demo<2,1,3,32,datalen>("213卷积码",nPins213,1e-3,true);
- /*
- 4 , 1 , 6 码,下面是抽头
- -[]-[]-[]-[]-[]-[]-+
- 1 0 1 1 0 1 1 -> 0
- 1 1 0 1 0 0 1 -> 1
- 1 1 0 0 1 1 1 -> 2
- 1 1 1 1 0 0 1 -> 3
- */
- int pins416 [1][4] = {{133,151,147,171}};
- demo<4,1,6,64,datalen>("416卷积码",pins416,1e-1);
- /*
- 3 , 2 , 4 反馈码,下面是输出抽头
- 0-[]-[]-[]-[]-+ 1-[]-[]-[]-[]-+
- 1 0 0 0 0 0 0 0 0 0
- 1 0 0 1 1 1 1 1 0 1
- 0 0 0 0 0 1 0 0 0 0
- 反馈抽头,自己瞎编的反馈,不知道会不会恶化码:
- 0-[]-[]-[]-[]-+ 1-[]-[]-[]-[]-+
- 0 1 1 0 1 0 1 0 0 1
- 0 1 0 1 1 0 1 1 1 1
- */
- int pins324 [2][3] = {{20,23,0},{0,35,20}};
- int feedbackpin[2][2] = {{15, 13},{11,17}};
- demo<3,2,4,64,datalen>("324双排寄存器反馈卷积码",pins324,1e-4,false,nullptr,feedbackpin);
- /*
- 3/4 2 , 1 , 6 打孔
- */
- int pins216 [1][2] = {{133,171}};
- int nDelMask [datalen];
- for (int i=0;i<datalen;i++)
- nDelMask[i] = (i%3);
- demo<2,1,6,50,datalen>("216打孔卷积码",pins216,1e-4,false,nDelMask);
- return 0;
- }
输出结果的函数
- void outputArray(const char * name,int array[], int nLen,int nMaxBytes)
- {
- printf ("\n%s:\n",name);
- int pc = 0;
- int ps = 80 / (nMaxBytes * 8+1);
- char pMask[] = "0123456789ABCDEF";
- for (int i=0;i<nLen;i++)
- {
- if (array[i]==0)
- {
- for (int j=1;j<nMaxBytes;j++) putchar (' ');
- putchar ('0');
- }
- else
- for (int j=0;j<nMaxBytes;j++) putchar (pMask[(array[i]>>(4*(nMaxBytes - 1 - j))) & 0x0f]);
- if ((i+1)%8==0)
- {
- pc ++;
- if (pc >= ps)
- {
- pc = 0;
- putchar ('\n' );
- }
- else
- putchar (' ' );
- }
- }
- putchar ('\n' );
- }
好了,可以运行一下啦!
- ------------------------
- 416卷积码
- ------------------------
- 信息:
- 01001111 10100001 01011011 11011110 00101010 11001100 01110010 11001010
- 10111011 01010001 11001110 11000100 11101000 00000000 01100001 11011111
- 00000100 10011010 11100101 10011110 01100010 10101010 00111000 10110111
- 10000011 00010000 11100100 11100100 10000000 00000011 00111101 10000000
- 初态 = 63
- 卷积码:
- 4CDE75B3 EBCDE8D5 86A4F318 99E3269E CA829A40 BF3EF0BB F7DE36A0 3ACEFF35
- 40BFC96D 9E7EF472 2E36AF4C 9D910726 2ABC92E8 DAF00000 0F8E4F8A 7139D691
- B3A75079 253DA448 E0C99A03 ACEF0431 C5FBBF72 9A40B0B0 4722E365 8295C189
- 9ECA7508 E4F726D2 57136A0C DABC6A0C D5322AF0 000000F8 E4004313 291085F0
- 错误图案:
- 00000080 00802880 00021000 00080438 08002228 10000070 12100640 45603000
- 00200000 00010034 52088002 04004010 20001800 0C682444 088012A0 00986000
- 10401082 00000300 20000000 01800000 01000400 00000001 21010802 20210008
- 35000005 9602C04A 01080010 E0000400 0A102080 00880940 00800C00 00000000
- 让 1024 比特中,有 129 bit 发生错误
- 被污染的卷积码:
- 4CDE7533 EB4DC055 86A6E318 99EB22A6 C282B868 AF3EF0CB E5CE30E0 7FAECF35
- 409FC96D 9E7FF446 7C3E2F4E 99914736 0ABC8AE8 D6982444 070E5D2A 71A1B691
- A3E740FB 253DA748 C0C99A03 AD6F0431 C4FBBB72 9A40B0B1 6623EB67 A2B4C181
- ABCA750D 72F5E698 561B6A1C 3ABC6E0C DF220A70 008809B8 E4804F13 291085F0
- 译码结果:
- 01001111 10100001 01011011 11011110 00101010 11001100 01110010 11001010
- 10111011 01010001 11001110 11000100 11101000 00000000 01100001 11011111
- 00000100 10011010 11100101 10011110 01100010 10101010 00111000 10110111
- 10000011 00010000 11100100 11100100 10000000 00000011 00111101 10000000
- 纠错后错了 0 bit
0 0
- 连载:有限状态机以及维特比(Viterbi)译码器(三)
- 连载:有限状态机以及维特比(Viterbi)译码器(三)
- 连载:有限状态机以及维特比(Viterbi)译码器(一)
- 连载:有限状态机以及维特比(Viterbi)译码器(二)
- 连载:有限状态机以及维特比(Viterbi)译码器(一)
- 连载:有限状态机以及维特比(Viterbi)译码器(二)
- 维特比算法(Viterbi Algorithm)
- 维特比算法(Viterbi Algorithm)
- viterbi,维特比算法通俗理解
- 维特比算法(Viterbi Algorithm)
- 维特比算法(Viterbi Algorithm)
- HMM——维特比算法(Viterbi algorithm)
- 维特比算法viterbi的简单实现 python版
- 自然语言处理之维特比(Viterbi)算法
- 隐马尔科夫(HMM)模型 前向后向(Forward_backward) 维特比 (viterbi)
- HMM学习笔记—002--维特比算法(viterbi algorithm)
- 动态规划之隐含马尔可夫模型(HMM)和维特比算法(Viterbi Algorithm)
- 自然语言处理 HMM 维特比算法(Viterbi Algorithm) 实例转载
- FastDFS之Binlog同步
- 连载:有限状态机以及维特比(Viterbi)译码器(二)
- JavaScript教程:如何定义全局函数
- SQL拼接
- android开发中PreferenceScreen的使用注意事项
- 连载:有限状态机以及维特比(Viterbi)译码器(三)
- 微营销,能否扭转市场老大的局面?
- 设计模式(一):从三类模式六种原则看设计模式
- linux tcpdump(抓包)
- android setCompoundDrawables和setCompoundDrawablesWithIntrinsicBounds区别
- 第16周C++兄弟营团队学习情况记录表
- LR逻辑回归Logistic Regression
- 从Alphacode看斐波那契数列与线性动态规划
- setsockopt的作用