自适应滤波器提取胎儿心电信号的MATLAB及FPGA实现

目录

一、前言
二、自适应滤波器概述
三、MATLAB提取
1、LMS算法(matlab)
2、主程序
3、结果展示
四、FPGA提取
1、生成存储器初始化文件(mif文件)
2、完整程序(Verilog HDL)
3、signaltap在线调试结果
五、参考文献
六、更新日志

一、前言

0、完整工程代码下载:添加链接描述
1、为了完成课程设计,本人查找了大量资料,然而找到的大多数资料都不完整或是只有MATLAB/FPGA,所以将我的全部代码上传上来,以帮助更多的大学生学习。另外由于本设计的输出结果不是特别好,因此仅供参考。
2、设计目标:使用自适应滤波器从母亲的腹部心电信号中提取出胎儿的心电信号。
3、基本思想:
自适应滤波器提取胎儿心电信号的MATLAB及FPGA实现_第1张图片

二、自适应滤波器概述

自适应滤波器是指根据环境的改变,使用自适应算法来改变滤波器的参数和结构的滤波器。一般情况下,不改变自适应滤波器的结构。而自适应滤波器的系数是由自适应算法更新的时变系数。即其系数自动连续地适应于给定信号,以获得期望响应。自适应滤波器的最重要的特征就在于它能够在未知环境中有效工作,并能够跟踪输入信号的时变特征。自适应滤波器常用的基础结构是FIR滤波器,IIR滤波器也有使用。

三、MATLAB提取

1、LMS算法(matlab)

% 输入参数:
%     x   输入序列
%     d   期望序列
%     M    滤波器阶数
%     mu   收敛因子(步长)      
% 输出参数:
%     w    滤波器的系数矩阵
%     e   误差序列
%     y   实际输出序列
%     G   收敛曲线
function [G,y,w,e]=mlms(x,d,M,mu)
N = length(x);
e = zeros(N,1);             % 误差序列,e(k)表示第k次迭代时预期输出与实际输入的误差
w  = zeros(M,N);             % 每一行代表一个加权参量,每一列代表-次迭代,初始为0
G  = zeros(N-M+1,1);        %收敛曲线 序列初始化
% 迭代计算
for k = M:N                  % 第k次迭代
    y = w(:,k-1).' * x(k:-1:k-M+1);        % 滤波器的输出
    e(k) = d(k) - y ;        % 第k次迭代的误差 
    G(k)=sum(abs(e).^2)/k;  %收敛曲线计算
    % 滤波器系数计算的迭代式
    w(:,k) = w(:,k-1) + 2*mu*e(k)*x(k:-1:k-M+1);
end
% 求最优时滤波器的输出序列
y = inf * ones(size(x)); % inf 是无穷大的意思
for k = M:N
    y(k) = w(:,end).'* x(k:-1:k-M+1);%用最后得到的最佳估计得到输出
end

2、主程序

心电信号数据下载地址:提取码:no88

%导入数据
%数据来源:https://homes.esat.kuleuven.be/~smc/daisy/index.html
signal_abdomen = abdomen('FOETAL_ECG.dat',1, 2500)';     %腹部信号  第三列
signal_chest = chest('FOETAL_ECG.dat',1, 2500)';       %胸部信号  第八列
n=time('FOETAL_ECG.dat',1, 2500);                   %时间  第一列
M = 16;     %滤波器的阶数
mu = 9.0635*10^(-8); %收敛因子,步长

%母亲胸腹部信号
figure;
subplot(311);
plot(n,signal_abdomen);
title('母亲腹部信号');xlabel('时间');ylabel('幅值');
subplot(312);
plot(n,signal_chest);
title('母亲胸部信号');xlabel('时间');ylabel('幅值');

%自适应滤波器信号过滤
x = signal_chest.';
d = signal_abdomen.';
[G,y,w,e] = mlms(x,d,M,mu);                           %调用函数
subplot(313);
plot(n,e);                                          %输出误差信号,即为需求的胎儿心电信号
title('胎儿心电信号');xlabel('时间');ylabel('幅值');

%收敛曲线
figure;
plot(1:2500,G,'.');
title('收敛曲线');

3、结果展示

自适应滤波器提取胎儿心电信号的MATLAB及FPGA实现_第2张图片
图片从上往下分别是从母亲的腹部、胸部读取的心电信号,腹部信号中包含了胎儿的心电信号;最下面一张图是自适应滤波器滤波得出的胎儿心电信号。
自适应滤波器提取胎儿心电信号的MATLAB及FPGA实现_第3张图片
滤波器的收敛曲线↑

四、FPGA提取

1、使用MATLAB生成存储器初始化文件(mif文件)

%信号处理
[max_chest,index1]=max(signal_chest);%maxxb是胸部信号的最大值
chest=127*signal_chest/max_chest;%将胸部信号归一化并放大127倍
fchest=zeros(2500,1);
for i=1:256
    fchest(i)=floor(chest(i))*127; %取整并放大
