一、前言
二、自适应滤波器概述
三、MATLAB提取
1、LMS算法(matlab)
2、主程序
3、结果展示
四、FPGA提取
1、生成存储器初始化文件(mif文件)
2、完整程序(Verilog HDL)
3、signaltap在线调试结果
五、参考文献
六、更新日志
0、完整工程代码下载:添加链接描述
1、为了完成课程设计,本人查找了大量资料,然而找到的大多数资料都不完整或是只有MATLAB/FPGA,所以将我的全部代码上传上来,以帮助更多的大学生学习。另外由于本设计的输出结果不是特别好,因此仅供参考。
2、设计目标:使用自适应滤波器从母亲的腹部心电信号中提取出胎儿的心电信号。
3、基本思想:
自适应滤波器是指根据环境的改变,使用自适应算法来改变滤波器的参数和结构的滤波器。一般情况下,不改变自适应滤波器的结构。而自适应滤波器的系数是由自适应算法更新的时变系数。即其系数自动连续地适应于给定信号,以获得期望响应。自适应滤波器的最重要的特征就在于它能够在未知环境中有效工作,并能够跟踪输入信号的时变特征。自适应滤波器常用的基础结构是FIR滤波器,IIR滤波器也有使用。
% 输入参数:
% 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
心电信号数据下载地址:提取码: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('收敛曲线');
图片从上往下分别是从母亲的腹部、胸部读取的心电信号,腹部信号中包含了胎儿的心电信号;最下面一张图是自适应滤波器滤波得出的胎儿心电信号。
滤波器的收敛曲线↑
%信号处理
[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元件。
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
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
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
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
计数器:up only,12 bits,modules of 2500;
存储器:16 bits 4096 words;
[1]颜庆津.数值分析[CD].北京:北京航空航天大学出版社,2006.
[2]heda3.自适应滤波-----LMS(Least Mean Square)算法.2018.
[3]爱学习的小野狼.LMS算法实现自适应滤波器(matlab版).2018.
[4]he.LMS.联合开发网.2012.
2020.9.18 发布
2020.9.19 修改