基于FPGA的A律压缩解压缩verilog实现,包含testbench

126 阅读3分钟

1.算法仿真效果

VIVADO2019.2仿真结果如下(完整代码运行后无水印):

 

dd307a5f2f20f2b9713b51032669fb30_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png

 

RTL图如下所示:

 

a261a1390fa0e9b50065987ea2408faf_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png

 

2.算法涉及理论知识概要

       A律压缩是一种广泛应用于语音编码的非均匀量化技术,尤其在G.711标准中被欧洲和中国等国家采纳。该技术的核心目的是在有限的带宽下高效传输语音信号,同时保持较高的语音质量。在基于现场可编程门阵列(Field-Programmable Gate Array, FPGA)的实现中,A律压缩解压缩算法的高效硬件实现成为可能,这对于实时通信系统尤为重要。

 

       A律压缩基于对数性质,对原始的模拟语音信号进行非线性变换,将较大的信号变化幅度分配更多的量化级,而较小的变化分配较少的量化级,以此达到降低数据速率的同时保持信号的主要特征不变。A律压缩的数学表达式如下:

 

33444c68b455bfbe328c0e5cb5b1c43f_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png

 

       其中,x是归一化后的输入信号(通常在−1−1到11之间),y是量化后的数字信号,A是压缩器的阈值,一般取A=1/1.5​。实际应用中,为了简化硬件实现,A律压缩通常采用13折线近似,即将输入信号范围分割为多个小段,每段采用不同的线性关系进行近似。

 

       解压缩过程是压缩的逆过程,其目标是将经过A律压缩的数字信号恢复成接近原始的模拟信号。解压缩数学表达式为:

 

c0ddf8a41133e1070d92b2833447fac5_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png

 

        其中,x′是解压缩后的近似原始信号,y是接收到的量化数字信号,A同压缩时使用的阈值。在FPGA实现中,解压缩同样可以通过查找表、算术逻辑单元(ALU)或专用的浮点运算单元完成。

 

FPGA实现要点

 

信号预处理:首先,模拟信号需经过采样和量化变为数字信号,这一过程通常在FPGA的模数转换器(ADC)部分完成。

 

非线性变换:接下来,通过查找表(LUT)或多项式近似实现上述非线性变换。FPGA的LUT资源丰富,适合存储折线近似所需的查找表值。例如,对于13折线近似,可以预先计算每个区间的输出值,存储在LUT中,输入信号根据其所在区间直接查表得到量化输出。

 

量化与编码:量化后的信号需要进一步编码为二进制数据进行传输。编码过程往往涉及将连续的量化值映射到固定的比特序列,这可以通过简单的逻辑门电路或者状态机在FPGA上实现。

 

同步与控制:FPGA实现中,还需要考虑时钟管理和状态控制逻辑,确保整个压缩流程按时序正确执行,同时处理好数据的流动和存储问题。

 

3.Verilog核心程序 ``timescale 1ns / 1ps

//

// Company:

// Engineer:

//

// Create Date: 2024/06/21 17:39:11

// Design Name:

// Module Name: TEST

// Project Name:

// Target Devices:

// Tool Versions:

// Description:

//

// Dependencies:

//

// Revision:

// Revision 0.01 - File Created

// Additional Comments:

//

//

 

 

module TEST();

 

reg i_clk;

reg i_rst;

wire [7:0]  o_y_alaw;

wire [11:0] o_y_dealaw;

 

 wire [31 : 0] m_axis_data_tdata;

dds_compiler_0 dds_compiler_0U (

  .aclk(i_clk),                                // input wire aclk

  .m_axis_data_tvalid(),    // output wire m_axis_data_tvalid

  .m_axis_data_tdata(m_axis_data_tdata),      // output wire [15 : 0] m_axis_data_tdata

  .m_axis_phase_tvalid(),  // output wire m_axis_phase_tvalid

  .m_axis_phase_tdata()    // output wire [31 : 0] m_axis_phase_tdata

);

 

wire signed[11:0]signal = {m_axis_data_tdata[31],m_axis_data_tdata[31:21]};

 

tops uut(

.i_clk       (i_clk),

.i_rst       (i_rst),

.i_x         (signal),

.o_y_alaw    (o_y_alaw),

.o_y_dealaw  (o_y_dealaw)

);

 

initial

begin

i_clk=1'b1;

i_rst=1'b1;

#100

i_rst=1'b0;

end

always #5 i_clk = ~i_clk;

endmodule`