8点流水线型FFT的Verilog_HDL实现

  • 格式:pdf
  • 大小:459.44 KB
  • 文档页数:29

8点流水线型FFT的Verilog HDL实现

梁志明

华南理工大学

calaok@sohu.com (一)算法介绍

采用图中的结构,x0(0)~x0(7)为输入数据,位宽为16位;输出数据的位宽为32位,倒

序输出。

图3 8点FFT算法图

(二)系统设计

图4 系统总框图

1、系统总框图如图4所示,总共包括一下几个模块:

1. 运算模块。

对应三阶运算,共采用三个运算子模块:

第一阶运算模块:对应蝶形算子只有W0 (W0=1),

第二阶运算模块:对应蝶形算子有W0 、W2(W2=-j),

第三阶运算模块:对应蝶形算子有W0 、W1 、W2 、W3。

2. 控制模块

针对各阶运算,控制模块也可分为三个子模快:

第一阶控制模块;

第二阶控制模块;

第三阶控制模块 。

2、各个运算模块分析。

1.第一阶运算模块:

模块功能:完成FFT第一阶蝶形运算。

模块设计:

此时蝶形算子只有W0,故蝶形运算结果为C=A+B,D=A-B。因此,只需要对输入

数据做加减法即可。

考虑资源复用,这里定义一个16位的有符号数加法器和减法器,每次运算直接调用即

可。

2.第二阶运算模块

模块功能:完成FFT第二阶蝶形运算。

模块设计:

第二阶运算有蝶形算子W0 、W2。对于W2蝶形运算结果为C=A+jB,D=A-jB,因

此,只需另运算结果实部为A,虚部为+/-B即可。

对于W0算子,这里定义了一个17位有符号数加法器和减法器处理。

对于W2算子,对于运算结果的实部,只需将A扩展成18位即可;针对虚部,对于结

果C,只需将B扩展成18位,对于结果D只用取B的补码,计算过程流程如下图。

图6 第二阶运算模块

3.第三阶运算模块

模块功能:完成FFT第三阶蝶形运算。 控制模块的作用是控制每个阶段的操作

相当于多路开关

这个部分是因为有负数的出现

模块设计:

第三阶运算模块:对应蝶形算子有W0 、W1 、W2 、W3。采用设计要求中提示的通用蝶形运算方法: Rc=Ra+Rb*cosaddsin+(Ib-Rb)sin Ic=Ia+Ib*cossubsin+(Ib-Rb)sin

Rd=Ra-[Rb*cosaddsin+(Ib-Rb)sin]

Id=Ia-[Ib*cossubsin+(Ib-Rb)sin]

