CDROM,CIRC 编码器中的 F2 Reed-Solomon P Q 码

CDROM, F2 Reed-Solomon P Q codes in CIRC encoder

我研究CDROM原理的资料。在标准 http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-130.pdf 在第 35 页(pdf 中的 45)我看到了 CIRC 编码器。而他的有Q码,还有P码,都是用reed-solomon算法计算出来的。 我尝试确认这一点并制作一些示例音轨(音轨未使用加扰器作为数据轨道)一个填充 0x01 模式,一个填充 0xA5(数据包中的 CIRC 交错字节而不是位,我在 F3 帧中看到 Q 和 P) .在我用逻辑分析仪从 CD(直接从激光输出)读取这个扇区,并通过脚本解密之后。我有这个数据用于跟踪模式 0x01

S1 01 01 01 01 01 01 01 01 01 01 01 01 e5 6e 4e c5 01 01 01 01 01 01 01 01 01 01 01 01 ff ff ff ff

S2 01 01 01 01 01 01 01 01 01 01 01 01 e5 6e 4e c5 01 01 01 01 01 01 01 01 01 01 01 01 ff ff ff ff

第一个字节是此示例中的子代码 sumbol SYNC_1 和 SYNC_2

对于模式为 0xA5 的曲目

S1 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 6b bc a5 72 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 ff ff ff ff

S1 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 6b bc a5 72 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 ff ff ff ff

如果在 CIRC 上看到正确的 12-15 字节它的反向 Q 奇偶校验和 28-32 P 奇偶校验(第一个字节它的 sybcode 他在 F3 添加)。

但是我找不到计算这个字节的算法,我的数学能力很差。我尝试使用 cdrecord 中的计算器,他使用其他代码,尝试使用其他 Reed-Solomon 实现,但我无法从此示例中获得相同的代码。 我在哪里可以获得此代码的有效实现。

我根据 edc_ecc.c 网络 github 文件,在取得进展时将我在这个答案中找到的内容放入其中。 RSL12 是 GF(2^8),多项式 x^8 + x^4 + x^3 + x^2 + 1 => 十六进制 11d。该字段中的所有非零数字都可以视为十六进制 02 的幂。

十六进制的 P 生成多项式为:

(x+01)(x+02)(x+04)(x+08) = 01 x^4 + 0f x^3 + 36 x^2 + 78 x + 40

如果您查看 AP[...][31] 的 4 个条目,您会看到值 75、249、78、6,这些是十六进制 0f、36、78、40 的十进制日志。注意AP应该是AP[4][28](不是[4][32]),修复如下图

根据您(现已删除)的评论,我在您在原始问题中给出的示例中“未反转”Q,并使用我自己的 RS 演示程序计算 P 奇偶校验,我现在得到 00 00 00 00:

01 01 01 01 01 01 01 01 01 01 01 01 1a 91 b1 3a 01 01 01 01 01 01 01 01 01 01 01 01 00 00 00 00
a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 94 43 5a 8d a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 00 00 00 00

Q生成多项式与P生成多项式相同。用于RS(28,24),但是奇偶校验字节在中间,所以常规编码需要修改,如下所述。

AQ[][]是错误的,使用AQ[3][],得到Q[3],我得到的是69而不是3a:

01 01 01 01 01 01 01 01 01 01 01 01 -- -- -- 69 01 01 01 01 01 01 01 01 01 01 01 01

另外,AQ[0]只定义了21个字节,AQ[1]只定义了22个字节,AQ[2]只定义了23个字节,AQ[3]只定义了24个字节,但是它们是显然是错误的。

有一个解决方法,使用 4 擦除解码,将位置 12 到 15 标记为擦除(xx xx xx xx)进行 Q 编码:

01 01 01 01 01 01 01 01 01 01 01 01 xx xx xx xx 01 01 01 01 01 01 01 01 01 01 01 01
a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 xx xx xx xx a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5

4次纠错后,Q个校验字节编码为:

01 01 01 01 01 01 01 01 01 01 01 01 1a 91 b1 3a 01 01 01 01 01 01 01 01 01 01 01 01
a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 94 43 5a 8d a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5 a5

使用4擦除解码方式,我生成了一个固定的AQ[][]:

