初识二维码 第11讲 里得所罗门纠错算法 也叫Reed-Solomon码的编码
类似于BCH编码,RS码通过生成(irreducible generator)和分解(dividing)多项
式来表达信息,分解余下的多项式(remainder)就是RS码,最后我们将RS码附
加在原信息后。
BCH编码乃至其它大多数的纠错码编码原则是:采用有限的字典(limited dictionary)
存储差异最大的信息元,越长的信息元差异往往越大。在上述RS编码方式中,我们
通过将RS码后缀在原信息码后面的方式,加长了原码长;而RS码基本是独一无二的,
通过巧妙的算法,可以用RS码来推断原信息。
通俗的讲,类比加密的过程,生成多项式(generator polynomial)就是我们编码用的
字典,而用它除原信息多项式的运算就是我们加密(RS编码)的过程。
RS生成多项式
RS码使用类似BCH码的生成多项式,将 (x - α^n) 乘起来
下面这个函数计算对于给定数量nsym个校验符号的RS码需要的生成多项式:
function rs_generator_poly(nsym)
{
var g = [1];
for(var i=0;i<nsym;i++)
// # g = gf_poly_mul(g, [1, gf_pow(2, i)]) # 指数运算,跟下面等效
{ g = gf_poly_mul(g, [1, gf_exp(i)]);}
return g;
}
多项式除法
现成的多项式除法算法中,最简单的是类似整数除法的算法。下面的例子展示了数
据 12 34 56 (注记:这是16进制表示的)是如何被编码的:
余数和原数据连起来得到编码后的数据 12 34 56 37 e6 78 d9
function gf_poly_div(dividend, divisor)
{
var msg_out= apply(dividend,function(a){
return a;
});
for(var i=0;i<dividend.length-(divisor.length-1);i++)
{
var coef = msg_out[i];
if (coef != 0)
{
for(var j=1;j<divisor.length;j++)
{
if (divisor[j] != 0)
{ msg_out[i + j] ^= gf_mul(divisor[j], coef); }
}
}
}
var remainder= get_array_sub(msg_out, dividend.length-(divisor.length-1),dividend.length-1)
return remainder;
}
编码函数
下面的这个函数实现了编码过程(译注:可以参考2.1的BCH编码过程
(fmt<<10) ^ qr_check_format(fmt << 10),那里有个译注解释为什么这么编码):
function rs_encode_msg(msg_in, nsym)
{
// '''Reed-Solomon main encoding function'''
var gen = rs_generator_poly(nsym);
var b_arr=initArray([gen.length-1],function(a){return 0;});
var dividend=arr_concat(msg_in,b_arr);
var remainder = gf_poly_div(dividend,gen);//(msg_in + [0] * (len(gen)-1), gen);
var msg_out = arr_concat(msg_in , remainder);
return msg_out;
}
下面这个例子演示了编码函数如何对第一节的样例QR码中的数据进行编码。
它计算出的结果中的第二行(译注:输出的第二行)与样例QR码中解码出来的纠错码相符
>>> msg_in = [ 0x40, 0xd2, 0x75, 0x47, 0x76, 0x17, 0x32, 0x06,
... 0x27, 0x26, 0x96, 0xc6, 0xc6, 0x96, 0x70, 0xec ]
>>> msg = rs_encode_msg(msg_in, 10)
0x40 0xd2 0x75 0x47 0x76 0x17 0x32 0x6 0x27 0x26 0x96 0xc6 0xc6
0x96 0x70 0xec0xbc 0x2a 0x90 0x13 0x6b 0xaf 0xef 0xfd 0x4b 0xe0