新闻详情

新闻详情

首页 / 资讯中心 / 详情

CIC数字下变频抽取滤波器:从MATLAB建模到FPGA实现

发布时间:2026/9/15 12:12:49来源:尧图网络
CIC数字下变频抽取滤波器:从MATLAB建模到FPGA实现
简介面向数字信号处理学习者的DDC数字下变频CIC滤波器实现资料聚焦利用CIC积分梳状滤波器完成射频/中频信号到基带的变频处理涵盖MATLAB脚本、Simulink模型及VHDL源码适合通信、雷达等方向学生与工程师对照学习。压缩包共6个文件约26KB包含2个VHDL文件、1个Simulink模型、1个MATLAB脚本、1个Verilog文件及1个TXT说明文本覆盖从CIC滤波器设计、下变频仿真到FPGA实现的完整链路。已有386人学习资源虽小但结构完整既能用于理解CIC下变频原理与参数配置也可作为DSPBuilder协同仿真或硬件综合的参考模板。通过分析源码与模型读者可掌握混频、积分梳状滤波、降采样等关键步骤并借鉴其工程化实现思路。1. 数字中频信号落地前的那一级 CIC接手一块 140MHz 中频采样的采集板第一件事不是直接上几百阶 FIR而是先把数据率降下来。之前做过一版纯 FIR 抽取4 倍抽取就吃掉十几个 DSP48E板子温度直接上去了。后来换成 CIC 抽取级逻辑单元只占原来三分之一性能却够用。这个工程里的fdcoeffR4N8M1L110.txt和ciccomp.m其实就把一套典型链路从参数到补偿系数都配好了R4 的抽取率、8 级级联、M1 差分延迟加上 110 点补偿 FIR。对做数字中频接收、软件无线电或雷达信号处理的人来说这是一套能直接从 MATLAB 仿真挪到 RTL 实现的模板。2. CIC 频率响应从哪里来零极点位置决定抽取安全性2.1 积分器与梳状器的级联模型CIC 滤波器的结构看起来只是“累加 延迟相减”的组合但它的频响完全由零极点分布决定理解这一点才能解释为什么它适合放在抽取器前面。单级积分器在 z 域的系统函数是H_I(z) 1 / (1 - z^{-1})在单位圆 z1 处有一个极点对应零频增益无穷大实际数字系统里就是直流增益为 R。梳状器的系统函数是H_C(z) 1 - z^{-RM}其中 R 是抽取倍数M 是差分延迟通常取 1 或 2它的零点均匀分布在单位圆上角度间隔是 2π/(RM)。把 N 级积分器和 N 级梳状器级联后系统函数写成H(z) [ (1 - z^{-RM}) / (1 - z^{-1}) ]^N这个式子约掉零极点之后等价于一个长度为 RM 的移动平均滤波器迭代 N 次。也就是说CIC 本质上是一种递归结构的 FIR 等效实现不需要乘法器只有加法器和寄存器。之前调过的另一个工程里把 M 从 1 改成 2零点就减半滚降变缓但混叠泄漏明显加重所以 M 不是随便拍的。2.2 为什么抽取前用 CIC 而不是直接抗混叠 FIR抽取操作最怕的是带外信号折返进通带。理论上抽取前需要一个低通滤波器截止频率在折叠频率以下。如果直接用 FIR阻带衰减做到 60dB 以上需要上百个抽头系数复杂不说时钟一高乘法器就吃紧。CIC 的优势在于系统函数已经保证了在抽取倍数整数倍频点上有零点也就是说混叠源所在的频点恰好被陷掉一部分。以 R4、M1 为例梳状零点在 0、fs/4、fs/2、3fs/4 处。抽取后折叠发生在 0、fs/4、fs/2 这些频点附近零点和折叠点重合所以只要不追求极高的阻带衰减CIC 的抗混叠能力是够用的。如果对带外抑制要求到 70dB 以上才需要在 CIC 后面再补一级 FIR 或者把 N 提高。注意 N 提高会带来两个副作用通带滚降加深以及增益按 R^N 指数增长后者直接决定位宽。下面这段 MATLAB 代码画出不同级数下的幅频响应可以直观看到 N 从 1 到 8 的变化趋势% cic_spectrum.m CIC频响对比R4M1N1/4/8 R 4; M 1; Nlist [1 4 8]; f linspace(0, 0.5, 2048); % 归一化频率 for N Nlist % CIC频响公式等价的sinc^N形式 H (sin(pi * f * R * M) ./ (R * M * sin(pi * f))) .^ N; H(1) (R * M) ^ N; % 直流处的极限值 plot(f, 20*log10(abs(H) / abs(H(1)))); hold on; end hold off; xlabel(归一化频率); ylabel(幅度 (dB)); grid on; legend(N1, N4, N8);这段脚本里sin(pi * f * R * M) ./ (R * M * sin(pi * f))是 CIC 频响的闭式表达直接用 MATLAB 的freqz按差分方程算也可以但容易遇到大数溢出的警告。H(1)单独赋值为(R*M)^N是因为 0/0 在数值上算不出来这个值对应直流增益。从图里能看出 N8 时通带边缘已经明显下垂所以后面必须补一个 CIC 补偿滤波器。2.3 增益、位宽与截断策略CIC 的直流增益是(R*M)^N。以这套参数 R4、N8、M1 计算增益是 4^8 65536相当于 16bit 的增益。如果 ADC 输出是 16bit全精度输出要 32bit 才不丢信息。实际工程里没人会把 32bit 全往下传通常只保留高有效位截断会带来量化噪声但噪声电平的绝对值远低于 CIC 自身通带滚降带来的信号失真。参数组合RMN直流增益3dB 带宽(归一化)硬件成本配置 A本工程41865536约 0.0816 级寄存器 16 个加法器配置 B4151024约 0.1410 级寄存器 10 个加法器配置 C82465536约 0.058 级寄存器 8 个加法器但混叠点较少配置 B 适合对通带回平要求不高、逻辑紧张的场合配置 C 虽然零点和配置 A 一样多但 M2 导致第一零点频率减半对低通性能要求高的场景不建议。选择时先用freqz把滚降点落到信号带宽的 1.5 倍以上再回头定级数这是我处理这类问题时一贯的顺序。提示CIC 不是“下变频器”它本身不做频谱搬移。真正把中频搬到基带的是坐标旋转数字计算CORDIC或者查表法本地振荡器NCO完成的混频。CIC 负责的是混频之后的抽取滤波两者职责别混。3. 从 fdcoeff 到 TDMDDCMATLAB 建模与补偿系数生成3.1 先读懂 fdcoeffR4N8M1L110.txt 里存的是什么这组文件里fdcoeffR4N8M1L110.txt的名字已经给出了大部分信息R4 表示抽取率N8 表示 CIC 级数M1 表示差分延迟L110 对应的是一组长度为 110 的 FIR 补偿系数。我一般先把它读进来做归一化检查避免后面级联时幅度对不上head -n 5 fdcoeffR4N8M1L110.txt如果文件开头是这样的格式每一行一个十进制浮点数0.001352081234 0.001491172345 ...那就是纯系数文本。如果只有一行且用空格分隔用load(fdcoeffR4N8M1L110.txt)也能读MATLAB 会把它按矩阵解析。读进来后先确认length(coeff)是不是 110以及sum(coeff)是否接近 1。补偿滤波器通常归一化到直流增益为 1这样级联后整体增益只由 CIC 部分决定。3.2 ciccomp.m 到底做了什么ciccomp.m这名字在国内不少教科书工程里出现过常见实现是用fdesign.ciccomp设计等波纹补偿 FIR它针对 CIC 的sinc形状取倒数匹配。我通常这样写% ciccomp.m 设计CIC补偿滤波器并保存系数 R 4; M 1; N 8; % 与fdcoeff文件名对应 Fp 0.05; % 通带截止频率归一化 Fst 0.0625; % 阻带起始频率取1/(2R)-一点余量 Ap 0.01; % 通带纹波 0.01dB Ast 60; % 阻带衰减 60dB d fdesign.ciccomp(decimator, N, M, R, Fp, Fst, Ap, Ast); Hd design(d, equiripple); coeff Hd.Numerator; fprintf(长度: %d\n, length(coeff)); % 保存系数供Simulink或RTL使用 fid fopen(fdcoeffR4N8M1L110.txt, w); fprintf(fid, %.12f\n, coeff); fclose(fid);这里fdesign.ciccomp(decimator, N, M, R, ...)的关键参数前三项是 CIC 的级数 N、差分延迟 M、抽取率 R这几个值必须和实际用的 CIC 完全一致差一个都会导致补偿曲线错位。实际验证时如果发现补偿后通带仍有 0.5dB 以上的起伏多半是 Fp 设置得太接近通带边缘导致补偿 FIR 在边缘处过度增益放大了带外噪声。3.3 Simulink 模型 TDMDDC.mdl 的链路组织打开TDMDDC.mdl或者DSPBuilder_TDMDDC_import对应的工程典型的 DDC 链路是这个顺序ADC输入(或仿真源) → NCO混频 → CIC抽取级(R4,N8,M1) → 增益归一化(右移或乘法) → ciccomp FIR补偿 → 基带输出注意 NCO 混频不只是乘一个余弦实信号输入时通常用两路正交本地振荡器输出 I/Q 两路分别对应余弦和正弦。混频后频谱被搬到 0 频附近但也会有一半分量落在两倍中频处这部分靠后面的 CIC 和 FIR 滤除如果中频落在 fs/4 附近经典的取法是用 [1, 0, -1, 0] 和 [0, 1, 0, -1] 的序列做混频整个混频级就不需要查表乘法器DSP Builder 里可以直接用常数序列实现。链路里 CIC 级联之后别忘了做一次位宽压缩。这里给出用 MATLAB System object 搭建等效链路的脚本% ddclink_sim.m 数字下变频链路仿真NCO混频 CIC抽取 补偿 fs 100e6; % 采样率 R 4; t (0:4095). / fs; f_if 20e6; % 中频 x cos(2*pi*f_if*t) 0.1*randn(size(t)); % 中频信号噪声 nco_i cos(2*pi*f_if*t); % 正交本振 nco_q -sin(2*pi*f_if*t); % 负频率搬移 i_bb x .* nco_i; q_bb x .* nco_q; % CIC 抽取R4, N8, M1 cic dsp.CICDecimator(R, M, 8); % 第三个参数是级数 i_dec cic(i_bb); q_dec cic(q_bb); % 归一化并送入补偿滤波器 i_comp filter(comp_coeff, 1, i_dec); q_comp filter(comp_coeff, 1, q_dec);这段脚本中dsp.CICDecimator的前两个参数分别是抽取率和差分延迟第三个参数是级数默认是 2 级这里必须显式写 8。如果仿真结果发现 I/Q 两路幅度不一致检查 NCO 初始相位是否对齐CIC 本身是不分相位的问题几乎总出在混频器上。提示dsp.CICDecimator默认内部采用双精度浮点仿出来的波形不会暴露位宽截断问题。真要评估硬件行为需要在tdmddc.mdl里将 CIC 的滤波结构设成定点并把输出位宽设成和 RTL 一致否则最后上板时 SNR 会掉 3~5dB。4. 到 RTL 的最后一跳DSP Builder 导入与 VHDL 接口对照4.1 DSPBuilder_TDMDDC_import 的定位DSPBuilder_TDMDDC_import是把 Simulink 定点模型转换为 VHDL/Verilog 的入口工程。DSP Builder 导出的代码默认是 Avalon-ST 接口风格也就是说数据通路带valid和ready握手信号。你如果过去只写过普通 FIFO 接口的滤波器这一节要重点看握手时序它的ready信号并不是每一拍都为高。处理这类导入模型的步骤是这样的在 Simulink 里双击DSPBuilder_TDMDDC_import模型确认信号采样率标注正确用 DSP Builder 的Signal Compiler配置目标器件和时钟频率比如 EP4CE115 或 Cyclone V生成 VHDL 之后在 Quartus 工程里把生成目录下的所有.vhd加入工程替换掉手写的cic.vhd和fir.vhd之间的手工连接。4.2 cic.vhd 端口与时序关系手写工程里cic.vhd的顶层接口一般是这样的默认结构-- cic.vhd R4, N8, M1 抽取滤波器顶层 entity cic is port ( clk : in std_logic; rst_n : in std_logic; data_in : in std_logic_vector(15 downto 0); data_out : out std_logic_vector(23 downto 0); -- 截断后16bit常用这里预留高位 valid_in : in std_logic; valid_out: out std_logic ); end entity;数据流内部是两级循环先跑 8 级积分器每级是一个累加器随后进入抽取器每抽 4 个点输出一个点最后进入 8 级梳状器梳状器是y[n] x[n] - x[n - 1]的延迟相减。这里最容易出错的是抽取使能的生成常见做法是-- 抽取使能每R拍产生一个高电平 process (clk, rst_n) begin if rst_n 0 then count (others 0); clk_en 0; elsif rising_edge(clk) then if count R_M1 then -- R-1 3 count (others 0); clk_en 1; else count count 1; clk_en 0; end if; end if; end process;这段代码里的R_M1是常量R - 1 3抽取使能clk_en每 4 个输入时钟产生一个高电平。逻辑上没问题但有一个隐蔽坑当data_in的valid_in不是持续为高时这个自由运行的计数器会把无效数据也计入抽取周期。正确做法是把valid_in与计数器自增条件做与if count R_M1 then count (others 0); clk_en 1; elsif valid_in 1 then count count 1; else clk_en 0; end if;这样即使前端丢数据抽取节奏仍然和数据帧对齐。之前在一个卫星接收机项目里就因为这个漏了valid_in条件导致解出的符号出现周期性误码排查了两天才定位。4.3 Avalon-ST 接口与 alt_avalonst_pfc_0.v 的衔接alt_avalonst_pfc_0.v在工程里起的是 Avalon-ST 数据打包/解包的作用它把来自 AD 的数据流规整成 DSP Builder 后端方便处理的时序格式。Avalon-ST 最重要的四个信号是valid、ready、sop、eop。sop和eop分别是包起始和包结束标志滤波器本身不关心包边界但下游解调模块会把它们作为帧同步信号用。信号方向含义注意点avst_sink_valid输入上游数据有效必须和data一起变化avst_sink_ready输出本模块可接收数据为低时上游要停流avst_sink_sop输入包起始每个包的第一个有效数据拉高avst_sink_eop输入包结束包内可背靠背传输avst_source_valid/ready输出/输入下游接口握手与 sink 侧可以完全异步fir.vhd就是那个 110 阶补偿 FIR它接收cic.vhd的data_out在内部按系数串行或半并行乘累加。如果直接沿用 MATLAB 生成的浮点系数在 VHDL 里要先量化到 16bit 定点。量化后的系数和fdcoeffR4N8M1L110.txt里的原始值会有微小偏差建议在仿真里把量化后频率响应打印出来看看阻带是否还能维持 50dB 以上。提示DSP Builder 生成的时序不会自动把 CIC 的高位宽输出截断到 FIR 能接受的范围。如果你在 RTL 里看到data_out(23 downto 8)这种写法别惊讶这是把 24bit CIC 输出右移 8 位取高 16bit等效于除以 256。它对应 MATLAB 模型里的增益归一化。若复位后第一包数据幅度异常检查这个移位是否设置在梳状器之后放在积分器之前会导致直流漂移。5. 验证 CIC 下变频的三种手段和一次资源优化5.1 双音测试验证抽取后混叠位置验证 CIC 下变频最实用的方法是双音测试把两个频率相差很小的信号同时送入链路观察输出频谱里是否有第三个或第四个互调峰。我常用的设置是中频 20MHz一个信号在 20.1MHz另一个在 20.2MHz经过 4 倍抽取后输出采样率 25MHz两个信号分别落在 0.1MHz 和 0.2MHz 处。如果抽取前滤波不到位0.2MHz 信号经过折叠会出现在 0.05MHz 附近频谱上会出现一个不属于原信号的峰。用pwelch看输出功率谱正常情况下两个主峰相差应在 40dB 以上。若出现多余谱线先调 N 或 MN8 还不够就把补偿 FIR 的阻带起始频率降低到1/(2R) * 0.8也就是 0.0625 缩到 0.05。5.2 检查时序和溢出上板调试时把cic.vhd的积分器输出用逻辑分析仪抓下来观察最高位是否频繁翻转。CIC 积分器内部是 32bit 全精度累加若你截断了低 8 位在高信号幅度下溢出表现为直流电平跳变频谱会在低频出现“毛刺裙”。一个简单检查法在 Simulink 里把定点仿真位宽设成与 RTL 一致然后把最大正弦幅度从满幅降到 -6dBFS看输出 SNR 是否随之线性下降。SNR 不是线性下降而是突变说明截断点位置不对或梳状器之前存在中间截断。5.3 逻辑紧张时的降阶策略资源不够时我不会优先改抽取率那会牵动整个后续处理。先试着把 N8 降到 N5代价是阻带衰减变差约 12dB但通带更平。此时要重新执行ciccomp.m把 N 参数同步改掉并让补偿 FIR 的阶数从 110 降到 80 左右省下的 DSP 块给后端复数混频。换完参数后把上一节的双音测试重新跑一遍重点比较通带边缘频率点上的增益平坦度只要带内纹波不超过 0.5dB这个降阶方案就可以继续往下走直到资源约束与性能共同找到那个平衡点。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

