离散傅里叶变换(DFT)的推导及C语言实现

1、傅里叶变换(FT)

傅里叶变换(连续时间傅里叶变换)是该部分内容的理论基础,回顾一下:

傅里叶变换:

        F(\omega ) = \int_{-\infty }^{+\infty}f(t)e^{-j\omega t}dt

傅里叶逆变换:

        f(t ) = \frac{1}{2\pi }\int_{-\infty }^{+\infty}F(\omega )e^{j\omega t}d\omega

以上是连续时间傅里叶变换,但计算机只能处理离散的数据。因此有了离散傅里叶变换(DFT),下面进行详细推导。


2、离散傅里叶变换(DFT)

2.1 采样和离散时间傅里叶变换(DTFT)

使用采样可将连续域上的数据离散化。信号学科里面使用冲激序列串来对连续信号采样。

有信号f(t),现对其采样。若采样频率为 f_{s},则采样间隔 T_{s} = \frac{1}{f_{s}} ,用以采样的冲激序列串定义为:

        \delta_{s}(t) = \sum_{n=-\infty}^{+\infty}\delta(t-nT_{s})

因此采样后的信号为:

        f_{s}(t)=\sum_{n=-\infty}^{+\infty}f(t)\delta(t-nT_{s})

此时将采样后信号 f_{s}(t) 代入傅里叶变换公式:

        F_s(\omega ) = \int_{-\infty }^{+\infty}\left [ \sum_{n=-\infty}^{+\infty}f(t)\delta(t-nT_{s}) \right ]e^{-j\omega t}dt

交换积分与求和次序:

        F_s(\omega ) = \sum_{n=-\infty}^{+\infty}\int_{-\infty }^{+\infty}f(t)\delta(t-nT_{s})e^{-j\omega t}dt

由 \delta (t) 函数的筛选性 \int_{-\infty}^{+\infty}x(t)\delta (t-t_0{})dt=x(t_0),将上式中 f(t)e^{-j\omega t} 看成x(t), 得到离散时间傅里叶变换(DTFT)

        F_s(\omega ) = \sum_{n=-\infty}^{+\infty}f(nT_{s})e^{-j\omega nT_s}

因为 nT_{s} 表示采样的时间点,所以可令 k = nT_{s},因此离散时间傅里叶变换的更一般形式为:

        F_s(\omega ) = \sum_{k=-\infty}^{+\infty}f(k)e^{-j\omega k}


2.2 离散傅里叶变换(DFT)

2.1中通过采样使得信号在时域离散化,但并不能保证其频域也离散化,同样不利于计算机处理。

由性质:时域离散,频域周期化;频域离散,时域周期化。因此若想让信号在频域也离散,则需要该信号在时域上为周期信号。

但原信号不一定为周期信号。解决方式是周期延拓:截取原无限长信号的N个采样点,假设:

N个采样点为原信号的一个周期;

  

② N个采样点外为该N点的周期延拓。

 

这样原先的离散非周期信号就变成离散周期信号,因此频域得以离散化。

在上述周期延拓的基础上,假设采样间隔为 T_{s} ,则N个采样点的采样周期 T_{0}=NT_{s},从连续信号f(t)中截取的N个采样点的信号可表示为:

        x(t) = \sum_{n=0}^{N-1}f(t)\delta (t-nT_s)

因为周期延拓,x(t)为是周期信号,周期函数的傅里叶级数为:​ 

        F(k\omega)=\frac{1}{T}\int_{0}^{T}f(t)e^{-jk\omega t}dt 

x(t)代入其中,得:

        X(k\omega)=\frac{1}{T_0}\int_{0}^{T_0}\left [ \sum_{n=0}^{N-1}f(t)\delta (t-nT_s) \right ]e^{-jk\omega_{}t}dt

交换积分与求和次序:

        X(k\omega)=\frac{1}{T_0}\sum_{n=0}^{N-1}\int_{0}^{T_0} f(t)\delta (t-nT_s) e^{-jk\omega_{}t}dt

同理,由 \delta (t) 函数的筛选性,上式变为:

        X(k\omega)=\frac{1}{T_0}\sum_{n=0}^{N-1}f(nT_s)e^{-jk\omega nT_s}

