(16) 有限码长下的 Polar 码:系统 Polar 码、CRC 与性能曲线怎么看

有限码长下的 Polar 码:系统 Polar 码、CRC 与性能曲线怎么看

前 15 篇已经介绍了 Polar 码的构造、SC、SCL 和 CA-SCL。本篇继续回答一个更接近实际的问题:理论上容量可达的 Polar 码,为什么在有限码长下还需要系统编码、CRC 和大量仿真?

本文先区分渐近结论和有限码长性能,再说明系统 Polar 码究竟改变了什么,最后解释 CRC、BER、BLER 和性能曲线之间的关系。全文采用 0-based 索引,并使用下面的基本符号:N=2^n 是 Polar 母码长,A 是消息向量比特数,L_{\mathrm{CRC}} 是 CRC 比特数,K 是实际进入 Polar 编码器的信息比特数,R=K/N 是 Polar 码率。

“容量可达”到底说明什么

“容量可达”描述的是码长趋于无穷时的一类理论性质,不是对某一个短码的性能承诺。设信道为二元输入离散无记忆信道 W,其对称容量为 I(W)。Polar 码的渐近结论可以概括为:当 N 越来越大时,可以选择合适的信息位集合,使

\frac{K}{N}\longrightarrow I(W),\qquad P_{\mathrm{BLER}}\longrightarrow 0

这里 P_{\mathrm{BLER}} 表示块错误概率。这个结论的含义是:码率可以逼近信道的对称容量,同时仍能把块错误概率压到 0。它没有说任意 N、任意构造方法、任意译码器下的 Polar 码都已经达到这个极限。

因此,“容量可达”至少包含三个条件:码长要进入渐近区域,信息位要按照信道可靠性合理选择,译码器也要采用与理论结论相对应的规则。实际系统往往使用有限的 N,还会加入 CRC、列表译码、量化和率匹配,所以最终性能必须通过有限码长实验观察。

为什么有限码长会产生性能差距

有限码长下,Polar 码的子信道还没有完全分成“几乎可靠”和“几乎不可靠”两类。可靠性排序中会有一批处在中间区域的子信道,构造器必须在这些位置中作出选择。这个选择一旦有偏差,就会直接影响译码错误率。

性能差距通常来自以下几方面:

  1. 极化仍不充分。 N 较小时,部分子信道的可靠性处于过渡区,不能简单按照渐近结论处理。
  2. 构造依赖条件。 GA 等构造方法使用 design-SNR,记为 \rho_{\mathrm{des}}。如果构造条件与实际仿真的 \rho_{\mathrm{sim}} 相差较大,可靠性排序可能不再合适。
  3. 译码能力有限。 SC 只保留一条判决路径;SCL 保留 L_{\max} 条路径,但列表宽度受复杂度和存储限制。
  4. 发送链路会改变观测。 率匹配、LLR 量化和饱和都会改变译码器实际看到的 \underline{\lambda}

有限块长理论常用下面的正规近似来说明这种差距的尺度:

R^*(N,\epsilon)\approx C-\sqrt{\frac{V}{N}}Q^{-1}(\epsilon)+O\left(\frac{\log N}{N}\right)

其中 C 是信道容量,V 是信道色散,\epsilon 是目标块错误概率,Q^{-1} 是高斯 Q 函数的反函数。这个式子不是某个具体 Polar 构造的性能公式,它只说明:当 N 有限时,可靠通信的最大码率一般会比容量低,并且会出现与 1/\sqrt{N} 有关的代价。

先核对消息长度、CRC 长度和码率

加入 CRC 后,进入 Polar 编码器的并不是只有消息向量。设消息向量为

\underline{m}_0^{A-1}\in\mathbb{F}_2^A

CRC 根据 \underline{m} 产生 L_{\mathrm{CRC}} 个校验比特,记为 \underline{r}_0^{L_{\mathrm{CRC}}-1}。把两者连接起来,得到 Polar 编码器真正接收的信息序列:

\underline{b}_0^{K-1}=\underline{m}_0^{A-1}\Vert\underline{r}_0^{L_{\mathrm{CRC}}-1},\qquad K=A+L_{\mathrm{CRC}}

因此,Polar 码率是

R=\frac{K}{N}=\frac{A+L_{\mathrm{CRC}}}{N}

而如果只关心消息向量占母码长的比例,还可以定义消息效率

R_{\mathrm{msg}}=\frac{A}{N}

这两个量不能混用。R 决定有多少比特进入 Polar 编码器,R_{\mathrm{msg}} 只计算真正要交付给上层的消息向量。

