首页 > 其他分享 >XILINX FIR IP核系数重载功能的学习以及测试

XILINX FIR IP核系数重载功能的学习以及测试

时间:2024-09-26 10:48:31浏览次数:11  
标签:FIR 系数 IP 重载 reload XILINX config reg axis

XILINX FIR IP核系数重载功能的学习以及测试

最近在学习宽带数字接收机的一些东西,其中多相滤波是属于其中比较关键的一环,笔者在matlab上成功仿真了多相滤波这一环节后,便想着在FPGA上实现多相滤波,多相滤波器的一个重要环节便是滤波器组的设计,简单来讲,滤波器组是由原型低通滤波器调制而成,在这里不做过多介绍,因为笔者信道化的数目是32信道,在实际工程中64,128,256信道都是可能采用的,就本文来讲,那么就需要32个不同系数的FIR滤波器,如果直接例化32个FIR ip核,生成32个coe文件,那未免也太过麻烦。所以笔者在想,是否有什么简单方法,可以导入滤波器系数至FIR IP。经过对fir ip核手册的查阅,发现该ip支持系数重载功能,即通过代码配置fir ip的滤波系数,显然,这是一个很有用的功能,既然IP支持这个功能,我们便要把它利用起来,以简化我们的工程设计。
在本文中,笔者并不直接构造多相滤波,而是使用matlab生成两个正弦叠加信号,进行低通滤波,然后将系数保存为coe文件,验证系数重载功能。

首先在matlab中生成1个1Mhz的正弦波信号与3Mhz的正弦波信号,采样率选择50Mhz,将二者叠加在一起。代码如下

% 参数设置
fs = 50e6;  % 采样频率 (50 MHz)
t = 0:1/fs:1e-3;  % 时间向量 (1 ms)

% 生成正弦波
f1 = 1e6;  % 1 MHz
f2 = 3e6;  % 3 MHz

signal1 = sin(2*pi*f1*t);  % 1 MHz 正弦波
signal2 = sin(2*pi*f2*t);  % 3 MHz 正弦波

% 叠加信号
combined_signal = signal1 + signal2;

为了能够在vivado仿真中,明显看出滤波器系数重载后的滤波变化,在matlab中生成两个低通滤波器,一个截至频率为2Mhz,一个截至频率为5Mhz,显然在截至频率为5Mhz的低通滤波器工作环境下,不考虑滤波器增益影响,信号波形不会发生变化,而在截至频率为2Mhz的低通滤波器工作环境下,3Mhz的信号将被滤除。
生成指定阶数的低通滤波器,至于为什么需要明确两个滤波器具有相同阶数,是因为在vivado中,系数重载时传输的系数个数需要与配置ip时,滤波系数的个数保持严格一致,否则会出现bug,无法成功更新,这点在fir ip手册中有明确说明。
分别使用2Mhz低通滤波器与5Mhz低通滤波器对叠加信号做滤波,绘制滤波后时域与频域波形,如下所示
在这里插入图片描述
将叠加信号与滤波器系数进行量化,存储至coe文件,供vivado使用
在这里插入图片描述
上图是导入了5Mhz的低通滤波器系数,可以看到vivado自动计算出了系数个数为51个,并且笔者勾选了Use Reloadable Coeefficients功能,可以看出在左侧框图出现了S_AXIS_RELOAD与S_AXIS_CONFIG通道。其符合标准AXI_STREAM流协议,S_AXIS_RELOAD通道为重载系数的传输通道,而S_AXIS_CONFIG通道为确认配置通道,在本文中,在传输完成系数后,使用该通道确定系数重载。

下图为系数位宽,与系数结构两个选项,系数位宽选择matlab量化系数时选取的位宽即可,当然,matlab的具体量化位宽,由用户综合考量决定。实际上对滤波器系数的量化上,需要综合考虑滤波增益,与位宽增加诸多情况,在本文中,不做详细讨论。

关于系数结构,第一种为可推测的,即ip通过配置ip核时填写的系数向量,推测系数向量属于哪种结构,第二种为非对称结构,第三种为对称结构;在测试demo中,使用的是普通低通滤波器,故选择第一种或第三种皆可,文中选用第三种对称结构。
在这里插入图片描述
需要特别注意的是,因为初始化的系数向量结构为对称类型,且包含51个系数,则在重载时,ip核默认只会接收26个数据,之后便将s_axis_reload_tready信号拉低,所以我们只需要输出26个前系数,对应的tvalid和tlast信号,也需要符合传输26个系数的逻辑变化,否则无法成功写入。在reload通道成功传输系数后,还需要进行使能,才能成功的使得IP核的工作系数发生变化,也即配置s_axis_config通道,ip手册给出的配置时序图,如下图所示
在这里插入图片描述

本demo中,在系数重载通道的last信号拉高后,进行周期延迟,之所以进行一定延迟,是因为在手册中提到要保证系数成功传输完成后,再将config通道的valid信号拉高,并data传输1,保证配置成功传输后,拉低valid,清零data。如下图逻辑所示。i_reload_cmd为系数重载命令,系数重载控制模块,接收到这一命令后开始进行系数重载逻辑。高电平有效,拉高一个周期即可。
在这里插入图片描述
系数重载控制模块的逻辑采用状态机设计,代码如下