因为T_{0}=NT_{s}\omega =\frac{2\pi }{T0}=\frac{2\pi }{NT_{s}},代入上式:

        X(k\omega)=\frac{1}{NT_{s}}\sum_{n=0}^{N-1}f(nT_s)e^{-j\frac{2\pi }{N} kn}

x[n]=f(nT_s)X(k\omega)T_s=X[k],得离散傅里叶变换(DFT)的表达式为:

        X[k]=\sum_{n=0}^{N-1}x[n]e^{-j\frac{2\pi }{N} kn},  0\leq k< N 且 k\in Z

离散傅里叶逆变换(IDFT)的表达式为:

        x[n]=\frac{1}{N}\sum_{n=0}^{N-1}X[k]e^{j\frac{2\pi }{N} kn}

注意:为了满足正逆变换的自洽,\frac{1}{N}放在正逆变换其中之一前就可以,通常放在逆变换前。

补充:令W_{N}^{kn}=e^{-j\frac{2\pi }{N} kn},则:

        X[k]=\sum_{n=0}^{N-1}x[n]W_{N}^{kn}


2.3 离散傅里叶变换(DFT)的C语言实现

根据上述推导出的公式,很容易编码实现。如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define PI 3.141593

double realComput(double xn[], int ndft, int k);
double imageComput(double xn[], int ndft, int k);

typedef struct {
	double real;
	double image;
} Complex;

Complex* dft(double x[], int ndft) {
	Complex* dftRes = (Complex*)malloc(ndft * sizeof(Complex));
	if (dftRes == NULL) {
		return;
	}

	for (int i = 0; i < ndft; ++i) {
		dftRes[i].real = realComput(x, ndft, i);
		dftRes[i].image = imageComput(x, ndft, i);
		// printf("%lf + %lfi\n", dftRes[i].real, dftRes[i].image);
	}
	return dftRes;
}

double realComput(double xn[], int ndft, int k) {
	double realPart = 0;
	for (int i = 0; i < ndft; ++i) {
		realPart += xn[i] * cos(2 * PI / ndft * k * i);
	}
	return realPart;
}

double imageComput(double xn[], int ndft, int k) {
	double imagePart = 0;
	for (int i = 0; i < ndft; ++i) {
		imagePart -= xn[i] * sin(2 * PI / ndft * k * i);
	}
	return imagePart;
}

double* ampSpectrum(Complex* dftRes, int ndft) {
	double* amp = (double*)malloc(sizeof(double) * ndft);
	if (amp == NULL) {
		return;
	}
	for (int i = 0; i < ndft; ++i) {
		amp[i] = sqrt(dftRes[i].real * dftRes[i].real+ dftRes[i].image* dftRes[i].image);
	}
	return amp;
}

double* phaseSpectrum(Complex* dftRes, int ndft) {
	double* phase = (double*)malloc(sizeof(double) * ndft);
	if (phase == NULL) {
		return;
	}
	for (int i = 0; i < ndft; ++i) {
		phase[i] = atan2(dftRes[i].image, dftRes[i].real);
	}
	return phase;
}

void testDFT() {
	double xn[] = { 1, 2, 3, 4, 6, 41, 0, 855, 954, -1 };
	int ndft = sizeof(xn) / sizeof(double);
	Complex* dftRes = dft(xn, ndft);

	double* ampRes = ampSpectrum(dftRes, ndft);
	double* phaRes = phaseSpectrum(dftRes, ndft);

	for (int i = 0; i < ndft; ++i) {
		printf("%lf + %lfi\n", dftRes[i].real, dftRes[i].image);
	}
	printf("\n");

	for (int i = 0; i < ndft; ++i) {
		printf("%lf, ", ampRes[i]);
	}
	printf("\n");

	for (int i = 0; i < ndft; ++i) {
		printf("%lf, ", phaRes[i]);
	}
	printf("\n");

	free(dftRes);
	free(ampRes);
	free(phaRes);
}

int main() {
	testDFT();
	return 0;
}

运行结果:

暂未发现问题。

  • 9
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: 离散傅里叶变换DFT)是指将一个离散的信号序列转换为其频域表示的过程。它把一个有限长的离散序列映射到一个有限长的频域序列。 离散傅里叶变换傅里叶变换在离散输入上的推广。它将一个长度为N的离散序列转换为一个长度为N的频域序列。在时域上,输入序列可以表示为离散时间的采样点集合。在频域上,它表示了输入信号的不同频率成分的幅度和相位。 离散傅里叶变换的计算过程包括两个步骤:首先,通过线性组合计算正弦和余弦函数的离散采样来表示信号;然后,再次对这些离散采样应用傅里叶变换公式以得到频域表示。 离散傅里叶变换广泛应用于信号处理和图像处理等领域。它可以用于频域滤波、快速傅里叶变换(FFT)、频谱分析等。通过DFT,我们能够将一个时域上的信号转换为其频域表示,从而能够更好地理解和处理信号的频率特性。 尽管离散傅里叶变换可以通过直接计算实现,但其计算复杂度较高,特别是对于较长的输入序列。快速傅里叶变换(FFT)是一种高效的算法,能够在O(NlogN)时间复杂度内计算离散傅里叶变换,其被广泛应用于实际应用中。 总之,离散傅里叶变换是将离散序列转换为其频域表示的过程,通过DFT我们可以了解信号的频率特性,并在信号处理中得到广泛应用。 ### 回答2: 离散傅里叶变换DFT)是将离散时间域信号转换成频域信号的一种数学变换方法。在信号处理和图像处理领域中广泛应用。 DFT的基本原理是将一个离散时间域信号分解为一系列复数的正弦和余弦函数分量,表示信号在不同频率上的振幅和相位信息。通过DFT,我们可以得到信号的频率特性,如频谱图、频率分量以及它们在时间上的实现方式。 DFT的计算是通过对输入信号的N个离散采样点进行离散傅里叶变换公式的运算得到的。公式可以描述为: X[k] = Σ(n=0 to N-1) x[n] * W^(-kn) 其中,X[k]表示输出频域信号的第k个频率分量,x[n]表示输入的时间域信号的第n个采样点,N表示信号的采样点数,W为复数旋转因子,定义为W = e^(-j2π/N)。 DFT计算的复杂度是O(N^2),这意味着当信号的采样点数增加时,计算所需的时间也会呈平方倍数增长。为了提高计算效率,可以使用快速傅里叶变换(FFT)算法,将计算复杂度降低到O(NlogN)的级别。 通过DFT,我们可以从时域的输入信号中得到其频域的频谱信息,进而可以进行频域滤波、频谱分析、频率特征提取等一系列信号处理操作。此外,DFT还广泛应用于音频处理、图像处理、通信系统等领域中。 ### 回答3: 离散傅里叶变换(Discrete Fourier Transform,DFT)是一种将离散序列(通常是时域上的信号)转换为频域上的表示的数学工具。它是傅里叶变换在离散信号上的推广。 DFT将一个长度为N的离散序列X={x_0, x_1, x_2, ..., x_{N−1}}转换为其频域表示X'={X_0, X_1, X_2, ..., X_{N−1}}。其中,X_k是X的第k个频谱系数,k=0,1,2,...,N−1。DFT的数学公式是: X_k = ∑_{n=0}^{N−1} x_n * exp(−2πikn/N),k=0,1,2,...,N−1。 DFT将一个信号分解为一系列正弦和余弦波的和,这些波的频率从0到N-1,每个波的振幅由X_k决定。相反地,逆DFT(IDFT)可以从频域表示恢复出原始的时域序列。 DFT的应用十分广泛。对于信号处理,DFT可以用于频域滤波、谱分析和频谱合成等。在通信系统中,DFT被广泛应用于正交频分复用(OFDM)技术,其中信号在频域上被划分为多个子载波进行传输,利用DFT实现时域与频域之间的转换。此外,DFT还被应用于图像处理、声音合成、压缩和音频编码等领域。 尽管DFT是一种强大的工具,它的计算复杂度较高,特别是对于大规模的输入序列。为了解决这个问题,人们发展出了快速傅里叶变换(Fast Fourier Transform,FFT)算法,它通过利用DFT的对称性和周期性,将计算复杂度从O(N^2)降低到O(NlogN)。FFT广泛应用于实际工程中,提高了计算效率。 总结来说,DFT是将离散序列转换为频域表示的数学工具,广泛应用于信号处理、通信系统、图像处理等领域。它的计算复杂度较高,但通过FFT等算法可以得到高效的计算方法,为实际应用提供了便利。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

伟大的马师兄

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

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

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

打赏作者

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

抵扣说明:

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

余额充值