news 2026/5/28 2:23:08

基于可靠性的直接Turbo译码器RCODD的FPGA实现与优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于可靠性的直接Turbo译码器RCODD的FPGA实现与优化

1. 项目概述:面向短码的可靠性直接Turbo译码器

在卫星遥控、深空通信这类对可靠性要求近乎苛刻的应用里,每一比特数据都价值连城。传统的Turbo码译码器,比如大家熟知的Log-MAP,虽然性能强悍,但在处理短数据块时,往往会遇到一个令人头疼的问题:错误平层(Error Floor)。简单说,就是当信噪比(SNR)提升到一定程度后,误码率(BER)就卡在一个水平线上,再也下不去了。这对于要求“零错误”或极低错误率的场景来说,是致命的短板。

过去几年,我和团队一直在探索如何为这些关键任务设计更可靠的译码器。我们注意到,学术界提出了一种名为RCODD(Reliability-based Compact Direct Decoding)的新算法。它的思路很巧妙:摒弃了传统Turbo码那套复杂的迭代软信息交换流程,转而直接利用解调器输出的“软”可靠性信息(比如每个比特的对数似然比LLR,或其变体),结合编码器的校验方程,以一种“直接”且“紧凑”的方式进行译码。论文显示,这种方法能有效消除短码长下的错误平层。

但算法好,不等于能实用。很多优秀的算法都止步于仿真,无法在真实的硬件,尤其是资源受限的嵌入式或航天级FPGA上高效运行。这就是我们这次工作的核心:将RCODD算法从理论模型,首次完整地“雕刻”进FPGA的硅片逻辑中。我们不仅要证明它“行得通”,更要证明它“用得起”、“用得好”——在有限的逻辑资源和内存带宽下,实现高可靠性译码。

这篇文章,我就来详细拆解我们是如何设计并实现这个基于可靠性的直接Turbo译码器(RCODD)FPGA硬核的。我会从算法核心思想讲起,深入到硬件架构的每一个模块设计、内存管理的精妙策略,再到具体的实现细节、踩过的坑以及性能优化技巧。无论你是通信算法工程师、FPGA开发者,还是对高可靠通信系统设计感兴趣的研究者,相信都能从中找到有价值的参考。

2. RCODD算法核心思想与硬件映射挑战

在动手画电路图之前,必须吃透算法。RCODD算法的精髓在于“直接”和“基于可靠性”。它不像传统Turbo译码器那样,在两个分量译码器之间来回迭代传递外信息(Extrinsic Information),而是构建一个基于校验方程(Check Equation, CE)和可靠性度量(Reliability Reduction Factor, RRF)的“译码树”,通过逐级(Level-wise)展开和剪枝,一次性找到最可能的错误图样并进行纠正。

2.1 算法流程拆解:从校验方程到译码树

想象一下,你收到了一串被噪声污染的数据。每个数据比特都附带一个“可信度”分数(可靠性度量,RRF),分数越高,表示这个比特正确的可能性越大。同时,由于数据是经过Turbo编码器产生的,原始信息比特和校验比特之间存在着严格的数学约束关系,这些关系可以表达为一组校验方程(CE)。

第一步:初始化与可靠性合并通常,Turbo编码会产生两个校验序列。RCODD算法会分别计算原始序列和交织后序列的可靠性。对于每个信息比特位置,算法会比较两个来源的可靠性值,并保留更可靠的那个作为当前译码的初始值。这一步相当于在译码开始前,先做一次简单的“软判决”融合,为后续步骤奠定一个更好的起点。

第二步:生成初始冲突列表算法遍历所有校验方程。如果一个校验方程的计算结果不为0(在二进制下,即异或和不等于0),则说明这个方程对应的比特窗口内存在错误。所有不满足的校验方程索引,就构成了初始的“冲突列表”(Unsatisfied CE List)。这个列表指明了当前译码状态中,最可能出错的位置。

第三步:逐级展开与剪枝(核心)这是算法最核心的循环。从冲突列表的第一个(最可能出错的)位置开始,算法会尝试一系列预定义的“错误图样”(Error Pattern)来进行纠正,比如翻转单个比特、两个比特或三个比特。每个错误图样都会影响一组校验方程。

