当前位置:首页 » 编程语言 » dft变换c语言
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

dft变换c语言

发布时间: 2023-03-17 23:39:21

㈠ dft这个函数什么意思

这是dft变换的函桥睁数呀~~你耐明找个信号处理,和数字数字信号敏亩岁处理 看看dft变换在含义和使用方法就能知道怎么用了

㈡ 我做“基于FFT算法与实现”和“FIR滤波器的设计与实现”的实验。。

1.1 实验目的

1.了解数字信号处理系统的一般构成;

2.掌握奈奎斯特抽样定理。

1.2 实验仪器

1.YBLD智能综合信号源测试仪 1台

2.双踪示波器 1台

3.MCOM-TG305数字信号处理与现代通信技术实验箱 1台

4.PC机(装有MATLAB、MCOM-TG305配套实验软件) 1台

1.3 实验原理

一个典型的DSP系统除了数字信号处理部分外,还包括A/D和D/A两部分。这是因为自然界的信号,如声音、图像等大多是模拟信号,因此需要将其数字化后进行数字信号处理,模拟信号的数字化即称为A/D转换。数字信号处理后的数据可能需还原为模拟信号,这就需要进行D/A转换。一个仅包括A/D和D/A两部分的简化数字信号处理系统功能如图1所示。

A/D转换包括三个紧密相关的过程,即抽样、量化和编码。A/D转换中需解决的以下几个重要问题:抽样后输出信号中还有没有原始信号的信息?如果有能不能把它取出来?抽样频率应该如何选择?

奈奎斯特抽样定理(即低通信号的均匀抽样定理)告诉我们,一个频带限制在0至fx以内的低通信号x(t),如果以fs≥2fx的抽样速率进行均匀抽样,则x(t)可以由抽样后的信号xs(t)完全地确定,即xs(t)包含有x(t)的成分,可以通过适当的低通滤波器不失真地恢复出x(t)。最小抽样速率fs=2fx称为奈奎斯特速率。

低通

译码

编码

量化

抽样

输入信号 样点输出 滤波输出

A/D(模数转换) D/A(数模转换)

图1 低通采样定理演示

为方便实现,实验中更换了一种表现形式,即抽样频率固定(10KHz),通过改变输入模拟信号的频率来展示低通抽样定理。我们可以通过研究抽样频率和模拟信号最高频率分量的频率之间的关系,来验证低通抽样定理。

1.4 实验内容

1.软件仿真实验:编写并调试MATLAB程序,分析有关参数,记录有关波形。

2.硬件实验:输入不同频率的正弦信号,观察采样时钟波形、输入信号波形、样点输出波形和滤波输出波形。

1.5 MATLAB参考程序和仿真内容

%*******************************************************************%

%f—余弦信号的频率

% M—基2 FFT幂次数 N=2^M为采样点数,这样取值是为了便于作基2的FFT分析

%2. 采样频率Fs

%*******************************************************************%

function samples(f,Fs,M)

N=2^M; % fft点数=取样总点数

Ts=1/Fs; % 取样时间间隔

T=N*Ts; % 取样总时间=取样总点数*取样时间间隔

n=0:N-1;

t=n*Ts;

Xn=cos(2*f*pi*t);

subplot(2,1,1);

stem(t,Xn);

axis([0 T 1.1*min(Xn) 1.1*max(Xn)]);

xlabel('t -->');

ylabel('Xn');

Xk=abs(fft(Xn,N));

subplot(2,1,2);

stem(n,Xk);

axis([0 N 1.1*min(Xk) 1.1*max(Xk)]);

xlabel('frequency -->');

ylabel('!Xk!');

%*******************************************************************%

假如有一个1Hz的余弦信号y=cos(2*π*t),对其用4Hz的采样频率进行采样,共采样32点,只需执行samples(1,4,5),即可得到仿真结果。

软件仿真实验内容如下表所示:

仿真参数
f
Fs
Wo(计算)
Xn(图形)
Xk(图形)

(1,4,5)

另外记录图形,并标图号

(1,8,5)

(2,8,6)

自 选

1.6 硬件实验步骤

本实验箱采样频率fs固定为10KHz,低通滤波器的截止频率约为4.5KHz。

1、用低频信号源产生正弦信号,正弦信号源频率f自定,并将其接至2TP2(模拟输入)端,将示波器通道一探头接至2TP6(采样时钟)端观察采样时钟波形,示波器通道二探头接至2TP2观察并记录输入信号波形。

2、将示波器通道二探头接至2TP3观察并记录样点输出波形。

3、将示波器通道二探头接至2TP4观察并记录滤波输出波形。

4、根据采样定理,分f=fs /8、f=fs/4、f=fs/2等3种情况更改正弦信号频率,重复步骤2至步骤3。

5、用低频信号源产生方波信号,重复步骤1至步骤4。

1.7 思考题

1、 讨论在仿真实验中所计算的数字域频率Wo和Xk的图形中非零谱线位置之间的对应关系。

2、 讨论在仿真实验中自选参数的意义。

3、将在2TP2端加方波信号后的恢复波形,与相同频率的正弦信号的恢复波形相比,能够得出哪些结论?

2 FFT频谱分析实验

2.1 实验目的

1.通过实验加深对快速傅立叶变换(FFT)基本原理的理解。

2.了解FFT点数与频谱分辨率的关系,以及两种加长序列FFT与原序列FFT的关系。

2.2 实验仪器

1.YBLD智能综合信号源测试仪 1台

2.双踪示波器 1台

3.MCOM-TG305数字信号处理与现代通信技术实验箱 1台

4.PC机(装有MATLAB、MCOM-TG305配套实验软件) 1台

2.3 实验原理

离散傅里叶变换(DFT)和卷积是信号处理中两个最基本也是最常用的运算,它们涉及到信号与系统的分析与综合这一广泛的信号处理领域。实际上卷积与DFT之间有着互通的联系:卷积可化为DFT来实现,其它的许多算法,如相关、滤波和谱估计等都可化为DFT来实现,DFT也可化为卷积来实现。

对N点序列x(n),其DFT变换对定义为:

在DFT运算中包含大量的重复运算。FFT算法利用了蝶形因子WN的周期性和对称性,从而加快了运算的速度。FFT算法将长序列的DFT分解为短序列的DFT。N点的DFT先分解为2个N/2点的DFT,每个N/2点的DFT又分解为2个N/4点的DFT。按照此规律,最小变换的点数即所谓的“基数(radix)。”因此,基数为2的FFT算法的最小变换(或称蝶形)是2点DFT。一般地,对N点FFT,对应于N个输入样值,有N个频域样值与之对应。一般而言,FFT算法可以分为时间抽取(DIT)FFT和频率抽取(DIF)两大类。

在实际计算中,可以采用在原来序列后面补0的加长方法来提高FFT的分辨率;可以采用在原来序列后面重复的加长方法来增加FFT的幅度。

