1024点fft原理及fpga实现

关于傅里叶变换的原理,可以参考以下的博文:
如何理解傅里叶变换公式.

FFT即快速傅里叶变换,是有限长序列作离散傅里叶变换(DFT)的快速算法。

DFT公式为
X[k]=∑n=0N−1x[n]e−j2πknN0≤n≤N−1X[k]=\sum_{n=0}^{N-1}x[n]e^{-j2\pi k\frac{n}{N}} \quad \quad 0\leq n \leq N-1 X[k]=n=0∑N−1​x[n]e−j2πkNn​0≤n≤N−1
令WN=e−j2πNW_N=e^{\frac{-j2\pi }{N}}WN​=eN−j2π​,则X[k]X[k]X[k]重写为
X[k]=∑n=0N−1x[n]WNkn0≤n≤N−1X[k]=\sum_{n=0}^{N-1}x[n]W_N^{kn}\quad \quad \quad 0\leq n \leq N-1 X[k]=n=0∑N−1​x[n]WNkn​0≤n≤N−1

从上面的公式可以看出,我们需要计算有限长序列中每个因子与对应的旋转因子WNW_NWN​的乘积,再对求出来的乘积进行求和。

1. WNW_NWN​是什么

我们知道WN=e−j2πNW_N=e^{\frac{-j2\pi }{N}}WN​=eN−j2π​,所以我们先要明白e−j2πNe^{\frac{-j2\pi }{N}}eN−j2π​的含义。

由欧拉公式知:对于θ∈R\theta\in Rθ∈R,有eiθ=cosθ+isinθe^{i\theta}=cos\theta+isin\thetaeiθ=cosθ+isinθ。那么这个公式是如何推出来的,有兴趣的可以参考

如何通俗地解释欧拉公式.

因此WNW_NWN​实际上就是一个在复平面单位圆上旋转的值,根据kn的不同,WNW_NWN​的值不同,因此我们通俗地解释为旋转因子。

2.基于时间和基于频率

在这里就讲讲概念,复杂的推导就不写了。

由离散傅里叶变换(DFT)的公式可以看出,我们计算DFT序列的每个样本需要进行NNN次复数相乘和N−1N-1N−1次复数相加,那么完整的计算DFT所有样本就需要N2N^2N2次复数相乘和(N−1)N(N-1)N(N−1)N次复数相加。当序列长度为N时,可以证明,计算其N点DFT序列需要4N2N^2N2次实数相乘和(4N−2)N(4N-2)N(4N−2)N次实数相加。

显然,随着点数增多,DFT的计算量急剧增加,因此,推导快速有效的DFT算法具有很大的实际意义。

一种方法是使用递归的计算方法,常用的方案是戈泽尔算法。而另一种方法则是用分解的思想将N点DFT的计算依次分解为尺寸较小的DFT计算并利用复数WNknW_N^{kn}WNkn​的周期性和对称性进行计算,这就是我们的快速傅里叶变换算法(FFT)。

基于时间的FFT是在计算之前,输入序列x[n]x[n]x[n]经过抽取,形成子序列,以奇偶作划分,输出的X[k]X[k]X[k]是按顺序输出。

基于时间的FFT算法是依次将输入序列x[n]x[n]x[n]分解为越来越小的子序列组,将这种分解的思想应用到DFT序列X[k]X[k]X[k]上,就形成基于频率的FFT算法。因此,输入序列x[n]x[n]x[n]以顺序输入,输出DFT序列以抽取后的形式出现。

而如果在每一级以因子RRR进行抽取,则得到的算法称为基RRR快速傅里叶变换算法。常用的为基2和基4算法。

基2按时间抽取的FFT算法的实现

明白原理后,我们使用veilog实现1024点基2按时间抽取的FFT算法。

(1).输入序列和每一级

首先,我们需要准备好输入的序列和每一级计算结果的缓存。注意:复数的实部和虚部是分开存储的

