找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2378|回复: 2
打印 上一主题 下一主题
收起左侧

维特比编码译码器 Viterbi译码算法 verilog代码

[复制链接]
跳转到指定楼层
楼主
本压缩包中包含维特比编码和译码的全部verilog代码,包含测试代码和部分仿真结果
Viterbi 算法是一种最大似然译码算法,它是通过计算累积汉明距离,在卷积网络图上寻找一条与接收码字具有最小汉明距离的最大似然路径。 Viterbi 译码算法不需要把每一条路径都与接收码字进行比较,而是接收一组码字,计算一组距离,比较一组路径,选择其中“最大”分支度量,再进行下一轮的比较。当接收完所有码字(多组码字)时,幸存下来的那条路径就是我们要寻找的最大似然路径度量路径。 Viterbi 译码的总体流程是比较各分支的度量值,选择一段最可能的分支,更新状态的度量,并根据比较结果获得状态转移表,最后通过状态转移表的回溯算法完成译码

总体:大致下面几个模块。我们的卷积码是(2,1,9),所以有256个状态。首先是control模块输出所有控制信号,保证其他模块有序译码。然后是bmg模块,根据输入的卷积码CODE,判断256个状态512个分支的汉明距,即分支度量值,发送给acs.然后asc模块从RAM里面的metricmemory里面取出前一级的256个状态路径度量值,与bmg送来的汉明距离,相加以后,进行比较,选择路径度量值较小的分支,最终得到256个状态的路径度量值,存储到RAM,并且把256个状态里面最小状态传给TBU回溯模块。把256个状态的幸存比特信息传给MMU。MMU一次从ACS得到4个状态的幸存比特信息,将其拼接成8个状态,存入RAM中。然后当TB-EN使能信号有效,开始回溯时,TBU模块给RAM发11位的地址,从RAM里面寻找当前状态的幸存比特信息,RAM把信息传给MMU,通过MMU传给TB模块。最后TB模块输出解码。

testbench.v

建立原始时钟信号,时钟周期是100ns,频率10MHz。再建立复位信号,低有效。Active信号为1,开始工作。创建编码器时钟D_CLOCK。

最后设置输入码字X或者卷积码code。T=DPERIOD=64*400ns。实例化编码器,输出卷积码。实例化解码器,输出解码。

DPERIOD =128*200=64*400,ACS模块时钟是clock1,2,周期是400.ACS模块里面有四个并行加比选单元,一个周期完成四个状态的加比选。然后迭代64次,才完成256个状态加比选,所以需要64个clock2。


仿真结果:

1.带有编码器。输入码字X给卷积编码器,编码器输出卷积码CODE给解码器,解码器输出DECODEOUT。如图正确解码。

下面两图是输入码字X,和解码输出码字DecodeOut,我们可以直观地看出两者一致。


2.不带编码器。直接输入卷积码CODE给解码器,解码器输出DECODEOUT。如图正确解码,下图的输入卷积码是和上图X输入,在编码器生成的卷积码一致。有图可见,波形一致,仿真正确。

3.维特比译码有一定的纠错能力,下图验证。因为维特比会选择一个路径度量最小的状态回溯,也即差错最小。可以看到错误代码中,lowestmetric不再为0,说明有差错,差错状态的路径度量值为10h.

correctcode代码

errorcode代码

control.v
功能:控制器模块//向各个模块发送控制信号,保证各模块有序进行解码
  input Reset, CLOCK, Active; //复位信号,低有效;原始时钟;开始工作信号
output [`WD_FSM-1:0] ACSSegment; //迭代次数64, 6bit
output [`WD_DEPTH-1:0] ACSPage; //输出码字信号 6bit
output Clock1, Clock2; //clock的四分频,有相位差
output Hold, Init, CompareStart; //码字结束;开始;比较开始(ACS)
output TB_EN; //开始回溯
控制单元使用Clock1更新ACSSegment(从而更新BMG单元和ACS单元的输出)。 时钟2用于指示何时将地址放置到地址总线。