一个参数核对例子

A=32,\qquad L_{\mathrm{CRC}}=6,\qquad N=64

K=32+6=38,\qquad R=\frac{38}{64}=0.59375,\qquad R_{\mathrm{msg}}=\frac{32}{64}=0.5

如果把 32/64=0.5 写成 Polar 码率,就漏掉了进入编码器的 6 个 CRC 比特。反过来,如果比较的是消息向量的传输效率,写成 38/64 又会把校验比特当成消息向量。

如果保持 K=38 不变而把码长改为 N=128,则

R=\frac{38}{128}=0.296875

这个配置和 N=64 的配置已经不是相同码率的比较。若要研究码长的影响,必须明确是固定 K、固定 A,还是固定 R。不同的固定方式会改变问题本身。

什么是系统 Polar 码

先回顾非系统 Polar 编码。设 \mathbf{G}_N 为 Polar 生成矩阵,信息位集合为 \mathcal{A},冻结位集合为 \mathcal{A}^c=[0,N-1]\setminus\mathcal{A}。冻结位固定为 0 时,极化输入向量 \underline{u}_0^{N-1} 经过编码得到

\underline{c}_0^{N-1}=\underline{u}_0^{N-1}\mathbf{G}_N

在非系统形式中,消息向量或消息向量加 CRC 的比特通常位于 \underline{u}_{\mathcal{A}} 中,但不一定会在码字 \underline{c} 的相同坐标上直接出现。

系统 Polar 码增加了一个坐标约束。选定码字中的系统坐标集合 \mathcal{I},满足 |\mathcal{I}|=K,希望

\underline{c}_{\mathcal{I}}=\underline{b}_0^{K-1}

这里的 \underline{b} 是消息向量与 CRC 连接后的信息序列。系统编码的关键不是把 \underline{b} 直接写进 \underline{u}_{\mathcal{A}},而是先求出一组 \underline{u}_{\mathcal{A}},使编码后的指定坐标恰好等于 \underline{b}

把生成矩阵抽取出信息位对应的行和系统坐标对应的列,记为

\mathbf{G}_{\mathcal{A},\mathcal{I}}=\mathbf{G}_N[\mathcal{A},\mathcal{I}]

在冻结位为 0 且该子矩阵可逆时,有

\underline{c}_{\mathcal{I}}=\underline{u}_{\mathcal{A}}\mathbf{G}_{\mathcal{A},\mathcal{I}}

要满足系统约束,就需要在 \mathbb{F}_2 中求解

\underline{u}_{\mathcal{A}}=\underline{b}_0^{K-1}\mathbf{G}_{\mathcal{A},\mathcal{I}}^{-1}

这说明系统编码是一次线性方程求解,而不是对码字的几位进行事后替换。

N=4 的系统编码例子

为了把这个过程算清楚,取自然顺序下的生成矩阵

\mathbf{G}_4=\begin{bmatrix}1&0&0&0\\1&1&0&0\\1&0&1&0\\1&1&1&1\end{bmatrix},\qquad \mathcal{A}=\{2,3\},\qquad \mathcal{I}=\{2,3\}

冻结位为 u_0=u_1=0,抽出的子矩阵是

\mathbf{G}_{\mathcal{A},\mathcal{I}}=\begin{bmatrix}1&0\\1&1\end{bmatrix}

设要发送的系统信息为 \underline{b}=(b_0,b_1)。在 \mathbb{F}_2 上有

\begin{bmatrix}1&0\\1&1\end{bmatrix}\begin{bmatrix}1&0\\1&1\end{bmatrix}=\begin{bmatrix}1&0\\0&1\end{bmatrix}

所以这个子矩阵的逆矩阵就是自身,从而

\underline{u}_{\mathcal{A}}=(b_0,b_1)\begin{bmatrix}1&0\\1&1\end{bmatrix}=(b_0\oplus b_1,b_1)

u_2=b_0\oplus b_1u_3=b_1 写回输入向量后,编码得到

c_2=u_2\oplus u_3=b_0,\qquad c_3=u_3=b_1

因此 (c_2,c_3)=(b_0,b_1),系统约束成立。

如果直接把 (b_0,b_1) 填入 (u_2,u_3),则

c_2=b_0\oplus b_1

通常不等于 b_0。这就是系统编码最容易被误解的地方:系统位置上的信息是经过求解后出现在码字中的,不是简单复制进去的。

系统 Polar 编码的 C++ 实现