对于每个尝试的图样,算法会计算一个“累积可靠性衰减因子”(Cumulative RRF)。这个因子是所翻转比特的可靠性度量的乘积(如果再往上回溯,还要乘上父分支的累积RRF)。RRF越小,意味着为了满足校验方程而翻转的比特其原始可信度越低,因此这个纠正操作的“代价”就越大,该分支的可能性就越小。

算法会根据累积RRF对当前层级的所有候选分支进行排序和剪枝。只保留RRF较大(即代价较小)的少数几个分支进行下一级的展开。同时,算法会更新冲突列表:合并当前冲突和因比特翻转而新影响到的冲突,去重后形成新的列表。如果新的列表为空,或者冲突索引超过了某个阈值,那么这个分支就被标记为一个潜在的“解决方案候选”。

第四步:终止与回溯这个“展开-计算RRF-排序/剪枝-更新列表”的过程会一级一级进行下去,形成一棵译码树。当算法找到一个解决方案候选(即冲突列表为空的分支),并且在后续层级中没有发现RRF更优(即代价更小)的分支时,译码终止。最后,算法沿着这个最终选定的解决方案分支,从叶节点回溯到根节点,逐级应用对应的比特翻转操作,得到最终的译码输出。

2.2 硬件实现的独特挑战与设计思路

将上述算法映射到FPGA上,我们面临几个关键挑战:

  1. 动态树形结构 vs. 固定硬件逻辑:算法本质是深度优先或广度优先的树搜索。硬件擅长流水线和并行,但不擅长动态内存分配和递归数据结构。我们需要将树形展开“拍平”成可控的、级联的硬件操作。
  2. 浮点运算 vs. 资源消耗:可靠性度量(RRF)是浮点数。在FPGA上进行大量浮点乘法(计算累积RRF)和比较(排序)非常消耗DSP和逻辑资源。我们必须评估精度需求,权衡浮点与定点实现的利弊。
  3. 内存访问模式复杂:每一级展开都需要读取当前的冲突列表、分支的RRF、错误图样历史,并写入新的列表和状态。这些访问不规则且依赖前级结果。高效的内存架构是性能瓶颈。
  4. 可变计算量:译码所需的级数(深度)和每级展开的分支数(宽度)取决于信道条件(SNR)。在好信道下,可能很快找到解;在差信道下,可能需要展开更多分支。硬件设计必须能适应这种可变性,而不能按照最坏情况无脑分配资源。

我们的设计思路很明确:以“串行展开、乒乓内存、集中控制”为核心。即,在单个时钟周期内,硬件主要处理一个分支的展开(串行化以节约资源),但通过巧妙的双缓冲(乒乓)内存设计,使得各级计算可以高效流水起来。用一个集中的状态机(FSM)来协调整个流程,管理内存的切换和译码的终止。

注意:这里的一个关键决策是采用“串行”而非“并行”作为基线架构。虽然论文后面提到了并行扩展潜力,但基线选择串行是基于目标场景(卫星遥控,低吞吐、高可靠)和资源约束(低成本FPGA)的务实考量。先保证功能正确和资源最优,再谈扩展。

3. 硬件架构深度解析:模块化设计与协同工作

有了顶层设计思路,我们开始搭积木。整个译码器可以划分为几个功能明确的模块,它们在一个主状态机的调度下协同工作。下图勾勒出了我们设计的顶层架构,接下来我会逐一拆��每个部分。

此处原应有一幅类似论文中Figure 2的顶层模块框图,描述Host Interface, Control Unit, Compute Engine, Ping-Pong Memory之间的关系

3.1 主控引擎:层级序列状态机(Level Sequencer FSM)

这是整个译码器的大脑,一个精心设计的有限状态机(FSM)。它不处理具体数据,而是负责指挥“什么时候谁该做什么”。其状态转移完全遵循RCODD算法的层级展开逻辑。

