可用于SDR的C语言纠错编码通用算法收集(2)-李德-所罗门(RS)编码

上一篇。为了配合学生借助 taskbus进行纯控制台STDIO模块的开发,我们收集了手头的通用纠错算法,便于学生进行开发学习。今天介绍李德-所罗门(RS)编码。

RS码是一种多进制的循环纠错编码。循环纠错编码的思路是对待校验的信息做除法(模N除),求余数。如果余数为0(或者某个特定的值),则说明信息是正确的。如果不是0,可以根据余数判断是哪些位置出现了错误。

这种模N的除法,不是通常意义的算术除法,而是基于符号多项式的代数除法。具体到RS码,是在Galois Field(伽罗华域,GF)中进行的。这个域是一个闭合的符号系统,加减乘除运算得到的结果依旧是域的元素。这和算术运算有本质的区别。

1. 伽罗华域

1.1 构造

按照GF( 2 m 2^m 2m)构造元素,则符号共有m个状态,超过m个状态,就绕回去了。比如,GF(2)上的4次多项式
g ( x ) = x 4 + x 3 + 1 g(x)=x^4+x^3+1 g(x)=x4+x3+1
构造出 G F ( 2 4 ) GF(2^4) GF(24)上的域元素为:

  using namespace  RC_DICTCODEC;
    const int mv = 4;
    //x^0 is at g[0]
    char g[mv+1] = {1,0,0,1,1};
    Galois_domain GFm(g,mv);
    puts(GFm.printGF().c_str());
    return 0;

Output:

元素表达式高幂在前二进制表示
a 0 a^0 a0 1 1 1 0001 0001 0001
a 1 a^1 a1 x x x 0010 0010 0010
a 2 a^2 a2 x 2 x^2 x2 0100 0100 0100
a 3 a^3 a3 x 3 x^3 x3 1000 1000 1000
a 4 a^4 a4 x 3 + 1 x^3+1 x3+1 1001 1001 1001
a 5 a^5 a5 x 3 + x + 1 x^3+x+1 x3+x+1 1011 1011 1011
a 6 a^6 a6 x 3 + x 2 + x + 1 x^3+x^2+x+1 x3+x2+x+1 1111 1111 1111
a 7 a^7 a7 x 2 + x + 1 x^2+x+1 x2+x+1 0111 0111 0111
a 8 a^8 a8 x 3 + x 2 + x x^3+x^2+x x3+x2+x 1110 1110 1110
a 9 a^9 a9 x 2 + 1 x^2+1 x2+1 0101 0101 0101
a 10 a^{10} a10 x 3 + x x^3+x x3+x 1010 1010 1010
a 11 a^{11} a11 x 3 + x 2 + 1 x^3+x^2+1 x3+x2+1 1101 1101 1101
a 12 a^{12} a12 x + 1 x+1 x+1 0011 0011 0011
a 13 a^{13} a13 x 2 + x x^2+x x2+x 0110 0110 0110
a 14 a^{14} a14 x 3 + x 2 x^3+x^2 x3+x2 1100 1100 1100
000

构造的方法很直观:
a i + 1 = m o d ( x a i , x 4 + x 3 + 1 ) a^{i+1}=mod(xa^i, x^4+x^3+1) ai+1=mod(xai,x4+x3+1)

1.2. GF运算

域上的加减乘除,均是查表完成。

	printf ("a + a2 = a%d\n",GFm.I(GFm.mod_m_add(GFm(1),GFm(2))));
	printf ("a * a2 = a%d\n",GFm.I(GFm.mod_m_cross(GFm(1),GFm(2))));
	printf ("a / a2 = a%d\n",GFm.I(GFm.mod_m_div(GFm(1),GFm(2))));
	printf ("a ^ 37= a%d\n",GFm.I(GFm.mod_m_pow(GFm(1),37)));
	printf ("a2 + a5 = a%d\n",GFm.I(GFm.mod_m_add(GFm(2),GFm(5))));
	printf ("a2 * a5 = a%d\n",GFm.I(GFm.mod_m_cross(GFm(2),GFm(5))));
	printf ("a2 / a5 = a%d\n",GFm.I(GFm.mod_m_div(GFm(2),GFm(5))));
	printf ("a2 ^ 120= a%d\n",GFm.I(GFm.mod_m_pow(GFm(2),120)));
    

输出:

a + a2 = a13
a * a2 = a3
a / a2 = a14
a ^ 37= a7
a2 + a5 = a6
a2 * a5 = a7
a2 / a5 = a12
a2 ^ 120= a0

有了这个运算规则,则可以把很长的一段数据切割为以符号a的幂为表达的多项式。

2. 编码

2.1 把二进制流切割为符号a

二进制流是0,1表示的无限长数据。以每m个比特为单位,可以切割为符号。高位在前还是低位在前,全看心情,只要保证后面还原回去时一致即可。

比如,接着上面的例子,m=4,则每4比特一个单位。

0110 1101 0001 0000 1001 1100…

以第0位置为a^0,则上述数据的符号表示为:

a 13 a^{13} a13, a 5 a^{5} a5, a 3 a^{3} a3,0, a 4 a^{4} a4, a 12 a^{12} a12,…

2.2 RS编码的生成多项式

RS编码生成多项式是使用连乘的方法定义的:
G ( x ) = ∏ i = 0 N − 1 ( x − a S + i ) G(x)=\prod_{i=0}^{N-1}(x-a^{S+i}) G(x)=i=0N1(xaS+i)

