整理于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. SLF4J门面日志框架源码探索

    1 SLF4J介绍 SLF4J即Simple Logging Facade for Java,它提供了Java中所有日志框架的简单外观或抽象.因此,它使用户能够使用单个依赖项处理任何日志框架,例如:L ...

  2. 前端自定义弹框组件、自定义弹框内容alertView popup组件

    快速实现前端自定义弹框.自定义弹框内容alertView popup组件, 请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=12491 效果图 ...

  3. 1. Mybatis 简介

    1. Mybatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code.随着 ...

  4. 05-面试必会-SpringBoot&SpringCloud

    01- 讲一讲 SpringBoot 自动装配的原理 1.在 SpringBoot 项目的启动引导类上都有一个注解@SpringBootApplication 这个注解是一个复合注解, 其中有三个注解 ...

  5. AI作画本地搭建

    前言 Novel AI (简称NAI)是一个线上的深度学习小说续写平台,而 NAI Diffusion 是 NAI 在2022年10月3日推出的基于 Stable Diffusion 算法的自动生成二 ...

  6. 关于Java已死,看看国外开发者怎么说的

    博主在浏览 medium 社区时,发现了一篇点赞量 1.5k 的文章,名称叫<Java is Dead - 5 Misconceptions of developers that still t ...

  7. while(1) ; CPU 会一直等下去吗

    标题答疑 不会,计算机从外部设备读取数据到存储器,每读取1word的数据,CPU对外设状态进行一次检查. 可能有小伙伴看到这就要退出了,别急,看下去或许会有收获. 首先解决第一个问题:一个字是多少字节 ...

  8. js: 获取Blob的值

    this.ws.onmessage = async (msg) => { console.log('从服务端获取到了数据') // 从真正服务端发送过来的原始数据时在msg中的data字段 co ...

  9. 行行AI人才直播第15期:【AIGC科技公司法律顾问】Amber《AIGC的法律挑战》

    近年来,AIGC技术的迅速进步为社会经济发展带来了新的机遇.各行各业都开始关注AIGC相关技术在商业落地中的应用,AIGC相关的创业及项目如雨后春笋般涌现.然而,AIGC的广泛应用也带来了一系列的法律 ...

  10. 解密Prompt系列13. LLM Agent-指令微调方案: Toolformer & Gorilla

    上一章我们介绍了基于Prompt范式的工具调用方案,这一章介绍基于模型微调,支持任意多工具组合调用,复杂调用的方案.多工具调用核心需要解决3个问题,在哪个位置进行工具调用(where), 从众多工具中 ...