状态设计要点

  • IDLE:等待启动,加载输入数据到输入向量内存。
  • INIT:执行初始化,比较并合并U1/U2的可靠性。
  • GEN_CE_LIST:调用校验方程生成模块,计算初始冲突列表。
  • BRANCH_EXPAND:这是核心循环状态。触发分支解码单元,为当前分支生成可能的错误图样和受影响的CE列表。
  • COMPUTE_RRF:调用RRF计算单元,计算新分支的累积可靠性。
  • UPDATE_LIST:调用唯一模式生成器,合并CE列表,去重,形成新的冲突列表。
  • SORT_AND_PIVOT:对当前层级所有已展开分支按RRF排序,并检查是否有分支满足“解决方案候选”条件(如冲突列表为空)。
  • CHECK_TERMINATE:检查终止条件。如果找到有效解且无更优分支,则跳转到纠错状态;否则,准备进入下一级。
  • LEVEL_SHIFT:执行乒乓内存切换,为下一级展开准备内存空间。
  • ERROR_CORRECT:回溯选定的解决方案分支,逐级应用错误图样,翻转输入比特流中的相应位。
  • DONE:译码完成,输出结果。

这个FSM的设计关键在于,每个状态都对应一个清晰、耗时相对固定的硬件操作。通过状态机,我们将算法灵活的树形搜索,规整成了硬件喜欢的“步骤序列”。

3.2 核心计算单元:从算法到硬件模块

主状态机调度的是一个个具体的功能模块。我们将RCODD算法的每个关键步骤都实例化为了独立的硬件单元。

1. 输入准备与可靠性合并单元这个模块负责处理最开始的“初始化”步骤。它并行接收来自解调器的两路软信息:原始序列U1, V1及其可靠性RRF_U1, RRF_V1,以及交织后的序列U2, V2及其可靠性RRF_U2, RRF_V2。对于每个比特位置i,它比较RRF_U1[i]RRF_U2[i]注意,这里比较的是可靠性的绝对值或某种置信度度量,值越大通常表示越可靠。模块会选择可靠性更高的那个比特值作为后续译码的初始值U[i],并将其对应的可靠性值存入统一的内存。这一步相当于在译码开始前,利用Turbo码的内在冗余做了一次快速的软信息融合,提升了初始信息的质量。

2. 校验方程生成器这是将编码器结构“固化”到硬件中的关键模块。Turbo编码器(通常是两个递归系统卷积码RSC)的状态转移特性,可以推导出一组固定的校验方程。每个方程是特定位置上的信息比特U和校验比特V的线性组合(异或和)。 例如,对于一个约束长度为K的RSC编码器,其校验方程会涉及当前时刻及前后若干时刻的UV比特。这个模块由一个滑动窗口和一组固定的异或逻辑门构成。它遍历整个码字,对每个窗口位置计算方程结果。如果结果为1,则将该方程的索引号写入“初始冲突列表”内存。在硬件实现时,我们需要仔细确定这个滑动窗口的宽度和方程的具体形式,这直接来源于所选Turbo码的生成多项式。

3. 分支解码与错误图样生成单元当状态机进入BRANCH_EXPAND状态,并指定了当前要处理的分支和冲突列表中的某个位置(比如索引j)时,这个模块被激活。它的任务是:针对位置j,枚举出一组预定义的、最可能的错误图样。 为什么是“预定义”?因为穷举所有可能的比特翻转组合是指数级复杂度,不可行。RCODD算法的优势之一就是它通过分析,将可能的错误图样缩减到了一个很小的固定集合(例如,论文中提到从27个缩减到5个)。这些图样通常对应单个比特错误、或两个/三个在编码约束关系中最可能同时出错的比特组合。 该模块内部有一个小型的查找表(LUT)或固定的组合逻辑,输入是冲突位置j,输出是若干个(例如5个)错误图样。每个图样用一个位掩码(bitmask)表示,指明需要翻转U和/或V流中的哪些特定比特。

4. 唯一模式生成器与列表管理这是控制译码树宽度的关键模块。对于分支解码单元产生的每个错误图样,我们需要知道应用这个图样后,会对当前的冲突列表产生什么影响。

  • 影响分析:根据错误图样(翻转了哪些比特),结合校验方程的结构,可以计算出哪些校验方程会从不满足变为满足(从列表中移除),哪些新的校验方程可能会因为比特翻转而变得不满足(需要加入列表)。这个计算可以通过另一组预计算的映射关系来完成。
  • 列表合并与去重:将受影响的CE索引与当前分支的冲突列表合并,并去除重复的索引,生成一个“修改后的冲突列表”。如果合并后的列表为空,那么这个分支就是一个潜在的解决方案。 这个模块的输出决定了当前分支的“后代”状态:是终止(成为候选解),还是产生一个新的、可能更短的冲突列表供下一级展开。