下面的函数实现文章前面定义的系统编码过程。输入的 message 是长度为 K 的消息序列;它可以只包含消息向量,也可以包含消息向量和 CRC,具体取决于上层约定。infoIndices 按母码索引升序给出信息位集合 \mathcal A,systemIndices 给出码字中的系统坐标集合 \mathcal I,两者长度都必须是 K

代码采用自然顺序生成矩阵

\mathbf G_N=\mathbf F_2^{\otimes n},\qquad [\mathbf G_N]_{i,j}=1\ \Longleftrightarrow\ (j\mathbin{\&}i)=j.

其中 C++ 的 & 只用于判断索引的二进制位关系;真正的编码加法仍然使用 GF(2) 中的异或。函数先求解 \underline{u}_{\mathcal A}\mathbf G_{\mathcal A,\mathcal I}=\underline b,再把求得的输入向量编码为长度 N 的码字。

#include <algorithm>
#include <cstddef>
#include <stdexcept>
#include <vector>

std::vector<int> systematicPolarEncode(
    const std::vector<int>& message,
    std::size_t N,
    const std::vector<std::size_t>& infoIndices,
    const std::vector<std::size_t>& systemIndices) {
    const std::size_t K = infoIndices.size();

    // Polar 母码长必须是 2 的幂;系统坐标和信息位集合都必须有 K 个位置。
    if (N == 0 || (N & (N - 1)) != 0 ||
        message.size() != K || systemIndices.size() != K) {
        throw std::invalid_argument("inconsistent Polar-code dimensions");
    }

    // 检查比特值、索引范围和索引唯一性。
    std::vector<bool> seenInfo(N, false);
    std::vector<bool> seenSystem(N, false);
    for (int bit : message) {
        if (bit != 0 && bit != 1) {
            throw std::invalid_argument("message bits must be binary");
        }
    }
    for (std::size_t i : infoIndices) {
        if (i >= N || seenInfo[i]) {
            throw std::invalid_argument("invalid information-bit index");
        }
        seenInfo[i] = true;
    }
    for (std::size_t i : systemIndices) {
        if (i >= N || seenSystem[i]) {
            throw std::invalid_argument("invalid systematic-bit index");
        }
        seenSystem[i] = true;
    }

    // 构造自然顺序下的 G_N。G[i][j] 表示输入位 u_i
    // 是否参与码字位 c_j;因此 c_j 是所有相关 u_i 的 GF(2) 异或。
    std::vector<std::vector<int>> G(N, std::vector<int>(N, 0));
    for (std::size_t i = 0; i < N; ++i) {
        for (std::size_t j = 0; j < N; ++j) {
            G[i][j] = ((j & i) == j) ? 1 : 0;
        }
    }

    // 把行向量方程 u_A * G[A,I] = message 改写成普通的
    // 方程组:每一行对应一个系统坐标,每一列对应一个未知的 u_A。
    std::vector<std::vector<int>> equation(
        K, std::vector<int>(K + 1, 0));
    for (std::size_t row = 0; row < K; ++row) {
        equation[row][K] = message[row];
        for (std::size_t col = 0; col < K; ++col) {
            equation[row][col] =
                G[infoIndices[col]][systemIndices[row]];
        }
    }

    // GF(2) Gauss-Jordan 消元。每一步把当前列化为单位阵的一列;
    // 如果找不到主元,说明 G[A,I] 不可逆,不能按这组坐标系统化。
    for (std::size_t col = 0; col < K; ++col) {
        std::size_t pivot = col;
        while (pivot < K && equation[pivot][col] == 0) {
            ++pivot;
        }
        if (pivot == K) {
            throw std::invalid_argument(
                "G[A,I] is singular; choose another system set");
        }
        if (pivot != col) {
            std::swap(equation[pivot], equation[col]);
        }

        for (std::size_t row = 0; row < K; ++row) {
            if (row != col && equation[row][col] != 0) {
                for (std::size_t j = col; j <= K; ++j) {
                    equation[row][j] ^= equation[col][j];
                }
            }
        }
    }

    // 消元完成后,左侧是单位阵,最后一列就是 u_A。
    std::vector<int> u(N, 0);
    for (std::size_t k = 0; k < K; ++k) {
        u[infoIndices[k]] = equation[k][K];
    }

    // 执行 c = u * G_N。每个 c_j 都在 GF(2) 中累加,
    // 因而这里使用异或,而不是普通整数加法。
    std::vector<int> codeword(N, 0);
    for (std::size_t i = 0; i < N; ++i) {
        for (std::size_t j = 0; j < N; ++j) {
            codeword[j] ^= (u[i] & G[i][j]);
        }
    }

    // 这是系统编码的最终不变量:指定系统坐标必须逐位等于 message。
    for (std::size_t k = 0; k < K; ++k) {
        if (codeword[systemIndices[k]] != message[k]) {
            throw std::logic_error("systematic-coordinate check failed");
        }
    }
    return codeword;
}

