纯 Python Reed Solomon 编码器/解码器
项目描述
纯 Python通用错误和擦除 Reed-Solomon 编解码器 ,基于 wikiversity 的精彩教程,由“Bobmath”和“LRQ3000”编写。
<nav class="contents local" id="table-of-contents" role="doc-toc">
目录
</nav>安装
pip install --upgrade reedsolo
用法
高级 RSCodec 类的基本用法
# Initialization
>>> from reedsolo import RSCodec
>>> rsc = RSCodec(10) # 10 ecc symbols
# Encoding
>>> rsc.encode([1,2,3,4])
b'\x01\x02\x03\x04,\x9d\x1c+=\xf8h\xfa\x98M'
>>> rsc.encode(bytearray([1,2,3,4]))
bytearray(b'\x01\x02\x03\x04,\x9d\x1c+=\xf8h\xfa\x98M')
>>> rsc.encode(b'hello world')
b'hello world\xed%T\xc4\xfd\xfd\x89\xf3\xa8\xaa'
# Note that chunking is supported transparently to encode any string length.
# Decoding (repairing)
>>> rsc.decode(b'hello world\xed%T\xc4\xfd\xfd\x89\xf3\xa8\xaa')[0]
b'hello world'
>>> rsc.decode(b'heXlo worXd\xed%T\xc4\xfdX\x89\xf3\xa8\xaa')[0] # 3 errors
b'hello world'
>>> rsc.decode(b'hXXXo worXd\xed%T\xc4\xfdX\x89\xf3\xa8\xaa')[0] # 5 errors
b'hello world'
>>> rsc.decode(b'hXXXo worXd\xed%T\xc4\xfdXX\xf3\xa8\xaa')[0] # 6 errors - fail
Traceback (most recent call last):
...
reedsolo.ReedSolomonError: Too many (or few) errors found by Chien Search for the errata locator polynomial!
1.0 之前用户的重要升级通知:请注意RSCodec.decode()返回 3 个变量:
解码(更正)的消息
解码的消息和纠错码(本身也被纠正)
以及勘误表的位置列表(错误和擦除)
这是一个例子:
>>> tampered_msg = b'heXlo worXd\xed%T\xc4\xfdX\x89\xf3\xa8\xaa'
>>> decoded_msg, decoded_msgecc, errata_pos = rsc.decode(tampered_msg)
>>> print(decoded_msg) # decoded/corrected message
bytearray(b'hello world')
>>> print(decoded_msgecc) # decoded/corrected message and ecc symbols
bytearray(b'hello world\xed%T\xc4\xfd\xfd\x89\xf3\xa8\xaa')
>>> print(errata_pos) # errata_pos is returned as a bytearray, hardly intelligible
bytearray(b'\x10\t\x02')
>>> print(list(errata_pos)) # convert to a list to get the errata positions as integer indices
[16, 9, 2]
由于我们使用设置为 10 个纠错码 (ecc) 符号的编解码器未能解码 6 个错误,因此让我们尝试使用更大的编解码器,具有 12 个 ecc 符号。
>>> rsc = RSCodec(12) # using 2 more ecc symbols (to correct max 6 errors or 12 erasures)
>>> rsc.encode(b'hello world')
b'hello world?Ay\xb2\xbc\xdc\x01q\xb9\xe3\xe2='
>>> rsc.decode(b'hello worXXXXy\xb2XX\x01q\xb9\xe3\xe2=')[0] # 6 errors - ok, but any more would fail
b'hello world'
>>> rsc.decode(b'helXXXXXXXXXXy\xb2XX\x01q\xb9\xe3\xe2=', erase_pos=[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 16])[0] # 12 erasures - OK
b'hello world'
这表明我们可以解码两倍于错误(位置未知)的擦除(我们自己提供错误的位置)。这是纠错与擦除校正相比的成本。
要获得可以独立纠正(即不同时)的最大错误或擦除数:
>>> maxerrors, maxerasures = rsc.maxerrata(verbose=True)
This codec can correct up to 6 errors and 12 erasures independently
>>> print(maxerrors, maxerasures)
6 12
要获得可以同时纠正的最大错误和擦除数,您需要指定您期望的错误或擦除数:
>>> maxerrors, maxerasures = rsc.maxerrata(erasures=6, verbose=True) # we know the number of erasures, will calculate how many errors we can afford
This codec can correct up to 3 errors and 6 erasures simultaneously
>>> print(maxerrors, maxerasures)
3 6
>>> maxerrors, maxerasures = rsc.maxerrata(errors=5, verbose=True) # we know the number of errors, will calculate how many erasures we can afford
This codec can correct up to 5 errors and 2 erasures simultaneously
>>> print(maxerrors, maxerasures)
5 2
请注意,如果一个块具有比maxerrata()方法计算的 Singleton Bound 更多的错误和擦除,编解码器将尝试引发ReedSolomonError异常,但很可能也不会检测到任何错误(这是错误的理论限制校正码)。换句话说,纠错码不能可靠地检测到消息的块是否在单例界限之外被破坏。如果您想在勘误检测中获得更高的可靠性,请在您的消息上使用校验和或哈希,例如 SHA 或 MD5,这些更可靠并且对勘误的数量没有限制(唯一的潜在问题是冲突,但概率非常非常低)。
要检查消息是否在给定纠错符号的情况下被篡改,无需解码,请使用check()方法:
# Checking
>> rsc.check(b'hello worXXXXy\xb2XX\x01q\xb9\xe3\xe2=') # Tampered message will return False
[False]
>> rmes, rmesecc, errata_pos = rsc.decode(b'hello worXXXXy\xb2XX\x01q\xb9\xe3\xe2=')
>> rsc.check(rmesecc) # Corrected or untampered message will return True
[True]
>> print('Number of detected errors and erasures: %i, their positions: %s' % (len(errata_pos), list(errata_pos)))
Number of detected errors and erasures: 6, their positions: [16, 15, 12, 11, 10, 9]
默认情况下,大多数 Reed-Solomon 编解码器仅限于可以编码为 256 位且最大长度为 256 个字符的字符。但是这个编解码器是通用的,你可以通过增加 Galois Field 来减少或增加长度和最大字符值:
# To use longer chunks or bigger values than 255 (may be very slow)
>> rsc = RSCodec(12, nsize=4095) # always use a power of 2 minus 1
>> rsc = RSCodec(12, c_exp=12) # alternative way to set nsize=4095
>> mes = 'a' * (4095-12)
>> mesecc = rsc.encode(mes)
>> mesecc[2] = 1
>> mesecc[-1] = 1
>> rmes, rmesecc, errata_pos = rsc.decode(mesecc)
>> rsc.check(mesecc)
[False]
>> rsc.check(rmesecc)
[True]
请注意,RSCodec类支持透明分块,因此您无需增加 Galois 字段以支持更长的消息,但字符仍将限制为 256 位(或您使用c_exp设置的任何字段)。
通过直接访问数学函数的低级使用
如果你想要完全控制,你可以跳过 API 直接使用库。就是这样:
首先,您需要初始化预先计算的表:
>> import reedsolo as rs
>> rs.init_tables(0x11d)
专业提示:如果您收到错误:ValueError: byte must be in range(0, 256),请检查您的素数多项式是否适合您的领域。专业提示2:默认情况下,您只能编码最大长度和最大符号值 = 256 的消息。如果要编码更大的消息,请使用以下内容(其中 c_exp 是您的伽罗瓦域的指数,例如,12 = 最大长度2^12 = 4096):
>> prim = rs.find_prime_polys(c_exp=12, fast_primes=True, single=True)
>> rs.init_tables(c_exp=12, prim=prim)
让我们定义我们的 RS 消息和 ecc 大小:
>> n = 255 # length of total message+ecc
>> nsym = 12 # length of ecc
>> mes = "a" * (n-nsym) # generate a sample message
为了优化,您可以预先计算生成多项式:
>> gen = rs.rs_generator_poly_all(n)
然后编码:
>> mesecc = rs.rs_encode_msg(mes, nsym, gen=gen[nsym])
让我们篡改我们的消息:
>> mesecc[1] = 0
解码:
>> rmes, recc, errata_pos = rs.rs_correct_msg(mesecc, nsym, erase_pos=erase_pos)
请注意,消息和 ecc 都已更正(当然,如果可能的话)。专业提示:如果您知道一些擦除位置,可以在列表中指定它们erase_pos以使修复能力加倍。但您也可以只指定一个空列表。
您可以检查纠正了多少错误和/或擦除,这对于设计自适应比特率算法很有用:
>> print('A total of %i errata were corrected over all chunks of this message.' % len(errata_pos))
如果解码失败,它通常会自动检查并引发您可以处理的 ReedSolomonError 异常。但是,如果您想手动检查修复的消息是否正确,您可以这样做:
>> rs.rs_check(rmes + recc, nsym)
注意:如果你想使用多个不同参数的reedsolomon,你需要在调用reedsolo函数之前备份全局并恢复它们:
>> rs.init_tables()
>> global gf_log, gf_exp, field_charac
>> bak_gf_log, bak_gf_exp, bak_field_charac = gf_log, gf_exp, field_charac
然后,您可以随时执行以下操作:
>> global gf_log, gf_exp, field_charac
>> gf_log, gf_exp, field_charac = bak_gf_log, bak_gf_exp, bak_field_charac
>> mesecc = rs.rs_encode_msg(mes, nsym)
>> rmes, recc, errata_pos = rs.rs_correct_msg(mesecc, nsym)
如果您使用 RSCodec,则不需要全局备份,它将被自动管理。
阅读源代码的注释以获取有关其工作原理的更多信息,以及如果您需要与其他 RS 编解码器交互可以设置的各种参数。
扩展描述
wikiversity 的代码在这里被整合到一个带有异常处理的漂亮 API 中。该算法最多可以纠正 2*e+v <= nsym,其中 e 是错误的数量,v 是擦除的数量,nsym = nk = ECC(纠错码)符号的数量。这意味着您可以准确地纠正 floor(nsym/2) 错误或 nsym 擦除(您知道位置的错误),以及错误和擦除的组合。这被称为 Singleton Bound,它是任何纠错算法可以纠正的最大/最优理论擦除和错误数(尽管有一些实验方法可以更进一步,命名为列表解码,此处未实现,但随意拉请求!)。该代码应该适用于几乎任何合理版本的 python (2.4-3.7),但我只在 2.7 和 3.7 上进行测试。蟒蛇 3。
如果您在纯 python 实现 (reedsolo.py) 上使用 PyPy,或者如果您编译 Cython 扩展 creedsolo.pyx(比 PyPy 快约 2 倍),则编解码器具有相当合理的性能。您可以预期几 MB/s 的编码速率。
该库也经过了彻底的单元测试,因此几乎可以涵盖任何编码/解码情况。
该编解码器是通用的,这意味着只要您提供正确的参数,它就可以解码由另一个 RS 编码器编码的任何消息。但是请注意,如果您使用更高的字段(即更大的 c_exp),算法会更慢,首先因为我们不能使用优化的 bytearray() 结构而只能使用 array.array('i', ...),还因为 Reed -所罗门的复杂性是二次的(在编码和解码方面),所以这意味着你的消息越长,编码/解码所需的时间就越长(二次!)。
该算法本身可以处理每个消息(或块)长度最多为 (2^c_exp)-1 个符号的消息,包括 ECC 符号,并且每个符号可以具有最多 (2^c_exp)-1 的值(实际上,一个字符的消息长度和最大值都受到相同的数学原因的约束)。默认情况下,我们使用 GF(2^8) 字段,这意味着您只能使用 0 到 255 之间的值(非常适合在计算机上表示单个十六进制符号,因此您可以编码任何二进制流)并且仅限于消息+ ecc 的最大长度为 255。但是,您可以“分块”更长的消息以使其符合消息长度限制。RSCodec _类将自动应用分块,通过将较长的消息分成块并分别编码/解码它们;从 API 的角度来看(即从您的 POV 来看),它不应该有所作为。
要使用 Cython 实现,您需要pip install cython和 C++ 编译器(Microsoft Visual C++ 14.0 for Windows 和 Python 3.7)。然后你可以简单地 cd 到 creedsolo.pyx 所在文件夹的根目录,然后输入python setup.py build_ext --inplace。或者,您可以通过键入cython -3 creedsolo.pyx仅生成 C++ 代码。在构建可分发的 egg 或从源代码安装模块时,如果同时安装了 Cython 和 C 编译器,Cython 模块将被自动转译和编译。可以使用setup.py的--nocython和--native-compile参数修改此行为。
执照
该软件已发布到公共领域。
如果公共领域不足以满足您的目的,您可以根据自己的喜好考虑使用 MIT 许可证下的此模块。
项目详情
下载文件
下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。