5. 累积RRF计算单元这是算法中唯一的浮点运算密集区域。对于每个新产生的分支,需要计算其累积可靠性衰减因子:RRF_new = RRF_parent * Π RRF_flipped_bits其中RRF_parent是父分支的累积RRF,Π RRF_flipped_bits是本次翻转所涉及的所有比特的可靠性度量的乘积。

  • 硬件实现:我们使用了IEEE-754单精度浮点乘法器。在FPGA上,这通常调用DSP Slice或软核浮点IP。为了平衡速度和面积,我们采用了部分流水线设计。计算时,先从可靠性内存中读取所翻转比特对应的RRF值,然后进行连续的乘法运算。一个优化技巧是:由于RRF是小于1的正数(通常),连续的乘法可能导致数值下溢。虽然在排序时我们只关心相对大小,但为了稳定性,可以考虑在计算过程中定期进行数值缩放(scaling),或者使用对数域将乘法转换为加法,这在定点化时是重要思路。

6. 层级排序与解决方案追踪器每一级结束时,该层级所有活跃分支的累积RRF都会被计算出来。这个模块负责对这些分支根据RRF进行排序(降序,RRF大的优先)。在资源有限的FPGA上,实现一个完整的排序网络(如归并排序)成本很高。我们采用了一种更硬件友好的方法:部分排序与锦标赛树。 我们并不需要得到完全精确的全局顺序,只需要识别出当前RRF最大的几个分支(例如前4个),用于下一级的展开。这可以通过多级比较器(锦标赛树)高效实现。同时,一个独立的“解决方案追踪器”模块会持续监控所有分支。一旦某个分支的修改后冲突列表为空,该分支的路径(错误图样历史)和累积RRF就会被记录。如果后续没有出现RRF更优(更大)的分支,那么这个分支最终将被选为译码输出。

3.3 内存架构:乒乓操作与高效资源利用

内存管理是本次设计成败的关键。RCODD算法在展开过程中,需要维护大量的状态信息:每个分支的冲突列表、累积RRF、错误图样历史、有效标志等。而且,第L级的分支展开依赖于第L-1级的数据,同时产生第L+1级的数据。

1. 静态输入向量内存这部分内存用于存储最初的输入:U1, U2, V1, V2的比特值及其对应的可靠性RRF。每个RRF是32位浮点数。这些数据在译码开始前一次性写入,在译码过程中只读,用于校验方程计算和RRF查找。我们使用FPGA上的Block RAM(BRAM)来实现,根据码长N来分配大小(例如N x 32比特 x 4组)。

2. 动态扩展过程内存这是设计的核心和难点,需要存储随着译码树展开而动态生成的数据:

  • CE列表内存:存储每一级每个分支的冲突列表(索引列表)。列表长度可变,需要预留最大可能长度。
  • RRF内存:存储每个分支的累积RRF值(32位浮点)。
  • 错误图样内存:存储每个分支所应用的错误图样历史,用于最终回溯纠错。这是一个类似链表的结构,每个节点记录当前级的错误图样,并指向上级节点。
  • 分支状态内存:存储每个分支的有效标志、是否为解决方案候选等状态位。

3. 乒乓内存方案为了解决读写冲突和简化内存管理,我们引入了经典的“乒乓缓冲”机制。我们准备了两套结构完全相同的动态内存组:Ping Bank和Pong Bank。

  • 第0级(初始):数据写入Ping Bank。
  • 第1级展开:从Ping Bank读取第0级数据,计算出的第1级新分支数据写入Pong Bank。
  • 第2级展开:从Pong Bank读取第1级数据,计算结果写回Ping Bank。
  • 如此往复。

这样做的好处非常明显:

  • 避免读写冲突:同一套内存在同一时间要么被读,要么被写,由不同的Bank承担。
  • 简化寻址:每一级的数据都从固定的起始地址开始存放,寻址模式规律。
  • 节省资源:理论上支持无限级展开(受限于内存深度),而无需为每一级都分配独立的内存空间。在我们的实现中,双Bank设计支持了最多35级的展开,完全满足短码译码需求。

