全串行、并行FIR滤波器

全串行、并行FIR滤波器

  FIR 滤波器,只要系数是对称的,就能实现线性相位。
  当FIR滤波器单位冲激响应 h(n) 满足对称条件时,FIR滤波器才具有线性相位特性。

  其对称条件可分为偶对称和奇对称:
    h(n) = h(M-n), 0 <= n <= M, 偶对称
    h(n) = -h(M-n), 0 <= n <= M, 奇对称

  一个系统的群延迟定义为相位对角频率的导数的负值:
    τ(ω)=grd[H(e^iω )]=-d/dω{arg⁡[H(e^iω )]}

  群延迟是系统平均延迟的一个度量,当要求滤波器具有线性相位响应特性时,通带内群延迟特性就应当是常数。延迟偏离一个常数的偏差表示相位的非线性程度。

  偶对称时,φ(ω)=-(M/2) ω ,群延迟为 M/2,即单位冲激响应长度的一半。
  奇对称时,φ(ω)=-(M/2) ω+π/2 ,群延迟为 M/2,即单位冲激响应长度的一半,但是还会产生一个90°相移的变换称为信号的正交变换,这种网络称为正交变换网络。

  n = 0 ~ M, M为偶整数还是奇整数在这里插入图片描述
  使用窗函数法设计时,群延迟为 (N-1)/2,N为FIR滤波器系数个数。

  n阶,对应冲激响应系数有 n+1个。


全串行FIR实现

在这里插入图片描述