2.4 实验内容

1.软件仿真实验:分别观察并记录正弦序列、方波序列及改变FFT的点数后的频谱;分别观察并记录正弦序列、方波序列及2种加长序列等信号的频谱。

2.硬件实验:分别观察并记录正弦信号、方波信号及改变FFT的点数后的频谱。

2.5 MATLAB参考程序和仿真内容

%*******************************************************************%

function[x]=ffts(mode,M)

Nfft=2^M;

x=zeros(1,Nfft); %定义一个长度为Nfft的一维全0数组

if mode= =1 for n=0:Nfft-1 x(n+1)=sin(2*pi*n/Nfft); end

end %定义一个长度为Nfft的单周期正弦序列

if mode= =2 for n=0:Nfft-1 x(n+1)=sin(4*pi*n/Nfft); end

end %定义一个长度为Nfft的双周期正弦序列

if mode= =3 for n=0:Nfft/2-1 x(n+1)=sin(4*pi*n/Nfft); end

end %定义一个长度为Nfft/2的正弦序列,后面一半为0序列。

if mode= =4 for n=0:Nfft-1 x(n+1)=square(2*pi*n/Nfft); end

end

if mode= =5 for n=0:Nfft-1 x(n+1)=square(2*pi*n/Nfft); end

end

if mode= =6 for n=0:Nfft/2-1 x(n+1)=square(4*pi*n/Nfft); end

end

n=0:Nfft-1;

subplot(2,1,1);

stem(n,x);

axis([0 Nfft-1 1.1*min(x) 1.1*max(x)]);

xlabel('Points-->');

ylabel('x(n)');

X=abs(fft(x,Nfft));

subplot(2,1,2);

stem(n,X);

axis([0 Nfft-1 1.1*min(X) 1.1*max(X)]);

xlabel('frequency-->');

ylabel('!X(k)!');

%*******************************************************************%

假设需观察方波信号的频谱,对一个周期的方波信号作32点的FFT,则只需在MATLAB的命令窗口下键入:[x]=ffts(21,5) ,程序进行模拟,并且输出FFT的结果。

关于软件仿真实验内容,建议在完成大量仿真例子的基础上,选择能够体现实验要求的4个以上的例子进行记录。例如要观察后面补0的加长方法来提高FFT的分辨率的现象,可以仿真ffts(4,5)和ffts(6,6)两个例子。

2.6 硬件实验步骤

1.将低频信号源输出加到实验箱模拟通道1输入端,将示波器探头接至模拟通道1输出端。

2.在保证实验箱正确加电且串口电缆连接正常的情况下,运行数字信号处理与DSP应用实验开发软件,在“数字信号处理实验”菜单下选择“FFT频谱分析”子菜单,出现显示FFT频谱分析功能提示信息的窗口。

3.用低频信号产生器产生一个1KHz的正弦信号。

4.选择FFT频谱分析与显示的点数为64点,开始进行FFT运算。此后,计算机将周期性地取回DSP运算后的FFT数据并绘图显示

5.改信号源频率,观察并记录频谱图的变化。

6.选择FFT的点数为128点,观察并记录频谱图的变化。

7.更改正弦信号的频率,重复步骤4 ~步骤6。

8.用低频信号产生器产生一个1KHz的方波信号,重复步骤4 ~步骤7。注意:应根据实验箱采样频率fs为10KHz和方波信号的频带宽度选择方波信号的频率。

本硬件实验要进行两种信号,每个信号两种频率,每个信号两种点数等共8次具体实验内容,性质能够体现实验要求的4个以上的例子进行记录。

2.7 思考题

1.对同一个信号,不同点数FFT观察到的频谱图有何区别?

2.序列加长后FFT与原序列FFT的关系是什么,试推导其中一种关系。

3.用傅立叶级数理论,试说明正弦信号频谱和方波信号频谱之间的关系。

3 IIR滤波器设计实验

3.1 实验目的

1.通过实验加深对IIR滤波器基本原理的理解。

2.学习编写IIR滤波器的MATLAB仿真程序。

3.2 实验仪器

1.YBLD智能综合信号源测试仪 1台

2.双踪示波器 1台

3.MCOM-TG305数字信号处理与现代通信技术实验箱 1台

4.PC机(装有MATLAB、MCOM-TG305配套实验软件) 1台

3.3 实验原理

IIR滤波器有以下几个特点:

1.IIR数字滤波器的系统函数可以写成封闭函数的形式。

2.IIR数字滤波器采用递归型结构,即结构上带有反馈环路。IIR滤波器运算结构通常由延时、乘以系数和相加等基本运算组成,可以组合成直接型、正准型、级联型、并联型四种结构形式,都具有反馈回路。由于运算中的舍入处理,使误差不断累积,有时会产生微弱的寄生振荡。

3.IIR数字滤波器在设计上可以借助成熟的模拟滤波器的成果,如巴特沃斯、契比雪夫和椭圆滤波器等,有现成的设计数据或图表可查,其设计工作量比较小,对计算工具的要求不高。在设计一个IIR数字滤波器时,我们根据指标先写出模拟滤波器的公式,然后通过一定的变换,将模拟滤波器的公式转换成数字滤波器的公式。

4.IIR数字滤波器的相位特性不好控制,对相位要求较高时,需加相位校准网络。

在MATLAB下设计IIR滤波器可使用Butterworth函数设计出巴特沃斯滤波器,使用Cheby1函数设计出契比雪夫I型滤波器,使用Cheby2设计出契比雪夫II型滤波器,使用ellipord函数设计出椭圆滤波器。下面主要介绍前两个函数的使用。

与FIR滤波器的设计不同,IIR滤波器设计时的阶数不是由设计者指定,而是根据设计者输入的各个滤波器参数(截止频率、通带滤纹、阻带衰减等),由软件设计出满足这些参数的最低滤波器阶数。在MATLAB下设计不同类型IIR滤波器均有与之对应的函数用于阶数的选择。

一、巴特沃斯IIR滤波器的设计

在MATLAB下,设计巴特沃斯IIR滤波器可使用butter函数。

Butter函数可设计低通、高通、带通和带阻的数字和模拟IIR滤波器,其特性为使通带内的幅度响应最大限度地平坦,但同时损失截止频率处的下降斜度。在期望通带平滑的情况下,可使用butter函数。

butter函数的用法为:

[b,a]=butter(n,Wn,/ftype/)

其中n代表滤波器阶数,Wn代表滤波器的截止频率,这两个参数可使用buttord函数来确定。buttord函数可在给定滤波器性能的情况下,求出巴特沃斯滤波器的最小阶数n,同时给出对应的截止频率Wn。buttord函数的用法为:

[n,Wn]= buttord(Wp,Ws,Rp,Rs)

