FPGA学习记录(12)<切比雪夫滤波器&IIR的FPGA实现>

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(n7)]+36[x(n1)+x(n6)]+76[x(n2)+x(n5)]+85[x(n3)+x(n4)][12399y(n1)+18735y(n2)16811y(n3)+9621y(n4)3437y(n5)+711y(n6)64y(n7)]
因此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比对数据的重要性。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于基于FPGA高通滤波器,可以使用FIR(Finite Impulse Response)IP核来实现。FIR滤波器是一种线性时不变滤波器,通过对输入信号的离散样本进行加权求和来实现滤波效果。在FPGA中,可以通过使用FIR IP核来快速实现高通滤波器。 FIR IP核通常提供了一些参数,例如滤波器的阶数、截止频率以及滤波器系数等。根据所需的滤波器规格,可以选择适当的参数值。一旦设置好参数,可以将FIR IP核实例化到FPGA设计中,并将输入信号和时钟连接到该IP核。 在FPGA中,FIR IP核通常采用流水线结构,以提高处理速度。输入信号经过滤波器系数的乘法和累加操作,得到输出信号。由于FPGA的并行计算能力,可以同时处理多个输入样本,从而实现高效的滤波操作。 使用FIR IP核进行高通滤波的具体步骤如下: 1. 根据滤波器要求设置FIR IP核的参数,包括阶数、截止频率等。 2. 实例化FIR IP核并将其连接到FPGA设计中。 3. 将输入信号和时钟连接到FIR IP核。 4. 根据需要,可以对输入信号进行预处理或后处理。 5. 在FPGA中生成时钟信号以驱动FIR IP核的工作。 6. 获取FIR IP核的输出信号,即滤波后的高通信号。 需要注意的是,具体的实现细节可能会根据所选用的FPGA和FIR IP核的供应商而有所不同。因此,在使用FIR IP核进行高通滤波之前,建议参考相关文档和资源,以确保正确配置和使用IP核。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值