【DA算法】基于DA算法的FIR滤波器的FPGA实现

1.软件版本

quartusii

2.本算法理论知识

      DA算法的主要特点是,巧妙地利用查找表将固定系数的MAC运算转化为查表操作,其运算速度不随系数和输入数据位数的增加而降低,而且相对直接实现乘法器而言,在硬件规模上得到了极大的改善。对于FIR(有限长单位冲激响应)滤波器,其基本结构是一个分节的延时线,每一节的输出加权累加,得到滤波器的输出。其输出y就是输入x和系数h的内积:

      

 将式(3)中的第二部分展开,重新分别求和,这也是“分布式算法”名称的由来,可以得到:

 这样就可以将式(3)化简为

 计算h[n]xb[n],就是用查找表实现一个映射,然后再将此映射经过相应的二次幂加权,最后即可得到滤波器的输出。

分布式FIR的实现结构

    图1给出了分布式FIR滤波器最直接的实现结构,虚线为流水线寄存器。对于小位宽的数据来讲,Da算法不仅速度快,而且所占用的芯片资源也很少。

 

对于式(4)括号中的每一个乘积项都代表了输入变量的某一位与常量的二进制“与”操作,加号代表了算术和操作,指数因子对括号中的值加权。如果事先构造一个查找表,该表储存了括号中所有可能的组合值,就可以通过所有输入变量相对应的组合向量(xb[N-1], xb[N-2], … ,xb[0])对该表进行寻址。该表结构如表1所示。

表1 构造规则

       在LUT实现分布式算法是,由于LUT的规模随着N的增加而呈指数增加,如果滤波器系数N过多,则查表的规模十分庞大。为了减小规模,可以利用部分表计算。由于FIR滤波器是线性滤波器,因此低阶滤波器输出可以相加,由此定义一个高阶滤波器的输出。例如,可以把16输入的查找表分割成4个并行的查找表,如图2所示。依次类推,可以将更大的LUT分割成多个小LUT。如果加上流水线,这一结构的改变并不会降低速度,却可以大大减小设计规模。

 下面开始在FPGA中进行设计与实现。

    考虑到,基于DA算的程序,其查找表的复杂度会随着输入的位宽和滤波器的阶数的增加而大大增加,这里,我们在满足设计指标的前提下,将滤波器的输入位宽改为12位,阶数为16阶。

3.核心代码

module firfilter_da(	CLK,
					Reset,
					DIN,
					Dout
					);
//-----------------------
//  port declaration
//-----------------------
	input	CLK;
	input	Reset;
	input [7:0]	DIN;
	output [15:0] Dout;

//输入信号寄存器	
	reg [7:0]		DIN_8b_0;
	reg [7:0]		DIN_8b_1;
	reg [7:0]		DIN_8b_2;
	reg [7:0]		DIN_8b_3;
	reg [7:0]		DIN_8b_4;
	reg	[7:0] 	DIN_8b_5;
	reg [7:0] 	DIN_8b_6;
	reg [7:0] 	DIN_8b_7;
	reg [7:0] 	DIN_8b_8;
	reg [7:0] 	DIN_8b_9;
	reg [7:0] 	DIN_8b_10;
	reg [7:0] 	DIN_8b_11;
	reg [7:0] 	DIN_8b_12;
	reg [7:0] 	DIN_8b_13;
	reg [7:0] 	DIN_8b_14;

//加法结果暂存器	
	reg [25:0] temp_1_1,temp_1_2,temp_1_3,temp_1_4;
	reg [25:0] temp_2_1,temp_2_2;
	reg [25:0] temp_3;  
	
	assign	Dout = temp_3[25:10]; 