其中Wp和Ws分别是通带和阻带的拐角频率(截止频率),其取值范围为0至1之间。当其值为1时代表采样频率的一半。Rp和Rs分别是通带和阻带区的波纹系数。

不同类型(高通、低通、带通和带阻)滤波器对应的Wp和Ws值遵循以下规则:

1.高通滤波器:Wp和Ws为一元矢量且Wp>Ws;

2.低通滤波器:Wp和Ws为一元矢量且Wp<Ws;

3.带通滤波器:Wp和Ws为二元矢量且Wp<Ws,如Wp=[0.2,0.7],Ws=[0.1,0.8];

4.带阻滤波器:Wp和Ws为二元矢量且Wp>Ws,如Wp=[0.1,0.8],Ws=[0.2,0.7]。

二、契比雪夫I型IIR滤波器的设计

在期望通带下降斜率大的场合,应使用椭圆滤波器或契比雪夫滤波器。在MATLAB下可使用cheby1函数设计出契比雪夫I型IIR滤波器。

cheby1函数可设计低通、高通、带通和带阻契比雪夫I型滤IIR波器,其通带内为等波纹,阻带内为单调。契比雪夫I型的下降斜度比II型大,但其代价是通带内波纹较大。

cheby1函数的用法为:

[b,a]=cheby1(n,Rp,Wn,/ftype/)

在使用cheby1函数设计IIR滤波器之前,可使用cheblord函数求出滤波器阶数n和截止频率Wn。cheblord函数可在给定滤波器性能的情况下,选择契比雪夫I型滤波器的最小阶和截止频率Wn。

cheblord函数的用法为:

[n,Wn]=cheblord(Wp,Ws,Rp,Rs)

其中Wp和Ws分别是通带和阻带的拐角频率(截止频率),其取值范围为0至1之间。当其值为1时代表采样频率的一半。Rp和Rs分别是通带和阻带区的波纹系数。

3.4 实验内容

1.软件仿真实验:编写并调试MATLAB程序,选择不同形式,不同类型的4种滤波器进行仿真,记录幅频和相频特性,对比巴特沃斯滤波器和契比雪夫滤波器。

2.硬件实验:设计IIR滤波器,在计算机上观察冲激响应、幅频特性和相频特性,然后下载到实验箱。用示波器观察输入输出波形,测试滤波器的幅频响应特性。

3.5 MATLAB参考程序和仿真内容

%*******************************************************************%

%mode: 1--巴特沃斯低通;2--巴特沃斯高通;3--巴特沃斯带通;4--巴特沃斯带阻

% 5--契比雪夫低通;6--契比雪夫高通;7--契比雪夫带通;8--契比雪夫带阻

%fp1,fp2: 通带截止频率,当高通或低通时只有fp1有效

%fs1, fs2: 阻带截止频率,当高通或低通时只有fs1有效

%rp: 通带波纹系数

%as: 阻带衰减系数

%sample: 采样率

%h: 返回设计好的滤波器系数

%*******************************************************************%

function[b,a]=iirfilt(mode,fp1,fp2,fs1,fs2,rp,as,sample)

wp1=2*fp1/sample;wp2=2*fp2/sample;

ws1=2*fs1/sample;ws2=2*fs2/sample;

%得到巴特沃斯滤波器的最小阶数N和3bd频率wn

if mode<3[N,wn]=buttord(wp1,ws1,rp,as);

elseif mode<5[N,wn]=buttord([wp1 wp2],[ws1 ws2],rp,as);

%得到契比雪夫滤波器的最小阶数N和3bd频率wn

elseif mode<7[N,wn]=cheb1ord(wp1,ws1,rp,as);

else[N,wn]=cheblord([wp1 wp2],[ws1 ws2],rp,as);

end

%得到滤波器系数的分子b和分母a

if mode= =1[b,a]=butter(N,wn);end

if mode= =2[b,a]=butter(N,wn,/high/);end

if mode= =3[b,a]=butter(N,wn);end

if mode= =4[b,a]=butter(N,wn,/stop/);end

if mode= =5[b,a]=cheby1(N,rp,wn);end

if mode= =6[b,a]=cheby1(N,rp,wn,/high/);end

if mode= =7[b,a]=cheby1(N,rp,wn);end

if mode= =8[b,a]=cheby1(N,rp,wn,/stop/);end

set(gcf,/menubar/,menubar);

freq_response=freqz(b,a);

magnitude=20*log10(abs(freq_response));

m=0:511;

f=m*sample/(2*511);

subplot(3,1,1);plot(f,magnitude);grid; %幅频特性

axis([0 sample/2 1.1*min(magnitude) 1.1*max(magnitude)]);

ylabel('Magnitude');xlabel('Frequency-->');

phase=angle(freq_response);

subplot(3,1,2);plot(f,phase);grid; %相频特性

axis([0 sample/2 1.1*min(phase) 1.1*max(phase)]);

ylabel('Phase');xlabel('Frequency-->');

h=impz(b,a,32); %32点的单位函数响应

t=1:32;

subplot(3,1,3);stem(t,h);grid;

axis([0 32 1.2*min(h) 1.1*max(h)]);

ylabel('h(n)');xlabel('n-->');

%*******************************************************************%

假设需设计一个巴特沃斯低通IIR滤波器,通带截止频率为2KHz,阻带截止频率为3KHz,通带波纹系数为1,阻带衰减系数为20,采样频率为10KHz,则只需在MATLAB的命令窗口下键入:

[b,a]=iirfilt(1,2000,3000,2400,2600,1,20,10000)

程序进行模拟,并且按照如下顺序输出数字滤波器系统函数

的系数

b= b0 b1 ……bn

a= a0 a1 ……an

关于软件仿真实验内容,建议在完成大量仿真例子的基础上,选择能够体现实验要求的4个例子进行记录,系统函数只要记录系统的阶数。

3.6 硬件实验步骤

1.根据实验箱采样频率fs为10KHz的条件,用低频信号发生器产生一个频率合适的低频正弦信号,将其加到实验箱模拟通道1输入端,将示波器通道1探头接至模拟通道1输入端,通道2探头接至模拟通道2输出端。

2.在保证实验箱正确加电且串口电缆连接正常的情况下,运行数字信号处理与DSP应用实验开发软件,在“数字信号处理实验”菜单下选择“IIR滤波器”子菜单,出现提示信息。

3.输入滤波器类型、滤波器截止频率等参数后,分别点击“幅频特性”和“相频特性”按钮,在窗口右侧观察IIR滤波器的幅频特性和相频特性。此时提示信息将消失,如需查看提示信息,可点击“设计说明”按钮。

4.点击“下载实现”按钮,IIR滤波器开始工作,此时窗口右侧将显示IIR滤波器的幅频特性。

