前言
因为使用了自编的FIFO IP,不在需要额外的FIFO IP了,原本使用寄存器实现的方式可以舍弃了,取滑动平均值的模块就只需要这一个就行了。
一. 模块功能与应用场景
模块功能:对输入信号取滑动平均值。
滑动平均值
:又名移动平均值,在简单平均值的基础上,通过顺序逐期增加新数据、减去旧数据求算移动平均值,借以消除偶然变动因素。
参考百度百科:滑动平均法
应用场景:
-
对平均值会变化,但变化速度较慢的信号求平均值 -
数字滤波中去除信号的直流偏置
二. 模块框图与信号接口
2.1 参数列表
参数名 | 说明 |
---|---|
FIFO_ADDR_WIDTH | FIFO地址位宽, 可取1, 2, 3, … , 默认10, 对应取平均值的点数 N = 2**FIFO_ADDR_WIDTH,此模块求N个点的平均值 |
FIFO_RAM_STYLE | FIFO实现方式, 可选”block”(默认), “distributed” |
DIN_WIDTH | 输入数据位宽, 可取1, 2, 3, … , 默认16 |
2.2 接口信号列表
信号分组 | 信号名 | 方向 | 说明 |
---|---|---|---|
动平均值输出 | moving_avg[DIN_WIDTH-1 : 0] | output | 滑动平均值 |
moving_avg_valid | output | 滑动平均值有效指示, 高电平有效 | |
ac信号输出 | ac_signal[DIN_WIDTH-1 : 0] | output | ac信号 |
ac_signal_valid | output | ac信号有效指示, 高电平有效 | |
输入信号 | din[DIN_WIDTH-1 : 0] | input | 输入信号 |
din_valid | input | 输入信号有效指示, 高电平有效 | |
时钟与复位 | clk | input | 模块工作时钟 |
rstn | input | 模块复位, 低电平有效 |
三. 模块部分代码
/*
! 模块功能: 求N个有符号数的滑动平均值
* 思路:
1.求N(N等于2**FIFO_ADDR_WIDTH)个数的和,再除以N即为N个数的平均值, 除以N等价于左移FIFO_ADDR_WIDTH位
2.实例化一个深度为N的同步FIFO, 用于暂存这N个数
3.当第N+1个数到来后, 总和减去第1个数再加上第N+1个数, 再求平均值即为1~N+1个数的平均值, 以此类推
4.对应的FIFO操作是: FIFO满后, 又来一个数, 先读取FIFO一次, 腾出一个位置, 再往FIFO中写入新的数
5.如果din_valid是连续有效的, 那么这里存在一个问题: FIFO满后, din_valid有效, 需要先读后写, 但对于连续的
din_valid, 读写是同时的, 读出没有问题, 但写入可能因为FIFO满而失效, 所以更好的办法是不让FIFO满
6.不让FIFO满的办法是使用一个暂存寄存器, 以almost_full作为指示, almost_full为1时, din_valid有效,
则进行一次读取和写入, 这时写入和读取都必然成功, FIFO也始终不会满, 而是留有一个位空余
7.未采用直接设置N的方式, 而保证了N是2的整数幂, 否则取平均值要用到除法, 而非简单的左移
~ 使用:
1.一般来说N越大, 取的滑动平均值越准确, 特别的, 对于单频率信号, 当N是一个周期点数的整数倍时, 平均值没有误差
2.对于一个混频信号, N一般要大于最大周期点数的4倍以上, 平均值才能取得比较准确, 可根据实际效果调整
3.模块数据输入之前需要至少一个时钟周期的复位
*/
`default_nettype none
module getMovingAvg
#(
parameter FIFO_ADDR_WIDTH = 10, // FIFO地址位宽, 可取1, 2, 3, ... , 默认10, 对应N=1024
parameter FIFO_RAM_STYLE = "block", // 可选"block"(默认), "distributed"
parameter DIN_WIDTH = 16 // 输入数据位宽, 可取1, 2, 3, ... , 默认16
)(
output wire signed [DIN_WIDTH-1 : 0] moving_avg,
output wire moving_avg_valid,
output wire signed [DIN_WIDTH-1 : 0] ac_signal,
output wire ac_signal_valid,
input wire signed [DIN_WIDTH-1 : 0] din,
input wire din_valid,
input wire clk,
input wire rstn
);
四. 仿真验证
仿真工具:Vivado 2021.1 Simulator。
-
输入为(sinx + 0.5)信号:
-
输入为(sinx – 0.5)信号:
-
输入为(sinx + 1.0)信号:
-
输入为(sinx – 1.0)信号:
五. 源码与仿真工程分享
Gitee与Github同步:
Verilog功能模块–滑动平均值: Verilog功能模块-滑动平均值(使用FIFO) (gitee.com)
zhengzhideakang/Verilog–moving-average: Verilog功能模块——滑动平均值(使用FIFO) (github.com)
因Git不擅管理非文本文件,工程仅通过网盘分享:verilog-functional-module–moving-average 取滑动平均值 Vivado 2021.2工程 20240925.7z。
欢迎大家关注我的公众号:徐晓康的博客,回复以下代码获取。
1653
建议复制过去不会码错字!
如果本文对你有所帮助,欢迎点赞、转发、收藏、评论让更多人看到,赞赏支持就更好了。
如果对文章内容有疑问,请务必清楚描述问题,留言评论或私信告知我,我看到会回复。
徐晓康的博客持续分享高质量硬件、FPGA与嵌入式知识,软件,工具等内容,欢迎大家关注。