其中,

)/2sin()/2cos(sincosNpNpaddππ+=

)/2sin()/2cos(sincosNpNpsubππ−=

)/2sin(sinNpπ=;这里,N=8。

根据上述公式,在进行一次蝶形运算时,只需首先确定cosaddsin,cossubsin,sin,然

后计算出(Ib-Rb)sin,Rb*cosaddsin,Ib*cossubsin,最后将结果相加减即可。

(三)仿真结果分析

1、数据输入

图7 数据输入

(1)输入数据是两组连续8个的串行数据:

A=[1 2 3 4 4 3 2 1];

B=[-5 -5 5 5 -5 -5 5 5];

数据在系统时钟的上升沿被采集。

2、最后蝶形算子运算波形

这个是蝶形运算的通用公式

图8 最后蝶形算子运算波形

(1)蝶形算子运算公式为: cabbbR=R+Rcos(2πp/N)+sin(2πp/N)+(I-R)sin(2πp/N)⎡⎤⎢⎥⎣⎦

bcabb+-RI=I+Icos(2πp/N)-sin(2πp/N)(I)sin(2πp/N)⎡⎤⎢⎥⎣⎦

{}adbbb-R=RRcos(2πp/N)+sin(2πp/N)+(I-R)sin(2πp/N)⎡⎤⎢⎥⎣⎦

{}badbb-+-RI=IIcos(2πp/N)-sin(2πp/N)(I)sin(2πp/N)⎡⎤⎢⎥⎣⎦

输入信号对应:Imul_Ra->Ra

Imul_Ia->Ia

Imul_Rb->Rb

Imul_Ib->Ib

Imulc_Rout->Rc

Imulc_Iout->Ic

Imuld_Rout->Rd

Imuld_Iout->Id

波形上的输入信号为实际大小的有符号数,由于在运算过程中进行了扩展,输出信号是

实际公式计算值的512倍。

3、输出信号波形

图9 输出信号波形

输出结果最后经过了排序,在输出数据有效信号高电平时系统时钟的下降沿稳定。输

出数据为经过位数扩展后的数据,为实际运算数值的512倍。

(1)当输入数据为A=[1 2 3 4 4 3 2 1]时,MATLAB运算的数据为:

20.0000

-5.8284 - 2.4142i

0

-0.1716 - 0.4142i

0

-0.1716 + 0.4142i

0

-5.8284 + 2.4142i

硬件运算的结果为: 这里P的取值有0,1,2,3

输入a和b,输出是c和d

10240 -2984-1236i 0 -88-212i 0 -88+212i 0

-2984+1236i

(2)当输入数据为B=[-5 -5 5 5 -5 -5 5 5]时,MATLAB运算的数据为:

0

0

-20.0000 +20.0000i

0

0

0

-20.0000 -20.0000i

0

硬件运算结果为:

0 0

-10240+10240i

0

0

0

-10240-10240i

0

(四)源程序

(1)add16.v

module add16(a,b,out);

input[15:0] a,b;

output[16:0] out;

reg[16:0] out;

wire[16:0] a1={a[15],a[15:0]};

wire[16:0] b1={b[15],b[15:0]};

always @(a1 or b1)

begin

out=a1+b1;

end

endmodule

两个数相加,所以要扩展一位数

这里的目的是什么呢?好像就是避免溢出进位造成结果不正确?

(2)sub16.v

module sub16(a,b,out);

input[15:0] a,b;

output[16:0] out;

reg[16:0] out;

wire[16:0] a1={a[15],a[15:0]};

wire[16:0] b1={b[15],b[15:0]};

always @(a1 or b1) begin out=a1-b1;

end

endmodule

(3)add17.v

module add17(a,b,out);

input[16:0] a,b;

output[17:0] out;

reg[17:0] out;

wire[17:0] a1={a[16],a[16:0]};

wire[17:0] b1={b[16],b[16:0]};

always @(a1 or b1)

begin

out=a1+b1;

end

endmodule

(4)sub17.v

module sub17(a,b,out);

input[16:0] a,b;

output[17:0] out;

reg[17:0] out;

wire[17:0] a1={a[16],a[16:0]};

wire[17:0] b1={b[16],b[16:0]};

always @(a1 or b1)

begin

out=a1-b1;

end

endmodule

(5)addw2_17.v module addw2_17(a,b,Rout,Iout);

input[16:0] a,b;

output[17:0] Rout,Iout;

reg[17:0] Rout,Iout;

wire[17:0] a1={a[16],a[16:0]};

wire[17:0] b1={b[16],b[16:0]};

always @(a1 or b1)

begin

Rout=a1;

Iout=18'b0-b1;

end

endmodule

(6)subw2_17.v

module subw2_17(a,b,Rout,Iout);

input[16:0] a,b;

output[17:0] Rout,Iout;

reg[17:0] Rout,Iout;

wire[17:0] a1={a[16],a[16:0]};

wire[17:0] b1={b[16],b[16:0]};

always @(a1 or b1)

begin

Rout=a1;

Iout=b1;

end

endmodule

(7)Imul.v

module Imul(p,

Ra_in,Ia_in,

Rb_in,Ib_in,

Rc_out,Ic_out,

Rd_out,Id_out

);