5.根据输入滤波器类型,更改低频信号源的频率,观察示波器上输入输出波形幅度的变化情况,测量IIR滤波器的幅频响应特性,看其是否与设计的幅频特性一致。

6.更改滤波器类型、滤波器截止频率等参数(共4种),重复步骤3至步骤5。所选择的例子参数最好和MATLAB仿真程序的例子一样。

7.用低频信号产生器产生一个500Hz的方波信号,分别设计3种滤波器,完成如下表要求的功能,并且记录参数和波形。

功 能
滤波器类型
参 数
输出波形

fp1
fp2
fs1
fs2

通过3次及以下次数的谐波

另外记录图形,并标图号

滤除5次及以下次数的谐波

通过3次到5次的谐波

3.7 思考题

1.在实验箱采样频率fs固定为10KHz的条件下,要观察方波信号频带宽度内的各个谐波分量,方波信号的频率最高不能超过多少,为什么?

2.硬件实验内容7中输出信号各个谐波分量,与原来方波信号同样谐波分量相比,有没有发生失真?主要发生了什么类型的失真?为什么?

4 窗函数法FIR滤波器设计实验

4.1 实验目的

1.通过实验加深对FIR滤波器基本原理的理解。

2.学习使用窗函数法设计FIR滤波器,了解窗函数的形式和长度对滤波器性能的影响。

4.2 实验仪器

1.YBLD智能综合信号源测试仪 1台

2.双踪示波器 1台

3.MCOM-TG305数字信号处理与现代通信技术实验箱 1台

4.PC机(装有MATLAB、MCOM-TG305配套实验软件) 1台

4.3 实验原理

数字滤波器的设计是数字信号处理中的一个重要内容。数字滤波器设计包括FIR(有限单位脉冲响应)滤波器与IIR(无限单位脉冲响应)滤波器两种。

与IIR滤波器相比,FIR滤波器在保证幅度特性满足技术要求的同时,很容易做到严格的线性相位特性。设FIR滤波器单位脉冲响应h(n)长度为N,其系统函数H(z)为:

H(z)是z-1的N-1次多项式,它在z平面上有N-1个零点,原点z=0是N-1阶重极点,因此H(z)是永远稳定的。稳定和线性相位特性是FIR滤波器突出的优点。

FIR滤波器的设计任务是选择有限长度的h(n)。使传输函数H( )满足技术要求。FIR滤波器的设计方法有多种,如窗函数法、频率采样法及其它各种优化设计方法,本实验介绍窗函数法的FIR滤波器设计。

窗函数法是使用矩形窗、三角窗、巴特利特窗、汉明窗、汉宁窗和布莱克曼窗等设计出标准响应的高通、低通、带通和带阻FIR滤波器。

一、firl函数的使用

在MATLAB下设计标准响应FIR滤波器可使用firl函数。firl函数以经典方法实现加窗线性相位FIR滤波器设计,它可以设计出标准的低通、带通、高通和带阻滤波器。firl函数的用法为:

b=firl(n,Wn,/ftype/,Window)

各个参数的含义如下:

b—滤波器系数。对于一个n阶的FIR滤波器,其n+1个滤波器系数可表示为:b(z)=b(1)+b(2)z-1+…+b(n+1)z-n。

n—滤波器阶数。

Wn—截止频率,0≤Wn≤1,Wn=1对应于采样频率的一半。当设计带通和带阻滤波器时,Wn=[W1 W2],W1≤ω≤W2。

ftype—当指定ftype时,可设计高通和带阻滤波器。Ftype=high时,设计高通FIR滤波器;ftype=stop时设计带阻FIR滤波器。低通和带通FIR滤波器无需输入ftype参数。

Window—窗函数。窗函数的长度应等于FIR滤波器系数个数,即阶数n+1。

二、窗函数的使用

在MATLAB下,这些窗函数分别为:

1.矩形窗:w=boxcar(n),产生一个n点的矩形窗函数。

2.三角窗:w=triang(n),产生一个n点的三角窗函数。

当n为奇数时,三角窗系数为w(k)=
当n为偶数时,三角窗系数为w(k)=
3.巴特利特窗:w=Bartlett(n),产生一个n点的巴特利特窗函数。

巴特利特窗系数为w(k)=
巴特利特窗与三角窗非常相似。巴特利特窗在取样点1和n上总以零结束,而三角窗在这些点上并不为零。实际上,当n为奇数时bartlett(n)的中心n-2个点等效于triang(n-2)。

4.汉明窗:w=hamming(n),产生一个n点的汉明窗函数。

汉明窗系数为w(k+1)=0.54-0.46cos( ) k=0,…,n-1

5.汉宁窗:w=hanning(n),产生一个n点的汉宁窗函数。

汉宁窗系数为w(k)=0.5[1-cos( )] k=1,…,n

6.布莱克曼窗:w=Blackman(n),产生一个n点的布莱克曼窗函数。

布莱克曼窗系数为w(k)=0.42-0.5cos(2π )+0.8cos(4π )] k=1,…,n

与等长度的汉明窗和汉宁窗相比,布莱克曼窗的主瓣稍宽,旁瓣稍低。

7.凯泽窗:w=Kaiser(n,beta),产生一个n点的凯泽窗数,其中beta为影响窗函数旁瓣的β参数,其最小的旁瓣抑制α与β的关系为:

0.1102(α-0.87) α>50

β= 0.5842(α-21)0.4+0.07886(α-21) 21≤α≤50

0 α<21

增加β可使主瓣变宽,旁瓣的幅度降低。

8.契比雪夫窗:w=chebwin(n,r)产生一个n点的契比雪夫窗函数。其傅里叶变换后的旁瓣波纹低于主瓣r个db数。

4.4 实验内容

1.软件仿真实验:编写并调试MATLAB程序,观察不同窗,不同类型滤波器不同点数等共4种FIR滤波器的h(n),并记录幅频特性和相频特性。

2.硬件实验:用窗函数法设计标准响应的FIR滤波器,在计算机上观察窗函数幅频特性、幅频特性和相频特性,然后下载到实验箱。用示波器观察输入输出波形,测试滤波器的幅频响应特性。

4.5 MATLAB参考程序和仿真内容

%*******************************************************************%

%mode: 模式(1--高通;2--低通;3--带通;4--带阻)

%n: 阶数,加窗的点数为阶数加1

%fp: 高通和低通时指示截止频率,带通和带阻时指示下限频率

%fs: 带通和带阻时指示上限频率

%window:加窗(1--矩形窗;2--三角窗;3--巴特利特窗;4--汉明窗;

% 5--汉宁窗;6--布莱克曼窗;7--凯泽窗;8--契比雪夫窗)

%r: 代表加chebyshev窗的r值和加kaiser窗时的beta值

%sample: 采样率

%h: 返回设计好的FIR滤波器系数

%*******************************************************************%

