FPGA离群值剔除算法
讲解视频:
https://www.bilibili.com/video/BV1mubWzvEsA/?spm_id_from=333.1387.homepage.video_card.click&vd_source=69fb997b62efa60ae1add8b53b6a5923
采用中位数MAD离群值剔除算法,即对于一组源源不断输入的离散数据,采用一个窗口进行动态存储,并每来一个数据就检验窗口内的中位数median,然后用所有数据减去median取绝对值得到绝对偏差,然后找出偏差的中位数median absult deviation(MAD),然后通过判断即将被移出窗口的那个数据是否超过k倍MAD,超过则将其视作离群值进行剔除并用当前窗口中位数median替代输出。
//中位数法剔除离群值
module outlier_removal(input i_clk ,input i_rst ,input [15:0] i_data ,input i_dvld ,output reg [15:0] o_data ,output reg o_dvld );localparam WIN = 16; genvar i;//寄存reg signed [15:0] r_data_shreg [0:WIN - 1];reg r_dvld_shreg [0:WIN - 1];reg signed [15:0] r_median ;//中位数wire [16 * WIN - 1:0] w_sorti_data ;wire [16 * WIN - 1:0] w_sorto_data ;//排完序的数据wire signed [15:0] w_data_sorted [0:WIN - 1];generatefor(i = 0; i < WIN; i = i + 1) beginassign w_sorti_data[16 * i + 15:16 * i] = r_data_shreg[i];assign w_data_sorted[i] = w_sorto_data[16 * i + 15:16 * i];endendgenerate//求数据中位数always@(posedge i_clk or posedge i_rst) beginif(i_rst)r_median <= 'd0;else r_median <= (w_data_sorted[WIN / 2] + w_data_sorted[WIN / 2 - 1]) / 2;end//中位数偏差缓存reg signed [15:0] r_dev_buff [0:WIN - 1] ;wire [15:0] w_adev_buff [0:WIN - 1] ;generatefor(i = 0; i < WIN; i = i + 1) beginalways@(posedge i_clk or posedge i_rst) beginif(i_rst)r_dev_buff[i] <= 'd0;elser_dev_buff[i] <= r_data_shreg[i] - r_median;endassign w_adev_buff[i] = r_dev_buff[i][15] ? $signed(-1) * r_dev_buff[i] : r_dev_buff[i];//取绝对值endendgeneratewire [16 * WIN - 1:0] w_sorti_adev ;wire [16 * WIN - 1:0] w_sorto_adev ;wire [15:0] w_adev_sorted [0:WIN - 1] ;generatefor(i = 0; i < WIN; i = i + 1) beginassign w_sorti_adev[i * 16 + 15:i * 16] = w_adev_buff[i];assign w_adev_sorted[i] = w_sorto_adev[i * 16 + 15:i * 16];endendgeneratereg [15:0] r_data_mad ;//绝对偏差中位数always@(posedge i_clk or posedge i_rst)beginif(i_rst)r_data_mad <= 'd0;else r_data_mad <= (w_adev_sorted[WIN / 2] + w_adev_sorted[WIN / 2 - 1]) / 2;end
//排序数据求中位值
bitonic_sort
sort_data_u (.i_clk (i_clk ),.i_rst (i_rst ),.i_buff (w_sorti_data),.o_buff (w_sorto_data)
);
//排序绝对偏差求MAD
bitonic_sort
sort_adev_u (.i_clk (i_clk ),.i_rst (i_rst ),.i_buff (w_sorti_adev),.o_buff (w_sorto_adev)
);wire w_outlier_judge;assign w_outlier_judge = (w_adev_buff[WIN - 1] >> 2) >= r_data_mad;//系数为4//移位寄存数据always@(posedge i_clk or posedge i_rst) beginif(i_rst) beginr_dvld_shreg[0] <= 'd0;r_data_shreg[0] <= 'd0;endelse if(i_dvld) beginr_dvld_shreg[0] <= 'd1;r_data_shreg[0] <= i_data;endelse beginr_dvld_shreg[0] <= r_dvld_shreg[0];r_data_shreg[0] <= r_data_shreg[0];endendgeneratefor(i = 1; i < WIN; i = i + 1) beginalways@(posedge i_clk or posedge i_rst) beginif(i_rst) beginr_dvld_shreg[i] <= 'd0;r_data_shreg[i] <= 'd0;endelse if(i_dvld) beginr_dvld_shreg[i] <= r_dvld_shreg[i - 1];r_data_shreg[i] <= r_data_shreg[i - 1];endelse beginr_dvld_shreg[i] <= r_dvld_shreg[i];r_data_shreg[i] <= r_data_shreg[i];endendendendgenerate//新到一个数据就排出一个数据always@(posedge i_clk or posedge i_rst) beginif(i_rst) begino_data <= 'd0;o_dvld <= 'd0;endelse if(i_dvld) begino_data <= w_outlier_judge ? r_median : r_data_shreg[WIN - 1];//如果是离群值则使用中位数替代o_dvld <= r_dvld_shreg[WIN - 1];endelse begino_data <= o_data;o_dvld <= 'd0;endendendmodule
tb文件
module out_rm_tb();reg i_clk ;reg i_rst ;reg [15:0] i_data ;reg i_dvld ;wire [15:0] o_data ;wire o_dvld ;always#10 i_clk = ~i_clk;initial begini_clk = 1;i_rst = 1;i_data = 'd0;i_dvld = 'd0;#105i_rst = 0;repeat(16) begini_data = $random()%16'hff;i_dvld = 'd1;#20;i_dvld = 'd0;#20;end#20i_data = 16'hFEBA;i_dvld = 'd1;#20i_dvld = 'd0;#20i_data = 16'h7d6e;i_dvld = 'd1;#20i_dvld = 'd0;#20i_data = 16'h78a8;i_dvld = 'd1;#20i_dvld = 'd0;#20i_data = 16'h00a0;i_dvld = 'd1;#20i_dvld = 'd0;#20repeat(32) begini_data = $random()%16'hfff;i_dvld = 'd1;#20;i_dvld = 'd0;#100;endendoutlier_removal
outlier_removal_u(i_clk ,i_rst ,i_data ,i_dvld ,o_data ,o_dvld
);endmodule