仿真结果:

  • reset=0时,异步复位,Clock1 <= 0; Clock2 <= 0; ACSSegment<=111_111;

ACSPage<=111_111;Hold<= 0;Init <=0; TB_EN <= 0;CompareStart <= 0;

2.CLOCK周期为100ns

3.看出count为二分频,最终Clock1,Clock2都为Clock的四分频,T=400ns。

并且,Clock2超前Clock1,90度。Clock1=1100时,Clock2=1001。

因为有的信号操作需要其他信号保持一段时间。所以利用相位差90度,将有些信号在使用前设置好,防止冲突延迟。

例如ASC里面最小路径产生模块。其功能是找出256个状态中路径度量最小的状态。它在Clock2下降沿更新最小状态,最后在Clock1下降沿输出。由于Clock2超前Clock1,刚好可以在更新完最后一个状态与重新进行下次256个状态的比较之间,输出最小状态。


  • 在Clock1的上升沿。{ACSPage,ACSSegment} <= {ACSPage,ACSSegment} + 1;所以ACSSegment由000_000到111_111,然后ACSPage再加一,ACSPage对应一个码字的输入时间。

一个码字的输入时间就是计数64个ACSSegment。一个码字在4个并行ACS单元下迭代64次,才能完成256个状态的路径度量值比较。

Init信号标志着一个码元处理的开始,在Clock1的上升沿,且ACSSegment=3F的时候为1,持续一个Clock1。

Hold信号标志着一个码元处理的结束,在Clock1的上升沿,且ACSSegment=3EH的时候为1,持续一个Clock1.


5.ACSPage = 'h3E且ACSSegment = 'h3F时,TB_EN为1,TB单元使能,路径开始回溯。



6.在Clock2的上升沿。comparecount计数到8以后并且ACSSegment = 6'h3F(init)。CompareStart <= 1,开始比较。对于前8个码字不进行比较。幸存者来自“0”分支,上支路。

从全0状态起始点开始讨论。到9级及以后,每个状态都有两支路,才需要加比选。


acs.v

ASCUNIT模块分为三块。一是四个并行的ASC单元,二是RAM Interface(RAM 接口模块),三是Lowest Pick block(最小路径选择模块)。


功能:ACS 单元从路径度量存储模单元中取出前一时刻幸存路径的度量值, 然后与送入 ACS 单元的分支度量值累计相加进行比较,相加度量值较小的作为该状态新的路径度量值存入RAM里的MetricMemory以备下一时刻加比选使用。并产生幸存比特信息survivor 给MMU模块。这个幸存信息表示在加比选操作中,表征该状态是由前一时刻进入该状态的哪条分支转移而来的,当 survivor =0 时表示该状态是由偶状态(即上支路)转移而来,当 survivor =1 时表示该状态是由奇状态(即下支路)转移而来。

最后把256个状态里面最小状态传给TBU回溯模块。

  1. module ACSUNIT (Reset, Clock1, Clock2, Active, Init, Hold, CompareStart,ACSSegment, Distance, Survivors,LowestState,MMReadAddress, MMWriteAddress, MMBlockSelect, MMMetric, MMPathMetric);
  2. input Reset, Clock1, Clock2, Active, Init, Hold, CompareStart; //由control产生的控制信号。复位;时钟1,2;开始工作;码字开始;码字结束;比较开始
  3. input [`WD_FSM-1:0] ACSSegment; //由control产生,指明当前的迭代次数 input [`WD_DIST*2*`N_ACS-1:0] Distance; //来自BMG,8个距离,16位
  4. //连接幸存路径存储器Survivor Memory ,MMU
  5. output [`N_ACS-1:0] Survivors; // 4个1bit的survivor输出 // 连接路径回溯单元TB Unit
  6. output [`WD_STATE-1:0] LowestState; //// 连接度量记忆单元 MetricMemory output [`WD_FSM-2:0] MMReadAddress; //5位,一次读入8个状态。32*8=64*4= output [`WD_FSM-1:0] MMWriteAddress; //6位,一次写入4个状态。64*4
  7. output MMBlockSelect; //选择RAMA或RAMB,乒乓操作
  8. output [`WD_METR*`N_ACS-1:0] MMMetric; //存入MM路径度量值,4个状态,32位
  9. input [`WD_METR*2*`N_ACS-1:0] MMPathMetric; //来自MM的路径度量值,8个状态,64位
