一、数字滤波器简介
数字滤波器是指通过一定的数据逻辑构成的可以滤除输入信号中的特定的噪声的算法,这里所指的数字滤波器主要包括平均值滤波、FIR滤波、CIC滤波等,在之后的实验中,我们将介绍不同数字滤波器的原理,通过MATLAB和FPGA分别实现不同数字滤波器,为之后工程中的应用打下基础。
二、滑动平均滤波
2.1 滑动平均滤波原理
若输入采样点的个数为N个,假设采用8倍的滑动平均滤波,其滑动平均滤波的原理如下:
- 滤波器输出的第一个数据在8个采样周期之后,即首先对输入的8个数据进行平均,平均结果为x_0=(x0+x1+…+x7)/8
- 8个周期之后即可以实现数据的滑动输入,并且滤波器输出为x_i=((7*x_i-1)+xi+7)/8 , i=1,2……
2.2 MATLAB实现
%%N倍滑动滤波算法
clear;
clc;
%数据输入
fileID = fopen('gnd_ch3.txt');
data = textscan(fileID,'%s');
data = data{1,1};
k = 1;
for i = 1 : length(data)-11
if strcmp(data(i),'61') && strcmp(data(i+1),'64')
Ain(k) = (((hex2dec(strcat(data(i+5),data(i+6),data(i+7)))*20/2^24)-10)*1e6)/50;
k = k + 1;
end
end
%变量定义
N = 8;%滑动滤波倍数
M = length(Ain);%输入数据个数
INIT_NUM = 0;%初始数据和
INIT_AVE = 0;%初始数据均值
NUM = 0;%数据和
AVE = 0;%数据均值
Aout = zeros(1,M);%数据输出
%初始均值
%求初始和
for i = 1:1:N-1
INIT_NUM = INIT_NUM + Ain(1,i);
end
%求初始均值
INIT_AVE = INIT_NUM / N;
Aout(1,N) = INIT_AVE;
AVE = INIT_AVE;
%滑动均值
for i = 1:1:M-N
NUM = (AVE * (N-1)) + Ain(1,i + N);
AVE = NUM / N;
Aout(1,i + N) = AVE;
end
figure
plot(Ain(N+100:M));
hold on;
plot(Aout(N+100:M));
绘图结果:
8倍滑动滤波
16倍滑动滤波
64倍滑动滤波
2.3 FPGA实现
1. 代码实现参考Move_Mean_filter工程
`timescale 1ns / 1ps
/******************************************************************************************************
**Author :CKM
**E-mail :15594951527@163.com
**Times :2022/4/10
**Editor :vs_code/notepad++
**EDATools :vivado 2017.4
**Module_name :move_mean_filter
**Functions :实现输入数据DATA_NUM位,MUL_NUM倍滑动滤波算法
*******************************************************************************************************/
module move_mean_filter#(
parameter DATA_NUM = 24 ,//数据位宽
parameter MUL_NUM = 8 ,//滑动倍数
parameter MOV_NUM = 3
)(
input clk_i ,
input rst_n ,
input [DATA_NUM-1 : 0] Ain ,
output reg [DATA_NUM-1 : 0] Aout
);
/*---------------------------------------------常量定义------------------------------------------------*/
localparam IDLE = 6'b000_001 ;//空闲状态
localparam INIT_NUM = 6'b000_010 ;//初始化赋值状态
localparam INIT_MEAN = 6'b000_100 ;//初始化赋值缓冲状态
localparam NUM = 6'b001_000 ;//滑动滤波状态
localparam NUM_BUFF = 6'b010_000 ;//滑动滤波缓冲状态
localparam MEAN = 6'b100_000 ;//等待状态
/*---------------------------------------------变量定义------------------------------------------------*/
reg [ 5 : 0] current_state ;//现态
reg [ 5 : 0] next_state ;//次态
reg [DATA_NUM - 1 : 0] Ain_temp1 ;//输入数据缓冲1
reg [DATA_NUM - 1 : 0] Ain_temp2 ;//输入数据缓冲2
reg [31 : 0] init_cnt ;//初始化计数器
reg [ 7 : 0] buffer_cnt ;//初始化计数器
reg [47 : 0] init_num ;//初始化数据和
reg [47 : 0] num ;//数据和
reg [24 : 0] A ;
reg [ 7 : 0] B ;
reg [24 : 0] C ;
wire [47 : 0] P ;
wire [47 : 0] PCOUT ;
/*---------------------------------------------程序开始------------------------------------------------*/
//输入数据缓冲
always @(posedge clk_i or negedge rst_n) begin
if(!rst_n)begin
Ain_temp1 <= 0;
Ain_temp2 <= 0;
end
else begin
Ain_temp1 <= Ain;
Ain_temp2 <= Ain_temp1;
end
end
//滑动滤波算法
//1.状态确定
always @(posedge clk_i or negedge rst_n) begin
if(!rst_n)begin
current_state <= 0;
end
else begin
current_state <= next_state;
end
end
//2.状态切换
always @(*)begin
if(!rst_n)begin
next_state <= IDLE;
end
else begin
case(current_state)
IDLE :begin
if(Ain_temp2 != Ain_temp1)begin
next_state <= INIT_NUM;
end
else begin
next_state <= IDLE;
end
end
INIT_NUM :begin
if(init_cnt == MUL_NUM)begin
next_state <= INIT_MEAN;
end
else begin
next_state <= INIT_NUM;
end
end
INIT_MEAN:begin
next_state <= NUM;
end
NUM :begin
if(Ain_temp2 != Ain_temp1)begin
next_state <= NUM_BUFF;
end
else begin
next_state <= NUM;
end
end
NUM_BUFF:begin
next_state <= MEAN;
end
MEAN :begin
next_state <= NUM;
end
default :begin end
endcase
end
end
//3.各状态逻辑
always @(posedge clk_i or negedge rst_n) begin
if(!rst_n)begin
init_cnt <= 0;
buffer_cnt <= 0;
init_num <= 0;
num <= 0;
Aout <= 0;
A <= 0;
B <= 0;
C <= 0;
end
else begin
case(next_state)
IDLE :begin
init_cnt <= 0;
buffer_cnt <= 0;
if(Ain_temp2 != Ain_temp1)begin
init_num <= Ain;
end
else begin
init_num <= init_num;
end
num <= 0;
Aout <= Ain;
A <= 0;
B <= 0;
C <= 0;
end
INIT_NUM :begin
if(Ain_temp2 != Ain_temp1)begin
init_cnt <= init_cnt + 1;
init_num <= init_num + Ain;
end
else begin
init_cnt <= init_cnt;
init_num <= init_num;
end
buffer_cnt <= 0;
num <= 0;
Aout <= Aout;
A <= 0;
B <= 0;
C <= 0;
end
INIT_MEAN:begin
init_cnt <= init_cnt;
buffer_cnt <= 0;
init_num <= init_num;
num <= 0;
if(init_cnt == MUL_NUM)begin
Aout <= init_num >> MOV_NUM;
end
else begin
Aout <= Aout;
end
A <= 0;
B <= 0;
C <= 0;
end
NUM :begin
init_cnt <= init_cnt;
buffer_cnt <= 0;
init_num <= init_num;
num <= num;
Aout <= Aout;
A <= Aout;
B <= MUL_NUM - 1;
C <= Ain;
end
NUM_BUFF :begin
init_cnt <= init_cnt;
buffer_cnt <= buffer_cnt + 1;
init_num <= init_num;
num <= P;
Aout <= Aout;
A <= A;
B <= B;
C <= C;
end
MEAN :begin
init_cnt <= init_cnt;
buffer_cnt <= 0;
init_num <= init_num;
num <= num;
Aout<= num >> MOV_NUM;
A <= A;
B <= B;
C <= C;
end
default :begin end
endcase
end
end
//乘加器例化
xbip_multadd_0 your_instance_name (
.CLK (clk_i ) ,// input wire CLK
.CE (1'b1 ) ,// input wire CE
.SCLR (1'b0 ) ,// input wire SCLR
.A (A ) ,// input wire [23 : 0] A
.B (B ) ,// input wire [7 : 0] B
.C (C ) ,// input wire [23 : 0] C
.SUBTRACT (1'b0 ) ,// input wire SUBTRACT
.P (P ) ,// output wire [47 : 0] P
.PCOUT (PCOUT ) // output wire [47 : 0] PCOUT
);
endmodule
2. 功能仿真结果:
(1)4倍滑动滤波
(2)8倍滑动滤波
(3)16倍滑动滤波
3. 将该滑动滤波模块应用于AD7734数据采集,AD7734采集到的数据进行滑动平均滤波,测试该算法与理论分析是否一致
(1)64倍滑动滤波效果
在线抓取信号
将串口接收到的数据利用matlab画图得
(2)16倍滑动滤波效果
在线抓取信号
将串口接收到的数据利用matlab画图得
(3)8倍滑动滤波效果
在线抓取信号
将串口接收到的数据利用matlab画图得
通过以上的实验可以看出,虽然滑动平均滤波的算法十分简单,但是以上的实验可以充分的理解了该算法的内涵与实现。滑动滤波倍数设置的越小,滤波效果越不好,但反应信号变化的实时性却很好;滑动滤波倍数设置的越大,滤波效果越很好,但反应信号变化的实时性变差。因此在实际应用中,如要用到该算法,需要权衡滤波效果和信号实时性这两个对立的性能,从而选择最优的滑动滤波倍数。