连载:有限状态机以及维特比(Viterbi)译码器(三)

来源:互联网 发布:mrtg windows下载 编辑:程序博客网 时间:2024/04/29 12:08

现在,我们有了一个通用的状态机编译码器,还有针对前向码、反馈码的具体状态生成器。测试一下。

就一个文件,main.cpp

先是为了弥合C++不同的编译器,弄些辅助代码。

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <memory>  
  3. #include "lsm_viterbi.h"  
  4. #include "front_conv_lsmaker.h"  
  5. #include "feedback_conv_lsmaker.h"  
  6. #include <time.h>  
  7. #include <stdlib.h>  
  8. using namespace LSMVIT;  
  9. using namespace std;  
  10. #if defined (_MSC_VER)  
  11. #if _MSC_VER <=1600  
  12. using namespace std::tr1::placeholders;  
  13. #else  
  14. using namespace std::placeholders;  
  15. #endif  
  16. #else  
  17. using namespace std::placeholders;  
  18. #endif  
  19. int bitweight[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};  
  20. //打印输出的工具函数  
  21. void outputArray(const char * name,int array[], int nLen,int nMaxBytes);  


这个程序可在VS2010及以上,或者GCC 4.6以上(要开C++0x 或 C++11开关)编译运行.

为了一次性的适合不同形式的演示,写一个模板函数来演示。

[cpp] view plaincopy
  1. /** \brief 用来演示的通用函数 
  2.  * 可以方便的演示各类码 
  3.  * \param pName const char* 演示的名称 
  4.  * \param pins[][n] int 前馈(输出)抽头,k*n 
  5.  * \param errRate double 误码率, 0~1 
  6.  * \param const int * nDelMask = nullptr 删除图案,某比特为1表示本比特被删除,共codelen长度 
  7.  * \param const int (* nFeedbackPins)[k] = nullptr 反馈抽头描述,k*k, 为nullptr 表示为前向码 
  8.  * \return void 
  9.  * 
  10.  */  
  11. template <int n, int k, int m, int L /*约束长度*/ , int codelen /*测试数据长度*/ >  
  12. void demo(  
  13.                 const char * pName,  
  14.                 const int pins[/*k*/][n],  
  15.                 double errRate,  
  16.                 bool outputViz = false,  
  17.                 const int * nDelMask = nullptr,/*数组长度必须是codelen*/  
  18.                 const int (* nFeedbackPins)[k] = nullptr/*反馈码反馈引脚*/  
  19.                 )  
  20. {  
  21.     puts ("------------------------");  
  22.     puts (pName);  
  23.     puts ("------------------------");  
  24.     putchar ('\n');  
  25.   
  26.     //编码译码器  
  27.     const int nRegStatus = (1<<(m*k)),nInStatus = 1<<k;  
  28.     typedef lsm_codec<nRegStatus,nInStatus,n,L> t_lcm_codec;  
  29.     //建立有限状态机编译码器  
  30.     shared_ptr<t_lcm_codec> pcodec (new t_lcm_codec);  
  31.     //用状态机填写器填写译码器的状态参数  
  32.     if (nFeedbackPins==nullptr)  
  33.     {  
  34.          //前向卷积码状态机填写器  
  35.         typedef fconv_lsmaker<n,k,m> t_fcmaker;  
  36.         t_fcmaker    fc_maker(pins);  
  37.         pcodec->init_status(bind(&t_fcmaker::cb_status,&fc_maker,_1,_2,_3,_4));  
  38.     }  
  39.     else  
  40.     {  
  41.          //反馈卷积码状态机填写器  
  42.         typedef feedback_lsmaker<n,k,m> t_bcmaker;  
  43.         t_bcmaker    bc_maker(pins,nFeedbackPins);  
  44.         pcodec->init_status(bind(&t_bcmaker::cb_status,&bc_maker,_1,_2,_3,_4));  
  45.   
  46.     }  
  47.   
  48.     if (outputViz==true)  
  49.     {  
  50.         //把状态图输出到文件,好用GraphviZ来查看跳转图  
  51.         string filename = pName;  
  52.         filename += ".txt";  
  53.         string strGraph = pcodec->make_graph();  
  54.         FILE * file = fopen(filename.c_str(),"wb");  
  55.         if (file)  
  56.         {  
  57.             fwrite(strGraph.c_str(),strGraph.size(),1,file);  
  58.             fclose(file);  
  59.         }  
  60.     }  
  61.   
  62.     //开始演示  
  63.     const int buflen = codelen;  
  64.     int nInputData[buflen], nOutputCode[buflen], nErrorBit[buflen];  
  65.     int nRecievedCode[buflen], nDecodedData[buflen],nErrGraph[buflen];  
  66.   
  67.     //产生输入,最后几个比特是全0冲洗  
  68.     for (int i=0;i<buflen;i++)  
  69.         nInputData[i] = (i<buflen-m)?rand() % (1<<k):0;  
  70.     outputArray("信息",nInputData,buflen,1);  
  71.   
  72.     //编码  
  73.     int nInitStatus = rand() % (nRegStatus);  
  74.     printf ("初态 = %d\n",nInitStatus);  
  75.     pcodec->encode(nInputData,buflen,nOutputCode,nInitStatus);  
  76.     outputArray("卷积码",nOutputCode,buflen,n/4 + n%4==0?0:1);  
  77.     //产生错误比特, 按照给定的误码率产生。  
  78.     int rawerr = 0;  
  79.     for (int i=0;i<buflen;i++)  
  80.     {  
  81.         nErrorBit[i] = 0;  
  82.         for (int j = 0;j<n;j++)  
  83.             nErrorBit[i] |=(i>=m && i<=buflen - m)? (rand() % 100 / 100.0 < errRate ? (1<<j):0):0;  
  84.         for(int j=0;j<n/4+1;j++)  
  85.             rawerr += bitweight[(nErrorBit[i]>>(j*4))&0x0f];  
  86.     }  
  87.     outputArray("错误图案",nErrorBit,buflen,n/4 + n%4==0?0:1);  
  88.     printf("\n让 %d 比特中,有 %d bit 发生错误\n",n*buflen,rawerr);  
  89.     printf("\n");  
  90.     //污染码字,直接进行XOR  
  91.     for (int i=0;i<buflen;i++)  
  92.         nRecievedCode[i] = nOutputCode[i] ^ nErrorBit[i];  
  93.     outputArray("被污染的卷积码",nRecievedCode,buflen,n/4 + n%4==0?0:1);  
  94.   
  95.     //如果有删除码,则需要在原始码的高位进行删除图样叠加  
  96.     if (nDelMask != nullptr)  
  97.     {  
  98.         for (int i=0;i<buflen;i++)  
  99.             nRecievedCode[i] += (nDelMask[i] << n);  
  100.         outputArray("输入译码器的删除图样和码",nRecievedCode,buflen,(2*n/4 + (2*n)%4==0?0:1));  
  101.     }  
  102.     //译码  
  103.     pcodec->decode(nRecievedCode, buflen, true);  
  104.     int nPoped = pcodec->pop_data(nDecodedData,buflen);  
  105.     outputArray("译码结果",nDecodedData,nPoped,n/4 + n%4==0?0:1);  
  106.   
  107.     int err = 0;  
  108.     for (int i=0;i<nPoped;i++)  
  109.     {  
  110.         nErrGraph[i] = (nDecodedData[i]^nInputData[i]);  
  111.         for(int j=0;j<n/4+1;j++)  
  112.             err += bitweight[(nErrGraph[i]>>(j*4))&0x0f];  
  113.   
  114.     }  
  115.     printf("纠错后错了 %d bit\n",err);  
  116.     if (err)  
  117.         outputArray("错误分布",nErrGraph,nPoped,n/4 + n%4==0?0:1);  
  118.     putchar('\n');  
  119.     putchar('\n');  
  120. }  