复制代码

仿真结果:

  • 当输入汉明距离Distance为16'b1000_0101_0010_0101时,即8个分支的汉明距离为2 0 1 1 0 2 1 1。如图Distance显示8525。并且路径度量值MMPathMetric为全0时,进行四个状态的加比选。经过加比选,得到四状态的路径度量值和幸存路径信息,如下图,输出MMMetric=00_01_00_01,Survivors=0111(7),与分析相符。


  • 当输入汉明距离Distance为16'b1000_1000_0000_0000时,即8个分支的汉明距离为2 0 2 0 0 0 0 0。如图Distance显示8800。并且路径度量值MMPathMetric为1 2 3 4 b c d e时,进行四个状态的加比选。经过加比选,得到四状态的路径度量值和幸存路径信息,如下图,输出MMMetric=02_04_0b_0d,Survivors=0011(3),与分析相符。



3.找到256个状态最小状态的功能。如图,只有在前四个状态八个分支输入的Distance=16'b1000_0101_0110_0101; //2 0 1 1 1 2 1 1 ;其余情况汉明距离均为1.又因为初始存储的路径度量值为0.故其,路径度量值最小的状态为0对应的状态,状态号为3,和仿真一致。



4.和RAM接口模块,存入和读取路径度量值。MMBlockSelect=0为A写B读。在下一个码字输入时,MMBlockSelect翻转。例如,写A读B时,实现先读取B中上一级的256个状态路径度量值,用于加比选,同时把加比选的结果存入A。然后下一状态读A写B,交替操作,实现同时读写。

A,B都是64个32bit的存储模块。64*4*8


下图仿真中,可以看到先是写A读B,在第一个码字输入时,取出的MMpathmetirc为0。然后第一个码字结束后,全部存入256个状态的路径度量值在A中。在一个码字来时,读A,

MMpathmetirc先为64H0101010100010101,可以看到3-0状态,路径度量值为0111,和之前输入一致。其余时刻均为64H0101010101010101(路径度量值都是1)

  •   output [`WD_FSM-2:0] MMReadAddress; //5位,一次读入8个状态。32*8=64*4

output [`WD_FSM-1:0] MMWriteAddress; //6位,一次写入4个状态。64*4=256

MMReadAddress <= ACSSegment [`WD_FSM-2:0]; //低五位。0-31

MMWriteAddress = ACSSegment; //写地址6bit        为什么读地址是五位,写地址是6位。

因为四个状态,有8个分支,对应着前面8个状态。所以需要读出8个状态的路径度量值。

如当 ACSSegment为ABCDEF时,他对应的4个状态是这样,它对应的前八个状态一定是BCDEF对应的8个状态。前后状态只有一位不同,相当于右移一位,输入放最高位。所以只需要ACSSegment低五位,就可以读出对应的前8个状态路径度量值。另一方面,读地址5BIT,寻址32个,即32*8=256,实现256个状态的读取。32个,32*8=256个状态。写地址6BIT,寻址64个,一次写4个状态,64*4=256,完成256个状态的存入。



以上8个.v文件下载(verilog程序): 维特比编码译码器.zip (1.49 MB, 下载次数: 85)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:1034281 发表于 2022-6-13 11:09 | 只看该作者
为什么我仿真的VD的时候,后面输出是高阻态??
回复

使用道具 举报

板凳
ID:1079826 发表于 2023-5-25 14:47 | 只看该作者
为什么没有bmg模块和parameter.v
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表