//查找表函数,将与A3,A2,A1,A0对应相乘的各个位进行查找	
function[15:0] look_A3_A0;
	  input [3:0] DIN;
	  begin
	  	case(DIN)
			   4'b0000: look_A3_A0=16'h0;
			   4'b0001: look_A3_A0=16'h0;
			   4'b0010: look_A3_A0=16'h65;
			   4'b0011: look_A3_A0=16'h65;
			   4'b0100: look_A3_A0=16'h18f;
			   4'b0101: look_A3_A0=16'h18f;
			   4'b0110: look_A3_A0=16'h1f4;
			   4'b0111: look_A3_A0=16'h1f4;
			   4'b1000: look_A3_A0=16'h35a;
			   4'b1001: look_A3_A0=16'h35a;
			   4'b1010: look_A3_A0=16'h3bf;
			   4'b1011: look_A3_A0=16'h3bf;
			   4'b1100: look_A3_A0=16'h4e9;
			   4'b1101: look_A3_A0=16'h4e9;
			   4'b1110: look_A3_A0=16'h54e;
			   4'b1111: look_A3_A0=16'h54e;
			endcase
		end
	endfunction
	  	  
//查找表函数,将与A7,A6,A5,A4对应相乘的各个位进行查找
	function[15:0] look_A7_A4;
	  input [3:0] DIN;
	  begin
	  	case(DIN) 
			   4'b0000: look_A7_A4=16'h0;
			   4'b0001: look_A7_A4=16'h579;
			   4'b0010: look_A7_A4=16'h78e;
			   4'b0011: look_A7_A4=16'hd07;
			   4'b0100: look_A7_A4=16'h935;
			   4'b0101: look_A7_A4=16'heae;
			   4'b0110: look_A7_A4=16'h10c3;
			   4'b0111: look_A7_A4=16'h163c;
			   4'b1000: look_A7_A4=16'h0a1f;
			   4'b1001: look_A7_A4=16'h0f98;
			   4'b1010: look_A7_A4=16'h11ad;
			   4'b1011: look_A7_A4=16'h1726;
			   4'b1100: look_A7_A4=16'h1354;
			   4'b1101: look_A7_A4=16'h18cd;
			   4'b1110: look_A7_A4=16'h1ae2;
			   4'b1111: look_A7_A4=16'h205b;
			endcase
		end
	endfunction 

//查找表查找结果寄存器	
	reg [16:0] lookup0_1,lookup0_2,lookup0_3,lookup0_4,
             lookup1_1,lookup1_2,lookup1_3,lookup1_4,
             lookup2_1,lookup2_2,lookup2_3,lookup2_4,
             lookup3_1,lookup3_2,lookup3_3,lookup3_4,
             lookup4_1,lookup4_2,lookup4_3,lookup4_4,
             lookup5_1,lookup5_2,lookup5_3,lookup5_4,
             lookup6_1,lookup6_2,lookup6_3,lookup6_4,
             lookup7_1,lookup7_2,lookup7_3,lookup7_4;
	reg [17:0] sum0_1,sum0_2,sum1_1,sum1_2,
             sum2_1,sum2_2,sum3_1,sum3_2,
             sum4_1,sum4_2,sum5_1,sum5_2,
             sum6_1,sum6_2,sum7_1,sum7_2;
	reg [18:0] sum0,sum1,sum2,sum3,sum4,sum5,sum6,sum7;
	
	reg	[3:0]	count_4b;
	