/*The module realizes receiving FIR filter coefficients update instructions and transmitting filter coefficients to FIR IP*/
module coe_reload(
    input               i_clk                   ,
    input               i_rst                   ,
    input               i_reload_cmd            ,
    output              m_axis_reload_tvalid    ,
    input               m_axis_reload_tready    ,
    output              m_axis_reload_tlast     ,
    output  [15:0]      m_axis_reload_tdata     ,
    output              m_axis_config_tvalid    ,
    input               m_axis_config_tready    ,
    output  [7 :0]      m_axis_config_tdata 
    );

localparam              P_RELOAD_LENGTH = 'd26  ;
localparam              P_ST_IDLE       = 0     ,
                        P_ST_RELOAD     = 1     ,
                        P_ST_WAIT       = 2     ,
                        P_ST_CONFIG     = 3     ;
                        
reg     [2 :0]          r_st_current            ;
reg     [2 :0]          r_st_next               ;
reg     [2 :0]          r_st_cnt                ;

reg                     ri_reload_cmd           ;
reg                     rm_axis_reload_tvalid   ;
reg                     rm_axis_reload_tlast    ;
reg     [2 :0]          rm_axis_reload_tlast_buf;
reg                     rm_axis_config_tvalid   ;
reg     [7 :0]          rm_axis_config_tdata    ;
reg                     r_rom_en                ;
reg     [5 :0]          r_rom_addr              ;
wire    signed  [11:0]  w_rom_dout              ;
wire                    w_config_activate       ;

ROM_12X51 ROM_12X51_U0 (
    .clka               (i_clk                  ),
    .ena                (r_rom_en               ),
    .addra              (r_rom_addr             ),
    .douta              (w_rom_dout             )
);

