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。
工具即可计算出FIR参数。同时可以看到滤波器的特性:如频率特性
单位冲击响应,(冲击响应左侧第一个点越接近0 效果越好)
单位阶跃响应
生成的滤波器系数,可以写到文本文件,以方便下一步输入到Xilinx FIR compiler
csvwrite('myFile.txt', Hps4.Numerator)
2 Xilinx FIR compiler
这个IP使用的方法不难,网上介绍的文章很多。这里只对关键步骤进行说明。
2.1 输入滤波器参数
Xilinx的IP可以提供自动的参数量化的功能,因此不需要进行在Matlab中进行量化,直接将参数输入即可。
输入参数向量以后,IP核会自动计算量化,并在左侧Freq. Response中给出滤波器频响曲线;之后在下方改变滤波器类型为“Interpolation”插值型,插值系数为5.
2.2 并行通道与硬件过采样设置
这里将通道数设置为2,(RFdc采用IQ输出,因此两个并行的通道对应IQ数据,两通道相互独立)。
硬件过采样按图设置,即不进行过采样。在此页面的最下方给出了结果。
每个时钟输入一次数据
每个时钟输出一次数据
每次并行输入一组数据
每次并行输出五组数据 (对应插值系数5)
2.3 输出位数设置
滤波器进行了乘法操作,数据位数理论上会变宽,即输入16位数据 输出数据位宽大于16位,但是RFdc的量化精度为16位,因此直接取输出结果的高16位即可。
这里不改变参数量化的设置,保持默认即可(图中参数含义:参数量化为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()
上图为数据10001100111111...的成形后波形。
3 RF data converter
说一点RFdc的配置,首先设置DAC的每个时钟周期的采样点数为10点(I, Q * 5 = 10)。
之后在手册中可以查知,总线上高位为Q,低位为I,高位为“后”采样点,低位为“先”采样点。正好与FIR滤波器的并行输出的位数一致,因此可以直接连接。
4 测试结果
从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