// 输入信号的初始化
always @(posedge CLK or posedge Reset)
begin
	if(Reset)
	  begin
		count_4b<=0;
		DIN_8b_0<=0;
		DIN_8b_1<=0;
		DIN_8b_2<=0;
		DIN_8b_3<=0;
		DIN_8b_4<=0;
		DIN_8b_5<=0;
		DIN_8b_6<=0;
		DIN_8b_7<=0;
		DIN_8b_8<=0;
		DIN_8b_9<=0;
		DIN_8b_10<=0;
		DIN_8b_11<=0;
		DIN_8b_12<=0;
		DIN_8b_13<=0;
		DIN_8b_14<=0;
	  end
	else
	  begin
		if(count_4b==15)
		  begin
			DIN_8b_0<=DIN_8b_1;
			DIN_8b_1<=DIN_8b_2;
			DIN_8b_2<=DIN_8b_3;
			DIN_8b_3<=DIN_8b_4;
			DIN_8b_4<=DIN_8b_5;
			DIN_8b_5<=DIN_8b_6;
			DIN_8b_6<=DIN_8b_7;
			DIN_8b_7<=DIN_8b_8;
			DIN_8b_8<=DIN_8b_9;
			DIN_8b_9<=DIN_8b_10;
			DIN_8b_10<=DIN_8b_11;
			DIN_8b_11<=DIN_8b_12;
			DIN_8b_12<=DIN_8b_13;
			DIN_8b_13<=DIN_8b_14;
			DIN_8b_14<=DIN;
		  end
		else	
		  begin
		  case(count_4b)
			'd0: DIN_8b_0=DIN;
			'd1: DIN_8b_1=DIN;
			'd2: DIN_8b_2=DIN;
			'd3: DIN_8b_3=DIN;			
			'd4: DIN_8b_4=DIN;
			'd5: DIN_8b_5=DIN;
			'd6: DIN_8b_6=DIN;
			'd7: DIN_8b_7=DIN;
			'd8: DIN_8b_8=DIN;
			'd9: DIN_8b_9=DIN;
			'd10: DIN_8b_10=DIN;
			'd11: DIN_8b_11=DIN;
			'd12: DIN_8b_12=DIN;
			'd13: DIN_8b_13=DIN;
			'd14: DIN_8b_14=DIN;
			default:;
		  endcase
		  	count_4b=count_4b+1;			
		  end
	  end
end

