讲解视频:
采用中位数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];
generate
for(i = 0; i < WIN; i = i + 1) begin
assign 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];
end
endgenerate
//求数据中位数
always@(posedge i_clk or posedge i_rst) begin
if(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] ;
generate
for(i = 0; i < WIN; i = i + 1) begin
always@(posedge i_clk or posedge i_rst) begin
if(i_rst)
r_dev_buff[i] <= 'd0;
else
r_dev_buff[i] <= r_data_shreg[i] - r_median;
end
assign w_adev_buff[i] = r_dev_buff[i][15] ? $signed(-1) * r_dev_buff[i] : r_dev_buff[i];//取绝对值
end
endgenerate
wire [16 * WIN - 1:0] w_sorti_adev ;
wire [16 * WIN - 1:0] w_sorto_adev ;
wire [15:0] w_adev_sorted [0:WIN - 1] ;
generate
for(i = 0; i < WIN; i = i + 1) begin
assign 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];
end
endgenerate
reg [15:0] r_data_mad ;//绝对偏差中位数
always@(posedge i_clk or posedge i_rst)begin
if(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) begin
if(i_rst) begin
r_dvld_shreg[0] <= 'd0;
r_data_shreg[0] <= 'd0;
end
else if(i_dvld) begin
r_dvld_shreg[0] <= 'd1;
r_data_shreg[0] <= i_data;
end
else begin
r_dvld_shreg[0] <= r_dvld_shreg[0];
r_data_shreg[0] <= r_data_shreg[0];
end
end
generate
for(i = 1; i < WIN; i = i + 1) begin
always@(posedge i_clk or posedge i_rst) begin
if(i_rst) begin
r_dvld_shreg[i] <= 'd0;
r_data_shreg[i] <= 'd0;
end
else if(i_dvld) begin
r_dvld_shreg[i] <= r_dvld_shreg[i - 1];
r_data_shreg[i] <= r_data_shreg[i - 1];
end
else begin
r_dvld_shreg[i] <= r_dvld_shreg[i];
r_data_shreg[i] <= r_data_shreg[i];
end
end
end
endgenerate
//新到一个数据就排出一个数据
always@(posedge i_clk or posedge i_rst) begin
if(i_rst) begin
o_data <= 'd0;
o_dvld <= 'd0;
end
else if(i_dvld) begin
o_data <= w_outlier_judge ? r_median : r_data_shreg[WIN - 1];//如果是离群值则使用中位数替代
o_dvld <= r_dvld_shreg[WIN - 1];
end
else begin
o_data <= o_data;
o_dvld <= 'd0;
end
end
endmodule
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 begin
i_clk = 1;
i_rst = 1;
i_data = 'd0;
i_dvld = 'd0;
#105
i_rst = 0;
repeat(16) begin
i_data = $random()%16'hff;
i_dvld = 'd1;
#20;
i_dvld = 'd0;
#20;
end
#20
i_data = 16'hFEBA;
i_dvld = 'd1;
#20
i_dvld = 'd0;
#20
i_data = 16'h7d6e;
i_dvld = 'd1;
#20
i_dvld = 'd0;
#20
i_data = 16'h78a8;
i_dvld = 'd1;
#20
i_dvld = 'd0;
#20
i_data = 16'h00a0;
i_dvld = 'd1;
#20
i_dvld = 'd0;
#20
repeat(32) begin
i_data = $random()%16'hfff;
i_dvld = 'd1;
#20;
i_dvld = 'd0;
#100;
end
end
outlier_removal
outlier_removal_u(
i_clk ,
i_rst ,
i_data ,
i_dvld ,
o_data ,
o_dvld
);
endmodule