reg signed [23:0] input_data [0:N-1];  //原始输入数据,最高位为符号位reg signed [23:0] dft_oridata [0:N-1];  //码位倒置后的输入数据,最高位为符号位reg signed [23:0] dft_firoutreal [0:N-1];  //第一级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_firoutimg [0:N-1];  //第一级DFT输出数据虚部,最高位为符号位reg signed [23:0] dft_secoutreal [0:N-1];  //第二级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_secoutimg [0:N-1];  //第二级DFT输出数据虚部,最高位为符号位reg signed [23:0] dft_trdoutreal [0:N-1];  //第三级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_trdoutimg [0:N-1];  //第三级DFT输出数据虚部,最高位为符号位reg signed [23:0] dft_foroutreal [0:N-1];  //第四级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_foroutimg [0:N-1];  //第四级DFT输出数据虚部,最高位为符号位reg signed [23:0] dft_fifoutreal [0:N-1];  //第五级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_fifoutimg [0:N-1];  //第五级DFT输出数据虚部,最高位为符号位reg signed [23:0] dft_sixoutreal [0:N-1];  //第六级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_sixoutimg [0:N-1];  //第六级DFT输出数据虚部,最高位为符号位reg signed [23:0] dft_sevoutreal [0:N-1];  //第七级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_sevoutimg [0:N-1];  //第七级DFT输出数据虚部,最高位为符号位reg signed [23:0] dft_eigoutreal [0:N-1];  //第八级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_eigoutimg [0:N-1];  //第八级DFT输出数据虚部,最高位为符号位reg signed [23:0] dft_ninoutreal [0:N-1];  //第九级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_ninoutimg [0:N-1];  //第九级DFT输出数据虚部,最高位为符号位reg signed [23:0] dft_tenoutreal [0:N-1];  //第十级DFT输出数据实部,最高位为符号位
reg signed [23:0] dft_tenoutimg [0:N-1];  //第十级DFT输出数据虚部,最高位为符号位
(2).旋转因子WNknW_N^{kn}WNkn​

在FPGA中直接计算旋转因子是一件比较麻烦的事,因此我们使用MATLAB将旋转因子计算好后,存储在ROM中。如何使用IP核ROM可以参考我之前的博文:
vivado三种常用IP核的调用.

我们已经知道WNkn=e−j2πknN=cos(−2πknN)+jsin(−2πknN)W_N^{kn}=e^{\frac{-j2\pi kn}{N}}=cos(\frac{-2\pi kn}{N})+jsin(\frac{-2\pi kn}{N})WNkn​=eN−j2πkn​=cos(N−2πkn​)+jsin(N−2πkn​),k是我们查表的地址,因此最终MATLAB计算旋转因子的代码为

%fft旋转因子生成表
%w代表返回值,n代表运算点数
%uint8一个字节,uint16两个字节,uint32四个字节,字节数越多,精度越高
%这里将w放大,是因为浮点运算比较消耗时间,因此将其化为整数
function [w]=fftw
clear all;
clc;
n=1024;  %fft点数,根据实际调整
for i=1:n/2%w(i)=cos(-2*pi*(i-1)/n);  %正变换用到的旋转因子实部w(i)=sin(-2*pi*(i-1)/n);    %正变换用到的旋转因子虚部
end%for i=1:i-2
%   w(2*i-1)=cos(2*pi*(i-1)/n);  %逆变换用到的旋转因子
%   w(2*i)=sin(2*pi*(i-1)/n);
%endw=w*256; %将w放大2^8次倍
w=int16(w);%取整
w(find(w<0))=2^11+w(find(w<0));%fid=fopen('C:\Users\Leixx\Desktop\fftwn_real.coe','wt');
fid=fopen('C:\Users\Leixx\Desktop\fftwn_img.coe','wt');
fprintf(fid,'%d,\n',w);
fclose(fid);

因为我的ADC是10位的无符号数,计算中我会将其扩展为11位,所以这里我将旋转因子设置为11位,最高位为符号位。

注意:我将旋转因子扩大了256倍,是因为旋转因子计算出来的值为小数,浮点数运算在FPGA中非常占用资源,因此将其扩为整数方便计算。

(3).码位倒置

按照前面提到的,输入序列在进行DFT运算前需要进行抽取,而抽取的方式就是码位倒置。码位倒置的原理图如下:

码位倒置即将原来的码再按高到底重新排序。verilog实现如下

            5'd1:begin                   //装载需要计算的数据       #15 input_data[data_cnt] = inputdata_r;inputdata_addr = inputdata_addr+1'b1;data_cnt = data_cnt+1'b1;if(!inputdata_addr) begin state <= state+1;data_cnt <= 11'd0; end end 5'd2:begin                //码位倒置dft_oridata[data_cnt] = input_data[{data_cnt[0],data_cnt[1],data_cnt[2],data_cnt[3],data_cnt[4],data_cnt[5],data_cnt[6],data_cnt[7],data_cnt[8],data_cnt[9]}];  data_cnt = data_cnt+1'b1; if(data_cnt==N)begindata_cnt <= 0;    state <= state+1'b1; end   end
(4).蝶形运算

前面的fft流图看上去就像是蝴蝶,因此fft运算也称为蝶形运算,下面是最简单的蝶形运算图

首先x2[k]x_2[k]x2​[k]乘以对应的旋转因子WNkW_N^kWNk​,再分别与x1[k]x_1[k]x1​[k]加减。非常简单。

但需要注意的是,这里的x1[k]x_1[k]x1​[k],WNkW_N^kWNk​和x2[k]x_2[k]x2​[k]都是复数,因此需要遵守复数的运算法则:

加法法则
复数的加法按照以下规定的法则进行:设z1=a+bi,z2=c+di是任意两个复数,则它们的和是 (a+bi)+(c+di)=(a+c)+(b+d)i。
两个复数的和依然是复数,它的实部是原来两个复数实部的和,它的虚部是原来两个虚部的和。
复数的加法满足交换律和结合律,
即对任意复数z1,z2,z3,有: z1+z2=z2+z1;(z1+z2)+z3=z1+(z2+z3)。

减法法则
复数的减法按照以下规定的法则进行:设z1=a+bi,z2=c+di是任意两个复数,
则它们的差是 (a+bi)-(c+di)=(a-c)+(b-d)i。
两个复数的差依然是复数,它的实部是原来两个复数实部的差,它的虚部是原来两个虚部的差。

乘法法则
规定复数的乘法按照以下的法则进行:
设z1=a+bi,z2=c+di(a、b、c、d∈R)是任意两个复数,那么它们的积(a+bi)(c+di)=(ac-bd)+(bc+ad)i。
其实就是把两个复数相乘,类似两个多项式相乘,展开得: ac+adi+bci+bdi2,因为i2=-1,所以结果是(ac-bd)+(bc+ad)i 。两个复数的积仍然是一个复数。
在极坐标下,复数可用模长r与幅角θ表示为(r,θ)。对于复数a+bi,r=√(a²+b²),θ=arctan(b/a)。此时,复数相乘表现为幅角相加,模长相乘。

除法法则
复数除法定义:满足(c+di)(x+yi)=(a+bi)的复数x+yi(x,y∈R)叫复数a+bi除以复数c+di的商。
运算方法:可以把除法换算成乘法做,在分子分母同时乘上分母的共轭.。所谓共轭你可以理解为加减号的变换,互为共轭的两个复数相乘是个实常数。
除法运算规则:
①设复数a+bi(a,b∈R),除以c+di(c,d∈R),其商为x+yi(x,y∈R),
即(a+bi)÷(c+di)=x+yi
分母实数化
分母实数化
∵(x+yi)(c+di)=(cx-dy)+(dx+cy)i
∴(cx-dy)+(dx+cy)i=a+bi
由复数相等定义可知 cx-dy=a dx+cy=b
解这个方程组,得 x=(ac+bd)/(c2+d2) y=(bc-ad)/(c2+d2)
于是有:(a+bi)/(c+di)=(ac+bd)/(c2+d2) +((bc-ad)/(c2+d2))i
②利用共轭复数将分母实数化得(见右图):
点评:①是常规方法;②是利用初中我们学习的化简无理分式时,都是采用的分母有理化思想方法,而复数c+di与复数c-di,相当于我们初中学习的 的对偶式,它们之积为1是有理数,而(c+di)·(c-di)=c2+d2是正实数.所以可以分母实数化。把这种方法叫做分母实数化法。
另外,由上述乘法法则可得另一计算方法,即幅角相减,模长相除。

