ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-04-07 12:34:51  阅读:551  来源: 互联网

标签:FIR 采样 16 适配 多通道 滤波器 数据格式 data out


在数字通信中,很重要的一步是做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中会给出输入输出的数据格式。

  • 输入
    • 高16位为通道1 数据格式为sfix16_0
    • 低16位为通道0 数据格式为sfix16_0
  • 输出
    • [159:144] 16位为通道1的第4个采样点 数据格式为sfix16_0
    • [143:128] 16位为通道0的第4个采样点 数据格式为sfix16_0
    • [127:112] 16位为通道1的第3个采样点 数据格式为sfix16_0
    • [111: 96] 16位为通道0的第3个采样点 数据格式为sfix16_0
    • [95 : 80] 16位为通道1的第2个采样点 数据格式为sfix16_0
    • [79 : 64] 16位为通道0的第2个采样点 数据格式为sfix16_0
    • [63 : 48] 16位为通道1的第1个采样点 数据格式为sfix16_0
    • [47 : 32] 16位为通道0的第1个采样点 数据格式为sfix16_0
    • [31 : 16] 16位为通道1的第0个采样点 数据格式为sfix16_0
    • [15 : 0] 16位为通道0的第0个采样点 数据格式为sfix16_0

务必注意输出格式。

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有