%mode: 模式(1--高通;2--低通;3--带通;4--带阻)

%n: 阶数,加窗的点数为阶数加1

%fp: 高通和低通时指示截止频率,带通和带阻时指示下限频率

%fs:

㈢ 求FFT的c语言程序

快速傅里叶变换 要用C++ 才行吧 你可以用MATLAB来实现更方便点啊

此FFT 是用VC6.0编写,由FFT.CPP;STDAFX.H和STDAFX.CPP三个文件组成,编译成功。程序可以用文件输入和输出为文件。文件格式为TXT文件。测试结果如下:

输入文件:8.TXT 或手动输入

8 //N

1

2

3

4

5

6

7

8

输出结果为:或保存为TXT文件。(8OUT.TXT)

8

(36,0)

(-4,9.65685)

(-4,4)

(-4,1.65685)

(-4,0)

(-4,-1.65685)

(-4,-4)

(-4,-9.65685)

下面为FFT.CPP文件:

// FFT.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"

#include <iostream>

#include <complex>

#include <bitset>

#include <vector>

#include <conio.h>

#include <string>

#include <fstream>

using namespace std;

bool inputData(unsigned long &, vector<complex<double> >&); //手工输入数据

void FFT(unsigned long &, vector<complex<double> >&); //FFT变换

void display(unsigned long &, vector<complex<double> >&); //显示结果

bool readDataFromFile(unsigned long &, vector<complex<double> >&); //从文件中读取数据

bool saveResultToFile(unsigned long &, vector<complex<double> >&); //保存结果至文件中

const double PI = 3.1415926;

int _tmain(int argc, _TCHAR* argv[])

{

vector<complex<double> > vecList; //有限长序列

unsigned long ulN = 0; //N

char chChoose = ' '; //功能选择

//功能循环

while(chChoose != 'Q' && chChoose != 'q')

{

//显示选择项

cout << "\nPlease chose a function" << endl;

cout << "\t1.Input data manually, press 'M':" << endl;

cout << "\t2.Read data from file, press 'F':" << endl;

cout << "\t3.Quit, press 'Q'" << endl;

cout << "Please chose:";

//输入选择

chChoose = getch();

//判断

switch(chChoose)

{

case 'm': //手工输入数据

case 'M':

if(inputData(ulN, vecList))

{

FFT(ulN, vecList);

display(ulN, vecList);

saveResultToFile(ulN, vecList);

}

break;

case 'f': //从文档读取数据

case 'F':

if(readDataFromFile(ulN, vecList))

{

FFT(ulN, vecList);

display(ulN, vecList);

saveResultToFile(ulN, vecList);

}

break;

}

}

return 0;

}

bool Is2Power(unsigned long ul) //判断是否是2的整数次幂

{

if(ul < 2)

return false;

while( ul > 1 )

{

if( ul % 2 )

return false;

ul /= 2;

}

return true;

}

bool inputData(unsigned long & ulN, vector<complex<double> >& vecList)

{

//题目

cout<< "\n\n\n==============================Input Data===============================" << endl;

//输入N

cout<< "\nInput N:";

cin>>ulN;

if(!Is2Power(ulN)) //验证N的有效性

{

cout<< "N is invalid (N must like 2, 4, 8, .....), please retry." << endl;

return false;

}

//输入各元素

vecList.clear(); //清空原有序列

complex<double> c;

for(unsigned long i = 0; i < ulN; i++)

{

cout << "Input x(" << i << "):";

cin >> c;

vecList.push_back(c);

}

return true;

}

bool readDataFromFile(unsigned long & ulN, vector<complex<double> >& vecList) //从文件中读取数据

{

//题目

cout<< "\n\n\n===============Read Data From File==============" << endl;

//输入文件名

string strfilename;

cout << "Input filename:" ;

cin >> strfilename;

//打开文件

cout << "open file " << strfilename << "......." <<endl;

ifstream loadfile;

loadfile.open(strfilename.c_str());

if(!loadfile)

{

cout << "\tfailed" << endl;

return false;

}

else

{

cout << "\tsucceed" << endl;

}

vecList.clear();

//读取N

loadfile >> ulN;

if(!loadfile)

{

cout << "can't get N" << endl;

return false;

}

else

{

cout << "N = " << ulN << endl;

}

//读取元素

complex<double> c;

for(unsigned long i = 0; i < ulN; i++)

{

loadfile >> c;

if(!loadfile)

{

cout << "can't get enough infomation" << endl;

return false;

}

else

cout << "x(" << i << ") = " << c << endl;

vecList.push_back(c);

}

//关闭文件

loadfile.close();

return true;

}

bool saveResultToFile(unsigned long & ulN, vector<complex<double> >& vecList) //保存结果至文件中

{

//询问是否需要将结果保存至文件

char chChoose = ' ';

cout << "Do you want to save the result to file? (y/n):";

chChoose = _getch();

if(chChoose != 'y' && chChoose != 'Y')

{

return true;

}

//输入文件名

string strfilename;

cout << "\nInput file name:" ;

cin >> strfilename;

cout << "Save result to file " << strfilename << "......" << endl;

//打开文件

ofstream savefile(strfilename.c_str());

if(!savefile)

{

cout << "can't open file" << endl;

return false;

}

//写入N

savefile << ulN << endl;

//写入元素

for(vector<complex<double> >::iterator i = vecList.begin(); i < vecList.end(); i++)

{

savefile << *i << endl;

}

//写入完毕

cout << "save succeed." << endl;

//关闭文件

savefile.close();

return true;

}

void FFT(unsigned long & ulN, vector<complex<double> >& vecList)

{

//得到幂数

unsigned long ulPower = 0; //幂数

unsigned long ulN1 = ulN - 1;

while(ulN1 > 0)

{

ulPower++;

ulN1 /= 2;

}

//反序

bitset<sizeof(unsigned long) * 8> bsIndex; //二进制容器

unsigned long ulIndex; //反转后的序号

unsigned long ulK;

for(unsigned long p = 0; p < ulN; p++)

{

ulIndex = 0;

ulK = 1;

bsIndex = bitset<sizeof(unsigned long) * 8>(p);

for(unsigned long j = 0; j < ulPower; j++)

{

ulIndex += bsIndex.test(ulPower - j - 1) ? ulK : 0;

ulK *= 2;

}

if(ulIndex > p)

{

complex<double> c = vecList[p];

vecList[p] = vecList[ulIndex];

vecList[ulIndex] = c;

}

}

//计算旋转因子

vector<complex<double> > vecW;

for(unsigned long i = 0; i < ulN / 2; i++)

{

vecW.push_back(complex<double>(cos(2 * i * PI / ulN) , -1 * sin(2 * i * PI / ulN)));

}

for(unsigned long m = 0; m < ulN / 2; m++)

{

cout<< "\nvW[" << m << "]=" << vecW[m];

}

//计算FFT

unsigned long ulGroupLength = 1; //段的长度

unsigned long ulHalfLength = 0; //段长度的一半

unsigned long ulGroupCount = 0; //段的数量

complex<double> cw; //WH(x)

complex<double> c1; //G(x) + WH(x)

complex<double> c2; //G(x) - WH(x)

for(unsigned long b = 0; b < ulPower; b++)

{

ulHalfLength = ulGroupLength;

ulGroupLength *= 2;

for(unsigned long j = 0; j < ulN; j += ulGroupLength)

{

for(unsigned long k = 0; k < ulHalfLength; k++)

{

cw = vecW[k * ulN / ulGroupLength] * vecList[j + k + ulHalfLength];

c1 = vecList[j + k] + cw;

c2 = vecList[j + k] - cw;

vecList[j + k] = c1;

vecList[j + k + ulHalfLength] = c2;

}

}

}

}

