Verilog功能模块——取滑动平均值(使用寄存器组)
我的另一篇博客:Verilog功能模塊——取滑動(dòng)平均值(使用FIFO)
兩者用不同的方式實(shí)現(xiàn)相同的功能,
-
使用FIFO占用較少寄存器資源,適用于取值N較大的場(chǎng)合。
-
使用寄存器組不需要額外的IP,更簡(jiǎn)單,但消耗寄存器資源較多,適用于取值N較小(一般不大于1024)的場(chǎng)合。
一. 模塊功能與應(yīng)用場(chǎng)景
模塊功能:對(duì)輸入信號(hào)取滑動(dòng)平均值。
滑動(dòng)平均值:又名移動(dòng)平均值,在簡(jiǎn)單平均值的基礎(chǔ)上,通過(guò)順序逐期增加新數(shù)據(jù)、減去舊數(shù)據(jù)求算移動(dòng)平均值,借以消除偶然變動(dòng)因素。
參考百度百科:滑動(dòng)平均法
應(yīng)用場(chǎng)景:
- 對(duì)平均值會(huì)變化,但變化速度較慢的信號(hào)求平均值
- 數(shù)字濾波中去除信號(hào)的直流偏置
二. 模塊框圖與使用說(shuō)明
參數(shù)N表示求N個(gè)點(diǎn)的平均值,參數(shù)DIN_WIDTH控制輸入信號(hào)位寬。
注意:
三. 模塊代碼
/** @Author : Xu Dakang* @Email : XudaKang_up@qq.com* @Date : 2021-04-14 16:14:46* @LastEditors : Xu Dakang* @LastEditTime : 2021-05-06 21:32:36* @Filename : getMovingAvg.sv* @Description : 求N個(gè)有符號(hào)數(shù)的滑動(dòng)平均值 *//* ! 模塊功能: 求N個(gè)有符號(hào)數(shù)的滑動(dòng)平均值 * 思路:1.求N個(gè)數(shù)的和,再除以N即為N個(gè)數(shù)的平均值2.當(dāng)?shù)贜+1個(gè)數(shù)到來(lái)后, 總和去除第1個(gè)數(shù)再加上第N+1個(gè)數(shù), 再求平均值即為1~N+1個(gè)數(shù)的平均值, 以此類推 */module getMovingAvg #(parameter N = 1024, // 求N個(gè)數(shù)的平均值,N應(yīng)等于2的n次方,如512,1024,2048等parameter DIN_WIDTH = 24 // 輸入數(shù)據(jù)的位寬 )(output logic signed [DIN_WIDTH-1 : 0] moving_avg,input logic signed [DIN_WIDTH-1 : 0] din,input logic din_valid,input logic clk,input logic rstn );//< 信號(hào)同步 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ logic signed [DIN_WIDTH-1 : 0] din_r1; logic signed [DIN_WIDTH-1 : 0] din_r2; always_ff @(posedge clk) begindin_r1 <= din;din_r2 <= din_r1; endlogic din_valid_r1; logic din_valid_r2; logic din_valid_r3; always_ff @(posedge clk) begindin_valid_r1 <= din_valid;din_valid_r2 <= din_valid_r1;din_valid_r3 <= din_valid_r2; end //< 信號(hào)同步 ------------------------------------------------------------//> 存儲(chǔ)N個(gè)數(shù) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ logic [$clog2(N)-1 : 0] din_cnt; always_ff @(posedge clk, negedge rstn) beginif (~rstn)din_cnt <= '0;else if (din_valid_r2)din_cnt <= din_cnt + 1'b1;elsedin_cnt <= din_cnt; endlogic signed [DIN_WIDTH-1 : 0] din_array [N]; always_ff @(posedge clk, negedge rstn) begin // 存儲(chǔ)輸入數(shù)據(jù)if (~rstn)din_array <= '{default : '0};else if (din_valid_r2)din_array[din_cnt] <= din_r2;elsedin_array <= din_array; end //> 存儲(chǔ)N個(gè)數(shù) ------------------------------------------------------------//< 求和 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ logic signed [$clog2(N)+DIN_WIDTH-1 : 0] sum; always_ff @(posedge clk, negedge rstn) beginif (~rstn)sum <= '0;else if (din_valid_r2)sum <= sum - din_array[din_cnt] + din_r2; // 先減再加,沒(méi)有位寬溢出的風(fēng)險(xiǎn)elsesum <= sum; end //< 求和 ------------------------------------------------------------//> 輸出平均值 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ always_ff @(posedge clk, negedge rstn) beginif (~rstn)moving_avg <= '0;else if (din_valid_r3)moving_avg <= sum[$clog2(N)+DIN_WIDTH-1 : $clog2(N)]; // 取高數(shù)據(jù)位elsemoving_avg <= moving_avg; end //> 輸出平均值 ------------------------------------------------------------endmodule四. testbench
/** @Author : Xu Dakang* @Email : XudaKang_up@qq.com* @Date : 2021-04-21 14:29:04* @LastEditors : Xu Dakang* @LastEditTime : 2021-05-06 20:54:14* @Filename : getMovingAvg_tb.sv* @Description : testbench of getMovingAvg */module getMovingAvg_tb;timeunit 1ns; timeprecision 1ps;localparam N = 1024; localparam DIN_WIDTH = 24;logic signed [DIN_WIDTH-1 : 0] moving_avg;logic signed [DIN_WIDTH-1 : 0] din; logic din_valid;logic clk; logic rstn;getMovingAvg #(.N (N),.DIN_WIDTH (DIN_WIDTH) ) getMovingAvg_inst (.*);// 生成時(shí)鐘 localparam CLKT = 2; initial beginclk = 0;forever #(CLKT / 2) clk = ~clk; end// 導(dǎo)入輸入波形文件,無(wú)法使用相對(duì)路徑,注意修改!!! string din_path = "F:/OneDrive/VivadoPrj/getMovingAvg/getMovingAvg.srcs/sim_1/new/sin-1.0.txt"; // 可選 sin+0.5 sin-0.5 sin+1.0 sin-1.0localparam DATA_NUM = 10240; // 數(shù)據(jù)量, 也就是txt文件的行數(shù), 如果此參數(shù)大于數(shù)據(jù)行數(shù), 讀取到的內(nèi)容為不定態(tài) logic [DIN_WIDTH-1 : 0] din_wave_data [DATA_NUM]; // 讀取輸入波形數(shù)據(jù)initial begin$readmemb(din_path, din_wave_data, 0, DATA_NUM-1); // vivado讀取txt文件 endinitial beginrstn = 0;din_valid = 0;#(CLKT * 10) rstn = 1;for (int i = 0; i < DATA_NUM; i++) begindin = din_wave_data[i];din_valid = 1;#(CLKT);din_valid = 0;#(CLKT * ({$random} % 5));enddin_valid = 0;#(CLKT * 10) $stop; endendmodule五. 仿真驗(yàn)證
仿真工具:Vivado 2020.2 Simulator。
輸入為(sinx + 0.5)信號(hào):
輸入為(sinx - 0.5)信號(hào):
輸入為(sinx + 1.0)信號(hào):
輸入為(sinx - 1.0)信號(hào):
六. 工程分享
getMovingAvg 取滑動(dòng)平均值模塊(使用寄存器組) vivado 2020.2工程.7z
鏈接:https://pan.baidu.com/s/1YL0q2i2UfWdlCGSN7GOgnQ
提取碼:uxxn
總結(jié)
以上是生活随笔為你收集整理的Verilog功能模块——取滑动平均值(使用寄存器组)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Verilog功能模块——降采样
- 下一篇: Verilog功能模块——符号位扩展