CIC滤波器仿真与实验过程及结果记录
整理于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 中仿真
步骤:
- 生成待滤波的混频信号信号
- 生成相应的CIC抽取滤波器(见:CIC滤波器设计仿真)
- 进行滤波
- 做图对比
%% 生成信号
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核调用
参考来源
xilinx 官方手册:
DS845_cic_compiler
PG140-cic-compiler
IP Catalog 中搜索CIC,打开CIC Compiler,配置cic ip核相关参数。
下图为实现50倍降采样配置。
Filter Options
- Filter Specification
- 滤波器类型 - 抽取
Filter Type : Decimation - 滤波器级数 - 3
Number Of Stages : 3 - 滤波器延迟因子 - 1
Differential Delay : 1 - 通道数 - 1
Number Of Channels : 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生成波形文件
参考来源
基本步骤简述:
- 生成波形(如上所述)
- 按要求位宽做量化处理
- 按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 中仿真调用外部数据文件
参考内容
读取文件
$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. 问题
- 如同在matlab仿真小节中看到的结果一样,经过CIC抽取滤波器后的数据出现了预期之外的谐波峰,后面需要讨论;

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

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

上述两种原因怀疑是因为数据长度选择不恰当和滤波器带宽内增益变化大引起,后面需要讨论验证。
CIC滤波器仿真与实验过程及结果记录的更多相关文章
- CIC滤波器
CIC滤波器是滑动平均滤波器的非常高效的迭代实现,只需要一个减法和一个加法,而滑动平均需要N-1个加法. cic滤波器相当于一个梳状滤波器y(n)=x(n)-x(n-D),H(z)=1-z-D,和一个 ...
- Audrion小车实验过程
Audrion小车实验过程 一.实验过程 拷贝光盘文件,安装驱动及Arduino软件,观看了教学视频,明白了软件操作界面的各类按钮的含义,进行了事例的上传实验. 接下来就进行了小车的安装工作,这部分不 ...
- Kettle 实现mysql数据库不同表之间数据同步——实验过程
下面是试验的主要步骤: 在上一篇文章中LZ已经介绍了,实验的环境和实验目的. 在本篇文章中主要介绍侧重于对Kettle ETL的相应使用方法, 在这里LZ需要说明一下,LZ成为了避免涉及索引和表连接等 ...
- VS项目属性配置实验过程
(原创,转载注明出处:http://www.cnblogs.com/binxindoudou/p/4017975.html ) 一.实验背景 cocos2d-x已经发展的相对完善了,从项目的创建.编译 ...
- S3C6410裸奔之旅——RVDS2.2编译、仿真、调试过程 LED流水灯---转的
S3C6410裸奔之旅——RVDS2.2编译.仿真.调试过程 LED流水灯 (2012-10-13 23:56:30) 转载▼ 标签: s3c6410裸奔 ok6410 rvds2.2 rvds2.2 ...
- Mysql: pt-table-checksum 和 pt-table-sync 检查主从一致性,实验过程
一.安装 percona 包 1.安装仓库的包 https://www.percona.com/doc/percona-repo-config/yum-repo.html sudo yum insta ...
- linux中LVM介绍及实验过程
LVM LVM这个词不仅一次出现过,在安装Centos时,磁盘分区时,默认分区就是使用LVM方式分区:再一个就是在OpenStack部署时候用到LVM作为后端存储.对LVM的理解还是不太清晰,查询资料 ...
- 搭建一套简单的web服务器,记录实验过程
搭建web服务器 一.实验内容: 实验要求: 1.完成一个简单的web服务器,web服务器从mysql里读取数据进行返回 2.Mysql需要有一个单独的数据盘,每个mysql虚拟机的磁盘挂载方式需要都 ...
- lab_1 清华大学ucore bootload启动ucore os(预备基础知识+实验过程)
实验1 :bootload启动ucore os 1.0实验内容: lab1中包含一个bootloader和一个OS.这个bootloader可以切换到X86保护模式,能够读磁盘并加载ELF执行文件格式 ...
- Vertica集群扩容实验过程记录
需求: 将3个节点的Vertica集群扩容,额外增加3个节点,即扩展到6个节点的Vertica集群. 实验环境: RHEL 6.5 + Vertica 7.2.2-2 步骤: 1.三节点Vertica ...
随机推荐
- [MAUI]弧形进度条与弧形滑块的交互实现
@ 目录 弧形基类 定义 绘制弧 弧形进度条(ProgressBar) 添加动画 宽度补偿 文本 弧形滑块(Slider) 创建控制柄 拖动事件处理 项目地址 进度条(ProgressBar)用于展示 ...
- Go 语言 context 都能做什么?
原文链接: Go 语言 context 都能做什么? 很多 Go 项目的源码,在读的过程中会发现一个很常见的参数 ctx,而且基本都是作为函数的第一个参数. 为什么要这么写呢?这个参数到底有什么用呢? ...
- Matlab GUI-Gamma选择工具
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path s ...
- 【转载】Linux虚拟化KVM-Qemu分析(三)之KVM源码(1)
原文信息: 作者:LoyenWang 出处:https://www.cnblogs.com/LoyenWang/ 公众号:LoyenWang 版权:本文版权归作者和博客园共有 转载:欢迎转载,但未经作 ...
- 利用Aspose.Word对Word文件添加印章处理以及实现业务数据的替换处理
有时候,我们在处理大量文档的时候,需要批量给Word文档添加印章处理,方便打印操作,本篇随笔介绍利用Aspose.Word对Word文件添加印章处理以及实现业务数据的替换处理. 1.利用Aspose. ...
- GaussDB技术解读丨高级压缩
本文作者|华为云数据库GaussDB首席架构师 冯柯 [背景介绍] 数据压缩与关系数据库的结合,早已不是一个新鲜的话题,当前我们已经看到了各种各样数据库压缩的产品和解决方案.对于GaussDB来说,在 ...
- MAUI 框架开发 将 MAUI 嵌入到 WPF 控件里
本文将介绍如何将 MAUI 的底层替换为 WPF 框架层,且将 MAUI 的内容嵌入到 WPF 的一个控件里面,无 UI 框架嵌入的空域问题 本文是 MAUI 框架开发博客,而不是 MAUI 应用开发 ...
- Unity自定义类使用携程--自身不继承MonoBehaviour
[TOC] 参考: https://www.jianshu.com/p/67f498cb839b 话不多说,直接上代码 1 using System.Collections; 2 using Unit ...
- 使用C#的窗体显示与隐藏动画效果方案 - 开源研究系列文章
今天继续研究C#的WinForm的显示动画效果. 上次我们实现了无边框窗体的显示动画效果(见博文:基于C#的无边框窗体动画效果的完美解决方案 - 开源研究系列文章 ),这次介绍的是未在任务栏托盘中窗体 ...
- [nginx]防范空主机头
空主机头防范主要是防止别人恶意将域名解析到服务器IP上. 配置示例 方式一,增加vhost # http的空主机头防范 server { listen 80 default; server_name ...