void display(unsigned long & ulN, vector<complex<double> >& vecList)

{

cout << "\n\n===========================Display The Result=========================" << endl;

for(unsigned long d = 0; d < ulN;d++)

{

cout << "X(" << d << ")\t\t\t = " << vecList[d] << endl;

}

}

下面为STDAFX.H文件:

// stdafx.h : 标准系统包含文件的包含文件,

// 或是常用但不常更改的项目特定的包含文件

#pragma once

#include <iostream>

#include <tchar.h>

// TODO: 在此处引用程序要求的附加头文件

下面为STDAFX.CPP文件:

// stdafx.cpp : 只包括标准包含文件的源文件

// FFT.pch 将成为预编译头

// stdafx.obj 将包含预编译类型信息

#include "stdafx.h"

// TODO: 在 STDAFX.H 中

//引用任何所需的附加头文件,而不是在此文件中引用

㈣ 离散傅立叶变换(DFT)和快速算法(FFT)的区别是什么

fft就是dft的快速坦辩算法, 结果让陆缺是一样的。

应该不会有这个差别。 搞不懂悉御就贴图看看

这个差别在于, 补0再fft这里0是不受你前面减mean的影响的, 所以你前面减东西相当于是减一个矩形, 所以fft的结果相当于减一个Sa,所以就会对形状有一些影响。 其实如果不是你选了一个过于短的列, 也不会有这么明显影响的

㈤ C语言 FFTW 二维

ELEM这个数答塌配组是为了确定二维数组的每个值的确定位置,因衫弊为你申请的in和out都是1维数组(不考虑实部虚部那个0和1)所以要确定在你开辟的这个1维数组中所对应的二维数组是哪个数就用到了ELEM,举个例子,比如你算二维数组[r,c]这个位置的值,其实是在一维数组的第r*N+c个数,所以就得到了in[r*N+c][0],清指也就是在做fft之前的fftw_complex表示,楼主可能混淆fftw_complex和文中ELEM数组了,ELEM并不是fftw_complex数组的表示,只是为了找到确定数组位置的一个中间数组而已,希望回答能让你满意

㈥ C语言计算基波幅值和功率因数,高人指点!

很高深啊

㈦ 离散傅里叶变换的C语言实现代码

int DFT(int dir,int m,double *x1,double *y1)
{
long i,k;
double arg;
double cosarg,sinarg;
double *x2=NULL,*y2=NULL;
x2=malloc(m*sizeof(double));
y2=malloc(m*sizeof(double));
if(x2==NULL||y2==NULL)return(FALSE);
for(i=0;i<m;i++)
{
x2[i]=0;
y2[i]=0;
arg=-dir*2.0*3.141592654*(double)i/(double)m;
for(k=0;k<m;k++)
{
cosarg=cos(k*arg);
sinarg=sin(k*arg);
x2[i]+=(x1[k]*cosarg-y1[k]*sinarg);
y2[i]+=(x1[k]*sinarg+y1[k]*cosarg);
}
}
/*Copythedataback*/
if(dir==1)
{
for(i=0;i<m;i++)
{
x1[i]=x2[i]/(double)m;
y1[i]=y2[i]/(double)m;
}
}
else
{
for(i=0;i<m;i++)
{
x1[i]=x2[i];
y1[i]=y2[i];
}
}
free(x2);
free(y2);
return(TRUE);
}

㈧ FFT , DTFT, DFT 的区别和联系

FFT ,DTFT,DFT的联系:FFT是DFT的一种高效快速算法,DFT是有限长序列的离散傅里叶变换,DTFT是非周期序列的傅里叶变换,DFT将信号的时域采样变换为其DTFT的频域采样。

FFT , DTFT, DFT 的区别是含义不同、性质不同、用途不同。

1、含义不同:DTFT是离散时间傅里叶变换,DFT是离散傅里叶变换,FFT是DFT的一种高效快速算法,也称作快速傅里叶变换。

2、性质不同:DTFT变换后的图形中的频率是一般连续的(cos(wn)等这样的特殊函数除外,其变换后是冲击串),而DFT是DTFT的等间隔抽样,是离散的点。

快速傅里叶变换FFT其实是一种对离散傅里叶变换的快速算法,它的出现解决了离散傅里叶散中变换的计算量极大、不实用的问题,使离散傅里叶变换的计算量降低了 一个或几个数量级,从而使离散傅里叶变换得到了广泛应用。

3、用途不同:DFT完全是应计算机技术的发展而来的,因为如果没有计算机,用DTFT分析看频率响应就可以,为了适应计算机计算,那么就必须要用离散的值,因为计算机不能处理连续的值,FFT是为了提高速度而来。另外,FFT的出现也解决了相当多的计算问题,使得其它计算也可以通过FFT来解决。

(8)dft变换c语言扩展阅读

DTFT是以2pi为周期的。而DFT的序列X(k)是棚渣有限长的。

DTFT是以复指数序列{exp(-jwn)}的加权和来表示的,而DFT是等间隔抽样,DFT里面有个重要的参数就是N,抽样间隔就是将单位元分成N个间隔来抽样,绕圆一周,(2*pi)/N是间隔(一个圆周是2*pi,分成N个等分)

DTFT和DFT都能表征原序列的信链掘悄息。因为现在计算主要使用计算机,必需要是离散的值才能参与运算,因此在工程中DFT应用比较广泛,DFT还有一个快速算法,那就是FFT。

㈨ 离散傅里叶变换的用DFT对模拟信号进行谱分析

