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
);