其他分享
首页 > 其他分享> > Xilinx FIR compiler 实现pulse-shaping滤波器,并利用多通道和插值适配RFdc

Xilinx FIR compiler 实现pulse-shaping滤波器,并利用多通道和插值适配RFdc

作者:互联网

在数字通信中,很重要的一步是做pulse-shaping(脉冲成形)。通常使用FIR滤波器实现成形滤波器。本文首先利用Matlab filterBuilder工具计算滤波器参数,之后利用Xilinx FIR compiler实现了滤波器,最后,通过配置FIR compiler的Parallel Channel 和 Interpolation 实现了对RF data converter适配,从而降低了总线速率。

1 生成滤波器系数

考虑到总线时钟速率,码速率等因素,设计成形滤波器,输入为类型 平方根升余弦,SPS(samples per symbol) = 5,interpolation = 5,滚降系数 = 0.5,指定FIR阶数 28。

image

工具即可计算出FIR参数。同时可以看到滤波器的特性:如频率特性
image

单位冲击响应,(冲击响应左侧第一个点越接近0 效果越好)
image

单位阶跃响应
image

生成的滤波器系数,可以写到文本文件,以方便下一步输入到Xilinx FIR compiler

csvwrite('myFile.txt', Hps4.Numerator)

2 Xilinx FIR compiler

这个IP使用的方法不难,网上介绍的文章很多。这里只对关键步骤进行说明。

2.1 输入滤波器参数

Xilinx的IP可以提供自动的参数量化的功能,因此不需要进行在Matlab中进行量化,直接将参数输入即可。
image

输入参数向量以后,IP核会自动计算量化,并在左侧Freq. Response中给出滤波器频响曲线;之后在下方改变滤波器类型为“Interpolation”插值型,插值系数为5.

2.2 并行通道与硬件过采样设置

image

这里将通道数设置为2,(RFdc采用IQ输出,因此两个并行的通道对应IQ数据,两通道相互独立)。
硬件过采样按图设置,即不进行过采样。在此页面的最下方给出了结果。

每个时钟输入一次数据
每个时钟输出一次数据
每次并行输入一组数据
每次并行输出五组数据 (对应插值系数5)

2.3 输出位数设置

滤波器进行了乘法操作,数据位数理论上会变宽,即输入16位数据 输出数据位宽大于16位,但是RFdc的量化精度为16位,因此直接取输出结果的高16位即可。
image
这里不改变参数量化的设置,保持默认即可(图中参数含义:参数量化为16位二进制数,其中小数位数17位)。下方的输出配置为舍弃低位(Truncate LSBs),输出位宽为16位。

左侧Implementation Details中会给出输入输出的数据格式。

务必注意输出格式。

2.4 仿真分析

对上述设置进行仿真,下面给出一个简单的testbench