这样,我们的Main 就简单了

[cpp] view plaincopy
  1. int main (int argc, char * argv[])  
  2. {  
  3.     srand((unsigned int)time(0));  
  4.     const int datalen = 256;  
  5.     /* 
  6.     2,1,3 码 
  7.     -[]-[]-[]-+ 
  8.     1  0  1  1 
  9.     1  1  1  1 
  10.     */  
  11.         int nPins213 [1][2] = {{13,17}};  
  12.         demo<2,1,3,32,datalen>("213卷积码",nPins213,1e-3,true);  
  13.     /* 
  14.     4 , 1 , 6 码,下面是抽头 
  15.     -[]-[]-[]-[]-[]-[]-+ 
  16.         1  0  1  1  0  1   1 -> 0 
  17.     1  1  0  1  0  0   1 -> 1 
  18.     1  1  0  0  1  1   1 -> 2 
  19.     1  1  1  1  0  0   1 -> 3 
  20.     */  
  21.     int pins416 [1][4] = {{133,151,147,171}};  
  22.     demo<4,1,6,64,datalen>("416卷积码",pins416,1e-1);  
  23.   
  24.     /* 
  25.     3 , 2 , 4 反馈码,下面是输出抽头 
  26.         0-[]-[]-[]-[]-+    1-[]-[]-[]-[]-+ 
  27.      1  0  0  0  0      0  0  0  0  0 
  28.      1  0  0  1  1      1  1  1  0  1 
  29.      0  0  0  0  0      1  0  0  0  0 
  30.      反馈抽头,自己瞎编的反馈,不知道会不会恶化码: 
  31.          0-[]-[]-[]-[]-+    1-[]-[]-[]-[]-+ 
  32.          0  1  1  0  1      0  1  0  0  1 
  33.          0  1  0  1  1      0  1  1  1  1 
  34.         */  
  35.     int pins324 [2][3] = {{20,23,0},{0,35,20}};  
  36.     int feedbackpin[2][2] = {{15, 13},{11,17}};  
  37.         demo<3,2,4,64,datalen>("324双排寄存器反馈卷积码",pins324,1e-4,false,nullptr,feedbackpin);  
  38.   
  39.     /* 
  40.        3/4 2 , 1 , 6 打孔 
  41.    */  
  42.     int pins216 [1][2] = {{133,171}};  
  43.     int nDelMask [datalen];  
  44.     for (int i=0;i<datalen;i++)  
  45.         nDelMask[i] = (i%3);  
  46.     demo<2,1,6,50,datalen>("216打孔卷积码",pins216,1e-4,false,nDelMask);  
  47.     return 0;  
  48. }  