其中,N是连乘次数,越高则纠错能力越强。S是起始幂,常见的是0,当然按照心情可以随便设置,设置太大了,就会环绕回去,没有意义。

接着上面的例子,我们产生多项式S=1,N=2:

	using namespace  RC_DICTCODEC;
    const int mv = 4;
    char g[mv+1] = {1,0,0,1,1};
    Galois_domain A(g,mv);
    //G是GF(2^m)上的生成式
    std::vector<unsigned short> Gx = A.geneGx(A(1),2);
    printf ("Gx=");
    for (size_t i=0;i<Gx.size();++i)
        printf("%1X",Gx[i]);
    printf ("\n");

也就是 G ( x ) = ( x − a ) ( x − a 2 ) = x 2 − ( a + a 2 ) x + a a 2 G(x)=(x-a)(x-a^2)=x^2-(a+a^2)x+aa^2 G(x)=(xa)(xa2)=x2(a+a2)x+aa2

输出:
Gx=1 6 8
查表,得到
G ( x ) = x 2 + a 13 x + a 3 G(x)=x^2+a^{13}x+a^3 G(x)=x2+a13x+a3

2.3 除法编码

RS码的码长是固定的,为 2 m − 1 2^m-1 2m1个符号。上面的例子就是15个符号。对应Gx,15个符号除出来的余数,有2个符号。因此,留给信息的符号为15-2=13个。

只要把连续的二进制数据切割为分组长度为13的组,并分别进行编码。就能形成编码序列。

   rc_codec_rs codec(n,k,Gx.data(),Gx.size(),A);
   unsigned short code[n] = rnd_syms(15,13);
   codec.encode(code,code);

3. 纠错译码

RS码一般采用迭代译码。参考Simon Rock liff 在1991年6月26日的开源代码版本。需要注意的是,该算法中数组0下标表示的是多项式的最低位。 我们已经在函数开始和结束做了转换,以弥和此差异。

同时, 由于原始算法根从 a 1 a^1 a1开始,如果起始根幂不是1, 在译码完毕后,还要做旋转。

    //Add err
    code[5] ^= 0x02;
   
    unsigned short decoded[15] = {0};
    codec.decode_rs(code,decoded);

    unsigned short check[n] = {0};
    codec.chcode(decoded,check);

4. C语言接口重封装

由于C++语言对其他语言包括python,C#不友好,我们参考这篇文章的方法,提供一个非常通用的C语言接口。

/**
 * @brief oc_rs_new_codec 分配一个RS纠错码编译码器
 * @param n 整个编码后的块长度(2^m符号),单位是1个伽罗华域符号
 * @param g_m  张成伽罗瓦域的域多项式的级数(m)
 * @param g 张成伽罗瓦域的域多项式的01表示
 * @param start_order 生成多项式连乘形式首个根的幂阶数
 * @param t 设计纠错个数
 * @param g_bigendian g的大小端
 * @return RS码编码译码器
 */
void * oc_rs_new_codec(size_t n, size_t g_m, const char g[/*g_m+1*/], size_t start_order, size_t t, int g_bigendian);

/**
 * @brief oc_rs_delete_codec 释放RS纠错码编译码器 codec
 * @param codec RS码编码译码器
 */
void oc_rs_delete_codec(void * codec);

/**
 * @brief oc_rs_get_k 获取RS编码的每轮信息符号数
 * @param codec RS码编码译码器
 * @return 信息符号个数
 */
int oc_rs_get_k(void * codec);

/**
 * @brief oc_rs_set_status 设置RS码的余数初态(默认是全0)
 * @param codec RS码编码译码器
 * @param status 余数初态
 */
void oc_rs_set_status(void * codec,unsigned short status[/*n-k*/]);

/**
 * @brief oc_rs_get_Gx 获取RS编码的生成多项式
 * @param codec RS码编码译码器
 * @param Gx 二进制表述(不是域上标幂数)
 * @param maxLen Gx的最大容积。
 * @return Gx的真正容积
 */
int oc_rs_get_Gx(void * codec, unsigned short Gx[], int maxLen);

//对信息data(二进制表述,不是域幂上标数)进行纠错编码,存储到code中。
/**
 * @brief oc_rs_encode 进行纠错编码
 * @param codec RS码编码译码器
 * @param data 信息data
 * @param code 编码code
 * @return 0表示成功
 */
int oc_rs_encode(void * codec,const unsigned short data[/*k*/], unsigned short code[/*n*/]) ;

//对数据code(二进制表述,不是域幂上标数)进行纠错译码,存储到data中。
/**
 * @brief oc_rs_decode 进行RS纠错译码
 * @param codec RS码编码译码器
 * @param code   数据code
 * @param result 纠错后的数据
 * @param checkedCode 除法校验后的结果
 * @return 0表示成功
 */
int oc_rs_decode(void * codec,const unsigned short code[/*n*/], unsigned short result[/*n*/], unsigned short * checkedCode/*n*/) ;

5. 测试GUI

如果有Qt,则可以编译并使用ocgui测试:

oc_gui

6. 代码链接

参考
https://gitcode.net/coloreaglestdio/taskbus_course/-/tree/master/src/a0channel_algs/ocalg
https://gitcode.com/colorEagleStdio/taskbus_course/tree/master/src/a0channel_algs/ocalg

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丁劲犇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值