static const unsigned char AQ[4][24] =
  {{58,152,173,95,88,43,134,205,143,131,163,75,249,66,151,116,125,184,110,16,58,62,137,113},
   {30,214,148,138,112,154,157,96,49,198,189,249,69,47,147,235,156,47,209,183,138,232,205,120},
   {162,244,13,171,213,236,71,177,253,162,59,78,243,180,186,34,78,136,130,85,108,115,178,246},
   {158,179,101,94,49,140,211,149,137,169,81,6,72,157,122,131,190,116,22,64,68,143,119,22}};

但是,如果您计划编写解码器(修复擦除 and/or 错误),那么您可以使用与我相同的方法,即使用 4 擦除解码而不是进行编码。如果我没记错的话,这就是一些早期 DAT(数字音频磁带)驱动器实现这一点的方式,因为它们在数据中间也有奇偶校验字节。


AP 应该是 AP[4][28]。 P是RS(32,28),28字节的数据用来生成4字节的校验位。 AP[...][32] 每行的前 4 个值应该被删除,所以它变成 AP[4][28],并且 encode_L1_P() 应该编码 28 个字节的数据(一个行修复如下所述)。

static const unsigned char AP[4][28] =
  {{249,142,180,197,5,155,153,132,143,244,101,76,102,155,203,104,58,152,173,95,88,43,134,205,143,131,163,75},
   {205,252,218,199,202,41,136,106,119,238,193,103,123,242,83,178,30,214,148,138,112,154,157,96,49,198,189,249},
   {67,11,131,40,7,41,80,147,151,17,245,253,208,66,228,116,162,244,13,171,213,236,71,177,253,162,59,78},
   {148,186,203,11,161,159,138,149,250,107,82,108,161,209,110,64,158,179,101,94,49,140,211,149,137,169,81,6}};

encode_L1_P() 需要固定一行:

static int
encode_L1_P(inout)
    unsigned char inout[L1_RAW + L1_Q + L1_P];
{
    unsigned char *P;
    int i;

    P = inout + L1_RAW + L1_Q;

    memset(P, 0, L1_P);
    for (i = 0; i < L1_RAW + L1_Q; i++) {   /* fix (remove + L1_P) */
        unsigned char data;

        data = inout[i];
        if (data != 0) {
            unsigned char base = rs_l12_log[data];

            P[0] ^= rs_l12_alog[(base+AP[0][i]) % (unsigned)((1 << RS_L12_BITS)-1)];
            P[1] ^= rs_l12_alog[(base+AP[1][i]) % (unsigned)((1 << RS_L12_BITS)-1)];
            P[2] ^= rs_l12_alog[(base+AP[2][i]) % (unsigned)((1 << RS_L12_BITS)-1)];
            P[3] ^= rs_l12_alog[(base+AP[3][i]) % (unsigned)((1 << RS_L12_BITS)-1)];
        }
    }
    return (0);
}

回应评论。为了生成AQ,我使用擦除校正生成了24组奇偶校验:

01 00 00 00 00 00 00 00 00 00 00 00 69 60 bf b7 00 00 00 00 00 00 00 00 00 00 00 00
00 01 00 00 00 00 00 00 00 00 00 00 49 f9 fa 4b 00 00 00 00 00 00 00 00 00 00 00 00
...
00 00 00 00 00 00 00 00 00 00 00 00 9e a7 ab 93 00 00 00 00 00 00 00 00 00 00 01 00
00 00 00 00 00 00 00 00 00 00 00 00 1f 3b cf ea 00 00 00 00 00 00 00 00 00 00 00 01

AQ[][ 0] = hex log2{69 60 bf b7} = decimal {058 030 162 158}
AQ[][ 1] = hex log2{49 f9 fa 4b} = decimal {152 214 244 179}
...
AQ[][22] = hex log2{9e a7 ab 93} = decimal {137 205 178 119}
AQ[][23] = hex log2{1f 3b cf ea} = decimal {113 120 246 022}

另一种方法是使用一个全长 255 字节的代码字,除了在适当位置模 255 处设置为 01 的一个字节外,以标准方式生成奇偶校验,parities = msg * x^4 %发电机。这会生成超出其目标位置 16 个字节的奇偶校验位,因此需要将偏移量调整 255-16 = +239 模 255 以生成目标奇偶校验位:

255_byte_message_offset = 28_byte_message_offset + 239 % 255:

msg[239] = 01 => parities = 69 60 bf b7
msg[240] = 01 => parities = 49 f9 fa 4b
...
msg[010] = 01 => parities = 9e a7 ab 93
msg[011] = 01 => parities = 1f 3b cf ea