输出结果的函数

[cpp] view plaincopy
  1. void outputArray(const char * name,int array[], int nLen,int nMaxBytes)  
  2. {  
  3.     printf ("\n%s:\n",name);  
  4.     int pc = 0;  
  5.     int ps = 80 / (nMaxBytes * 8+1);  
  6.     char  pMask[] = "0123456789ABCDEF";  
  7.     for (int i=0;i<nLen;i++)  
  8.     {  
  9.   
  10.         if (array[i]==0)  
  11.         {  
  12.             for (int j=1;j<nMaxBytes;j++) putchar (' ');  
  13.             putchar ('0');  
  14.         }  
  15.         else  
  16.             for (int j=0;j<nMaxBytes;j++) putchar (pMask[(array[i]>>(4*(nMaxBytes - 1 - j))) & 0x0f]);  
  17.         if ((i+1)%8==0)  
  18.         {  
  19.             pc ++;  
  20.             if (pc >= ps)  
  21.             {  
  22.                 pc = 0;  
  23.                 putchar ('\n' );  
  24.             }  
  25.             else  
  26.                 putchar (' ' );  
  27.         }  
  28.   
  29.     }  
  30.     putchar ('\n' );  
  31. }  


 

好了,可以运行一下啦!

 

[plain] view plaincopy
  1. ------------------------  
  2. 416卷积码  
  3. ------------------------  
  4.   
  5.   
  6. 信息:  
  7. 01001111 10100001 01011011 11011110 00101010 11001100 01110010 11001010  
  8. 10111011 01010001 11001110 11000100 11101000 00000000 01100001 11011111  
  9. 00000100 10011010 11100101 10011110 01100010 10101010 00111000 10110111  
  10. 10000011 00010000 11100100 11100100 10000000 00000011 00111101 10000000  
  11.   
  12. 初态 = 63  
  13.   
  14. 卷积码:  
  15. 4CDE75B3 EBCDE8D5 86A4F318 99E3269E CA829A40 BF3EF0BB F7DE36A0 3ACEFF35  
  16. 40BFC96D 9E7EF472 2E36AF4C 9D910726 2ABC92E8 DAF00000 0F8E4F8A 7139D691  
  17. B3A75079 253DA448 E0C99A03 ACEF0431 C5FBBF72 9A40B0B0 4722E365 8295C189  
  18. 9ECA7508 E4F726D2 57136A0C DABC6A0C D5322AF0 000000F8 E4004313 291085F0  
  19.   
  20.   
  21. 错误图案:  
  22. 00000080 00802880 00021000 00080438 08002228 10000070 12100640 45603000  
  23. 00200000 00010034 52088002 04004010 20001800 0C682444 088012A0 00986000  
  24. 10401082 00000300 20000000 01800000 01000400 00000001 21010802 20210008  
  25. 35000005 9602C04A 01080010 E0000400 0A102080 00880940 00800C00 00000000  
  26.   
  27.   
  28. 让 1024 比特中,有 129 bit 发生错误  
  29.   
  30.   
  31. 被污染的卷积码:  
  32. 4CDE7533 EB4DC055 86A6E318 99EB22A6 C282B868 AF3EF0CB E5CE30E0 7FAECF35  
  33. 409FC96D 9E7FF446 7C3E2F4E 99914736 0ABC8AE8 D6982444 070E5D2A 71A1B691  
  34. A3E740FB 253DA748 C0C99A03 AD6F0431 C4FBBB72 9A40B0B1 6623EB67 A2B4C181  
  35. ABCA750D 72F5E698 561B6A1C 3ABC6E0C DF220A70 008809B8 E4804F13 291085F0  
  36.   
  37.   
  38. 译码结果:  
  39. 01001111 10100001 01011011 11011110 00101010 11001100 01110010 11001010  
  40. 10111011 01010001 11001110 11000100 11101000 00000000 01100001 11011111  
  41. 00000100 10011010 11100101 10011110 01100010 10101010 00111000 10110111  
  42. 10000011 00010000 11100100 11100100 10000000 00000011 00111101 10000000  
  43.   
  44. 纠错后错了 0 bit 
0 0
原创粉丝点击