对前面的 N=4 例子,可以这样调用:

#include <cstddef>
#include <vector>

std::vector<int> systematicPolarEncode(
    const std::vector<int>& message,
    std::size_t N,
    const std::vector<std::size_t>& infoIndices,
    const std::vector<std::size_t>& systemIndices);

const std::vector<int> message = {1, 0};
const std::vector<std::size_t> information = {2, 3};
const std::vector<std::size_t> systematic = {2, 3};

const std::vector<int> codeword =
    systematicPolarEncode(message, 4, information, systematic);
// 返回 (1, 0, 1, 0),其中 c_2=1、c_3=0。

这里 information 和 systematic 的顺序都决定了 message[k] 对应哪个位置:message[0] 对应 c_2,message[1] 对应 c_3。如果只把消息比特直接写入 u_2,u_3,就会得到不同的码字,这正是系统编码需要先解线性方程的原因。

系统 Polar 码、CRC 和译码器各自解决什么问题

系统编码和 CRC 经常一起出现,但它们不是同一种机制。

机制主要作用是否增加校验约束
系统 Polar 编码让信息序列在码字的指定坐标上直接可见
CRC在消息和校验比特之间建立代数关系
SCL保留多条候选,降低单路径判决造成的损失
CA-SCL用 CRC 从 SCL 候选中排除不合法序列CRC 提供约束

系统化主要改变同一个线性码的表示方式。对于相同的信息位集合和相同的码线性子空间,系统编码不会凭空增加冗余;它的优点是信息比特在码字中有直接位置,便于观测和统计。CRC 则确实增加了 L_{\mathrm{CRC}} 个校验比特,并且会使进入 Polar 编码器的比特数从 A 变为 K=A+L_{\mathrm{CRC}}

因此,比较系统 Polar 码和非系统 Polar 码时,必须说明比较的是哪一种错误:码字错误、极化输入信息位错误,还是消息向量错误。比较 SCL 和 CA-SCL 时,还要说明 CRC 长度和 L_{\max},否则码率和译码条件可能同时发生变化。

BER、BLER 和 CRC 失败不是一回事

性能曲线首先要说明统计对象。设发送的消息向量为 \underline{m}_0^{A-1},译码后得到 \hat{\underline{m}}_0^{A-1}。定义第 i 个消息向量比特是否错误:

e_i=\begin{cases}1,&\hat{m}_i\ne m_i,\\0,&\hat{m}_i=m_i\end{cases}

一个消息块是否错误,则定义为

e_{\mathrm{blk}}=\begin{cases}1,&\exists i\in[0,A-1],\ \hat{m}_i\ne m_i,\\0,&\text{otherwise}\end{cases}

经过 n_{\mathrm{blk}} 个消息块后,若错误比特总数为 N_{\mathrm{bit,err}},错误块数为 N_{\mathrm{blk,err}},则

\widehat{\mathrm{BER}}=\frac{N_{\mathrm{bit,err}}}{A n_{\mathrm{blk}}},\qquad \widehat{\mathrm{BLER}}=\frac{N_{\mathrm{blk,err}}}{n_{\mathrm{blk}}}

BER 的统计单位是比特,BLER 的统计单位是消息块。一个错误块可能只有 1 个错误比特,也可能有很多错误比特,所以 BER 和 BLER 不会相同。

CRC 失败应单独记录。它表示候选没有通过校验,不等于消息向量一定错误,也不等于消息向量一定正确。比如译码出的消息部分恰好正确,但 CRC 部分有一位错误,此时 CRC 失败而消息向量 BLER 为 0;反过来,消息部分发生错误的候选也可能以很小的概率通过 CRC。

如果资料使用 FER,必须先确认它的统计对象和本文的消息块是否相同。只有在两者都按“一个消息块是否出错”统计时,才可以明确写出 \mathrm{FER}\equiv\mathrm{BLER}。不能把 CRC 失败次数直接当成 BER,也不能无条件把它替换成 BLER。

一个完整的统计例子

假设在某个 \rho_{\mathrm{sim}} 点发送 n_{\mathrm{blk}}=10\,000 个消息块,每个消息含 A=32 个比特。译码结果中有 20 个消息块出错,错误消息比特总数为 64 个,则