//利用查找表对输入的信号进行结果的查找,等到七个结果
always @(posedge CLK or posedge Reset)
begin
		if(Reset)
			begin
						//0
						lookup0_1 <= 0;
            lookup0_2 <= 0;
            lookup0_3 <= 0;
            lookup0_4 <= 0;
            sum0_1 <= 0;
            sum0_2 <= 0;
            sum0     <= 0;
            //1
            lookup1_1 <= 0;
            lookup1_2 <= 0;
            lookup1_3 <= 0;
            lookup1_4 <= 0;
            sum1_1 <= 0;
            sum1_2 <= 0;
            sum1     <= 0;
            //2
            lookup2_1 <= 0;
            lookup2_2 <= 0;
            lookup2_3 <= 0;
            lookup2_4 <= 0;
            sum2_1 <= 0;
            sum2_2 <= 0;
            sum2     <= 0;
            //3
            lookup3_1 <= 0;
            lookup3_2 <= 0;
            lookup3_3 <= 0;
            lookup3_4 <= 0;
            sum3_1 <= 0;
            sum3_2 <= 0;
            sum3     <= 0;
            //4
            lookup4_1 <= 0;
            lookup4_2 <= 0;
            lookup4_3 <= 0;
            lookup4_4 <= 0;
            sum4_1 <= 0;
            sum4_2 <= 0;
            sum4     <= 0;
            //5
            lookup5_1 <= 0;
            lookup5_2 <= 0;
            lookup5_3 <= 0;
            lookup5_4 <= 0;
            sum5_1 <= 0;
            sum5_2 <= 0;
            sum5     <= 0;
            //6
            lookup6_1 <= 0;
            lookup6_2 <= 0;
            lookup6_3 <= 0;
            lookup6_4 <= 0;
            sum6_1 <= 0;
            sum6_2 <= 0;
            sum6     <= 0;
            //7
            lookup7_1 <= 0;
            lookup7_2 <= 0;
            lookup7_3 <= 0;
            lookup7_4 <= 0;
            sum7_1 <= 0;
            sum7_2 <= 0;
            sum7     <= 0;
          end
		else
			if(count_4b==15)
			begin
          	//0
          	lookup0_1 <= look_A3_A0({DIN_8b_12[0],DIN_8b_13[0],DIN_8b_14[0],DIN[0]});
          	lookup0_2 <= look_A7_A4({DIN_8b_8[0],DIN_8b_9[0],DIN_8b_10[0],DIN_8b_11[0]});
          	lookup0_3 <= look_A7_A4({DIN_8b_7[0],DIN_8b_6[0],DIN_8b_5[0],DIN_8b_4[0]});
          	lookup0_4 <= look_A3_A0({DIN_8b_3[0],DIN_8b_2[0],DIN_8b_1[0],DIN_8b_0[0]});
          	sum0_1 <= lookup0_1 + lookup0_2;
          	sum0_2 <= lookup0_3 + lookup0_4;
          	sum0     <= sum0_1 + sum0_2;
          	//1
          	lookup1_1 <= look_A3_A0({DIN_8b_12[1],DIN_8b_13[1],DIN_8b_14[1],DIN[1]});
          	lookup1_2 <= look_A7_A4({DIN_8b_8[1],DIN_8b_9[1],DIN_8b_10[1],DIN_8b_11[1]});
          	lookup1_3 <= look_A7_A4({DIN_8b_7[1],DIN_8b_6[1],DIN_8b_5[1],DIN_8b_4[1]});
          	lookup1_4 <= look_A3_A0({DIN_8b_3[1],DIN_8b_2[1],DIN_8b_1[1],DIN_8b_0[1]});
          	sum1_1 <= lookup1_1 + lookup1_2;
          	sum1_2 <= lookup1_3 + lookup1_4;
          	sum1     <= sum1_1 + sum1_2;
          	//2
          	lookup2_1 <= look_A3_A0({DIN_8b_12[2],DIN_8b_13[2],DIN_8b_14[2],DIN[2]});
          	lookup2_2 <= look_A7_A4({DIN_8b_8[2],DIN_8b_9[2],DIN_8b_10[2],DIN_8b_11[2]});
          	lookup2_3 <= look_A7_A4({DIN_8b_7[2],DIN_8b_6[2],DIN_8b_5[2],DIN_8b_4[2]});
          	lookup2_4 <= look_A3_A0({DIN_8b_3[2],DIN_8b_2[2],DIN_8b_1[2],DIN_8b_0[2]});
          	sum2_1 <= lookup2_1 + lookup2_2;
          	sum2_2 <= lookup2_3 + lookup2_4;
          	sum2     <= sum2_1 + sum2_2;
          	//3
          	lookup3_1 <= look_A3_A0({DIN_8b_12[3],DIN_8b_13[3],DIN_8b_14[3],DIN[3]});
          	lookup3_2 <= look_A7_A4({DIN_8b_8[3],DIN_8b_9[3],DIN_8b_10[3],DIN_8b_11[3]});
          	lookup3_3 <= look_A7_A4({DIN_8b_7[3],DIN_8b_6[3],DIN_8b_5[3],DIN_8b_4[3]});
          	lookup3_4 <= look_A3_A0({DIN_8b_3[3],DIN_8b_2[3],DIN_8b_1[3],DIN_8b_0[3]});
          	sum3_1 <= lookup3_1 + lookup3_2;
          	sum3_2 <= lookup3_3 + lookup3_4;
          	sum3     <= sum3_1 + sum3_2;
          	//4
          	lookup4_1 <= look_A3_A0({DIN_8b_12[4],DIN_8b_13[4],DIN_8b_14[4],DIN[4]});
          	lookup4_2 <= look_A7_A4({DIN_8b_8[4],DIN_8b_9[4],DIN_8b_10[4],DIN_8b_11[4]});
          	lookup4_3 <= look_A7_A4({DIN_8b_7[4],DIN_8b_6[4],DIN_8b_5[4],DIN_8b_4[4]});
          	lookup4_4 <= look_A3_A0({DIN_8b_3[4],DIN_8b_2[4],DIN_8b_1[4],DIN_8b_0[4]});
          	sum4_1 <= lookup4_1 + lookup4_2;
          	sum4_2 <= lookup4_3 + lookup4_4;
          	sum4     <= sum4_1 + sum4_2;
          	//5
          	lookup5_1 <= look_A3_A0({DIN_8b_12[5],DIN_8b_13[5],DIN_8b_14[5],DIN[5]});
          	lookup5_2 <= look_A7_A4({DIN_8b_8[5],DIN_8b_9[5],DIN_8b_10[5],DIN_8b_11[5]});
          	lookup5_3 <= look_A7_A4({DIN_8b_7[5],DIN_8b_6[5],DIN_8b_5[5],DIN_8b_4[5]});
          	lookup5_4 <= look_A3_A0({DIN_8b_3[5],DIN_8b_2[5],DIN_8b_1[5],DIN_8b_0[5]});
          	sum5_1 <= lookup5_1 + lookup5_2;
          	sum5_2 <= lookup5_3 + lookup5_4;
          	sum5     <= sum5_1 + sum5_2;
          	//6
          	lookup6_1 <= look_A3_A0({DIN_8b_12[6],DIN_8b_13[6],DIN_8b_14[6],DIN[6]});
          	lookup6_2 <= look_A7_A4({DIN_8b_8[6],DIN_8b_9[6],DIN_8b_10[6],DIN_8b_11[6]});
          	lookup6_3 <= look_A7_A4({DIN_8b_7[6],DIN_8b_6[6],DIN_8b_5[6],DIN_8b_4[6]});
          	lookup6_4 <= look_A3_A0({DIN_8b_3[6],DIN_8b_2[6],DIN_8b_1[6],DIN_8b_0[6]});
          	sum6_1 <= lookup6_1 + lookup6_2;
          	sum6_2 <= lookup6_3 + lookup6_4;
          	sum6     <= sum6_1 + sum6_2;
          	//7
          	lookup7_1 <= look_A3_A0({DIN_8b_12[7],DIN_8b_13[7],DIN_8b_14[7],DIN[7]});
          	lookup7_2 <= look_A7_A4({DIN_8b_8[7],DIN_8b_9[7],DIN_8b_10[7],DIN_8b_11[7]});
          	lookup7_3 <= look_A7_A4({DIN_8b_7[7],DIN_8b_6[7],DIN_8b_5[7],DIN_8b_4[7]});
          	lookup7_4 <= look_A3_A0({DIN_8b_3[7],DIN_8b_2[7],DIN_8b_1[7],DIN_8b_0[7]});
          	sum7_1 <= lookup7_1 + lookup7_2;
          	sum7_2 <= lookup7_3 + lookup7_4;
          	sum7     <= sum7_1 + sum7_2;
          end
         else;