在工程实际中经常遇到的模拟信号xn(t),其频谱函数Xn(jΩ)也是连续函数,为了利用DFT对xn(t)进行谱分析,对xn(t)进行时域采样得到x(n)= xn(nT),再对x(n)进行DFT,得到X(k)则是x(n)的傅里叶变换X(ejω)在频率区间[0,2π]上的N点等间隔采样,这里x(n)和X(k)都是有限长序列
然而,傅里叶变换理论证明,时间有限长的信号其频谱是无限宽的,反之,弱信号的频谱有限款的则其持续时间将为无限长,因此,按采样定理采样时,采样序列应为无限长,这不满足DFT的条件。实际中,对于频谱很宽的信号,为防止时域采样后产生‘频谱混叠’,一般用前置滤波器滤除幅度较小的高频成分,使信号的贷款小于折叠频率;同样对于持续时间很长的信号,采样点数太多也会导致存储和计算困难,一般也是截取有限点进行计算。上述可以看出,用DFT对模拟信号进行谱分析,只能是近似的,其近似程度取决于信号带宽、采样频率和截取长度
模拟信号xn(t)的傅里叶变换对为
X(jΩ)={-∞,+∞}x(t)*exp^-jΩt dt
x(t)=1/2π{-∞,+∞} X(JΩ)*e^jΩt dt
用DFT方法计算这对变换对的方法如下:
(a)对xn(t)以T为间隔进行采样,即xn(t)|t=nT= xa(nT)= x(n),由于
t→nT,dt→T, {-∞,+∞}→∑n={-∞,+∞}
因此得到
X(jΩ)≈∑n={-∞,+∞}x(nT)*exp^-jΩnT*T
x(nT)≈1/2π{0, Ωs} X(JΩ)*e^jΩnT Dω
(b)将序列x(n)= xn(t)截断成包含有N个抽样点的有限长序列
X(jΩ)≈T∑n={0,N-1}x(nT)*exp^-jΩnT*T
由于时域抽样,抽样频率为fs=1/T,则频域产生以fs为周期的周期延拓,如果频域是带限信号,则有可能不产生频谱混叠,成为连续周期频谱序列,频谱的周期为fs=1/T
(c)为了数值计算,频域上也要抽样,即在频域的一个周期中取N个样点,fs=NF0,每个样点间隔为F0,频域抽样使频域的积分式变成求和式,而在时域就得到原来已经截断的离散时间序列的周期延拓,时间周期为T0=1/F0。因此有
Ω→kΩ0,dΩ→Ω0,{-∞,+∞} dΩ→∑n={-∞,+∞}Ω0
T0=1/F0=N/fs=NT
Ω0=2ΠF0
Ω0T=Ω0/fs=2π/N
X(jkΩ0)≈T∑n={0,N-1}x(nT)*exp^-jkΩ0nT