在verilog中实现如下:

                cache_real = dft_firoutreal[data_cnt+cal_stage]*wndatareal[wndatareal_addr]-dft_firoutimg[data_cnt+cal_stage]*wndataimg[wndataimg_addr];        //先计算旋转因子,分别计算实部和虚部cache_img = dft_firoutreal[data_cnt+cal_stage]*wndataimg[wndataimg_addr]+dft_firoutimg[data_cnt+cal_stage]*wndatareal[wndatareal_addr];cache_realres[31:0] = (dft_firoutreal[data_cnt]<<8) + cache_real;cache_imgres[31:0] = (dft_firoutimg[data_cnt]<<8) + cache_img;dft_secoutreal[data_cnt] = cache_realres[31:8];dft_secoutimg[data_cnt] = cache_imgres[31:8];cache_realres[31:0] = (dft_firoutreal[data_cnt]<<8) - cache_real;cache_imgres[31:0] = (dft_firoutimg[data_cnt]<<8)-cache_img;dft_secoutreal[data_cnt+cal_stage] = cache_realres[31:8];dft_secoutimg[data_cnt+cal_stage] = cache_imgres[31:8];

最上面四行是乘以旋转因子,下面8行则是两个序列值加减。关于代码中的位移操作,请注意:因为旋转因子扩大了2^8 倍,因此我们在作加减法时也需要将另一个没有乘旋转因子的序列值扩大2^8 倍,在加减完成后,再缩小2^8倍。

同时,蝶形运算中会出现负数相乘的情况,一定要保证位宽对齐!

(5).循环

在上面的代码中,我用到了一个个变量,cal_stage。那么这个变量是干什么的?这里就涉及到了fft流图如何循环的问题。

上面提到了,fft算法是将DFT序列分解为更小的序列进行计算。第一级DFT运算是N/2点DFT,第二级是N/4点DFT,第三级是N/8点DFT…,并且都是偶序列和奇序列分开计算。

根据这个原理,我们可以设置两个寄存器fft_stage和cal_stage,一个寄存器记录当前是第几级fft,另一个寄存器记录当前每组做几次蝶形运算。

以第二级DFT举例。此时是N/4点DFT,共有4组,每组有4个点,每组进行两次蝶形运算,此时fft_stage=2,cal_stage=2。观察图我们发现,进行蝶形运算的两个序列值,中间间隔恰好为cal_stage,这便是加上cal_stage的原因。

那么旋转因子呢,同样,观察图我们发现,不同级的旋转因子变化和fft_stage紧密相关,旋转因子间隔值是N>>fft_stage的关系。

每组有两个蝶形运算,我们用wndata_cnt对蝶形运算的个数进行计数。

偶序列和奇序列都有多个分组,我们还需要用group_cnt对组数进行计数。