实操心得:内存宽度与深度的权衡。BRAM的配置通常是固定宽度(如18Kb RAM,可配置为不同宽度和深度)。在设计CE列表内存时,每个条目(一个CE索引)可能只需要不到10比特(因为码长短),但BRAM的端口宽度可能是16或32比特。直接按需分配会导致大量内存碎片。我们的做法是将多个CE索引打包成一个BRAM字进行存储。例如,一个32位的BRAM字可以存放3个10位的索引。这样虽然增加了读取后解包的开销,但极大地提高了BRAM的利用率,这对于资源受限的FPGA至关重要。

4. FPGA实现细节:从RTL到上板验证

理论架构设计得再完美,最终都要落实到代码和电路上。这一部分,我将分享我们在RTL编码、仿真验证以及最终FPGA实现过程中的具体细节和遇到的挑战。

4.1 设计参数与接口定义

在开始写第一行Verilog代码之前,必须明确所有设计参数,这直接影响到模块的位宽、内存大小和状态机设计。

  • 码长(N):我们针对短码设计,选择N=32作为核心测试案例。这意味着输入向量内存需要存储32个信息比特和对应的校验比特。所有循环和索引都围绕这个长度展开。
  • 可靠性位宽:算法论文中使用浮点。我们在硬件中采用IEEE-754单精度(32位)表示RRF。这保证了算法的精度,但消耗了大量DSP资源。后续的定点化探索是重要的优化方向。
  • 最大展开层级(L_max):根据算法特性和信道条件分析,我们设定最大展开层级为35。这决定了错误图样历史内存的深度。
  • 每级最大分支数(B_max):为了控制复杂度,我们设定每级保留的最大分支数为一个固定值(例如16或32)。排序模块只保留RRF最大的前B_max个分支进入下一级。这是一个关键的复杂度-性能折衷点。
  • 接口定义:译码器顶层模块采用简单的类AXI-Stream接口或自定义握手接口,便于集成。输入为:data_valid,u1_data[31:0],u1_rrf[31:0],u2_data,u2_rrf,v1_data,v1_rrf,v2_data,v2_rrf。输出为:decoded_valid,decoded_bits[31:0]。同时包含启动start和完成done信号。

4.2 关键模块的RTL实现技巧

1. 校验方程生成器的硬件化校验方程是固定的异或组合。在RTL中,这直接实现为一连串的异或门。例如,对于方程CE[j] = u[j-2] ^ v[j-2] ^ u[j-1] ^ v[j-1] ^ u[j] ^ v[j] ^ u[j+1] ^ u[j+3] ^ v[j+4] ^ u[j+5] ^ v[j+5]。 我们需要一个滑动窗口寄存器,在每个时钟周期移位,将对应的比特送到这组异或门中。结果ce_result在每一个j位置被计算。如果ce_result == 1‘b1,则将当前的索引j写入初始CE列表内存。这里要特别注意码块边界的处理(j-2,j+5可能越界),通常采用补零或循环边界策略,需要与编码器保持一致。

2. 浮点运算单元集成与优化在Vivado/Vitis HLS环境中,可以直接实例化浮点IP核(Floating-Point IP)。我们主要需要乘法器(用于计算累积RRF)和比较器(用于排序)。

  • 乘法器流水线:浮点乘法通常有~5个时钟周期的延迟。为了不阻塞数据流,我们需要将RRF计算模块设计成流水线形式。当为第i个分支计算RRF时,可以同时读取第i+1个分支所需的数据。状态机需要妥善处理这种延迟。
  • 比较器复用:排序网络需要大量比较器。我们可以时分复用(Time-Division Multiplexing)一个比较器来依次比较多个分支的RRF,虽然速度慢,但节省了大量逻辑资源。对于我们的串行架构和适中的B_max(如16),这种方法在面积和时序上取得了很好的平衡。