㈩ 基于FFT的算法优化 要C语言完整程序(利用旋转因子的性质),有的请留言,答谢!!!(有核心代码,望指教

实现(C描述)

#include <stdio.h>

#include <math.h>

#include <stdlib.h>

//#include "complex.h"

// --------------------------------------------------------------------------

#define N 8 //64

#define M 3 //6 //2^m=N

#define PI 3.1415926

// --------------------------------------------------------------------------

float twiddle[N/2] = {1.0, 0.707, 0.0, -0.707};

float x_r[N] = {1, 1, 1, 1, 0, 0, 0, 0};

float x_i[N]; //N=8

/*

float twiddle[N/2] = {1, 0.9951, 0.9808, 0.9570, 0.9239, 0.8820, 0.8317, 0.7733,

0.7075, 0.6349, 0.5561, 0.4721, 0.3835, 0.2912, 0.1961, 0.0991,

0.0000,-0.0991,-0.1961,-0.2912,-0.3835,-0.4721,-0.5561,-0.6349,

-0.7075,-0.7733, 0.8317,-0.8820,-0.9239,-0.9570,-0.9808,-0.9951}; //N=64

float x_r[N]={1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,

0,0,0,0,0,0,0,0,

0,0,0,0,0,0,0,0,

0,0,0,0,0,0,0,0,

0,0,0,0,0,0,0,0,};

float x_i[N];

*/

FILE *fp;

// ----------------------------------- func -----------------------------------

/**

* 初始化输出虚部

*/

static void fft_init( void )

{

int i;

for(i=0; i<N; i++) x_i[i] = 0.0;

}

/**

* 反转算法.将时域信号重新排序.

* 这个算法有改进的空间

*/

static void bitrev( void )

{

int p=1, q, i;

int bit_rev[ N ]; //

float xx_r[ N ]; //

bit_rev[ 0 ] = 0;

while( p < N )

{

for(q=0; q<p; q++)

{

bit_rev[ q ] = bit_rev[ q ] * 2;

bit_rev[ q + p ] = bit_rev[ q ] + 1;

}

p *= 2;

}

for(i=0; i<N; i++) xx_r[ i ] = x_r[ i ];

for(i=0; i<N; i++) x_r[i] = xx_r[ bit_rev[i] ];

}

/* ------------ add by sshc625 ------------ */

static void bitrev2( void )

{

return ;

}

/* */

void display( void )

{

printf("\n\n");

int i;

for(i=0; i<N; i++)

printf("%f\t%f\n", x_r[i], x_i[i]);

}

/**

*

*/

void fft1( void )

{ fp = fopen("log1.txt", "a+");

int L, i, b, j, p, k, tx1, tx2;

float TR, TI, temp; // 临时变量

float tw1, tw2;

/* 深M. 对层进行循环. L为当前层, 总层数为M. */

for(L=1; L<=M; L++)

{

fprintf(fp,"----------Layer=%d----------\n", L);

/* b的意义非常重大,b表示当前层的颗粒具有的输入样本点数 */

b = 1;

i = L - 1;

while(i > 0)

{

b *= 2;

i--;

}

// -------------- 是否外层对颗粒循环, 内层对样本点循环逻辑性更强一些呢! --------------

/*

* outter对参与DFT的样本点进行循环

* L=1, 循环了1次(4个颗粒, 每个颗粒2个样本点)

* L=2, 循环了2次(2个颗粒, 每个颗粒4个样本点)

* L=3, 循环了4次(1个颗粒, 每个颗粒8个样本点)

*/

for(j=0; j<b; j++)

{

/* 求旋转因子tw1 */

p = 1;

i = M - L; // M是为总层数, L为当前层.

while(i > 0)

{

p = p*2;

i--;

}

p = p * j;

tx1 = p % N;

tx2 = tx1 + 3*N/4;

tx2 = tx2 % N;

// tw1是cos部分, 实部; tw2是sin部分, 虚数部分.

tw1 = ( tx1>=N/2)? -twiddle[tx1-N/2] : twiddle[ tx1 ];

tw2 = ( tx2>=N/2)? -twiddle[tx2-(N/2)] : twiddle[tx2];

/*

* inner对颗粒进行循环

* L=1, 循环了4次(4个颗粒, 每个颗粒2个输入)

* L=2, 循环了2次(2个颗粒, 每个颗粒4个输入)

* L=3, 循环了1次(1个颗粒, 每个颗粒8个输入)

*/

for(k=j; k<N; k=k+2*b)

{

TR = x_r[k]; // TR就是A, x_r[k+b]就是B.

TI = x_i[k];

temp = x_r[k+b];

/*

* 如果复习一下 (a+j*b)(c+j*d)两个复数相乘后的实部虚部分别是什么

* 就能理解为什么会如下运算了, 只有在L=1时候输入才是实数, 之后层的

* 输入都是复数, 为了让所有的层的输入都是复数, 我们只好让L=1时候的

* 输入虚部为0

* x_i[k+b]*tw2是两个虚数相乘

*/

fprintf(fp, "tw1=%f, tw2=%f\n", tw1, tw2);

x_r[k] = TR + x_r[k+b]*tw1 + x_i[k+b]*tw2;

x_i[k] = TI - x_r[k+b]*tw2 + x_i[k+b]*tw1;

x_r[k+b] = TR - x_r[k+b]*tw1 - x_i[k+b]*tw2;

x_i[k+b] = TI + temp*tw2 - x_i[k+b]*tw1;

fprintf(fp, "k=%d, x_r[k]=%f, x_i[k]=%f\n", k, x_r[k], x_i[k]);

fprintf(fp, "k=%d, x_r[k]=%f, x_i[k]=%f\n", k+b, x_r[k+b], x_i[k+b]);

} //

} //

} //

}

/**

* ------------ add by sshc625 ------------

* 该实现的流程为

* for( Layer )

* for( Granule )

* for( Sample )

*

*

*

*

*/

void fft2( void )

{ fp = fopen("log2.txt", "a+");

int cur_layer, gr_num, i, k, p;

float tmp_real, tmp_imag, temp; // 临时变量, 记录实部

float tw1, tw2;// 旋转因子,tw1为旋转因子的实部cos部分, tw2为旋转因子的虚部sin部分.

int step; // 步进

int sample_num; // 颗粒的样本总数(各层不同, 因为各层颗粒的输入不同)

/* 对层循环 */

for(cur_layer=1; cur_layer<=M; cur_layer++)

{

/* 求当前层拥有多少个颗粒(gr_num) */

gr_num = 1;

i = M - cur_layer;

while(i > 0)

{

i--;

gr_num *= 2;

}

/* 每个颗粒的输入样本数N' */

sample_num = (int)pow(2, cur_layer);

/* 步进. 步进是N'/2 */

step = sample_num/2;

/* */

k = 0;

/* 对颗粒进行循环 */

for(i=0; i<gr_num; i++)

{

/*

* 对样本点进行循环, 注意上限和步进

*/

for(p=0; p<sample_num/2; p++)

{

// 旋转因子, 需要优化...

tw1 = cos(2*PI*p/pow(2, cur_layer));

tw2 = -sin(2*PI*p/pow(2, cur_layer));

tmp_real = x_r[k+p];

tmp_imag = x_i[k+p];

temp = x_r[k+p+step];

/*(tw1+jtw2)(x_r[k]+jx_i[k])

*

* real : tw1*x_r[k] - tw2*x_i[k]

* imag : tw1*x_i[k] + tw2*x_r[k]

* 我想不抽象出一个

* typedef struct {

* double real; // 实部

* double imag; // 虚部

* } complex; 以及针对complex的操作

* 来简化复数运算是否是因为效率上的考虑!

*/

/* 蝶形算法 */

x_r[k+p] = tmp_real + ( tw1*x_r[k+p+step] - tw2*x_i[k+p+step] );

x_i[k+p] = tmp_imag + ( tw2*x_r[k+p+step] + tw1*x_i[k+p+step] );

/* X[k] = A(k)+WB(k)

* X[k+N/2] = A(k)-WB(k) 的性质可以优化这里*/

// 旋转因子, 需要优化...

tw1 = cos(2*PI*(p+step)/pow(2, cur_layer));

tw2 = -sin(2*PI*(p+step)/pow(2, cur_layer));

x_r[k+p+step] = tmp_real + ( tw1*temp - tw2*x_i[k+p+step] );

x_i[k+p+step] = tmp_imag + ( tw2*temp + tw1*x_i[k+p+step] );

printf("k=%d, x_r[k]=%f, x_i[k]=%f\n", k+p, x_r[k+p], x_i[k+p]);

printf("k=%d, x_r[k]=%f, x_i[k]=%f\n", k+p+step, x_r[k+p+step], x_i[k+p+step]);

}

/* 开跳!:) */

k += 2*step;

}

}

}

/*

* 后记:

* 究竟是颗粒在外层循环还是样本输入在外层, 好象也差不多, 复杂度完全一样.

* 但以我资质愚钝花费了不少时间才弄明白这数十行代码.

* 从中我发现一个于我非常有帮助的教训, 很久以前我写过一部分算法, 其中绝大多数都是递归.

* 将数据量减少, 减少再减少, 用归纳的方式来找出数据量加大代码的规律

* 比如FFT

* 1. 先写死LayerI的代码; 然后再把LayerI的输出作为LayerII的输入, 又写死代码; ......

* 大约3层就可以统计出规律来. 这和递归也是一样, 先写死一两层, 自然就出来了!

* 2. 有的功能可以写伪代码, 不急于求出结果, 降低复杂性, 把逻辑结果定出来后再添加.

* 比如旋转因子就可以写死, 就写1.0. 流程出来后再写旋转因子.

* 寥寥数语, 我可真是流了不少汗! Happy!

*/

void dft( void )

{

int i, n, k, tx1, tx2;

float tw1,tw2;

float xx_r[N],xx_i[N];

/*

* clear any data in Real and Imaginary result arrays prior to DFT

*/

for(k=0; k<=N-1; k++)

xx_r[k] = xx_i[k] = x_i[k] = 0.0;

// caculate the DFT

for(k=0; k<=(N-1); k++)

{

for(n=0; n<=(N-1); n++)

{

tx1 = (n*k);

tx2 = tx1+(3*N)/4;

tx1 = tx1%(N);

tx2 = tx2%(N);

if(tx1 >= (N/2))

tw1 = -twiddle[tx1-(N/2)];

else

tw1 = twiddle[tx1];

if(tx2 >= (N/2))

tw2 = -twiddle[tx2-(N/2)];

else

tw2 = twiddle[tx2];

xx_r[k] = xx_r[k]+x_r[n]*tw1;

xx_i[k] = xx_i[k]+x_r[n]*tw2;

}

xx_i[k] = -xx_i[k];

}

// display

for(i=0; i<N; i++)

printf("%f\t%f\n", xx_r[i], xx_i[i]);

}

// ---------------------------------------------------------------------------

int main( void )

{

fft_init( );

bitrev( );

// bitrev2( );

//fft1( );

fft2( );

display( );

system( "pause" );

// dft();

return 1;

}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sshcx/archive/2007/06/14/1651616.aspx