理清这些后,代码就很好写了。

            5'd5:begin                //第二级蝶形运算,N/4点DFT,计算偶数部分cache_real = dft_firoutreal[data_cnt+cal_stage]*wndatareal[wndatareal_addr]-dft_firoutimg[data_cnt+cal_stage]*wndataimg[wndataimg_addr];        //先计算旋转因子,分别计算实部和虚部cache_img = dft_firoutreal[data_cnt+cal_stage]*wndataimg[wndataimg_addr]+dft_firoutimg[data_cnt+cal_stage]*wndatareal[wndatareal_addr];cache_realres[31:0] = (dft_firoutreal[data_cnt]<<8) + cache_real;cache_imgres[31:0] = (dft_firoutimg[data_cnt]<<8) + cache_img;dft_secoutreal[data_cnt] = cache_realres[31:8];dft_secoutimg[data_cnt] = cache_imgres[31:8];cache_realres[31:0] = (dft_firoutreal[data_cnt]<<8) - cache_real;cache_imgres[31:0] = (dft_firoutimg[data_cnt]<<8)-cache_img;dft_secoutreal[data_cnt+cal_stage] = cache_realres[31:8];dft_secoutimg[data_cnt+cal_stage] = cache_imgres[31:8];                wndatareal_addr = wndatareal_addr+(N>>fft_stage);wndataimg_addr = wndataimg_addr+(N>>fft_stage); wndata_cnt = wndata_cnt+1;  data_cnt = data_cnt+1;if(wndata_cnt==cal_stage)begin           //说明该分组已完成计算,切换到下一个分组data_cnt = data_cnt+cal_stage;  wndatareal_addr = 0;wndataimg_addr = 0; wndata_cnt = 0;group_cnt = group_cnt+1;        //已计算完一个分组if(group_cnt==N>>(fft_stage+1))begin       //说明偶数部分已计算完成group_cnt <= 0;state <= state+1;data_cnt <= N>>1;                        endend               end5'd6:begin                //第二级蝶形运算,N/4点DFT,计算奇数部分cache_real = dft_firoutreal[data_cnt+cal_stage]*wndatareal[wndatareal_addr]-dft_firoutimg[data_cnt+cal_stage]*wndataimg[wndataimg_addr];        //先计算旋转因子,分别计算实部和虚部cache_img = dft_firoutreal[data_cnt+cal_stage]*wndataimg[wndataimg_addr]+dft_firoutimg[data_cnt+cal_stage]*wndatareal[wndatareal_addr];cache_realres[31:0] = (dft_firoutreal[data_cnt]<<8) + cache_real;cache_imgres[31:0] = (dft_firoutimg[data_cnt]<<8) + cache_img;dft_secoutreal[data_cnt] = cache_realres[31:8];dft_secoutimg[data_cnt] = cache_imgres[31:8];cache_realres[31:0] = (dft_firoutreal[data_cnt]<<8) - cache_real;cache_imgres[31:0] = (dft_firoutimg[data_cnt]<<8)-cache_img;dft_secoutreal[data_cnt+cal_stage] = cache_realres[31:8];dft_secoutimg[data_cnt+cal_stage] = cache_imgres[31:8];                wndatareal_addr = wndatareal_addr+(N>>fft_stage);wndataimg_addr = wndataimg_addr+(N>>fft_stage); wndata_cnt = wndata_cnt+1;  data_cnt = data_cnt+1;if(wndata_cnt==cal_stage)begin           //说明该分组已完成计算,切换到下一个分组data_cnt = data_cnt +cal_stage;  wndatareal_addr = 0;wndataimg_addr = 0; wndata_cnt = 0;group_cnt = group_cnt+1;        //已计算完一个分组if(group_cnt==(N>>(fft_stage+1)))begin       //说明奇数部分已计算完成group_cnt <= 0;state<= state+1;cal_stage <= cal_stage<<1;fft_stage <= fft_stage+1;data_cnt <= 4'd0;                        endend                   end

在上面的代码中,我全部使用了寄存器取代特定的数值,具有很好的移植性,只需要将输入的序列和输出的序列修改,就生成了下一级DFT计算的代码。

最后一级计算略有不同,因为最后一级是偶序列和奇序列作蝶形运算,因此不用分偶序列和奇序列

            5'd21:begin                //第十级蝶形运算,N/1024点DFTcache_real = dft_ninoutreal[data_cnt+cal_stage]*wndatareal[wndatareal_addr]-dft_ninoutimg[data_cnt+cal_stage]*wndataimg[wndataimg_addr];        //先计算旋转因子,分别计算实部和虚部cache_img = dft_ninoutreal[data_cnt+cal_stage]*wndataimg[wndataimg_addr]+dft_ninoutimg[data_cnt+cal_stage]*wndatareal[wndatareal_addr];cache_realres[31:0] = (dft_ninoutreal[data_cnt]<<8) + cache_real;cache_imgres[31:0] = (dft_ninoutimg[data_cnt]<<8) + cache_img;dft_tenoutreal[data_cnt] = cache_realres[31:8];dft_tenoutimg[data_cnt] = cache_imgres[31:8];cache_realres[31:0] = (dft_ninoutreal[data_cnt]<<8) - cache_real;cache_imgres[31:0] = (dft_ninoutimg[data_cnt]<<8) - cache_img;dft_tenoutreal[data_cnt+cal_stage] = cache_realres[31:8];dft_tenoutimg[data_cnt+cal_stage] = cache_imgres[31:8];                wndatareal_addr = wndatareal_addr+(N>>fft_stage);wndataimg_addr = wndataimg_addr+(N>>fft_stage); wndata_cnt = wndata_cnt+1;  data_cnt = data_cnt+1;if(wndata_cnt==cal_stage)begin           //说明该分组已完成计算,切换到下一个分组data_cnt = data_cnt +cal_stage;  wndatareal_addr = 0;wndataimg_addr = 0; wndata_cnt = 0;group_cnt = group_cnt+1;        //已计算完一个分组if(group_cnt==(N>>fft_stage))begin       //最后一阶只有一个小组group_cnt <= 0;state<= state+1;cal_stage <= cal_stage<<1;data_cnt <= 0;                        endend                  end