`timescale 1ns / 1ps
module fir_tb();

reg clk;
reg [15:0] in_data_i, in_data_q;
reg in_tvalid;
wire in_tready;
wire [15:0] out_data0_i, out_data1_i, out_data2_i, out_data3_i, out_data4_i;
wire [15:0] out_data0_q, out_data1_q, out_data2_q, out_data3_q, out_data4_q;
wire out_tvalid;
initial clk = 0;
always #4 clk=~clk;


fir_compiler_0 your_instance_name (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(in_tvalid),  // input wire s_axis_data_tvalid
  .s_axis_data_tready(in_tready),  // output wire s_axis_data_tready
  .s_axis_data_tdata({in_data_i, in_data_q}),    // input wire [31 : 0] s_axis_data_tdata
  .m_axis_data_tvalid(out_tvalid),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata({{out_data4_i, out_data4_q}, {out_data3_i, out_data3_q}, {out_data2_i, out_data2_q}, {out_data1_i, out_data1_q}, {out_data0_i, out_data0_q}})    // output wire [159 : 0] m_axis_data_tdata
);
integer i;
integer r;
// save to file
integer out0, out1, out2, out3, out4;
integer out0_q, out1_q, out2_q, out3_q, out4_q;
initial begin
    in_tvalid = 1;
    r = $random;
    in_data_i = (r>0) ? 16'h6665 : 16'h999b;
    in_data_q = (r<=0) ? 16'h6665 : 16'h999b;
    for (i=0; i<200; i=i+1)begin
        #40  // sps=5
        r = $random;
        in_data_i = (r>0) ? 16'h6665 : 16'h999b;
        in_data_q = (r<=0) ? 16'h6665 : 16'h999b;
    end
    $fclose(out0);
    $fclose(out1);
    $fclose(out2);
    $fclose(out3);
    $fclose(out4);
    
    $fclose(out0_q);
    $fclose(out1_q);
    $fclose(out2_q);
    $fclose(out3_q);
    $fclose(out4_q);
    $stop;
end


initial begin
    out0 = $fopen("out0.txt", "w");
    out1 = $fopen("out1.txt", "w");
    out2 = $fopen("out2.txt", "w");
    out3 = $fopen("out3.txt", "w");
    out4 = $fopen("out4.txt", "w");
    
    out0_q = $fopen("out0q.txt", "w");
    out1_q = $fopen("out1q.txt", "w");
    out2_q = $fopen("out2q.txt", "w");
    out3_q = $fopen("out3q.txt", "w");
    out4_q = $fopen("out4q.txt", "w");
end

always @(posedge clk) begin
    if (out_tvalid) begin
        $fwrite(out0, "%x\n", out_data0_i);
        $fwrite(out1, "%x\n", out_data1_i);
        $fwrite(out2, "%x\n", out_data2_i);
        $fwrite(out3, "%x\n", out_data3_i);
        $fwrite(out4, "%x\n", out_data4_i);
        
        $fwrite(out0_q, "%x\n", out_data0_q);
        $fwrite(out1_q, "%x\n", out_data1_q);
        $fwrite(out2_q, "%x\n", out_data2_q);
        $fwrite(out3_q, "%x\n", out_data3_q);
        $fwrite(out4_q, "%x\n", out_data4_q);
    end
end

endmodule

因为是输出是并行输出,在仿真器中不容易观察波形,因此在testbench中,将数据分别保持到文件中,并写了个简单的python脚本进行绘图。

from bitstring import BitArray
import matplotlib.pyplot as plt

f0 = open('./out0.txt')
f1 = open('./out1.txt')
f2 = open('./out2.txt')
f3 = open('./out3.txt')
f4 = open('./out4.txt')

data_int = []

while True:
    s0 = f0.readline()
    s1 = f1.readline()
    s2 = f2.readline()
    s3 = f3.readline()
    s4 = f4.readline()
    if len(s0) == 0:
        break
    if s0[0] == 'x':
        continue

    data_int.append(BitArray(hex=s0).int)
    data_int.append(BitArray(hex=s1).int)
    data_int.append(BitArray(hex=s2).int)
    data_int.append(BitArray(hex=s3).int)
    data_int.append(BitArray(hex=s4).int)

plt.plot(data_int)
plt.show()

f0.close()
f1.close()
f2.close()
f3.close()
f4.close()

image
上图为数据10001100111111...的成形后波形。

3 RF data converter

说一点RFdc的配置,首先设置DAC的每个时钟周期的采样点数为10点(I, Q * 5 = 10)。
image
之后在手册中可以查知,总线上高位为Q,低位为I,高位为“后”采样点,低位为“先”采样点。正好与FIR滤波器的并行输出的位数一致,因此可以直接连接。
image

4 测试结果

image
从FIR滤波器的图中,可以看出,第一个0点对应的归一化频率是0.32,
这里对应的是采样率。因此可以计算半带宽为5(sps) * 10Mbps(码速率)*0.32 = 16MHz
图中M1 delta频率为15.85MHz。

标签:FIR,采样,16,适配,多通道,滤波器,数据格式,data,out
来源: https://www.cnblogs.com/ArtisticZhao/p/16111653.html