目录
Written by @hzj
//JinXing Project
#2021.11.28 V1.0
基于切比雪夫滤波器&IIR高通滤波器的FPGA实现
之前实现过了IIR滤波器,但是发现有部分的地方的实现不好,有点小毛刺,因此重新设计一个IIR滤波器,一是对过去的滤波器的流程的回顾,另外一个是为了探讨新的设计方案,让整个滤波器的设计更为简单。
1、切比雪夫滤波器的设计参数
还是像以前博文所讲述的那样,设计一个滤波器,参数如下所示:
采
样
频
率
:
f
s
a
m
p
l
e
=
5000
H
z
采样频率:f_{sample} = 5000Hz
采样频率:fsample=5000Hz
截
止
频
率
:
f
s
t
o
p
=
1000
H
z
截止频率:f_{stop} = 1000Hz
截止频率:fstop=1000Hz
衰
减
:
f
f
a
l
l
i
n
g
=
60
d
B
衰减:f_{falling} = 60dB
衰减:ffalling=60dB
滤
波
器
的
阶
数
:
n
u
m
f
i
l
t
e
r
=
7
滤波器的阶数:num_{filter}=7
滤波器的阶数:numfilter=7
通过
c
h
e
b
y
2
cheby2
cheby2参数进行实现,输入参数使用切比雪夫滤波器实现,对应构建的matlab代码如下所示:
clear ;
clc;
f_sample = 5000;%采样频率
f_stop = 1000;%截止频率
f_falling = 60;%db衰减
num_filter = 7;%设置滤波器阶数
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%量化处理模块
[Num, Den] = cheby2(7, f_falling, f_stop*2/f_sample, "low");
max_den_num = max(max(abs(Num), abs(Den)));
mid_compute = log2(max_den_num/Den(1));
Number = floor(mid_compute);
if Number < log2(max_den_num/Den(1))
Number = Number + 1;
end
Number = 2^Number;
Q_den = round(Den/Number * (2^15-1));
Q_num = round(Num/Number * (2^15-1));
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fprintf("Num = \n")
for i = 1:1:(num_filter+1)
fprintf("\t %f",Num(i));
end
fprintf("\n");
fprintf("Den = \n")
for i = 1:1:(num_filter+1)
fprintf("\t %f",Den(i));
end
fprintf("\n");
fprintf("Q_num = \n")
for i = 1:1:(num_filter+1)
fprintf("\t %f",Q_num(i));
end
fprintf("\n");
fprintf("Q_den = \n")
for i = 1:1:(num_filter+1)
fprintf("\t %f",Q_den(i));
end
fprintf("\n");
命令行中的得到的结果如下所示:
Num =
0.007046 0.008669 0.018551 0.020733 0.020733 0.018551 0.008669 0.007046
Den =
1.000000 -3.027243 4.574142 -4.104494 2.348938 -0.839118 0.173509 -0.015738
Q_num =
29.000000 36.000000 76.000000 85.000000 85.000000 76.000000 36.000000 29.000000
Q_den =
4096.000000 -12399.000000 18735.000000 -16811.000000 9621.000000 -3437.000000 711.000000 -64.000000
>>
2、根据IIR滤波器的系统函数,滤波器的差分方程表示
由于有如下的系数:
Q_num =
29 36 76 85 85 76 36 29
Q_den =
4096 -12399 18735 -16811 9621 -3437 711 -64
>>
对应的差分方程展示如下所示:
4096
y
(
n
)
=
29
∗
[
x
(
n
)
+
x
(
n
−
7
)
]
+
36
∗
[
x
(
n
−
1
)
+
x
(
n
−
6
)
]
+
76
∗
[
x
(
n
−
2
)
+
x
(
n
−
5
)
]
+
85
∗
[
x
(
n
−
3
)
+
x
(
n
−
4
)
]
−
[
−
12399
∗
y
(
n
−
1
)
+
18735
∗
y
(
n
−
2
)
−
16811
∗
y
(
n
−
3
)
+
9621
∗
y
(
n
−
4
)
−
3437
∗
y
(
n
−
5
)
+
711
∗
y
(
n
−
6
)
−
64
∗
y
(
n
−
7
)
]
4096y(n)=29*[x(n)+x(n-7)]+36*[x(n-1)+x(n-6)]+76*[x(n-2)+x(n-5)]+85*[x(n-3)+x(n-4)] - [-12399*y(n-1)+18735*y(n-2)-16811*y(n-3)+9621*y(n-4)-3437*y(n-5)+711*y(n-6)-64*y(n-7)]
4096y(n)=29∗[x(n)+x(n−7)]+36∗[x(n−1)+x(n−6)]+76∗[x(n−2)+x(n−5)]+85∗[x(n−3)+x(n−4)]−[−12399∗y(n−1)+18735∗y(n−2)−16811∗y(n−3)+9621∗y(n−4)−3437∗y(n−5)+711∗y(n−6)−64∗y(n−7)]
因此FPGA对应的实现方式是,先将式子分为一个零点一个极点模块进行实现,然后进行一次运算之后,进行相减,再除以4096,这个地方故意设置成为是2的阶数,为的是将除法的操作变得更加简单,直接通过移位的操作,就可以实现除法,这样能够减少FPGA内部的器件的使用。这个观念对于以后的滤波器的设置,也相当重要。
3、根据这个系统函数的系数,编写对应的滤波器的Verilog代码
顶层模块,包括一个零点模块的调用,一个极点模块的调用,一个零点模块以及极点模块的相差,最终输出的的差值sub进行一个除法,除法的大小已经由前期的设计所决定,大小为4096, 由于输出的值的大小与输入值的位数大小应该是相同的,所以这个地方进行除法之后,输出的数据位数应该也是为16位,因此,最后一步进行一个截取。
`timescale 1ns/1ps
//-------------------------------------------------------
// IIR滤波器顶层模块
//-------------------------------------------------------
module IIR_top(
input clk ,
input rst_n ,
input signed [15:0] IIR_input ,
output reg signed [15:0] IIR_output
);
parameter U_DLY = 1;//时序仿真信号,加上U_DLY模拟信号的电路中传输的延迟
//-------------------------------------------------------
// 调用零点模块
//-------------------------------------------------------
wire signed [25:0] zero_out ;
wire signed [15:0] pole_in ;
wire signed [32:0] feedback ;
wire signed [17:0] pole_div ;
//-------------------------------------------------------
// 根据时钟信号,来控制波形的输入值wave_in;
//-------------------------------------------------------
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)begin
IIR_output <= #U_DLY 12'b0; //复位信号,下降沿有效
end
else begin
IIR_output <= #U_DLY pole_in; //正常周期信号clk状态下依次进行输入波形数据
end
zero_module zero
(
.rst_n (rst_n) ,
.clk (clk) ,
.zero_input (IIR_input) ,
.zero_output(zero_out)
);
//-------------------------------------------------------
// 调用极点模块
//-------------------------------------------------------
pole_module pole
(
.clk (clk) ,
.rst_n (rst_n) ,
.pole_input (pole_in) ,
.pole_output(feedback)
);
//-------------------------------------------------------
// 顶层模块进行求差值以及乘积的工作,构成IIR模块
//-------------------------------------------------------
wire signed [32:0] sub_module;
assign sub_module = {{{7{zero_out[25]}}, zero_out} - feedback};//零点的输出与极点的输出进行相减,21位
assign pole_div = {sub_module[32:12]} ;//求出的差值进行移位除法
assign pole_in = pole_div[15:0];
endmodule
零点模块,这个模块相当于一个FIR滤波器,并通过其对称性,可以进行加法寄存器进行对称相加,然后分别乘以29、36、76、85。
`timescale 1ns/1ps
//-------------------------------------------------------
// IIR滤波器零点系数模块
//-------------------------------------------------------
//-------------------------------------------------------
// 引脚模块定义
//-------------------------------------------------------
module zero_module(
input clk , //时钟信号clk
input rst_n , //定义一个复位信号,复位信号按照下降沿有效
input signed [15:0] zero_input , //零点模块的输入
output signed [25:0] zero_output //零点模块的输出
);
parameter U_DLY = 1;//时序仿真信号,加上U_DLY模拟信号的电路中传输的延迟
//-------------------------------------------------------
// IIR滤波器中进行移位的部分,按照clk时钟周期,依次输入波
// IIR形数据,同时也应该在rst_n为1'b0的时候进行置零
//-------------------------------------------------------
reg signed [15:0] data_reg [6:0];
always@(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin //复位信号,系统进行置零操作,复位信号低电平有效
data_reg[0] <= #U_DLY 12'b0 ;
data_reg[1] <= #U_DLY 12'b0 ;
data_reg[2] <= #U_DLY 12'b0 ;
data_reg[3] <= #U_DLY 12'b0 ;
data_reg[4] <= #U_DLY 12'b0 ;
data_reg[5] <= #U_DLY 12'b0 ;
data_reg[6] <= #U_DLY 12'b0 ;
end
else
begin //普通时钟周期信号,依次进行移位操作,将新的数据进行送入
data_reg[6] <= #U_DLY data_reg[5] ;
data_reg[5] <= #U_DLY data_reg[4] ;
data_reg[4] <= #U_DLY data_reg[3] ;
data_reg[3] <= #U_DLY data_reg[2] ;
data_reg[2] <= #U_DLY data_reg[1] ;
data_reg[1] <= #U_DLY data_reg[0] ;
data_reg[0] <= #U_DLY zero_input ;
end
end
//-------------------------------------------------------
// IIR滤波器的零点由于系数都是对称的,因此可以通过这样子减
// 少器件,先进行加法运算
//-------------------------------------------------------
wire signed [16:0] add_reg [3:0];
assign add_reg[0] = {zero_input[15], zero_input} + {data_reg[6][15], data_reg[6]} ;
assign add_reg[1] = {data_reg[0][15], data_reg[0]} + {data_reg[5][15], data_reg[5]} ;
assign add_reg[2] = {data_reg[1][15], data_reg[1]} + {data_reg[4][15], data_reg[4]} ;
assign add_reg[3] = {data_reg[2][15], data_reg[2]} + {data_reg[3][15], data_reg[3]} ;
//-------------------------------------------------------
// IIR滤波器使用已经加好的数进行卷积
//-------------------------------------------------------
wire signed [24:0] mult_reg [3:0];
assign mult_reg[0] = { {{8{add_reg[0][16]}}, add_reg[0]}
+ {{6{add_reg[0][16]}}, add_reg[0], 2'b0}
+ {{5{add_reg[0][16]}}, add_reg[0], 3'b0}
+ {{4{add_reg[0][16]}}, add_reg[0], 4'b0}} ;//*29_1 1101
assign mult_reg[1] = { {{6{add_reg[1][16]}}, add_reg[1], 2'b0}
+ {{3{add_reg[1][16]}}, add_reg[1], 5'b0}} ;//*36_10 0100
assign mult_reg[2] = { {{6{add_reg[2][16]}}, add_reg[2], 2'b0}
+ {{5{add_reg[2][16]}}, add_reg[2], 3'b0}
+ {{2{add_reg[2][16]}}, add_reg[2], 6'b0}} ;//*76_100 1100
assign mult_reg[3] = { {{8{add_reg[3][16]}}, add_reg[3]}
+ {{6{add_reg[3][16]}}, add_reg[3], 2'b0}
+ {{4{add_reg[3][16]}}, add_reg[3], 4'b0}
+ {{2{add_reg[3][16]}}, add_reg[3], 6'b0}} ;//*85_101 0101
//-------------------------------------------------------
// 卷积运算之后进行求和输出
//-------------------------------------------------------
assign zero_output = {mult_reg[0][24], mult_reg[0]}
+ {mult_reg[1][24], mult_reg[1]}
+ {mult_reg[2][24], mult_reg[2]}
+ {mult_reg[3][24], mult_reg[3]};
endmodule
极点模块,极点模块的输入是整个模型的输出作为其输入,依次乘以-12399、18735、-16811、9621、-3437、711、-64。
`timescale 1ns/1ps
//-------------------------------------------------------
// IIR滤波器极点系数模块
//-------------------------------------------------------
module pole_module(
input clk ,//时钟信号
input rst_n ,//复位信号,使能高电平有效
input signed [15:0] pole_input ,//输入信号
output signed [32:0] pole_output //输出信号
);
parameter U_DLY = 1;//时序仿真信号,加上U_DLY模拟信号的电路中传输的延迟
//-------------------------------------------------------
// 还是pole模块由于是N-1位,因此这个地方我们只需要8-1个寄存器进行存储
// 因此该处定义的是7位的reg信号,信号的带宽与输入的带宽相同,也就是即
// 16位。复位信号清零;clk信号进行移位;
//-------------------------------------------------------
reg signed [15:0] data_reg [6:0];
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0) begin //复位信号,系统进行置零操作,复位信号低电平有效
data_reg[0] <= #U_DLY 12'd0 ;
data_reg[1] <= #U_DLY 12'd0 ;
data_reg[2] <= #U_DLY 12'd0 ;
data_reg[3] <= #U_DLY 12'd0 ;
data_reg[4] <= #U_DLY 12'd0 ;
data_reg[5] <= #U_DLY 12'd0 ;
data_reg[6] <= #U_DLY 12'd0 ;
end
else begin //普通时钟周期信号,依次进行移位操作,将新的数据进行送入
data_reg[6] <= #U_DLY data_reg[5] ;
data_reg[5] <= #U_DLY data_reg[4] ;
data_reg[4] <= #U_DLY data_reg[3] ;
data_reg[3] <= #U_DLY data_reg[2] ;
data_reg[2] <= #U_DLY data_reg[1] ;
data_reg[1] <= #U_DLY data_reg[0] ;
data_reg[0] <= #U_DLY pole_input ;
end
//-------------------------------------------------------
// 滤波器的系数,量化之后,量化2^6
// 使用组合逻辑进行乘法的操作。
//-------------------------------------------------------
wire [31:0] mult_pole [6:0];
wire [31:0] reg_1;
wire [31:0] reg_2;
wire [31:0] reg_3;
wire [31:0] reg_4;
assign reg_1 = {{{16{data_reg[0][15]}}, data_reg[0]}
+ {{15{data_reg[0][15]}}, data_reg[0], 1'b0}
+ {{14{data_reg[0][15]}}, data_reg[0], 2'b0}
+ {{13{data_reg[0][15]}}, data_reg[0], 3'b0}
+ {{11{data_reg[0][15]}}, data_reg[0], 5'b0}
+ {{10{data_reg[0][15]}}, data_reg[0], 6'b0}
+ {{ 4{data_reg[0][15]}}, data_reg[0], 12'b0}
+ {{ 3{data_reg[0][15]}}, data_reg[0], 13'b0}};//*-12399_11 0000 0110 1111
assign mult_pole[0] = ~reg_1 + 1'b1;
assign mult_pole[1] = {{{16{data_reg[1][15]}}, data_reg[1]}
+ {{15{data_reg[1][15]}}, data_reg[1], 1'b0}
+ {{14{data_reg[1][15]}}, data_reg[1], 2'b0}
+ {{13{data_reg[1][15]}}, data_reg[1], 3'b0}
+ {{11{data_reg[1][15]}}, data_reg[1], 5'b0}
+ {{ 8{data_reg[1][15]}}, data_reg[1], 8'b0}
+ {{ 5{data_reg[1][15]}}, data_reg[1], 11'b0}
+ {{ 2{data_reg[1][15]}}, data_reg[1], 14'b0}};//*18735_100 1001 0010 1111
assign reg_2 = {{{16{data_reg[2][15]}}, data_reg[2]}
+ {{15{data_reg[2][15]}}, data_reg[2], 1'b0}
+ {{13{data_reg[2][15]}}, data_reg[2], 3'b0}
+ {{11{data_reg[2][15]}}, data_reg[2], 5'b0}
+ {{ 9{data_reg[2][15]}}, data_reg[2], 7'b0}
+ {{ 8{data_reg[2][15]}}, data_reg[2], 8'b0}
+ {{ 2{data_reg[2][15]}}, data_reg[2], 14'b0}};//*-16811_100 0001 1010 1011
assign mult_pole[2] = ~reg_2 + 1'b1;
assign mult_pole[3] = {{{16{data_reg[3][15]}}, data_reg[3]}
+ {{14{data_reg[3][15]}}, data_reg[3], 2'b0}
+ {{12{data_reg[3][15]}}, data_reg[3], 4'b0}
+ {{ 9{data_reg[3][15]}}, data_reg[3], 7'b0}
+ {{ 8{data_reg[3][15]}}, data_reg[3], 8'b0}
+ {{ 6{data_reg[3][15]}}, data_reg[3], 10'b0}
+ {{ 3{data_reg[3][15]}}, data_reg[3], 13'b0}};//*9621_10 0101 1001 0101
assign reg_3 = {{{16{data_reg[4][15]}}, data_reg[4]}
+ {{14{data_reg[4][15]}}, data_reg[4], 2'b0}
+ {{13{data_reg[4][15]}}, data_reg[4], 3'b0}
+ {{11{data_reg[4][15]}}, data_reg[4], 5'b0}
+ {{10{data_reg[4][15]}}, data_reg[4], 6'b0}
+ {{ 8{data_reg[4][15]}}, data_reg[4], 8'b0}
+ {{ 6{data_reg[4][15]}}, data_reg[4], 10'b0}
+ {{ 5{data_reg[4][15]}}, data_reg[4], 11'b0}};//*-3437_1101 0110 1101
assign mult_pole[4] = ~reg_3 + 1'b1;
assign mult_pole[5] = {{{16{data_reg[5][15]}}, data_reg[5]}
+ {{15{data_reg[5][15]}}, data_reg[5], 1'b0}
+ {{14{data_reg[5][15]}}, data_reg[5], 2'b0}
+ {{10{data_reg[5][15]}}, data_reg[5], 6'b0}
+ {{ 9{data_reg[5][15]}}, data_reg[5], 7'b0}
+ {{ 7{data_reg[5][15]}}, data_reg[5], 9'b0}};//*711_10 1100 0111
assign reg_4 = {{{10{data_reg[6][15]}}, data_reg[6], 6'b0}};//*-64_100 0000
assign mult_pole[6] = ~reg_4 + 1'b1;
//-------------------------------------------------------
// 求卷积和;将前面所有的乘积进行求和,并且输出置Yout
// 将前面7个已经完成乘法的寄存器中的数据进行加法运算
//-------------------------------------------------------
assign pole_output = {mult_pole[0] +
mult_pole[1] +
mult_pole[2] +
mult_pole[3] +
mult_pole[4] +
mult_pole[5] +
mult_pole[6] };
endmodule
测试模块、tb文件代码如下:
//~ `New testbench
`timescale 1ns / 1ps
module tb_IIR_top;
// IIR_top Parameters
parameter PERIOD = 10;
// IIR_top Inputs
reg clk ;
reg rst_n ;
reg [15:0] wave_in ;
// IIR_top Outputs
wire [15:0] wave_out ;
integer i ;
initial begin
clk = 0 ;
rst_n = 0 ;
wave_in = 12'd0 ;
i = 0 ;
end
initial
begin
forever #(PERIOD/2) clk=~clk;
end
initial
begin
#(PERIOD*2) rst_n = 1;
end
parameter DATA_NUM = 32'd1000000;
reg [15:0] data_men[DATA_NUM:1];
initial begin
$readmemb("C:/Users/64441/Desktop/Verilog_IIR_Butterworth/tb/sin.txt",data_men); //注意斜杠的方向,不能反<<<<<<<
end
always @(posedge clk or negedge rst_n) begin //每1个clk_sig信号来临后,进行一次数据输入,将新的一个波形数据输入Din中。
wave_in <= data_men[i];
i <= i+1;
end
IIR_top u_IIR_top (
.clk ( clk ),
.rst_n ( rst_n ),
.IIR_input ( wave_in [15:0] ),
.IIR_output ( wave_out [15:0] )
);
integer w_file;
initial w_file = $fopen("C:/Users/64441/Desktop/Verilog_IIR_Butterworth/tb/simulation_after_IIR.txt");
always @(i)
begin
$fdisplay(w_file,"%b",wave_out);
end
endmodule
为了验证此滤波器的功能,因此需要仿真一个源波形信号,源波形信号是由一个波形频率大小为500Hz以及一个2000Hz的波形进行合成,采样的频率大小为5000Hz。输出的位数大小为16位的数据。
f1 = 500;
f2 = 2000;
Fs = 5000;
N = 16;
End = 200;
t = 0:1/Fs:End-1/Fs;
c1 = 2*pi*f1*t;
c2 = 2*pi*f2*t;
s1 = sin(c1);
s2 = 0.5*sin(c2);
s = s1+s2;
s = s/max(abs(s));
Q_s = round(s*(2^(N-1) - 1));
fid = fopen('..\tb\sin_ten.txt','w');
fprintf(fid, '%12d\r\n',Q_s);
fprintf(fid, ';');
fclose(fid);
fid = fopen('..\tb\sin.txt','w');
for k=1:length(Q_s)%二进制变换
B_s=dec2bin(Q_s(k)+((Q_s(k))<0)*2^N,N);
for j=1:N
if B_s(j)=='1'
tb=1;
else
tb=0;
end
fprintf(fid,'%d',tb);
end
fprintf(fid,'\r\n');
end
fprintf(fid,';');
fclose(fid);
fid = fopen('..\tb\sin.txt','w');
for k=1:length(Q_s)%二进制变换
B_s=dec2bin(Q_s(k)+((Q_s(k))<0)*2^N,N);
for j=1:N
if B_s(j)=='1'
tb=1;
else
tb=0;
end
fprintf(fid,'%d',tb);
end
fprintf(fid,'\r\n');
end
fprintf(fid,';');
fclose(fid);
采用上述的代码进行仿真,输入模拟输入的波形,仿真之后的结果如下所示:
从上述的图像可以看出,wave_in代表的是输入波形的信号,wave_out代表的是输出波形的信号。可以看出,整个滤波的效果还是很明显的,当时这个不能验证我们的滤波功能,需要和实际的matalb仿真数据进行compare比对。因此,对应编写的IIR切比雪夫实现方式代码如下所示:
%将二进制转化为十进制的数据,所有的数据都是从sin.txt原始文件中导出
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
str_in = importdata('..\tb\sin.txt');
str_length = length(str_in);
str_out = zeros(str_length, 1);
MAX_DATA = 2^15-1;
for number = 1 : str_length
str_out(number) = bin2dec( num2str(str_in(number)) );
if(str_out(number) > MAX_DATA)
str_out(number) = bin2dec( num2str(str_in(number)) ) - 2^16;
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%设置IIR滤波器的卷积系数(一般设置的大小为8位)
zero_1 = 29;
zero_2 = 36;
zero_3 = 76;
zero_4 = 85;
pole_1 = -12399;
pole_2 = 18735;
pole_3 = -16811;
pole_4 = 9621;
pole_5 = -3437;
pole_6 = 711;
pole_7 = -64;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
x_in= str_out;
pole_out = 0;
%定义每一个变量的初值,按照电路中复位的原则,所有的卷积器中的变量,都给予初值
%初值的大小设置位为0
x_in_2 = 0;
x_in_3 = 0;
x_in_4 = 0;
x_in_5 = 0;
x_in_6 = 0;
x_in_7 = 0;
x_in_8 = 0;
div = 0;
x_in_7_pole = 0;
x_in_6_pole = 0;
x_in_5_pole = 0;
x_in_4_pole = 0;
x_in_3_pole = 0;
x_in_2_pole = 0;
x_in_1_pole = 0;
add_reg_1 = 0;
add_reg_2 = 0;
add_reg_3 = 0;
add_reg_4 = 0;
%定义一个矩阵数组,用来存放我们的输出值
output = zeros(1, str_length);
%定义一个二进制数组存储单元
binary_tem = zeros(1, 16);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for i=1:1:str_length
%进行第一次卷积操作,第一次卷积操作是进行零点运算
%卷积操作,将原来的寄存器中的数据进行卷积,卷积后的数据放入到y中。
add_reg_1 = x_in(i) + x_in_8;
add_reg_2 = x_in_2 + x_in_7;
add_reg_3 = x_in_3 + x_in_6;
add_reg_4 = x_in_4 + x_in_5;
% y = x_in(i) * zero_1 + x_in_2 * zero_2 + x_in_3 * zero_3 + x_in_4 * zero_4 + x_in_5 * zero_4 + x_in_6 * zero_3 + x_in_7 * zero_2 + x_in_8 * zero_1;
y = add_reg_1 * zero_1 + add_reg_2 * zero_2 + add_reg_3 * zero_3 + add_reg_4 * zero_4;
%依次进行数据的搬移工作
x_in_8 = x_in_7;
x_in_7 = x_in_6;
x_in_6 = x_in_5;
x_in_5 = x_in_4;
x_in_4 = x_in_3;
x_in_3 = x_in_2;
x_in_2 = x_in(i);
%依次进行数据的搬移工作
x_in_7_pole = x_in_6_pole;
x_in_6_pole = x_in_5_pole;
x_in_5_pole = x_in_4_pole;
x_in_4_pole = x_in_3_pole;
x_in_3_pole = x_in_2_pole;
x_in_2_pole = x_in_1_pole;
x_in_1_pole = div;
%进行第二次卷积操作,第二次卷积操作是进行极点运算
%卷积操作,将卷积后的值运算得出,放在pole中
pole = x_in_1_pole * pole_1 + x_in_2_pole * pole_2 + x_in_3_pole * pole_3 + x_in_4_pole * pole_4 + x_in_5_pole * pole_5 + x_in_6_pole * pole_6 + x_in_7_pole * pole_7;
%pole = x_in_1_pole * div + x_in_2_pole * pole_1 + x_in_3_pole * pole_2 + x_in_4_pole * pole_3 + x_in_5_pole * pole_4 + x_in_6_pole * pole_5 + x_in_7_pole * pole_6;
%进行数据的相减,相当于零点的运算值与极点的运算值进行相差
sub = y - pole;
%相当于数据的截位运算,由于需要进行截位除法,因此,模拟一次数据的截位操作,原来的21位的数据,最终只需要得到12位的值
%因此,只需要读取前十二位的数据,便相当于对后9位的数据进行一个截取
B_s=dec2bin(sub+(sub<0)*2^33,33);
for j=1:21
if B_s(j)=='1'
binary_tem(1, j) = 1;
else
binary_tem(1, j) = 0;
end
end
if(binary_tem(1, 6) == 0)
div = binary_tem(1, 6) * 32768 + binary_tem(1, 7) * 16384 + binary_tem(1, 8) * 8192 + binary_tem(1, 9) * 4096 + binary_tem(1, 10) * 2048 + binary_tem(1, 11) * 1024 + binary_tem(1, 12) * 512 + binary_tem(1, 13) * 256 + binary_tem(1, 14) * 128 + binary_tem(1, 15) * 64 + binary_tem(1, 16) * 32 + binary_tem(1, 17) * 16 + binary_tem(1, 18) * 8 + binary_tem(1, 19) * 4 + binary_tem(1, 20) * 2 + binary_tem(1, 21) * 1;
else
div = ~(binary_tem(1, 6)) * 32768 + ~(binary_tem(1, 7)) * 16384 + ~(binary_tem(1, 8)) * 8192 + ~(binary_tem(1, 9)) * 4096 + ~(binary_tem(1, 10)) * 2048 + ~(binary_tem(1, 11)) * 1024 + ~(binary_tem(1, 12)) * 512 + ~(binary_tem(1, 13)) * 256 + ~(binary_tem(1, 14)) * 128 + ~(binary_tem(1, 15)) * 64 + ~(binary_tem(1, 16)) * 32 + ~(binary_tem(1, 17)) * 16 + ~(binary_tem(1, 18)) * 8 + ~(binary_tem(1, 19)) * 4 + ~(binary_tem(1, 20)) * 2 + ~(binary_tem(1, 21)) * 1;
div = div + 1;
div = -div;
end
%获得div截位之后的值,得到的结果放入输出矩阵output(1, i)中去
output(1, i) = div;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%波形数据的数据的写入,将截位之后的数据,也就是即输出的滤波波形数据进行输出
fid = fopen('..\tb\simulation_MATLAB_IIR.txt','w');
for k=1:length(output)
B_s=dec2bin(output(k)+((output(k))<0)*2^16,16);
for j=1:16
if B_s(j)=='1'
tb=1;
else
tb=0;
end
fprintf(fid,'%d',tb);
end
fprintf(fid,'\r\n');
end
fprintf(fid,';');
fclose(fid);
将两者输出的值进行比对,使用的Beyond Compare工具,两者的比对之后的结果如下所示:
可以看出,中间的100W的数据相同,因此数据是一样的,可以认为,这里已经实现了整个滤波的操作。
*tips:这个地方的MATLAB仿真看似不重要,其实是很重要的。因为这个仿真比对,可以发现很多问题,然后通过这个地方出现的问题,重新在波形里面进行逻辑推导,从而找出代码上的错误。本文在进行书写代码的过程中,其实也遇到了很多问题,比如乘法运算的时候,zero模块的最高位为16,而非15,但是笔者在书写的时候写成了15,但是这个错误在直接看滤波后的效果时又是有滤波效果的,因此很难发现这个问题,而在后面的比对过程中,才逐渐从逻辑数据的推导中才发现了这个问题,改正后便比对正常。
总结一下这次重新实现的收获:
1、采用了不使用FDA模块来进行模拟仿真IIR滤波器的方法。
2、明白了pole极点模块输出前进行除法的原由,同时实现了一种不使用耗费资源贼大情况下的除法(也就是移位除法),直接使用位移的工作,就实现了整个除法工作。
3、进一步明确了定点定位的方法,也就是加法的时候拓展一位,另外乘法的话是拓展a+b位。
4、明确了matlab比对数据的重要性。