验证

使用MATLAB生成输入数据,将输入数据存到ROM中读取出来并作FFT运算。
MATLAB代码如下:

%=============设置系统参数==============%
f1=1e6;        %设置波形频率
f2=500e3;
f3=800e3;
Fs=20e6;        %设置采样频率
L=8192;         %数据长度
N=11;           %数据位宽
%=============产生输入信号==============%
t=0:1/Fs:(1/Fs)*(L-1);
y1=sin(2*pi*f1*t);
y2=sin(2*pi*f2*t);
y3=sin(2*pi*f3*t);
y4=y1+y2+y3;
y_n=round(y4*(2^(N-3)-1));      %N比特量化;如果有n个信号相加,则设置(N-n)
%=================画图==================%
a=50;           %改变系数可以调整显示周期
stem(t,y_n);
axis([0 L/Fs/a -2^N 2^N]);      %显示
%=============写入外部文件==============%
fid=fopen('C:\Users\Leixx\Desktop\sin_test.txt','w');    %把数据写入sin_data.txt文件中,如果没有就创建该文件
%fid=fopen('C:\Users\Leixx\Desktop\input_data.coe','wt');
for k=1:1024B_s=dec2bin(y_n(k)+((y_n(k))<0)*2^N,N);
%    fprintf(fid,'%d,',y_n(k));for j=1:Nif B_s(j)=='1'tb=1;elsetb=0;endfprintf(fid,'%d',tb);endfprintf(fid,',\n');
end
fprintf(fid,';');
fclose(fid);

仿真结果

可以发现,存在一些误差,主要是因为旋转因子只扩大了2^8 倍,损失了一些精度。但说明我们的算法基本是正确的。

以上就是fft原理及fpga实现。

总结

快速傅里叶变换是通信中常用的重要算法,它将时域的信号转换到频域进行分析,具有非常重要的价值。

以往即使了解这个算法,但是将其用代码也是非常困难的事情。我在编写的过程中,遇到了很多问题,但在解决这些问题的同时,我对FFT算法的理解又进了一步。

这个代码存在很多的不足,一个很显著的可以改进的地方就是蝶形运算那里,可以将蝶形运算编写成一个模块,使用时进行调用即可,这样会大量节省代码。

如果文章有什么问题,欢迎交流!

