卡尔曼(Kalman)滤波器的FPGA实现

卡尔曼(Kalman)滤波器的FPGA实现

关于kalman滤波器的原理我这里就不介绍了,直接贴出代码,代码注释中有简要的介绍。该模块适用于一维数据的滤波处理,通过设置Q、R两个参数可以改变其滤波特性。

/******************************FILE HEAD**********************************
 * file_name         : Kalman.v
 * function          : 卡尔曼滤波器
 * author            : 今朝无言
 * date & version    : 2021/12/16 & v1.0
 *************************************************************************/
module Kalman(
input				rst_n,
input		[31:0]	data_in,
input				en,			//数据使能,上升沿有效
output	reg	[31:0]	data_out
);

// kalman滤波
// 流程:
// initial:
//   out=0;
//   P=0;
//   LastP=0;
//   Q=Q0;		//Q、R通过影响卡尔曼增益K=(Pk+Q)/(Pk+Q+R)的值,影响预测值和测量值的权重
//   R=R0;		//Q=inf(过程噪声过大) or R=0(没有观测噪声) 时,完全相信观测值,此时没有滤波效果
// end initial
// while 1:
//   %预测协方差方程:k时刻系统估算协方差 = k-1时刻的系统协方差 + 过程噪声协方差
//   P = LastP + Q;
//   %卡尔曼增益方程:卡尔曼增益 = k时刻系统估算协方差 / (k时刻系统估算协方差 + 观测噪声协方差)
//   Kg = P / (P + R);
//   %更新最优值方程:k时刻状态变量的最优值 = 状态变量的预测值 + 卡尔曼增益 * (测量值 - 状态变量的预测值)
//   out = out + Kg * (input(i) - out);%因为这一次的预测值就是上一次的输出值
//   %更新协方差方程: 本次的系统协方差赋给 kfp->LastP 为下一次运算准备。
//   LastP = (1 - Kg) * P;
//   output(i) = out;
// end while

parameter	Q	= 32'd655;		//参与计算的P,Q,R均为16-16定点数
parameter	R	= 32'd65536;

reg	[31:0]	P		= 32'd0;
reg	[31:0]	LastP	= 32'd0;
reg	[15:0]	Kg		= 16'd0;	//Kg为0-16定点数
reg	[31:0]	LastOut	= 32'd0;

always @(posedge en or negedge rst_n) begin
	if(~rst_n)begin
		P		= 32'd0;
		LastP	= 32'd0;
		Kg		= 16'd0;
		LastOut	= 32'd0;
	end
	else begin
		P			= LastP + Q;	//用‘=’阻塞运算,以保证顺序执行
		Kg			= (P<<16) / (P + R);
		data_out	= (data_in>LastOut)?
					   LastOut + ((Kg * (data_in - LastOut))>>16):
					   LastOut - ((Kg * (LastOut - data_in))>>16);
		LastP		= ((16'd65535 - Kg) * P)>>16;
		LastOut		= data_out;
	end
end

endmodule
//END OF Kalman.v FILE***************************************************

testbench

/******************************FILE HEAD**********************************
 * file_name         : Kalman_tb.v
 * function          : Kalman的testbench
 * author            : 今朝无言
 * date & version    : 2021/12/20 & v1.0
 *************************************************************************/
`default_nettype none
`timescale 1ns/1ps

module Kalman_tb();

reg [15:0]	data_noised	[0:1023];	//带噪数据
reg			start_tb	= 0;

reg				rst_n		= 1;
reg		[31:0]	data_in;
reg				en			= 1;
wire	[31:0]	data_out;

initial begin
	$readmemh("data_noised.hex", data_noised, 0); //读取带噪数据
	#(5); //延迟奇数个ns,以避免读入xxx的data_in
	start_tb 	= 1;
end

initial begin
	wait(start_tb);
	
	#(1024*2);
	#(1024*2);
	
	$stop();
end

always #1 begin
	en	= ~en;
end

reg	[9:0]	k	= 0;
always @(negedge en) begin	//下降沿导入数据,则上升沿可保证向滤波器发送的是当前周期的数据
	if(start_tb)begin
		k		<= k + 1;
		data_in	<= data_noised[k];
	end
end

//Kalman滤波器
Kalman	#(
	.Q(32'd655),
	.R(32'd65536))
Kalman_inst(
	.rst_n		(rst_n),
	.data_in	(data_in),
	.en			(en&start_tb),
	.data_out	(data_out)
);

endmodule
//END OF Kalman_tb.v FILE***************************************************

使用matlab生成噪声数据的.hex文件

%-------------产生一批带噪数据------------------
clc,clear,close all

t=linspace(0,10,1024);
noise=0.2*randn(size(t)); %过程噪声
%data=sin(t)+3*sin(0.2*t+pi/3)+0.3*sin(3*t)+sin(10*t)+noise;
data=(t>5)+noise;

data=data-min(data);
data=data./max(data);
data=floor(data*65535);

plot(t,data)

% fid=fopen('data_noised.hex','w');
% for k=1:1024
%     fprintf(fid,[dec2hex(data(k)),'\n']); %16进制文件
% end
% fclose(fid);

时序仿真

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今朝无言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值