end
[max_abdomen,index2]=max(signal_abdomen);%maxe是腹部信号的最大值,index是最大值点的横坐标
abdomen=127*signal_abdomen/max_abdomen;%将腹部信号归一化并放大127倍
fabdomen=zeros(2500,1);
for i=1:256
    fabdomen(i)=floor(abdomen(i))*127; %取整并放大
end

%生成mif文件
fid = fopen('***','w');   %***为mif文件名
fprintf(fid,'%s\n','DEPTH = 2500;');
fprintf(fid,'%s\n','WIDTH = 16;');
fprintf(fid,'%s\n','DATA_RADIX = UNS;');
fprintf(fid,'%s\n','ADDRESS_RADIX = DEC;');
fprintf(fid,'%s\n','CONTENT BEGIN');
for i=1:256
   fprintf(fid, '%d',i-1);              %address
   fprintf(fid, '%s',' : '); 
   fprintf(fid, '%d;\n',fchest(i));        %数值点
end
fprintf(fid,'%s\n','END ;');
fclose(fid);

重复步骤(1),将需要的mif文件全部生成,即可导入quartus ii 中的rom元件。

2、完整程序

(1)顶层文件

自适应滤波器提取胎儿心电信号的MATLAB及FPGA实现_第4张图片

(2)DelayUnit

module DelayUnit(Clk,Reset,Data_in,Delay_out); 
	input	Clk,Reset; 
	input	   [15:0] Data_in; 
	output	[15:0] Delay_out; 
 
	reg[15:0] Delay_out; 
 
	always @(posedge Clk or posedge Reset) begin 
		if (Reset ==1'b1) begin 
			Delay_out <= 0; 
		end 
		else begin
				Delay_out <= Data_in; 
			end 
		end 
endmodule

(3)LMSx16

module LMSx16(Clk,Reset,Data_in,Step_size,Sum_in,Sum_out); 
	input	Clk,Reset; 
	input   signed [15:0] Data_in,Step_size; 
	input   signed [31:0] Sum_in; 
	output  signed [31:0] Sum_out; 
 
	wire signed [15:0] LMS_tap_1_delay_out,
	LMS_tap_2_delay_out,
	LMS_tap_3_delay_out, 
	LMS_tap_4_delay_out,
	LMS_tap_5_delay_out,
	LMS_tap_6_delay_out,
	LMS_tap_7_delay_out,
	LMS_tap_8_delay_out,
	LMS_tap_9_delay_out, 
	LMS_tap_10_delay_out,
	LMS_tap_11_delay_out,
	LMS_tap_12_delay_out,
	LMS_tap_13_delay_out,
	LMS_tap_14_delay_out,
	LMS_tap_15_delay_out;
	wire signed [31:0] LMS_tap_1_out,
	LMS_tap_2_out,
	LMS_tap_3_out,
	LMS_tap_4_out, 
	LMS_tap_5_out,
	LMS_tap_6_out,
	LMS_tap_7_out,
	LMS_tap_8_out, 
	LMS_tap_9_out,
	LMS_tap_10_out,
	LMS_tap_11_out,
	LMS_tap_12_out,
	LMS_tap_13_out,
	LMS_tap_14_out,
	LMS_tap_15_out,
	LMS_tap_16_out;
 
	LMS_tap		LMS_tap_1	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(Data_in),  
							.Step_size(Step_size), 
							.Delay_out(LMS_tap_1_delay_out), 
							.Tap_out(LMS_tap_1_out) 
							); 
 
	LMS_tap		LMS_tap_2	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_1_delay_out),  
							.Step_size(Step_size), 
							.Delay_out(LMS_tap_2_delay_out), 
							.Tap_out(LMS_tap_2_out) 
							); 
	LMS_tap		LMS_tap_3	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_2_delay_out),  
							.Step_size(Step_size), 
							.Delay_out(LMS_tap_3_delay_out), 
							.Tap_out(LMS_tap_3_out) 
							); 
	LMS_tap		LMS_tap_4	(.Clk(Clk), 
							.Reset(Reset),  
							.Data_in(LMS_tap_3_delay_out),  
							.Step_size(Step_size), 
							.Delay_out(LMS_tap_4_delay_out), 
							.Tap_out(LMS_tap_4_out) 
							); 
	LMS_tap		LMS_tap_5	(.Clk(Clk), 
							.Reset(Reset),  
							.Data_in(LMS_tap_4_delay_out),  
							.Step_size(Step_size), 
							.Delay_out(LMS_tap_5_delay_out), 
							.Tap_out(LMS_tap_5_out) 
							); 
	LMS_tap		LMS_tap_6	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_5_delay_out),  
							.Step_size(Step_size), 
							.Delay_out(LMS_tap_6_delay_out), 
							.Tap_out(LMS_tap_6_out) 
							); 
	LMS_tap		LMS_tap_7	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_6_delay_out),  
							.Step_size(Step_size), 
							.Delay_out(LMS_tap_7_delay_out), 
							.Tap_out(LMS_tap_7_out) 
							); 
	LMS_tap		LMS_tap_8	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_7_delay_out),  
							.Step_size(Step_size), 
							.Tap_out(LMS_tap_8_out) 
							); 
 LMS_tap		LMS_tap_9	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_8_delay_out),  
							.Step_size(Step_size), 
							.Tap_out(LMS_tap_9_out) 
							); 