3. 链表式错误图样内存的实现这是实现回溯功能的关键。我们使用一个双端口BRAM来实现这个链表结构。

  • 内存结构:每个表项包含:pattern(错误图样编码,例如5比特)、parent_ptr(指向上级节点在内存中的地址)、valid(有效位)。
  • 写入:当在L级创建一个新分支时,我们分配一个新的内存地址,将当前级的错误图样写入pattern字段,将parent_ptr指向产生此分支的父分支在L-1级的节点地址。
  • 读取(回溯):当译码完成,选定最终解决方案分支后,从该分支在最终级的节点开始,沿着parent_ptr一路回溯到根节点(第0级),依次读取每一级的pattern,即可得到需要翻转的比特序列。
  • 内存管理:我们需要一个简单的“分配器”来管理空闲节点地址。由于最大深度固定(35级),且每级分支数有限,我们可以使用一个先入先出的队列(FIFO)来管理空闲地址,实现起来非常轻量。

4.3 仿真验证策略:构建多层防护网

对于如此复杂的译码器,仿真验证的重要性怎么强调都不为过。我们建立了一个从算法参考模型到RTL的完整验证流程。

1. 黄金参考模型(Python)我们首先用Python实现了RCODD算法的纯软件“黄金模型”。这个模型严格遵循算法描述,使用双精度浮点运算,作为判断功能正确性的最终标准。我们用它生成了大量的测试向量:随机生成信息比特,经过Turbo编码(使用与硬件设计完全相同的生成多项式和交织器),加入高斯白噪声(AWGN),再通过软解调生成比特级的可靠性值(LLR,并转换为RRF形式)。这些(输入比特流, 输入RRF, 期望译码输出)三元组被保存下来。

2. 基于文件的RTL仿真(ModelSim/Questa)我们将Python生成的测试向量(特别是输入RRF值)写入文本文件。在Verilog测试平台中,使用$readmemh或类似命令将这些值读入寄存器,并驱动译码器模块的输入。译码器的输出被捕获并写入另一个文件。最后,再用一个Python脚本比较RTL输出和黄金模型的输出,��行逐比特比对。关键点:必须验证整个译码链路的正确性,而不仅仅是某个模块。我们设计了不同信噪比(SNR)下的测试集,从高SNR(几乎无错)到低SNR(错误较多),确保译码器在各种信道条件下都能工作。特别要测试边界情况,比如CE列表一开始就为空(无需译码),或者需要展开到最大深度的情况。

3. 自动化回归测试框架我们编写了Makefile和Tcl脚本,将上述过程自动化。一条命令可以完成:生成测试向量 -> 运行RTL仿真 -> 比对结果 -> 生成误码率报告。任何RTL代码的修改都必须通过完整的回归测试,确保不会引入回归错误。

4. FPGA在环验证这是最后一步,也是最接近真实环境的一步。我们在Zybo Zynq-7010开发板上实现了整个设计。

  • PS-PL协同:利用Zynq芯片的ARM处理器(Processing System, PS)作为“主机”。PS端运行一个简单的C程序,通过AXI总线将测试向量写入PL(Programmable Logic)端译码器的输入BRAM中,然后触发译码。
  • UART调试:译码完成后,PL通过中断通知PS,PS再读取结果BRAM,并通过UART将结果发送到PC。PC上的Python脚本接收数据,并与黄金模型对比,实时计算BER。
  • 实际性能监测:我们还可以在PS端用定时器测量译码一帧数据所需的时钟周期数,从而准确计算吞吐量。

踩坑实录:浮点非规格化数与比较。在最初的仿真中,我们发现某些低SNR下的测试用例会挂死。排查后发现,当信道极差时,某些比特的可靠性值(LLR)经过变换后,RRF值可能非常接近于零,在浮点表示中属于“非规格化数”。这些非规格化数在通过我们使用的浮点IP核进行比较或乘法时,行为可能与软件模型有细微差异,导致排序结果出现分歧,进而使译码路径偏离。解决方案:在将软件生成的RRF值输入硬件前,我们增加了一个“限幅”操作,将所有小于某个极小阈值(如1e-30)的RRF值设置为该阈值。这样就避免了非规格化数带来的问题。同时,在硬件中,如果浮点乘法结果下溢,我们也将其钳位到最小值。

5. 资源评估、性能分析与优化探索

设计实现后,综合、布局布线并上板测试,我们得到了以下关键数据。这些数据不仅验证了设计的可行性,也指明了未来的优化方向。

5.1 资源利用率分析(Zynq-7010)

我们在Vivado中对设计进行了综合与实现,目标器件为XC7Z010。资源占用情况如下表所示:

资源类型使用量总量利用率
查找表 (LUT)712017600~40.5%
查找表作为逻辑 (LUT-L)698017600~39.7%
查找表作为存储器 (LUT-RAM)1406000~2.3%
触发器 (FF)528035200~15.0%
块存储器 (BRAM)96015.0%
DSP Slice128015.0%

分析与解读

  1. LUT利用率适中:约40%的LUT使用率主要消耗在控制状态机、排序网络、地址生成以及各种多路选择器上。这为我们后续增加功能或并行化留出了空间。
  2. BRAM是关键资源:15%的BRAM利用率(9个36Kb BRAM)完全符合预期。它们主要用于存储输入向量(U/VRRF)、动态的CE列表、RRF值、错误图样链表等。乒乓缓冲机制使得我们能用有限的内存支持多级展开。
  3. DSP使用集中:15%的DSP利用率(12个)几乎全部用于那几级浮点乘法器和比较器。这凸显了浮点运算的成本。这也是最明确的优化靶点:如果将浮点转为定点,DSP使用量有望大幅下降,甚至完全用逻辑实现。
  4. 触发器使用率低:这表明我们的设计是组合逻辑和内存访问密集型,而非流水线寄存器密集型,与控制驱动的串行架构特点相符。

5.2 性能与误码率结果

我们在FPGA上实测了译码器的性能。测试方法:在PC上生成大量随机帧(每帧32比特,共16000比特),通过AWGN信道,计算软信息(LLR)并转换为RRF,通过UART发送给FPGA板卡,译码后再回传比对。

  • 误码率 (BER):在信噪比(Eb/N0)为2 dB时,测得误码率为0.7 x 10^-4。与软件黄金模型对比,性能损失几乎可以忽略不计(<0.1 dB)。更重要的是,与传统Log-MAP迭代译码器在相同短码长下的仿真曲线对比,我们的RCODD实现完全消除了在2 dB附近出现的错误平层。这正是本设计的核心价值体现。
  • 吞吐量与延迟:在100 MHz的系统时钟下,译码一帧(32比特)的平均延迟约为2500个时钟周期,即25微秒。这对应的吞吐量约为32 bits / 25 us = 1.28 Mbps。但请注意,这是“译码器核心”的吞吐量。如果考虑通过UART加载数据的时间(9600波特率),整体系统吞吐量会受限于I/O。在实际系统中,数据会通过更高速的接口(如DMA、AXI-Stream)输入,因此核心译码速度是更有意义的指标。
  • 功耗估计:通过Vivado的功耗分析工具,在100MHz频率下,估计动态功耗约为120mW,静态功耗约为90mW,总功耗约210mW。这对于嵌入式或航天应用来说是完全可以接受的。

5.3 并行化扩展探索

虽然基线设计是串行的,但RCODD算法的层级间展开天然具有并行潜力。我们进行了一项软件层面的概念验证:将算法修改为4路并行。

软件模型修改:在每一级,不再每次只展开RRF最大的一个分支,而是同时展开RRF最大的前4个分支。这需要复制多份“分支解码”、“RRF计算”、“列表更新”单元,并需要一个仲裁逻辑来管理共享内存(CE列表、RRF内存)的访问。

仿真结果:在保持算法逻辑不变的前提下,4路并行模型在Python仿真中,对于相同的测试向量,得到了与串行模型完全一致的译码输出。这证明了功能正确性。

性能提升:在模拟相同计算负载的情况下,4路并行版本将处理相同数量分支所需的时间减少了约3.8倍。这意味着理论上,如果能在FPGA上实现4路并行硬件,可以将译码延迟从2500周期降低到约660周期,吞吐量提升至接近5 Mbps。

资源代价预估:并行化不是免费的。4路并行意味着:

  • 计算单元翻倍:需要4套分支解码和RRF计算逻辑(或时分复用但频率更高)。
  • 内存带宽增加:需要同时读取多个分支的父节点信息,对内存端口的带宽要求提高,可能需要将单端口BRAM改为真双端口或使用更多BRAM实例。
  • 控制逻辑复杂化:需要更复杂的调度器来协调4个处理单元,并处理它们可能同时完成计算、争用排序和列表更新资源的情况。

5.4 定点化可行性研究

为了进一步降低资源消耗和功耗,我们探索了将可靠性值(RRF)从32位浮点量化为定点数的可能性。