assign  w_config_activate    = rm_axis_config_tvalid & m_axis_config_tready;
assign  m_axis_reload_tvalid = rm_axis_reload_tvalid    ;
assign  m_axis_reload_tlast  = rm_axis_reload_tlast     ;
assign  m_axis_reload_tdata  = {4'd0,w_rom_dout}        ;
assign  m_axis_config_tvalid = rm_axis_config_tvalid    ;
assign  m_axis_config_tdata  = rm_axis_config_tdata     ;

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_st_current <= 'd0;
    else
        r_st_current <= r_st_next;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_st_cnt <= 'd0;
    else if(r_st_current != r_st_next)
        r_st_cnt <= 'd0;
    else
        r_st_cnt <= r_st_cnt + 1;
end

always@(*)
begin
    case(r_st_current)
        P_ST_IDLE   : r_st_next = i_reload_cmd ? P_ST_RELOAD : P_ST_IDLE;
        P_ST_RELOAD : r_st_next = r_rom_addr == P_RELOAD_LENGTH - 1 ? P_ST_WAIT : P_ST_RELOAD;
        P_ST_WAIT   : r_st_next = r_st_cnt == 'd2 ? P_ST_CONFIG : P_ST_WAIT;
        P_ST_CONFIG : r_st_next = w_config_activate ? P_ST_IDLE : P_ST_CONFIG;
        default     : r_st_next = P_ST_IDLE;
    endcase
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_rom_en <= 'b0;
    else if(r_rom_addr == P_RELOAD_LENGTH - 1)
        r_rom_en <= 'b0;
    else if(r_st_current == P_ST_RELOAD && m_axis_reload_tready)
        r_rom_en <= 'b1;
    else
        r_rom_en <= 'b0;    
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_rom_addr <= 'd0;
    else if(r_rom_addr == P_RELOAD_LENGTH - 1)
        r_rom_addr <= 'd0;
    else if(r_rom_en)
        r_rom_addr <= r_rom_addr + 1;
    else
        r_rom_addr <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        rm_axis_reload_tvalid <= 'b0;
    else if(rm_axis_reload_tlast & rm_axis_reload_tvalid)
        rm_axis_reload_tvalid <= 'b0;
    else if(r_rom_en)
        rm_axis_reload_tvalid <= 'b1;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        rm_axis_reload_tlast <= 'b0;
    else if(rm_axis_reload_tlast)
        rm_axis_reload_tlast <= 'b0;
    else if(rm_axis_reload_tvalid && r_rom_addr == P_RELOAD_LENGTH - 1)
        rm_axis_reload_tlast <= 'b1;
    else
        rm_axis_reload_tlast <= 'b0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        rm_axis_config_tvalid <= 'b0;
    else if(rm_axis_config_tvalid & m_axis_config_tready)
        rm_axis_config_tvalid <= 'b0;
    else if(r_st_current == P_ST_CONFIG)
        rm_axis_config_tvalid <= 'b1;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        rm_axis_config_tdata <= 'd0;
    else if(rm_axis_config_tvalid & m_axis_config_tready)
        rm_axis_config_tdata <= 'd0;
    else if(r_st_current == P_ST_CONFIG)
        rm_axis_config_tdata <= 'd1;
end

编写tb文件,进行实际测试,因为笔者默认导入的滤波器系数为5Mhz低通滤波器,所以可以看出,在该滤波器工作下,信号的波形并无明显变化。在i_reload_cmd指令拉高一个周期后,系数重载控制模块开始工作,滤波后波形发生变化,整体情况如下图所示
在这里插入图片描述
实际在该仿真中,笔者使用了DDS ip核进行了两个信号的产生,并进行了叠加。而DDS同样也支持在工作过程中,改变输出波形频率,有时间笔者也会对这一功能做篇文章,如果大家感兴趣的话。

整体来说,这个功能实现起来还是比较简单的,笔者也是个萌新,在学习过程中探索,如果有什么问题,欢迎大家在评论区批评指正。

如果觉得笔者的文章对您有些帮助,希望点个赞,激励下笔者的创作,不胜感激!

关于本文的完整matlab代码与vivado工程,可以私信博主免费领取!!!

标签:FIR,系数,IP,重载,reload,XILINX,config,reg,axis
From: https://blog.csdn.net/zy12022000/article/details/142547774

相关文章

  • JavaScript有哪些数据类型?
    JavaScript共有八种数据类型,分别是Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。Symbol和BigInt其中Symbol和BigInt是ES6+(ECMAScript2015+)中新增的数据类型:Symbol可以理解为一个独特的标识符。想象一下,你有一把独一无二的钥匙,这把钥匙就是S......
  • apparatus、instrument、equipment和device的区别
    equipment:装备。指做某种事情需要用到的一系列工具。或这些工具中的某一个。比如游泳装备,指的是泳镜、泳帽、泳裤等等一系列的东西。但是单拿泳镜出来,你也可以说它是一件游泳装备。device:设备。指具有某种或某些功能的一件工具。apparatus是一种equipment,instrument是一种device......
  • 使用 Vue3、TypeScript 和 Spring Boot 实现文件上传至 MinIO 和 OSS
    目录《使用Vue3、TypeScript和SpringBoot实现文件上传至MinIO和OSS》一、技术选型二、环境搭建三、前端实现四、后端实现五、代码解析在现代web应用开发中,文件上传是一个常见的需求。本文将介绍如何使用Vue3、TypeScript和SpringBoot实现文件上传功能,并......
  • javascript
    letconst\(let\)局部声明$const$全局声明StringNumberBooleannullundefined字符串,数字,布尔值,空值,未定义console.log(typeofA);//A的类型连接&模板字符串constusername="dzk";constage=20;consthello=`Mynameis${username}andIam${age}......
  • 鸿蒙HarmonyOS HCIP认证题库
    鸿蒙HarmonyOSHCIP认证题库学习分享,本题库一共409道。反复刷考场得来,手打不易。记住不要光背选项,考试时可能打乱顺序,主要还是记住内容。一、单选题和填空题1.某开发者想要使用类Web开发范式的属性样式动画设置text组件的颜色变化动效,以下代码空白处应该填写什么?text......
  • javaScript 值的比较
    值的比较值的比较是指判断两个数的大小,返回一个布尔值。  比较运算符列表:   大于>  小于<  大于等于>= 小于等于<= 等于== 严格等于===不进行类型转换不等于!= 严格不等于!==不进行类型转换 字符串比较大小字符串间的比较大小遵循以下规则:1比较字符串首字母的大小。......
  • JavaScript中if嵌套 assert
    在JavaScript中,通常我们不会直接使用assert这个词,因为JavaScript标准库中并没有直接提供assert函数(尽管在一些测试框架如Jest、Mocha中经常看到)。但是,我们可以模拟一个assert函数的行为,即当某个条件不满足时抛出一个错误。结合if语句进行嵌套判断时,可以在每个需要断言的地方调用这......
  • x509: cannot validate certificate for 192.168.0.56 because it doesn't contain an
    containerd里无法拉取镜像无法从私建的harbor上拉取报错FATA[0000]pullingimage:rpcerror:code=Unknowndesc=failedtopullandunpackimage x509:cannotvalidatecertificatefor192.168.0.56becauseitdoesn'tcontainanyIPSANs 若是配置之后还是一直报x5......
  • JavaScript中if嵌套assert的方法
    在JavaScript中,通常我们不会直接使用assert这个词,因为JavaScript标准库中并没有直接提供assert函数(尽管在一些测试框架如Jest、Mocha中经常看到)。但是,我们可以模拟一个assert函数的行为,即当某个条件不满足时抛出一个错误。结合if语句进行嵌套判断时,可以在每个需要断言的地方调用这......
  • 【做题纪要】NOIp长训营期间做题纪要
    [AGC006D]MedianPyramidHard看了一圈感觉就这题比较可做,那就先写这个,但是还是没啥头绪。首先看咋写,这题的暴力肯定是直接从第\(n\)层开始反推就行的,但是复杂度好像很劣的样子,这肯定不行考虑二分答案,我们二分塔顶的值,如果比这个点大我们就设为\(1\),如果比这个点小我们就设......