整理于2023-10-08

0.0 前言:

前面介绍了使用matlab中的Filter Designer工具箱进行CIC抽取滤波器设计的仿真过程与结果。下面在前面的基础上针对现有的【正点原子ZYNQ】平台,进行CIC实际设计实验测试。

0.1 平台简介

所使用的演示平台为【正点原子】的领航者ZYNQ开发板以及高速adda模块

1. 实验设计

adc以25MSPS采集一混频(比如:1.25MHz+62.5kHz)信号,经cic抽取滤波后,数据速率降至500kHz,之后由dac输出,通过示波器观察滤波前后波形。

2. matlab 中仿真

步骤:

  1. 生成待滤波的混频信号信号
  2. 生成相应的CIC抽取滤波器(见:CIC滤波器设计仿真)
  3. 进行滤波
  4. 做图对比
%% 生成信号
Fs = 25e6;
Ts = 1/Fs;
Ts2 = 50/Fs;
T = 1e-2;
N = T*Fs;
N2 = T * (Fs/50);
n = (0:N-1)';
n2 = (0:N2-1)';
t = Ts * n;
t2 = Ts2 * n2;
f = Fs/N*n;
R = 50; f1 = 1.25e6;
f2 = 50e3;
f3 = 125e3; s1 = sin(2*pi*f1*t);
s2 = sin(2*pi*f2*t);
s3 = s1 + s2;
% 计算混叠频率
Aliasingf = (1 - (f1/(Fs/R/2) - floor(f1/(Fs/2/50))))*(Fs/R/2) % 使用cic filtersigner 进行50倍抽取滤波
y3 = H_CIC50(s3); % 信号s3 50倍降采样后得到信号y
y3 = double(y3)/(50^3); % 增益调整,此处未进行补偿滤波器设计

仿真计算结果:

上面两幅图为生成的高采样率混频信号以及其频谱;下面两幅图为滤波后信号及其频谱。可以观察到,经过cic抽取滤波器后,高采样率混频信号得到了显著的降采样和滤波效果,且降采样符合预期;但是波形或者说频谱分布,与预期相差较大,怀疑原因是滤波过程有相位延迟造成的数据点移位而引入的,需要进一步确认。

3. vivado 中仿真

版本:vivado2019.1

3.1 vivado 中 CIC ip核调用

参考来源

FPGA数字信号处理(十九)Vivado CIC IP核实现-CSDN博客

xilinx 官方手册:

DS845_cic_compiler

PG140-cic-compiler

IP Catalog 中搜索CIC,打开CIC Compiler,配置cic ip核相关参数。

下图为实现50倍降采样配置。

Filter Options

  1. Filter Specification
  • 滤波器类型 - 抽取 Filter Type : Decimation
  • 滤波器级数 - 3 Number Of Stages : 3
  • 滤波器延迟因子 - 1 Differential Delay : 1
  • 通道数 - 1 Number Of Channels : 1
  1. Sample Rate Change Specification
  • 选择固定采样率倍数,设置为 50

另外,还需注意数据位宽设置,根据所需数据特性设置,最终设计结果可以在 Summary 中查看。

左侧可以选择到频响窗口,观察频响特性

生成CIC ip核后,在主程序中例化调用

 cic_compiler_0 u_cic_compiler_0 (
.aclk(sys_clk), // input wire aclk
.s_axis_data_tdata(ad_data), // input wire [7 : 0] s_axis_data_tdata
.s_axis_data_tvalid(s_axis_data_tvalid), // input wire s_axis_data_tvalid
.s_axis_data_tready(), // output wire s_axis_data_tready
.m_axis_data_tdata(cic_out_data), // output wire [31 : 0] m_axis_data_tdata
.m_axis_data_tvalid(m_axis_data_tvalid) // output wire m_axis_data_tvalid
);

3.2 程序设计

本次实验例程主要参考【正点原子】教程中关于高速adda部分的例程。