end

//对得到的七个结果进行移位和相加
always @(posedge CLK or posedge Reset)
begin
	 		if (Reset)
          begin
          	  temp_1_1 <= 0;
          	  temp_1_2 <= 0;
          	  temp_1_3 <= 0;
          	  temp_1_4 <= 0;
          	  temp_2_1 <= 0;
          	  temp_2_2 <= 0;
          	  temp_3   <= 0;
          end          	  
      else
          if(count_4b==15)
						begin
          	  temp_1_1 <= {{7{sum0[18]}},sum0} + {{6{sum1[18]}},sum1,1'b0};
          	  temp_1_2 <= {{5{sum2[18]}},sum2,2'b0} + {{4{sum3[18]}},sum3,3'b0};
          	  temp_1_3 <= {{3{sum4[18]}},sum4,4'b0} + {{2{sum5[18]}},sum5,5'b0};
          	  temp_1_4 <= {sum6[18],sum6,6'b0}- {sum7,7'b0}; 
          	  
          	  temp_2_1 <= temp_1_1 + temp_1_2;
          	  temp_2_2 <= temp_1_3 + temp_1_4;
          	  
          	  temp_3   <= temp_2_1 + temp_2_2 ;
						end 
		   		else;
end
endmodule

 4.操作步骤与仿真结论

滤波器系数结果如下所示:

综合结果如下所示:

其仿真结果如下所示:

5.参考文献

[1]朱涛玉,余志勇. 高效实现FPGA数字下变频的多类滤波器分组级联技术[J]. 现代电子技术, 2008, 31(23):4.

A01-115

6.完整源码获得方式

方式1:微信或者QQ联系博主

方式2:订阅MATLAB/FPGA教程,免费获得教程案例以及任意2份完整源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fpga和matlab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值