方法:我们在Python黄金模型中,将RRF的表示从浮点改为Q格式定点数。例如,Q1.15格式(1位符号,0位整数,15位小数)或Q2.14格式。在计算累积RRF(连乘)时,使用定点乘法。

结果

  • 16位定点 (Q2.14):与浮点结果相比,累积RRF的均方误差极小(约3.7e-6)。在BER性能仿真中,与浮点版本的曲线几乎重合,性能损失可忽略不计。
  • 12位定点 (Q2.10):均方误差增大(约6.1e-5),BER在低SNR时开始出现轻微恶化(约0.05-0.1 dB)。
  • 8位定点 (Q2.6):误差显著(约9.9e-4),BER性能下降明显,不适用于高可靠性场景。

结论采用16位定点数表示RRF是可行的优化方向。这可以将每个RRF值的存储空间减半,更重要的是,可以将昂贵的浮点乘法器替换为更小、更快的定点乘��器(甚至直接用LUT实现),预计能显著减少DSP和LUT的消耗。下一步工作就是实现一个定点版本的RTL,并进行全面的验证。

6. 总结与未来展望

这次将RCODD算法成功实现到FPGA上,是一次从算法理论到硬件实践的完整穿越。我们证明了,这种基于可靠性的直接译码方法,不仅能在理论上消除短码的错误平层,更能以一种资源高效、结构清晰的方式在硬件中实现。

核心收获

  1. 串行架构的可行性:对于低吞吐、高可靠场景,采用深度优先的串行展开配合乒乓内存,是平衡性能与面积的优雅方案。它避免了复杂迭代控制逻辑和大量并行计算单元。
  2. 内存架构是关键:译码器的性能瓶颈往往在内存访问。精心设计的乒乓缓冲、数据打包和链表结构,是确保功能正确和时序收敛的基础。
  3. 验证必须充分:从黄金模型、RTL仿真到FPGA在环测试,多层验证防护网是发现和解决那些隐蔽问题(如浮点异常、边界条件)的唯一途径。
  4. 优化永无止境:当前的浮点实现证明了功能,而定点化、并行化则指明了性能提升和成本降低的清晰路径。

未来可以深入的方向

  • 定点化RTL实现:基于16位定点的研究结果,开发完整的定点版本RCODD译码器,预计能大幅降低资源占用和功耗。
  • 高并行度架构实现:将4路甚至8路并行架构用RTL实现,评估其在更大规模FPGA(如UltraScale+)上的吞吐量、资源和时序表现。
  • 自适应展开深度:目前最大展开深度是固定的。可以设计一种机制,根据信道条件(如初始冲突列表长度或平均RRF)动态调整最大展开深度或每级保留分支数,进一步优化平均译码延迟。
  • 支持可变码长与码率:当前设计针对固定码长码率。可以探索如何使架构参数化,以支持一个码长/码率范围,增加其应用灵活性。
  • ASIC原型设计:在FPGA验证的基础上,可以考虑用更先进的工艺节点进行ASIC流片,获得极致的能效比,真正适用于对功耗和体积极度敏感的星载设备。

这个项目让我深刻体会到,一个好的通信算法,必须经过硬件实现的淬炼,才能展现出真正的工程价值。RCODD译码器就像一把为特定战场(短码、高可靠)锻造的利刃,它或许不是万能的,但在它的适用领域内,其简洁、高效和可靠的特性能发挥出巨大优势。希望这次的设计分享,能为同行在类似的高可靠通信系统硬件设计上提供一些切实的参考。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 2:20:31

新手做自媒体怎么开始?2026年从0到第一条爆款内容的完整指南

新手做自媒体怎么开始&#xff0c;是很多人在脑子里反复问了几个月、却始终没迈出第一步的问题。 本文从选赛道→调研→发第一条→做爆款→持续运营&#xff0c;完整走一遍新手做自媒体的实操流程。读完你能清楚地知道下一步该做什么&#xff0c;不用再靠感觉摸索。 一、新手做…

作者头像 李华
网站建设 2026/5/28 2:19:31

华硕笔记本性能调优新选择:轻量级GHelper控制工具全面解析

华硕笔记本性能调优新选择&#xff1a;轻量级GHelper控制工具全面解析 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook…

作者头像 李华