程序设计顶层原理图:

3.3 仿真结果

编写testbench文件,调用由matlab生成的波形文件作为仿真输入,观察滤波输出。

3.3.1 matlab生成波形文件

参考来源

verilog--使用FIR滤波器IP对数据降采样 - 知乎 (zhihu.com)

基本步骤简述:

  1. 生成波形(如上所述)
  2. 按要求位宽做量化处理
  3. 按16进制写入文件保存

参考程序:

sig2 = s2;						% 输入信号
sig2=sig2/max(abs(sig2)); % 归一化处理
sig2=round(sig2*(2^(N-1)-1)); % N比特量化 此处 N = 8
fid=fopen('fitFliterTestData2.txt','w'); % 写入文件保存
data2_i = real(sig2); % 按照指数法生成信号时,提取实部信号
data2_q = imag(sig2); % 按照指数法生成信号时,提取虚部信号
for n=1:length(sig2) % 进行补码替换操作
if data2_i(n) <0
data2_i(n) = 2^N + data2_i(n);
end
if data2_q(n) <0
data2_q(n) = 2^N + data2_q(n);
end
end
fprintf(fid,'%x \n',data2_i); % 按照16进制保存文件
fclose(fid);

3.3.2 vivado 中仿真调用外部数据文件

参考内容

vivado仿真 文件读取和写入-小李干净又卫生的博客-CSDN博客

VIVADO仿真读写文件方式_vivado readmemh-CSDN博客

读取文件

$readmemb$readmemh 用来从文件中读取数据到存储器中。其中 readmemb 要求每个数字是二进制数,readmemh 要求每个数字必须是十六进制数字。数字不能包含位宽说明,数字中可以有不定值x或X,高阻值z或Z,和下划线(_),和Verilog语法中的用法是一样的。

一共有下边6种用法:

(1)$readmemb("<数据文件名>",<存储器名>);

(2)$readmemb("<数据文件名>",<存储器名>,<起始地址>);

(3)$readmemb("<数据文件名>",<存储器名>,<起始地址>,<终止地址>);

(4)$readmemh("<数据文件名>",<存储器名>);

(5)$readmemh("<数据文件名>",<存储器名>,<起始地址>);

(6)$readmemh("<数据文件名>",<存储器名>,<起始地址>,<终止地址>);

写入文件

写入文件的操作与C语言类似,首先打开文件,写入数据之后关闭文件。

outputfile = $fopen("file2.txt","w"); 打开文件

$fwrite(outputfile,"%b\n",memory); 写入数据

$fclose(outputfile); 关闭文件

注意:

在写入数据的时候,写入的数据不能是一个数组,必须是单个的数字,因此想写入数组的时候必须要循环单个写入数据,写入数据的数据格式可以是2进制10进制16进制,方式与C语言类似,%控制写入的类型。

代码参考:

//** 数据来源:MATLAB
//** 函数:$readmemh 【以读取16进制形式读取TXT文件】 localparam DATA_NUM = 25000; // 数据量, 也就是txt文件的行数, 如果此参数大于数据行数, 读取到的内容为不定态
reg [7:0] memory[0:DATA_NUM-1] ;//申请250000个8位的存储单元
reg [4:0] n; initial
begin
$readmemh("../../../../fitFliterTestData3.txt",memory); //fitFliterTestData2.txt中的数字到memory
for(n=0;n<=15;n=n+1) //把15个存储单元的数字打印到 Tcl Console
$display("%h",memory[n]); // outputfile = $fopen("file2.txt","w");
// for(n=0;n<=7;n=n+1)
// $fwrite(outputfile,"%b\n",filter_out[n]);
// $fclose(outputfile);
end
//<<-- 导入数据 --------------------------------------------------- //>>-- 传递数据至输入 控制仿真结束 ---------------------
//** 传递数据
//** 数据传递结束 10 个时钟周期后 停止仿真
reg[$clog2(DATA_NUM)-1:0] i=0;
initial
begin ad_data = 8'd0;
#(clk_period * 10)
for (i = 0; i < DATA_NUM; i=i+1) begin ad_data = memory[i][7:0];
#(clk_period*2);
end #(clk_period * 10) $stop;
end
//<<-- 传递数据至 fir_filter 输入 控制仿真结束 -------------------