VirtualApp 沙盒多开全景图:五类进程 + 一套配置的最短跑通路径 2026/9/15 13:00:55

VirtualApp 沙盒多开全景图:五类进程 + 一套配置的最短跑通路径

VirtualApp 沙盒多开全景图:五类进程 一套配置的最短跑通路径 【免费下载链接】VirtualApp Virtual Engine for Android(Support 14.0 in business version) 项目地址: https://gitcode.com/GitHub_Trending/vi/VirtualApp VirtualApp 是一个 Android 沙盒 …

阅读更多 →
CubeSandbox 的 BoltCacheStore 泛型缓存存储:Kubernetes cache.Store 与 BoltDB 的融合设计 2026/9/15 13:00:55

CubeSandbox 的 BoltCacheStore 泛型缓存存储:Kubernetes cache.Store 与 BoltDB 的融合设计

CubeSandbox 的 BoltCacheStore 泛型缓存存储:Kubernetes cache.Store 与 BoltDB 的融合设计 【免费下载链接】CubeSandbox Instant, Concurrent, Secure & Lightweight Sandbox for AI Agents. 项目地址: https://gitcode.com/GitHub_Trending/cu/CubeSandbo…

阅读更多 →
一文掌握点击上传与拖拽上传:从File对象到FormData提交 2026/9/15 13:00:55

