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];
	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
相关推荐
Q741_1474 小时前
C++ 面试高频考点 力扣 162. 寻找峰值 二分查找 题解 每日一题
c++·算法·leetcode·面试·二分查找
j_xxx404_4 小时前
数据结构:栈和队列(上)
c语言·数据结构·算法·leetcode
墨染点香5 小时前
LeetCode 刷题【62. 不同路径】
算法·leetcode·职场和发展
艾醒5 小时前
大模型面试题剖析:大模型微调数据集构建
人工智能·算法·程序员
CoovallyAIHub5 小时前
YOLO-ELA:用于高性能实时绝缘子缺陷检测的高效局部注意力建模
深度学习·算法·计算机视觉
一起努力啊~5 小时前
算法题打卡力扣第3题:无重复字符的最长子串(mid)
算法·leetcode·哈希算法
古译汉书5 小时前
蓝桥杯算法之基础知识(6)
数据结构·算法·蓝桥杯
熙客6 小时前
基础思想:动态规划与贪心算法
算法·贪心算法·动态规划
Liverpool05196 小时前
代码随想录算法训练营第四十三天|LeetCode300. 最长递增子序列,LeetCode674. 最长连续递增序列,LeetCode718. 最长重复子数组
算法