1024点fft原理及fpga实现相关推荐

  1. 【边学边记_12】——VGA原理与FPGA实现

    VGA原理与FPGA实现 推荐参考小梅哥视频学习 使用FPGA驱动VGA不适合用来显示复杂多变的图像内容,但是却常用于显示实时图像内容,例如显示图像传感器实时采集到的图像.此种方式数据流由图像传感器实 ...

  2. FFT原理(基2DIT-FFT)及C语言编程思路及实现

    1.FFT原理(fast Fourier transform) 首先说明:采用的是基2时域抽取法(Decimation-In-Time FFT 简称DIT-FFT). FFT实际上是对DFT的一种快速 ...

  3. FFT物理意义: 1024点FFT就是1024个实数,实际进入fft的输入是1024个复数(虚部为0),输出也是1024个复数,有效的数据是前512个复数

    2019.02.19更新为了方便简洁记住FFT,总结了一下两段来记录 1024点FFT中的1024是指的输入实数个数,但是FFT输入的一般是复数,也就是1024个复数.FFT输出也是1024个复数,其 ...

  4. FFT原理 C++实现简单FFT代码

    傅里叶变换的意义 为什么我们要用正弦曲线来代替原来的曲线呢? 用正余弦来表示原信号会更加简单,因为正余弦拥有其他信号所不具备的性质:正弦曲线保真度.一个正弦曲线信号输入后,输出的仍是正弦曲线,只有幅度 ...

  5. 十分钟搞懂基-2 FFT原理及编程思想

    0.写在最前 写本文的目的一是为了帮人理清FFT算法思路,二是有几个疑问(在5总结部分提到)希望得到解答.看懂本文的基础:至少听说过.简单了解过傅里叶变换.离散傅里叶变换(DFT).基于时间抽取的基2 ...

  6. 8B10B编解码原理与FPGA代码

    1.发展 8B/10B编码是1983年由IBM公司的Al Widmer和PeterFranaszek所提出的数据传输编码标准,目前已经被广泛应用到高速串行总线,如IEEE1394b.SATA.PCI- ...

  7. c语言实现1024点fft程序,数字信号处理的步骤与注意事项,并编写1024个采样点的FFT C语言程序...

    数字信号处理的步骤与注意事项,并编写1024个采样点的FFT C语言程序 1. 数字信号处理 1.1 数字信号处理概述 数字信号处理是研究如何用数字或符号序列来表示信号以及如何对这些序列进行处理的一门 ...

  8. 循环码生成原理与FPGA实现

    近日,因为项目的需要,重新拾起编码理论,这个项目当中,发送端的信息序列添加了CRC码字,好在接收端进行CRC校验,检测接收到的信息序列是否在传输过程中出现了错误.CRC编码作为循环码字的一种,通常用在 ...

  9. 请写一个长度为1024的FFT C语言函数代码

    以下是一个使用 C 语言实现的快速傅里叶变换(FFT)的代码,输入的数组长度为 1024. #include <stdio.h> #include <math.h> #defi ...

最新文章

  1. 远程办公项目团队如何进行团队协作?
  2. applicationContext.xml中设置读取jdbc.properties文件
  3. (转)Android 常用 adb 命令总结
  4. 南充一中计算机机房被盗,四川省CCF CSP-JS第一轮认证考试在南充一中成功举行...
  5. php代码练习,PHP模拟测试练习
  6. 查询一个月一来表空间的变化情况
  7. shell脚本100例
  8. 百度面试题:从海量日志中提取访问百度次数最多的IP
  9. MySQL官方提供的日志分析工具_MySQL 日志分析的几款工具-Fun言
  10. 金三银四,教你编写一份脱颖而出的简历,从而 offer 手到擒来,要参加校招的同学要提前准备了
  11. 什么是SYN包 以及SYN攻击原理
  12. 33.iptables备份与恢复 firewalld的9个zone以及操作 service的操作
  13. TSDB在高速公路大数据平台的应用
  14. Java内存模型(JMM)详解-可见性volatile
  15. HoloLens初入——研究模式
  16. 电脑启用网络发现以后在点开又成关闭状态了,导致网上邻居访问不了 。如何处理
  17. 【外汇天眼】外汇周回顾:MT5发布新功能,M4Markets收购计划成功
  18. 云产品经理相关技术知识(一)
  19. user()与current_user()
  20. greasemonkey_Google Chrome浏览器中的Greasemonkey脚本入门指南

热门文章

  1. 缓慢的http拒绝服务攻击
  2. 【POJ3122】Pie(二分)
  3. C# SolidWorks 二次开发 API---后台隐藏打开指定类型的文件
  4. 【vue】图片加载动画效果
  5. 非AB实验的效果评估
  6. 理解vue中的slot-scope=“scope“
  7. python | pivot table
  8. 华硕B85主板使用PCI-E阵列卡
  9. python登录邮箱#183;
  10. 今天搞点linux的安装和管理程序常用命令,整zeng高,!!!!!(linux的安装和管理程序常用命令)