\widehat{\mathrm{BLER}}=\frac{20}{10\,000}=2\times10^{-3} \widehat{\mathrm{BER}}=\frac{64}{32\times10\,000}=2\times10^{-4}

如果另外有 35 个候选没有通过 CRC,应该再记录 CRC 失败率

\widehat{P}_{\mathrm{CRC\text{-}fail}}=\frac{35}{10\,000}=3.5\times10^{-3}

分子表示的事件不同。CRC 失败率比消息 BLER 高,并不能据此得出消息错误更多;其中可能包含消息正确但 CRC 位错误的情况。

性能曲线应该怎样比较

横轴通常是仿真信噪比 \rho_{\mathrm{sim}},纵轴可以是 BER 或 BLER。读图时按下面顺序检查:

  1. 先确认纵轴统计的是消息向量 BER、信息比特 BER,还是码字 BER;
  2. 再确认纵轴是 BLER 还是 CRC 失败率;
  3. 确认不同曲线使用相同的 NAL_{\mathrm{CRC}}、构造方法和 L_{\max}
  4. 确认横轴的单位是 dB 还是线性信噪比,并确认噪声方差定义一致;
  5. 最后比较同一个目标错误率下所需的 \rho_{\mathrm{sim}}

例如,假设两条曲线在目标 BLER 10^{-2} 处分别对应 2.4\,\mathrm{dB}2.8\,\mathrm{dB},前者在该实验条件下少需要 0.4\,\mathrm{dB} 的信噪比。这个结论只能说明两条曲线在给定 N、码率、构造和译码配置下的差异,不能直接推广为某个方法在所有参数下都更好。

比较时最容易出现的错误,是同时改变多个条件。例如一条曲线使用 N=128L_{\max}=8,另一条使用 N=64L_{\max}=4,即使前者性能更好,也不能把全部增益归因于系统 Polar 码或 CRC。一个可复现的比较表至少应包含:

类别需要记录的参数
消息与码长AL_{\mathrm{CRC}}KNR
构造构造方法、\rho_{\mathrm{des}}、信息位集合 \mathcal{A}
译码SC、SCL 或 CA-SCL、L_{\max}、LLR 量化范围
信道\rho_{\mathrm{sim}}、噪声方差、是否率匹配
统计总块数、错误块数、错误比特数、CRC 失败次数、停止条件

本篇小结

Polar 码的“容量可达”是码长趋于无穷时的渐近结论,不能直接等同于短码性能。有限码长下,极化过渡区、构造条件、译码列表宽度、率匹配和统计数量都会影响曲线。

系统 Polar 码改变的是信息序列在码字中的呈现方式:它需要通过线性方程求解,让信息比特出现在指定码字坐标中。CRC 改变的是候选的合法性约束:它为 CA-SCL 提供额外的筛选依据。二者经常一起使用,但作用不同。

最后,BER 统计错误比特,BLER 统计错误消息块,CRC 失败统计校验未通过事件。只有先明确统计对象,再固定实验参数,性能曲线才具有可比较性。下一篇将讨论率匹配,解释为什么发送长度 E 不等于 Polar 母码长 N 时,接收端必须以不同方式恢复 LLR。

参考

  • E. Arıkan, “Channel polarization: A method for constructing capacity-achieving codes for symmetric binary-input memoryless channels,” IEEE Transactions on Information Theory, vol. 55, no. 7, pp. 3051–3073, Jul. 2009, doi: 10.1109/TIT.2009.2021379.
  • E. Arıkan, “Systematic polar coding,” IEEE Communications Letters, vol. 15, no. 8, pp. 860–862, Aug. 2011, doi: 10.1109/LCOMM.2011.061711.110862.
  • K. Niu and K. Chen, “CRC-aided decoding of polar codes,” IEEE Communications Letters, vol. 16, no. 10, pp. 1668–1671, Oct. 2012, doi: 10.1109/LCOMM.2012.090312.121720.
  • I. Tal and A. Vardy, “List decoding of polar codes,” IEEE Transactions on Information Theory, vol. 61, no. 5, pp. 2213–2226, May 2015, doi: 10.1109/TIT.2015.2410251.
  • Y. Polyanskiy, H. V. Poor, and S. Verdú, “Channel coding rate in the finite blocklength regime,” IEEE Transactions on Information Theory, vol. 56, no. 5, pp. 2307–2359, May 2010, doi: 10.1109/TIT.2010.2043769.
  • 牛凯,《极化码原理与应用》,科学出版社,2021,ISBN 978-7-03-071269-1。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