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

news/2024/7/5 4:01:45

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.1415927

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

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

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

	free(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;
}

int main() {
	double xn[9] = {1,2,3,4,5,0,0,0,85};
	dft(xn, sizeof(xn) / sizeof(double));
	system("pause");
	return 0;
}

运行结果:

暂未发现问题。


http://lihuaxi.xjx100.cn/news/1605111.html

相关文章

ssm+vue的车辆出租管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的车辆出租管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

基于SpringBoot的音乐网站

目录 前言 一、技术栈 二、系统功能介绍 用户信息管理 歌曲分类管理 歌曲信息管理 轮播图管理 歌曲信息 歌曲评论 用户注册 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施…

windows桌面程序与服务程序通过公共文件目录交互

windows权限管理越来越严格&#xff0c;桌面应用和服务之间的交互就很成问题。服务通常以独立的服务身份运行&#xff0c;而且在用户登录之前就开始运行&#xff0c;显然不能去访问用户私人的数据&#xff0c;况且既然是服务&#xff0c;同时为多个不同的登录用户服务也是很常见…

mysql双主主键冲突

在MySQL中&#xff0c;当使用双主键&#xff08;也称为复合主键&#xff09;时&#xff0c;可能会遇到主键冲突的问题。主键冲突通常发生在以下情况&#xff1a; 插入冲突&#xff1a;当尝试插入一行数据时&#xff0c;该行的复合主键已经存在于表中时&#xff0c;就会发生主键…

记录宝塔面板申请ssl证书报错 Invalid version. The only valid version for X509Req is 0

问题 宝塔面板申请ssl证书报错 Invalid version. The only valid version for X509Req is 0。 原因是由于服务器端使用了不兼容的 OpenSSL 版本导致的&#xff0c;服务器端的X509Req 版本只支持 0&#xff0c;而宝塔这边默认的版本为2。 我的是之前可以申请ssl&#xff0c;过…

面试算法25:链表中的数字相加

题目 给定两个表示非负整数的单向链表&#xff0c;请问如何实现这两个整数的相加并且把它们的和仍然用单向链表表示&#xff1f;链表中的每个节点表示整数十进制的一位&#xff0c;并且头节点对应整数的最高位数而尾节点对应整数的个位数。例如&#xff0c;两个分别表示整数98…

RPA技术如何重塑制造业的未来

根据Statista的预测&#xff0c;2023年RPA技术的全球市场规模预计将达到100亿美元&#xff0c;制造业将在实现这一目标方面发挥重要作用。这个蓬勃发展的行业面临着对不同重复过程的更多依赖&#xff0c;因此选择了数字化转型&#xff0c;制造业中的RPA有助于实现自动化和优化核…

智安网络|边缘计算与分布式存储:数字化时代的新趋势

随着数字化时代的到来&#xff0c;数据的产生和存储需求呈现爆炸式增长&#xff0c;传统的集中式存储架构已经无法满足大规模数据存储和处理的需求。分布式存储系统应运而生&#xff0c;成为应对数据存储和处理挑战的解决方案。然而&#xff0c;技术的发展不会止步于此&#xf…