一文掌握点击上传与拖拽上传:从File对象到FormData提交

很多后台项目里,文件上传这块的交互往往被当成"一个input加一个按钮"来处理。但真正上线后你会发现,用户群里总会分成两拨:一拨习惯老老实实点按钮,从弹出的系统对话框里选文件;另一拨则直接拖着一堆图片往页…

阅读更多 →
数组探针是什么? 2026/9/15 13:00:55

数组探针是什么?

数组探针是一个编程领域中的新概念。 概述 数组探针(Array Probe)是一个编程中常用的概念,用于描述在数组中遍历和检查元素的过程。它通常通过一个变量(即探针)来访问数组中的每个元素,并执行相应的操作。…

阅读更多 →
Flutter+OpenHarmony实现PUBG安全区预测技术解析 2026/9/15 13:00:55

Flutter+OpenHarmony实现PUBG安全区预测技术解析

1. 项目背景与核心价值PUBG作为一款现象级战术竞技游戏,其核心玩法机制"缩圈"直接决定了游戏策略走向。传统玩家依赖经验判断安全区刷新规律,而通过技术手段实现圈型预测能显著提升竞技优势。这个项目采用Flutter框架在OpenHarmony系统上构建跨…

阅读更多 →
Macro标签系统详解:如何一次性搞定邮件、任务、文档的全局Tag管理 2026/9/15 12:57:54

Macro标签系统详解:如何一次性搞定邮件、任务、文档的全局Tag管理

Macro标签系统详解:如何一次性搞定邮件、任务、文档的全局Tag管理 【免费下载链接】macro Macro is a unified workspace for teams: email, chat, docs, tasks, agents, calls, and CRM — -linked together with shared AI memory. 项目地址: https://gitcode.c…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