A律13折现编解码实现,SystemVerilog实现,实测可用带完整的testbench

1.前言

话不多说,先上结果图。

搞错了,再来!

 图像中,上下两个三角波分别是原数据和经过A律13折现编码,并解码后的数据。如果感觉下面这个图的两个三角波是一样的数据,感觉我在套路你就对了,要的就是这个效果,不然要这算法干嘛。

从图中几乎看不出经过A律13折现编码再解码后的区别。然而就我的例程而言,原数据是12位的,A律13折线编码后是8位的,再经过A律13折现解码后重新回到12位。这样一来,中间的传输环节用编码后的数据传输将大大缩减传输的成本。

2. A律13折线的FreeStyle

首先,13折线的13是怎么来的?

 这幅图展现了原始数据与压缩数据的对应关系,其中x是原始数据,y是压缩后数据。其中第一象限总共有8个点,曲线被分为7段,第三象限与第一象限情况相同,故曲线总共被分为了14段。然而原点左右的两段曲线在实际使用中看作同一条曲线,故14-1=13 。

其次,眼尖的小伙伴也许已经发现了,这个图在第一章的仿真截图中似曾相识,没错就是他。由于仿真时输入数据为三角波,而三角波随着时间的推移以一次性质增长,这样正好与曲线图中的x轴的变化规律吻合,于是便能看到曲线图连续得跟随三角波出现。其实,这也是测试此算法的最佳策略。

最后,A-LAW曲线图是理念,即分段函数不同段对应不同的斜率和不同的初始值。那么,实际实现呢?当然要换图了。

此图中总共有三列数据,第一列是编码前的数据,第二列是编码后的数据,第三列是解码后的数据。由此可见此算法的本质是,当输入数据较大时损失精度而增大数值范围。说得直白些,第二列列压缩后的数据是实际中传输的数据,此数据只有8位,而8位数据原本能够表示的范围是-128~127,但是采用此方法压缩后,8位数可以表示-2048~2048,相当于12位数的表示范围。

损失精度不可避免,但编解码效果不可小觑,不信的小伙伴请翻到开头,再仔细看看开头第一章的第二幅仿真图。 

3. FPGA想要A律13折线编解码器

A-LAW13折线编解码算法并不一定和特定的总线协议绑定,例如虽然此类压缩方法广泛应用于语言信号传输比如E1帧通讯,而E1帧采用的是具有32个时隙的PCM协议,这种情况下确实是与硬件绑定的。而如果单独用这个算法进行数据压缩传输,是没有硬件方面的限制的,例如可以用此算法压缩数据后通过串口传输。

其次,算法是解决问题的过程及方法,具体用什么器件实现也没有限制,例如可以使用单片机通过软件来实现,也可以将此算法利用FPGA,即通过硬件实现。其中软件实现是学习此算法的基础,本文主要介绍通过硬件实现。

3.1基于Verilog的A-LAW13折线编码器设计

仔细观察第二章的第二幅图的第一列和第二列不难发现第二列三位二进制数表示的数值正是第一列原始数据第一个1出现的位置。然后abcd对应位置直接照抄。例如:

 第一行可以放置“1”的位置有7个,符号位右边的7位。图中第一行的原始数据中1在最低位的位置,所以第二列压缩后的数中符号位后3位表示的数为1 。同理可以发现,第二行的原始数据的第一个1比第一行原始数据左1位,故其压缩后的前三位为1+1=2 。

代码实际编写时的思路也同分析一样,从符号位右侧找起找到第一个1,如果没有找到即为0 。

核心代码如下:

    function [7:0]encoder_out;
        input [11:0]data_input;
        reg  [2:0]group_num;
        byte c;

        //clear the data_out
        encoder_out = 8'h00;
        for(c = 7; c > 0; c--)    begin
            if(data_input[c+3] == 1'b1)
                break;
        end
        group_num = c;  
        case(group_num)
        3'b000:encoder_out[6:0] = {group_num[2:0],data_input[3:0]};  
        3'b001:encoder_out[6:0] = {group_num[2:0],data_input[3:0]};
        3'b010:encoder_out[6:0] = {group_num[2:0],data_input[4:1]};
        3'b011:encoder_out[6:0] = {group_num[2:0],data_input[5:2]};
        3'b100:encoder_out[6:0] = {group_num[2:0],data_input[6:3]};
        3'b101:encoder_out[6:0] = {group_num[2:0],data_input[7:4]};
        3'b110:encoder_out[6:0] = {group_num[2:0],data_input[8:5]};
        3'b111:encoder_out[6:0] = {group_num[2:0],data_input[9:6]};
        default:encoder_out[6:0] = {group_num[2:0],data_input[3:0]};  
        endcase  
    endfunction

首先,for循环找到第一个1的位置,标定后同时也确定了在A-LAW13折线中的分段。接下来,照抄abcd,这个过程正是这段代码下方的case选择结构。选择结构根据不同组别abcd放置的位置不同决定具体在原始数据的位置,从而正确读出abcd并存入8位数据的第四位。最后,压缩完成。

3.2基于Verilog的A-LAW13折线解码器设计

解码器实质上是编码器的反向操作,而在实现时却不一定必须反向执行编码器的每一个步骤。在设计解码器时,下图可以起到事倍功半的效果。

接收端收到的数据是8位的:格式为SXXXABCD。其中XXX正是图中所示的段落码,而ABCD则为权重值,量化范围的下限即为量化的基础值。具体解码过程为:

首先,根据XXX中的段落码确定在图中的哪一行,确定后会找到对应的量化范围和权重值;其次,ABCD各代表权重值的选择开关,即ABCD分别对应权重值表的4个权重值,如果为1则选中并添加此权重值 ;再者,量化范围的最小值是该段落码对应的基础值;最后,计算结果为:量化范围最小值+A*权重值1+B*权重值2+C*权重值3+D*权重值4(权重值从左到右编号)。

核心代码如下:

    function [12:0]decoder_out;
        input [7:0]data_input;

        decoder_out = 13'h0000;
        case (data_input[6:4])
            3'b000: decoder_out = 0;
            3'b001: decoder_out = 16;
            3'b010: decoder_out = 32;
            3'b011: decoder_out = 64;
            3'b100: decoder_out = 128;
            3'b101: decoder_out =  256;
            3'b110: decoder_out =  512;
            3'b111: decoder_out = 1024; 
            default: decoder_out = 0;
        endcase  
        if(data_input[3] == 1'b1)  
            decoder_out = decoder_out + decoder_table[data_input[6:4]][3];
        else
            decoder_out = decoder_out;
        if(data_input[2] == 1'b1) 
            decoder_out = decoder_out + decoder_table[data_input[6:4]][2];
        else
            decoder_out = decoder_out;
        if(data_input[1] == 1'b1)
            decoder_out = decoder_out + decoder_table[data_input[6:4]][1];
        else
            decoder_out = decoder_out;
        if(data_input[0] == 1'b1)
            decoder_out = decoder_out + decoder_table[data_input[6:4]][0];
        else
            decoder_out = decoder_out; 
        decoder_out = {decoder_out[10:0],decoder_out[11]};
        if(data_input[6:4] > 3'h0)
            decoder_out[data_input[6:4]-1] = 1'b1;
        else    
            decoder_out[0] = 1'b1;
        decoder_out[12] = data_input[7];       
    endfunction

4. 感兴趣下载玩玩哦

A律13折线编解码器Verilog实现,带testbeench。-嵌入式文档类资源-CSDN下载

猜你喜欢

转载自blog.csdn.net/Fairchild_1947/article/details/124412243