基于Excel的QR二维码生成工具——原理及算法详解(之三)
在上一篇文章中我们讨论了使用工作表函数计算RS码的算法,接下来,我们将讨论生成多项式的计算以及RS码计算的VBA算法。在已经有了工作表函数计算RS码的情况下,还要探讨使用VBA的原因是因为VBA的计算速度比工作表函数快得多。
在开始探讨生成多项式之前,必须要说明的是,在QR码标准GB18284-2000的附录中已经附带了所有在QR计算中可能会需要的生成多项式,甚至不需要的都一并附上了:
但是,有意思的是,RS码的生成多项式其实并不止一个,而且QR标准中给出的并不是标准生成多项式。我尝试了使用标准生成多项式所计算的纠错码,将其填充到QR矩阵中后,同样能够正确解码而且能够正确地纠错。因此,如果没有耐心,只想寻求干货的同学可以绕过这一段,而有兴趣的同学可以一起探讨一下,使用不同的生成多项式来创建与QR标准中完全不同的二维码。
我们知道标准生成多项式的公式为:
我们可以如同上一节中一样,将上述多项式的计算通过一个表格来实现:
v= | x <script id="MathJax-Element-24316" type="math/tex">x</script>的幂次 | x 1 <script id="MathJax-Element-24318" type="math/tex">x^1</script> | x 2 <script id="MathJax-Element-24319" type="math/tex">x^2</script> | x 3 <script id="MathJax-Element-24320" type="math/tex">x^3</script> | x 4 <script id="MathJax-Element-24321" type="math/tex">x^4</script> | x 5 <script id="MathJax-Element-24322" type="math/tex">x^5</script> | |
---|---|---|---|---|---|---|---|
g 1 (x) <script id="MathJax-Element-24323" type="math/tex">g_1(x)</script> | a <script id="MathJax-Element-24324" type="math/tex">a</script>的幂次 | 1 | 0 | ||||
乘数 | 2 | 0 |
上表中使用不同的列代表多项式的不同次数的项,并且将系数写到单元格中,可见第二行表示的就是
g 1 (x)
<script id="MathJax-Element-24326" type="math/tex">g_1(x)</script>,因为这个多项式的
x 0
<script id="MathJax-Element-24327" type="math/tex">x^0</script>项系数为
a
<script id="MathJax-Element-24328" type="math/tex">a</script>的1次幂,而
v= | x <script id="MathJax-Element-24336" type="math/tex">x</script>的幂次 | x 1 <script id="MathJax-Element-24338" type="math/tex">x^1</script> | x 2 <script id="MathJax-Element-24339" type="math/tex">x^2</script> | x 3 <script id="MathJax-Element-24340" type="math/tex">x^3</script> | x 4 <script id="MathJax-Element-24341" type="math/tex">x^4</script> | x 5 <script id="MathJax-Element-24342" type="math/tex">x^5</script> | |
---|---|---|---|---|---|---|---|
g 1 (x) <script id="MathJax-Element-24343" type="math/tex">g_1(x)</script> | a <script id="MathJax-Element-24344" type="math/tex">a</script>的幂次 | 1 | 0 | ||||
乘数 | 2 | 0 | |||||
g 1 (x) <script id="MathJax-Element-24346" type="math/tex">g_1(x)</script>乘以2 | a <script id="MathJax-Element-24347" type="math/tex">a</script>的幂次 | 3 | 2 | ||||
a <script id="MathJax-Element-24349" type="math/tex">a</script>的幂次 | 1 | 0 | |||||
a <script id="MathJax-Element-24351" type="math/tex">a</script>的幂次 | 3 | 26 | 0 |
上表中表示了这样的计算,请注意
同理我们可以用上面的表格计算 g 3 (x) <script id="MathJax-Element-24355" type="math/tex">g_3(x)</script>乃至于 g v (x) <script id="MathJax-Element-24356" type="math/tex">g_v(x)</script>
v= | x <script id="MathJax-Element-24357" type="math/tex">x</script>的幂次 | x 1 <script id="MathJax-Element-24359" type="math/tex">x^1</script> | x 2 <script id="MathJax-Element-24360" type="math/tex">x^2</script> | x 3 <script id="MathJax-Element-24361" type="math/tex">x^3</script> | x 4 <script id="MathJax-Element-24362" type="math/tex">x^4</script> | x 5 <script id="MathJax-Element-24363" type="math/tex">x^5</script> | |
---|---|---|---|---|---|---|---|
g 2 (x) <script id="MathJax-Element-24364" type="math/tex">g_2(x)</script> | a <script id="MathJax-Element-24365" type="math/tex">a</script>的幂次 | 3 | 26 | 0 | |||
乘数 | 3 | 0 | |||||
g 2 (x) <script id="MathJax-Element-24367" type="math/tex">g_2(x)</script>乘以3 | a <script id="MathJax-Element-24368" type="math/tex">a</script>的幂次 | 6 | 29 | 3 | |||
a <script id="MathJax-Element-24370" type="math/tex">a</script>的幂次 | 3 | 26 | 0 | ||||
a <script id="MathJax-Element-24372" type="math/tex">a</script>的幂次 | 6 | 201 | 199 | 0 |
在Excel中可以很容易根据上面的表格来构造
需要注意的是,在上面的算法中表格的最左列是
x
<script id="MathJax-Element-24374" type="math/tex">x</script>的最低次幂,而在RS计算表格中,最左列是
好了,现在我们已经完成了生成多项式的构造,并且探讨了RS码的表格式计算算法。已经完全可以开始进行QR的制作了么?不,没那么简单,使用工作表函数的RS码在进行小规模计算时,计算速度是完全可以胜任的,但是,如果填充的是高版本的QR码,计算量就非常可观了。通常情况下,一个QR码需要对长达上百位的数据码计算30个纠错码,并且因为QR的分段设计,同样的纠错码计算需要重复几十次,这样就导致计算表十分庞大,计算次数达到上百万次。我验证了一下,这样的表格在我的电脑上需要大约25秒才能完成计算,不具备实用性。因此,下面的VBA代码被用来实现同样的RS计算功能,但结果可以瞬间得到:
Private Function ECCALC(dataWords, N, k, gp)
' function that calculates error correction code of the input code words by generate polynomial
' codewords as first argument is the code word for which EC code is calculated
' n as second argument total number of code words
' k as third argument defines the number of data code words, thus n-k is the number of error correction code words
' output of the function is also defined as an array that contains the error correction code
' the error correction code is calculated on the galois field with primitive polynomial= x^8+x^4+x^3+x^2+1=0
'
Dim gpWords(), cWords(), dWords(), prod() As Long
ReDim gpWords(N - k), cWords(N), dWords(N), prod(N - k)
Dim divider As Long
Dim num, EC As Variant
Dim i,j As Long
With Sheets("RS Calc")
For i = 0 To 254
GF(i) = .Cells(7, i + 6)
GFP(i) = .Cells(8, i + 6)
Next
End With
'read genpoly
i = 0
For Each num In dataWords
If IsNumeric(num) Then
cWords(i) = num
i = i + 1
End If
Next
i = 0
For Each num In gp
If IsNumeric(num) Then
gpWords(i) = num
i = i + 1
End If
Next
'RS calculation starts
For i = 0 To k - 1
divider = cWords(0)
For j = 0 To N - 2 'calculate next code words by multiply genopoly with divider, and substract code word
If j < N - k And divider <> 0 Then
num = cWords(j + 1) Xor nGfMult(divider, gpWords(j + 1))
Else
num = cWords(j + 1) Xor 0
End If
cWords(j) = num
Next
Next
ECCALC = cWords
End Function