仿真结果

图中 sys_clk 为系统时钟,50MHz;sys_rst_n 为系统复位信号;ad_data 为输入信号; da_data 为输出信号。可以看出,经过混频信号经过CIC抽取滤波器后,实现了滤波和降采样。

3.4 下载验证

程序编写完成,经vivado编译综合布局布线,生成比特流文件,连接开发板下载,实验验证。本程序中还例化有一个ila,观察采集信号与滤波后信号。

ila探针结果-00:此结果存在有bug,经CIC滤波器输出数据为补码,但是所使用的dac码值使用原码,需要做一下转换

assign da_din = (cic_to_da[7] == 1'b0) ? (cic_to_da + 8'b0111_1111) : (cic_to_da - 8'b0111_1111) ;

修正后的ila结果,可以看出数据正常,并且符合预期。

示波器观察对比:黄色为输入信号,绿色为输出信号。可以看出,此程序实现了滤波和降采样操作。

4. 问题

  1. 如同在matlab仿真小节中看到的结果一样,经过CIC抽取滤波器后的数据出现了预期之外的谐波峰,后面需要讨论;

  1. 在进行单频信号做输入时,低频(低于50kHz)信号严重失真;高频(接近截至频率fc=250kHz)信号幅度衰减严重

  1. 叠加有高频信号时,上述现象会消失,尤其是低频段的现象

上述两种原因怀疑是因为数据长度选择不恰当和滤波器带宽内增益变化大引起,后面需要讨论验证。

CIC滤波器仿真与实验过程及结果记录的更多相关文章

  1. CIC滤波器

    CIC滤波器是滑动平均滤波器的非常高效的迭代实现,只需要一个减法和一个加法,而滑动平均需要N-1个加法. cic滤波器相当于一个梳状滤波器y(n)=x(n)-x(n-D),H(z)=1-z-D,和一个 ...

  2. Audrion小车实验过程

    Audrion小车实验过程 一.实验过程 拷贝光盘文件,安装驱动及Arduino软件,观看了教学视频,明白了软件操作界面的各类按钮的含义,进行了事例的上传实验. 接下来就进行了小车的安装工作,这部分不 ...

  3. Kettle 实现mysql数据库不同表之间数据同步——实验过程

    下面是试验的主要步骤: 在上一篇文章中LZ已经介绍了,实验的环境和实验目的. 在本篇文章中主要介绍侧重于对Kettle ETL的相应使用方法, 在这里LZ需要说明一下,LZ成为了避免涉及索引和表连接等 ...

  4. VS项目属性配置实验过程

    (原创,转载注明出处:http://www.cnblogs.com/binxindoudou/p/4017975.html ) 一.实验背景 cocos2d-x已经发展的相对完善了,从项目的创建.编译 ...

  5. S3C6410裸奔之旅——RVDS2.2编译、仿真、调试过程 LED流水灯---转的

    S3C6410裸奔之旅——RVDS2.2编译.仿真.调试过程 LED流水灯 (2012-10-13 23:56:30) 转载▼ 标签: s3c6410裸奔 ok6410 rvds2.2 rvds2.2 ...

  6. Mysql: pt-table-checksum 和 pt-table-sync 检查主从一致性,实验过程

    一.安装 percona 包 1.安装仓库的包 https://www.percona.com/doc/percona-repo-config/yum-repo.html sudo yum insta ...

  7. linux中LVM介绍及实验过程

    LVM LVM这个词不仅一次出现过,在安装Centos时,磁盘分区时,默认分区就是使用LVM方式分区:再一个就是在OpenStack部署时候用到LVM作为后端存储.对LVM的理解还是不太清晰,查询资料 ...

  8. 搭建一套简单的web服务器,记录实验过程

    搭建web服务器 一.实验内容: 实验要求: 1.完成一个简单的web服务器,web服务器从mysql里读取数据进行返回 2.Mysql需要有一个单独的数据盘,每个mysql虚拟机的磁盘挂载方式需要都 ...

  9. lab_1 清华大学ucore bootload启动ucore os(预备基础知识+实验过程)

    实验1 :bootload启动ucore os 1.0实验内容: lab1中包含一个bootloader和一个OS.这个bootloader可以切换到X86保护模式,能够读磁盘并加载ELF执行文件格式 ...

  10. Vertica集群扩容实验过程记录

    需求: 将3个节点的Vertica集群扩容,额外增加3个节点,即扩展到6个节点的Vertica集群. 实验环境: RHEL 6.5 + Vertica 7.2.2-2 步骤: 1.三节点Vertica ...

随机推荐

  1. 【python基础】类-初识类

    1.面向对象思想 在认识类之前,我们需要理解面向对象思想和面向过程思想. 面向过程思想:要拥有一间房屋,面向过程像是自己来修盖房屋,如果需要经过选址.购买材料.砌墙.装修等步骤,面向过程编程,就相当于 ...

  2. Pinot2的无人机传感器和摄像头

    目录 1. 引言 2. 技术原理及概念 2.1 基本概念解释 2.2 技术原理介绍 2.3 相关技术比较 无人机传感器和摄像头在Pinot 2中得到广泛应用,其目的是为Pinot 2提供全面的传感器和 ...

  3. ABP - 本地事件总线

    1. 事件总线 在我们的一个应用中,经常会出现一个逻辑执行之后要跟随执行另一个逻辑的情况,例如一个用户创建了后续还需要发送邮件进行通知,或者需要初始化相应的权限等.面对这样的情况,我们当然可以顺序进行 ...

  4. 1.3 Metasploit 生成SSL加密载荷

    在本节中,我们将介绍如何通过使用Metasploit生成加密载荷,以隐藏网络特征.前一章节我们已经通过Metasploit生成了一段明文的ShellCode,但明文的网络传输存在安全隐患,因此本节将介 ...

  5. 基于GPT搭建私有知识库聊天机器人(二)环境安装

    1.需要安装的包 pip3 install flask //python开发web框架 pip3 install langchain //LLM开发框架 pip3 install openai //L ...

  6. Java杂记————object.getClass()和object.class以及Java中的toString()方法的的区别

    不说废话,直接上干货: (注意大小写:object为对象,Object为类) 1,object.getClass()它是Object类的实例方法,返回一个对象运行时的类的Class对象,换句话说,它返 ...

  7. 可视化容器管理工具-portainer.io使用

    续docker日常使用指南 背景 当我们开始使用docker后,我们的机器上镜像和容器会越来越多,或者有时候我们有多台开发机的时候,单纯使用命令行去管理镜像和容器就变得麻烦了,这时,我们就可以选择一些 ...

  8. ASL单芯片CS5366TypeC转HDMI4K60HZ加HUB多口方案|CS5366带PD拓展方案原理图

    CS5366芯片是ASL集睿致远最新推出的2Len带PD的扩展坞方案芯片,CS5366支持4K60HZ. 在分辨率4K下,刷新率60HZ对于30HZ看似提升不多,但是对于应用在游戏主座的客户来说至关重 ...

  9. 渲染路径 - Deferred Texturing

    目录 Deferred Texturing 为什么需要 Deferred Texturing? 光栅化的 Helper Lane 开销 Draw Call 更容易合批 利用 V-Buffer 可以做更 ...

  10. Redis理论

    什么是Redis Redis(Remote Dictionary Server)是使用C语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库. Redis可以存储键和五种不同类型 ...