LMS_tap		LMS_tap_10	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_9_delay_out),  
							.Step_size(Step_size), 
							.Tap_out(LMS_tap_10_out) 
							); 
LMS_tap		LMS_tap_11	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_10_delay_out),  
							.Step_size(Step_size), 
							.Tap_out(LMS_tap_11_out) 
							); 
LMS_tap		LMS_tap_12	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_11_delay_out),  
							.Step_size(Step_size), 
							.Tap_out(LMS_tap_12_out) 
							); 
LMS_tap		LMS_tap_13	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_12_delay_out),  
							.Step_size(Step_size), 
							.Tap_out(LMS_tap_13_out) 
							); 
LMS_tap		LMS_tap_14	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_13_delay_out),  
							.Step_size(Step_size), 
							.Tap_out(LMS_tap_14_out) 
							); 
LMS_tap		LMS_tap_15	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_14_delay_out),  
							.Step_size(Step_size), 
							.Tap_out(LMS_tap_15_out) 
							); 
LMS_tap		LMS_tap_16	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(LMS_tap_15_delay_out),  
							.Step_size(Step_size), 
							.Tap_out(LMS_tap_16_out) 
							); 
	assign Sum_out = Sum_in + LMS_tap_1_out + LMS_tap_2_out + 
					 LMS_tap_3_out + LMS_tap_4_out + LMS_tap_5_out + 
					 LMS_tap_6_out + LMS_tap_7_out + LMS_tap_8_out +
					 LMS_tap_9_out + LMS_tap_10_out + LMS_tap_11_out + 
					 LMS_tap_12_out + LMS_tap_13_out + LMS_tap_14_out + 
					 LMS_tap_15_out + LMS_tap_16_out; 
 
endmodule 

(4)LMS_tap

module LMS_tap(Clk,Reset,Data_in,Step_size,Delay_out,Tap_out); 
	input	Clk,Reset; 
	input	   signed [15:0] Data_in,Step_size; 
	output	signed [15:0] Delay_out; 
	output   signed [31:0] Tap_out; 
 
	wire signed [15:0] Weight_in,Weight_out,Product_16; 
   wire signed [31:0] Product_32; 
 
	DelayUnit Delay_reg (.Clk(Clk), 
						.Reset(Reset), 
						.Data_in(Data_in), 
						.Delay_out(Delay_out) 
						); 
 
	assign Product_32 = Data_in * Step_size; 
    assign Product_16 = Product_32[26:11]; 
    assign Weight_in = (Reset == 1'b1) ? 16'h0000 : (Product_16 + Weight_out); 
 
	DelayUnit Data_reg  (.Clk(Clk), 
						.Reset(Reset), 
						.Data_in(Weight_in), 
						.Delay_out(Weight_out) 
						);	 
 
	assign Tap_out = Weight_out * Data_in; 
 
endmodule 

(5)LMS

module lms(Clk,Reset,Data_in,Desired_in,Error_out); 
	input	Clk,Reset; 
	input   signed [15:0] Data_in,Desired_in; 
	output  signed [15:0] Error_out; 
 
	wire signed [15:0] Error_in,
	Data_in_reg, //通过延迟单元后的输入信号(胸部)
	Desired_in_reg, //通过延迟单元后的期望信号(腹部)
	Step_size, //步长
	Product_16; 
	wire signed [31:0] Product_32,LMSx16_sum_out; 
 
	DelayUnit	Data_reg_1	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(Data_in), 
							.Delay_out(Data_in_reg) 
							); 
							 
	DelayUnit	Data_reg_2	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(Desired_in), 
							.Delay_out(Desired_in_reg) 
							); 
 
	assign Product_32 = Step_size * Error_in; 
   assign Product_16 = Product_32[26:11]; 
	assign Step_size=16'b0000000000000010;
 
	LMSx16	LMSx16   (.Clk(Clk), 
					.Reset(Reset),  
					.Data_in(Data_in_reg), 
					.Step_size(Product_16), 
					.Sum_in(32'h0000_0000), 
					.Sum_out(LMSx16_sum_out) 
					); 
 
    assign Error_in = Desired_in_reg - LMSx16_sum_out[26:11];  
 
	DelayUnit	Data_reg_3	(.Clk(Clk), 
							.Reset(Reset), 
							.Data_in(Error_in), 
							.Delay_out(Error_out) 
							); 
 
endmodule 

(6)MegaWizard

计数器:up only,12 bits,modules of 2500;
存储器:16 bits 4096 words;

3、signaltap在线调试结果

在这里插入图片描述
删除了两位符号位后的结果↑在这里插入图片描述
删除了一位符号位后的结果↑

五、参考文献

[1]颜庆津.数值分析[CD].北京:北京航空航天大学出版社,2006.
[2]heda3.自适应滤波-----LMS(Least Mean Square)算法.2018.
[3]爱学习的小野狼.LMS算法实现自适应滤波器(matlab版).2018.
[4]he.LMS.联合开发网.2012.

六、更新日志

2020.9.18 发布
2020.9.19 修改

你可能感兴趣的:(matlab,fpga,算法)