跳至正文

Verilog功能模块——取滑动平均值

getMovingAvg


前言

因为使用了自编的FIFO IP,不在需要额外的FIFO IP了,原本使用寄存器实现的方式可以舍弃了,取滑动平均值的模块就只需要这一个就行了。


一. 模块功能与应用场景

模块功能:对输入信号取滑动平均值。

滑动平均值:又名移动平均值,在简单平均值的基础上,通过顺序逐期增加新数据、减去旧数据求算移动平均值,借以消除偶然变动因素。

参考百度百科:滑动平均法

应用场景:

  • 对平均值会变化,但变化速度较慢的信号求平均值
  • 数字滤波中去除信号的直流偏置

二. 模块框图与信号接口

getMovingAvg

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。

  1. 输入为(sinx + 0.5)信号:

  1. 输入为(sinx – 0.5)信号:

  1. 输入为(sinx + 1.0)信号:

  1. 输入为(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与嵌入式知识,软件,工具等内容,欢迎大家关注。

0 0 投票数
文章评分
订阅评论
提醒
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x
目录