`timescale 1ns / 1ps
//
// Create Date: 2021/03/13 17:28:28
// Design Name: FIR滤波器全串行结构实现仿真
// Module Name: FIR_FULL_SERIAL
//

module tb_lowpass();
reg clk;
reg clk_data;
reg rst;

   parameter PERIOD = 62500;

   always begin
      clk = 1'b1;
      #(PERIOD/2) clk = 1'b0;
      #(PERIOD/2);
   end
   parameter PERIOD1 = 500000;

   always begin
      clk_data = 1'b0;
      #(PERIOD1/2) clk_data = 1'b1;
      #(PERIOD1/2);
   end
   
parameter data_num = 2001;

//-----------------------------------//
reg signed [11:0] din_signal;
integer j;   //数组坐标
reg [11:0] signal[data_num-1:0];  //数组形式存储读出的数据
initial
begin
    rst = 1'b1;
    #500000;
    rst = 1'b0;
    $readmemb("D:/xilinx_project/serial_FIR/signal.txt", signal);  //将txt文件中的数据存储在数组中
    j = 0;
    repeat(data_num) begin   //重复读取数组中的数据
        @(posedge clk_data)     din_signal = signal[j];
        j = j + 1;
    end
end
//------------------------------------------//
wire [28:0] Yout;
FIR_FULL_SERIAL FIR_FULL_SERIAL(
        .clk(clk),
        .rst(rst),
        .Xin(din_signal),
        .Yout(Yout)
    );

endmodule
module FIR_FULL_SERIAL (
	rst,clk,Xin,
	Yout);
	
	input		rst;   //复位信号,高电平有效
	input		clk;   //FPGA系统时钟,频率为16kHz
	input	 signed [11:0]	Xin;  //数据输入频率为2khZ
	output   signed [28:0]	Yout; //滤波后的输出数据
	
//3位计数器,计数周期为8,为输入数据速率
reg [2:0] count = 0;
always @(posedge clk or posedge rst)
if (rst)
    count <= 3'd0;
else
    count <= count + 1;

//将数据存入移位寄存器Xin_Reg中
reg [11:0] Xin_Reg[15:0];
reg [3:0] i,j; 
always @(posedge clk or posedge rst)
if (rst)
    //初始化寄存器值为0
    begin
        Xin_Reg[15] <= 'd0;
        for (i=0; i<15; i=i+1)
            Xin_Reg[i]=12'd0;
    end
else
    begin
        if (count==7)
            begin
                for (j=0; j<15; j=j+1)
                    Xin_Reg[j+1] <= Xin_Reg[j];
                Xin_Reg[0] <= Xin;
            end
    end

	//实例化有符号数乘法器IP核mult
   reg  signed [11:0] coe;   //滤波器为12比特量化数据
	wire signed [12:0] add_s; //输入为12比特量化数据,两个对称系数相加需要13比特存储
	wire signed [24:0] Mout;  
	mult	Umult (
		.CLK (clk),
		.A (coe),
		.B (add_s),
		.P (Mout));

	//实例化有符号数加法器IP核,对输入数据进行1位符号位扩展,输出结果为13比特数据
	reg signed [12:0] add_a;
	reg signed [12:0] add_b;
	c_addsub_0 Uadder (
	    .CLK(clk),
		.A (add_a),
		.B (add_b),
		.S (add_s));

	//将对称系数的输入数据相加,同时将对应的滤波器系数送入乘法器
	//需要注意的是,下面程序只使用了一个加法器及一个乘法器资源
	//以8倍数据速率调用乘法器IP核,由于滤波器长度为16,系数具有对称性,故可在一个数据
	//周期内完成所有8个滤波器系数与数据的乘法运算
	//为了保证加法运算不溢出,输入输出数据均扩展为13比特。
	
	//------------  注意:  ---------------//
	//滤波器系数为 c0-c7循环往后移动一个周期
	//------------  注意:  ---------------//
	
	always @(posedge clk or posedge rst)
		if (rst)
			begin
				add_a <= 'd0;
				add_b <= 'd0;
				coe <= 'd0;
			end
		else
			begin
				if (count == 'd0)
					begin
						add_a <= {Xin_Reg[0][11],Xin_Reg[0]};
						add_b <= {Xin_Reg[15][11],Xin_Reg[15]};
						coe <= 12'h7ff;//c7
					end
				else if (count=='d1)
					begin
						add_a <= {Xin_Reg[1][11],Xin_Reg[1]};
						add_b <= {Xin_Reg[14][11],Xin_Reg[14]};					
						coe <= 12'h000; //c0
					end
				else if (count=='d2)
					begin
						add_a <= {Xin_Reg[2][11],Xin_Reg[2]};
						add_b <= {Xin_Reg[13][11],Xin_Reg[13]};						
						coe <= 12'hffd; //c1
					end
				else if (count=='d3)
					begin
						add_a <= {Xin_Reg[3][11],Xin_Reg[3]};
						add_b <= {Xin_Reg[12][11],Xin_Reg[12]};
						coe <= 12'h00f; //c2
					end
				else if (count=='d4)
					begin
						add_a <= {Xin_Reg[4][11],Xin_Reg[4]};
						add_b <= {Xin_Reg[11][11],Xin_Reg[11]};						
						coe <= 12'h02e; //c3
					end
				else if (count=='d5)
					begin
						add_a <= {Xin_Reg[5][11],Xin_Reg[5]};
						add_b <= {Xin_Reg[10][11],Xin_Reg[10]};				
						coe <= 12'hf8b; //c4
					end
				else if (count=='d6)
					begin
						add_a <= {Xin_Reg[6][11],Xin_Reg[6]};
						add_b <= {Xin_Reg[9][11],Xin_Reg[9]};						
						coe <= 12'hef9; //c5
					end
				else
					begin
						add_a <= {Xin_Reg[7][11],Xin_Reg[7]};
						add_b <= {Xin_Reg[8][11],Xin_Reg[8]};						
						coe <= 12'h24e; //c6
					end
			end

	//对滤波器系数与输入数据的乘法结果进行累加,并输出滤波后的数据
	//考虑到乘法器及累加器的延时,需要计数器为2时对累加器清零,同时输出滤波器结果数据。
	//类似的时延长度一方面可通过精确计算获取,但更好的方法是通过行为仿真查看
	reg signed [28:0] sum;
	reg signed [28:0] yout;
	always @(posedge clk or posedge rst)
		if (rst)
			begin 
				sum <= 'd0; 
				yout <= 'd0;
			end
		else
			begin
				if (count == 'd3)   begin
						yout <= sum;  sum <= Mout;
					end
				else
				   sum <= sum + Mout;
			end
	
	assign Yout = yout;
			
endmodule

按照书中代码参考,count == 'd3系数加载 两处加以修改后波形正确。

在这里插入图片描述


并行FIR实现

在这里插入图片描述

注意并行结构时,时钟就是采样率。

module FirParallel (
	rst,clk,Xin,
	Yout);
	
	input		rst;   //复位信号,高电平有效
	input		clk;   //FPGA系统时钟,频率为2kHz
	input	 signed [11:0]	Xin;  //数据输入频率为2khZ
	output   signed [28:0]	Yout; //滤波后的输出数据

	//将数据存入移位寄存器Xin_Reg中
	reg signed[11:0] Xin_Reg[15:0];
	reg [3:0] i,j; 
	always @(posedge clk or posedge rst)
		if (rst)
			//初始化寄存器值为0
			begin
			    Xin_Reg[15]='d0;
				for (i=0; i<15; i=i+1)
					Xin_Reg[i]='d0;
			end
		else
			begin
			   //与串行结构不同,此处不需要判断计数器状态
				for (j=0; j<15; j=j+1)
					Xin_Reg[j+1] <= Xin_Reg[j];
				    Xin_Reg[0] <= Xin;
			end
			
	//将对称系数的输入数据相加,同时将对应的滤波器系数送入乘法器
	//为了进一步提高运行速度,另外增加了一级寄存器
	reg signed [12:0] Add_Reg[7:0];
	always @(posedge clk or posedge rst)
		if (rst)
			//初始化寄存器值为0
			begin 
				for (i=0; i<8; i=i+1)
					Add_Reg[i]=13'd0;
			end
		else
			begin
				for (i=0; i<8; i=i+1)
					Add_Reg[i]={Xin_Reg[i][11],Xin_Reg[i]} + {Xin_Reg[15-i][11],Xin_Reg[15-i]};
			end

	//与串行结构不同,另外需要实例化8个乘法器IP核
	//实例化有符号数乘法器IP核mult
   wire signed [11:0] coe[7:0] ;   //滤波器为12比特量化数据
	wire signed [24:0] Mout[7:0];   //乘法器输出为25比特数据
	assign coe[0]=12'h000;
	assign coe[1]=12'hffd;
	assign coe[2]=12'h00f; 
	assign coe[3]=12'h02e;	
	assign coe[4]=12'hf8b;
	assign coe[5]=12'hef9; 	
	assign coe[6]=12'h24e;
	assign coe[7]=12'h7ff; 
	mult	Umult0 (
		.CLK (clk),
		.A (coe[0]),
		.B (Add_Reg[0]),
		.P (Mout[0]));
	mult	Umult1 (
		.CLK (clk),
		.A (coe[1]),
		.B (Add_Reg[1]),
		.P (Mout[1]));
	mult	Umult2 (
		.CLK (clk),
		.A (coe[2]),
		.B (Add_Reg[2]),
		.P (Mout[2]));		
	mult	Umult3 (
		.CLK (clk),
		.A (coe[3]),
		.B (Add_Reg[3]),
		.P (Mout[3]));		
	mult	Umult4 (
		.CLK (clk),
		.A (coe[4]),
		.B (Add_Reg[4]),
		.P (Mout[4]));		
	mult	Umult5 (
		.CLK (clk),
		.A (coe[5]),
		.B (Add_Reg[5]),
		.P (Mout[5]));		
	mult	Umult6 (
		.CLK (clk),
		.A (coe[6]),
		.B (Add_Reg[6]),
		.P (Mout[6]));				
	mult	Umult7 (
		.CLK (clk),
		.A (coe[7]),
		.B (Add_Reg[7]),
		.P (Mout[7]));
		
	//对滤波器系数与输入数据的乘法结果进行累加,并输出滤波后的数据
	//与串行结构不同,此处在一个时钟周期内直接将所有乘法器结果相加
	reg signed [28:0] sum;
	reg signed [28:0] yout;
	reg [3:0] k;
	always @(posedge clk or posedge rst)
		if (rst)
			begin
				sum <= 29'd0;
				yout <= 29'd0;
			end
		else
			begin
			   yout <= sum;
				sum <= Mout[0] + Mout[1] + Mout[2] + Mout[3] + Mout[4] + Mout[5] + Mout[6] + Mout[7];
			end
	assign Yout = yout;

endmodule

在这里插入图片描述

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值