浅谈傅里叶——8. 一维iDFT的实现

article/2025/9/26 21:38:43

这是本系列的最后一章,原先计划是把这部分内容一并挪到上一章里的,不过喜欢凑一个整数,而且想骗一点流量,所以把它们拆成了两部分。我们在前面的内容中,通过使用不同的频率信号对原始信号进行采样,从而分析出原始波形的频率组成。
我们通过离散傅里叶DFT计算出频率后,经过处理后,有时候还是有需要将频率转换回时域信号。虽然这个部分也不是什么困难的事,作为这个系列的收尾,我还是提供它的1维的逆计算代码实现。

文章目录

  • 前期准备
    • 复平面空间
    • iDFT基本公式
    • 复数乘法
    • 基信号
  • 实现代码
    • 基信号实现
    • 信号叠加
    • 实数平面映射
  • 后记

前期准备

复平面空间

虽然我已经在前面的文章里提到过复平面空间,对于一个向量来说,它在复平面上存在着和它实数部相同,虚数部相反的另一个向量,这个称为共轭。

在这里插入图片描述
由于我们的数据经过傅里叶变换后,全部变成了在复平面表示,所以在求解出 C k C_k Ck 数组后,我们要做的一个工作就是把复数重新映射到实数平面。为了方便计算,我们把全部复数,以复平面上的向量进行表示,那么对于原函数 f ( x ) f(x) f(x) 来说,对于某一点 x o x_o xo 上的振幅,就可以表示为该点在复平面上的向量的模,即:

a m p l i t u d e ( x o ) = a 2 + b 2 amplitude(x_o) = \sqrt{ a^2 + b^2 } amplitude(xo)=a2+b2

而该点在原函数上处于正区间还是负区间,则与该点在复平面上映射的实数轴的正负号是一致的。所以,如果试图绘制原函数,那么我们唯一缺少的就是它在X轴上的长度,即时间 t t t

所幸,时间 t t t 与我们定义的采样率相关,即DFT函数里指数部分的 2 π k n / N 2\pi k n/N 2πkn/N。也就是说,如果DFT 长度为100,采样率为100Hz,那么原函数在X轴上也有100个点。

iDFT基本公式

f ( x ) = 1 N Σ F ( k ) e 2 j π k n / N f(x) = \frac{1}{N} \Sigma F(k) e^{2j \pi kn/N} f(x)=N1ΣF(k)e2jπkn/N

复数乘法

观察离散傅里叶函数 f ( x ) = 1 N Σ F ( k ) e 2 j π k n / N f(x) = \frac{1}{N} \Sigma F(k) e^{2j \pi kn/N} f(x)=N1ΣF(k)e2jπkn/N,其核心部分就是 F ( k ) F(k) F(k) e 2 j π k n / N e^{2j \pi kn/N} e2jπkn/N ,这里的 F ( k ) F(k) F(k) 也就是 C k C_k Ck 我们前面章节程序求解出的复数数组。而 e 2 j π k n / N e^{2j \pi kn/N} e2jπkn/N 用欧拉公式展开后,

e 2 j π k n / N = c o s ( 2 π k n / N ) + j s i n ( 2 π k n / N ) e^{2j \pi kn/N} = cos(2 \pi kn/N) + j sin(2 \pi kn/N) e2jπkn/N=cos(2πkn/N)+jsin(2πkn/N)

通过带入不同的 k k k,也就是采样频率后,也会得到一组复数数组。所以这里可以用到矩阵乘法,也可以逐项的使用复数乘法直接计算,复数乘法的运算法表示如下:

A ⃗ ⋅ B ⃗ = ( a , b j ) ( c , d j ) = a c − b d + ( a d + c b ) j \vec{A} \cdot \vec{B} = (a, bj)(c, dj) = ac - bd + (ad + cb)j A B =(a,bj)(c,dj)=acbd+(ad+cb)j

基信号

傅里叶的本质是有一组不同频率的基信号加和而成。而基信号由公式 s ( x o ) = C k ⋅ e ω s(x_o) =C_k \cdot e^{\omega} s(xo)=Ckeω 描述,你可以采用两种不同的方式构成这个信号,一种是基于欧拉坐标系,以给定实数轴长度,然后根据 C k C_k Ck 贡献值,生成新的基信号;

另一种是比较常见的,基于极坐标的方式,生成基信号。

不论你使用哪一种方法,我的建议是最好重构信号的过程,与频率分析的过程一致,因为一个细微的疏忽,你会得到完全不一样的答案。

在上一章的代码中,我采用的是基于极坐标的方式生成 C k C_k Ck,那么基于这一原则,我们就采用逆过程,重新生成基信号。

实现代码

基信号实现

def calculate_base_fx(Ck, freq, N):pi = np.pi  # pik = freq  # sampling frequencysig_cos = []sig_sin = []for n in range(N):  # x(0), x(1), x(2), ... x(N)r_sig = cos(2 * pi * n * k / N)i_sig = sin(2 * pi * n * k / N)real, imag = complex_multi(r_sig, i_sig, Ck.real, Ck.imag)# reconstruct signalssig_cos.append(real)sig_sin.append(imag)return sig_cos, sig_sin

这一块代码我不做过多解释,它实现的功能,即基信号的生成:

e 2 j π k n / N = c o s ( 2 π k n / N ) + j s i n ( 2 π k n / N ) e^{2j \pi kn/N} = cos(2 \pi kn/N) + j sin(2 \pi kn/N) e2jπkn/N=cos(2πkn/N)+jsin(2πkn/N)

信号叠加

def idft_1d(dft):N = len(dft)freq_real, freq_imag = np.zeros(N), np.zeros(N)maximum_sampling_freq = N  # 希望使用的采样最大频率increased_sampling_freq = maximum_sampling_freq / N  # 采样率步进current_sampling_freq = 0  # 当前的采样率,从 0Hz 开始进行采样for ck in dft:fxc, fxs = calculate_base_fx(ck, current_sampling_freq, N)# sigma all basis frequenciesfreq_real = freq_real + np.array(fxc)freq_imag = freq_imag + np.array(fxs)# increase freqcurrent_sampling_freq = current_sampling_freq + increased_sampling_freqreturn freq_real / N, freq_imag / N

这一部执行完毕后,我们会得到原始信号,但是是在复平面上的表达,所以接下来要增加一个简单的过程,把信号映射到实数平面上。

实数平面映射

def reconstruct(real, imag):signal = []for i in range(len(real)):# compute amplitudeamp = np.sqrt(real[i] ** 2 + imag[i] ** 2)if real[i] < 0:signal.append(-amp)else:signal.append(amp)return signal

至此,信号复原完毕,然后我们检查一下输出:

    _axis, _signal = generate_original_signals(50) # 生成长度50的原始信号_dft = dft_1d(_signal) # 使用之前的dft函数,对信号频率进行解析_real, _imag = idft_1d(_dft)  # 执行逆计算,重构信号_re_sig = reconstruct(_real, _imag)  # 把原始信号映射到实数平面validate_idft(_signal, _re_sig)  # 验证结果

输出

pt:0    sig:    0.0             res:    0.0             var     0.0
pt:1    sig:    1.1623          res:    1.1623          var     0.0
pt:2    sig:    1.5515          res:    1.5515          var     0.0
pt:3    sig:    1.0498          res:    1.0498          var     0.0
pt:4    sig:    0.2424          res:    0.2424          var     0.0
pt:5    sig:    -0.1726         res:    -0.1726         var     0.0
pt:6    sig:    -0.0364         res:    -0.0364         var     0.0
pt:7    sig:    0.1802          res:    0.1802          var     0.0
pt:8    sig:    -0.0831         res:    -0.0831         var     0.0
pt:9    sig:    -0.8452         res:    -0.8452         var     0.0
pt:10   sig:    -1.4958         res:    -1.4958         var     0.0
pt:11   sig:    -1.351          res:    -1.351          var     0.0
pt:12   sig:    -0.3271         res:    -0.3271         var     0.0
pt:13   sig:    0.9217          res:    0.9217          var     0.0
pt:14   sig:    1.5475          res:    1.5475          var     0.0
pt:15   sig:    1.2347          res:    1.2347          var     0.0
pt:16   sig:    0.4294          res:    0.4294          var     0.0
pt:17   sig:    -0.1271         res:    -0.1271         var     0.0
pt:18   sig:    -0.1036         res:    -0.1036         var     0.0
pt:19   sig:    0.1546          res:    0.1546          var     0.0
pt:20   sig:    0.0415          res:    0.0415          var     0.0
pt:21   sig:    -0.6342         res:    -0.6342         var     0.0
pt:22   sig:    -1.3871         res:    -1.3871         var     0.0
pt:23   sig:    -1.4807         res:    -1.4807         var     0.0
pt:24   sig:    -0.6391         res:    -0.6391         var     0.0
pt:25   sig:    0.6391          res:    0.6391          var     0.0
pt:26   sig:    1.4807          res:    1.4807          var     0.0
pt:27   sig:    1.3871          res:    1.3871          var     0.0
pt:28   sig:    0.6342          res:    0.6342          var     0.0
pt:29   sig:    -0.0415         res:    -0.0415         var     0.0
pt:30   sig:    -0.1546         res:    -0.1546         var     0.0
pt:31   sig:    0.1036          res:    0.1036          var     0.0
pt:32   sig:    0.1271          res:    0.1271          var     0.0
pt:33   sig:    -0.4294         res:    -0.4294         var     0.0
pt:34   sig:    -1.2347         res:    -1.2347         var     0.0
pt:35   sig:    -1.5475         res:    -1.5475         var     0.0
pt:36   sig:    -0.9217         res:    -0.9217         var     0.0
pt:37   sig:    0.3271          res:    0.3271          var     0.0
pt:38   sig:    1.351           res:    1.351           var     0.0
pt:39   sig:    1.4958          res:    1.4958          var     0.0
pt:40   sig:    0.8452          res:    0.8452          var     0.0
pt:41   sig:    0.0831          res:    0.0831          var     0.0
pt:42   sig:    -0.1802         res:    -0.1802         var     0.0
pt:43   sig:    0.0364          res:    0.0364          var     0.0
pt:44   sig:    0.1726          res:    0.1726          var     0.0
pt:45   sig:    -0.2424         res:    -0.2424         var     0.0
pt:46   sig:    -1.0498         res:    -1.0498         var     0.0
pt:47   sig:    -1.5515         res:    -1.5515         var     0.0
pt:48   sig:    -1.1623         res:    -1.1623         var     0.0
pt:49   sig:    -0.0            res:    0.0             var     0.0

重构的信号与原始信号之间的方差为0,完美重构。

后记

尽管从理论上说,离散傅里叶是连续傅里叶的扩展形式,但实际上用的最多的还是离散傅里叶,甚至你可以不必理解什么是复平面,什么是连续傅里叶,什么是无穷级数。毕竟无论是python,还是C/C++,甚至其他工程语言,只要涉及数值计算,就一定有包含傅里叶分析的数学工具包可以使用,而且执行效率已经被优化的非常快。

这是否意味着入门者不再需要了解傅里叶怎么计算了吗?对此我有一些个人体会,当你遇到一些噪音特别大,有效信号很弱的场景时,你需要根据使用场景进行巧妙的设计参数才能比较理想的提取出你需要的信号部分。

如果单纯的设定滤波阈值,很可能在某些情况下可以正常使用,而其他场景下随缘了。事实上,使用傅里叶处理数据都是在假设数据是理想条件下输入,比如有较高的SNR比。但是实际工作中,这种情况往往难得,换句话说,真实环境实在过于Egg疼了,所以在很多情况下我并不会优先考虑傅里叶。

但是,这不妨碍傅里叶本人及其思想对于科学、工程界的重要贡献。事实上通过对傅里叶这一伟大思想的梳理,能学会更多,你说是吧?


http://chatgpt.dhexx.cn/article/8aNTYUxo.shtml

相关文章

idft重建图像 matlab_1周学FFT——第2天 DFT和IDFT的MATLAB实现

根据定义式&#xff0c;可写出DFT的MATLAB代码如下[从玉良&#xff0c;2009&#xff0c;p72]&#xff1a; function [f, Xk] mydft(xn, fs, N) % DFT n [0:1:N-1]; k n; WN exp(-j*2*pi/N); nk n * k; % N^2 times multiply Xk xn(1:N) * WN.^nk; % N^3 times multiply f …

FT,DTFT,DFT,IDFT,FFT含义

1.傅立叶变换FT(Fourier Transform) 性质&#xff1a;时域连续&#xff0c;频域连续 周期信号只有傅立叶级数&#xff0c;严格意义上讲&#xff0c;没有傅立叶变换&#xff1b;但可以令周期信号的周期趋于无穷大&#xff0c;这样&#xff0c;将周期信号变为非周期信号&#x…

DFT与IDFT

DFT与IDFT 一.方法简介 序列x(n)(n0,1,…N-1)的DFT定义为 X &#xff08; k &#xff09; ∑ n 0 N − 1 x ( n ) e − j 2 π n k N X&#xff08;k&#xff09;\sum_{n0}^{N-1}x(n)e^{-j\frac{2\pi nk}{N}} X&#xff08;k&#xff09;n0∑N−1​x(n)e−jN2πnk​ 设 x …

IDFT的python实现

IDFT IDFT(Inverse Discrete Fourier Transform), 傅里叶逆变换&#xff0c;可以将频域信号转换到时域中, 它的公式非常简单&#xff1a; x [ n ] 1 N ∑ k 0 N − 1 X [ k ] e j 2 π k n / N x[n] \frac{1}{N} \sum_{k0}^{N-1} X[k] e^{j2\pi kn/N} x[n]N1​k0∑N−1​X…

一文搞懂:FT、DTFT、DFT、IDFT

一文搞懂&#xff1a;FT、DTFT、DFT、IDFT 写在前面一切为了计算机的处理推导步骤 总结 写在前面 近期重温了一下可爱的数字信号处理&#xff0c;又回想起当初被 FT、DTFT、DFT、IDFT 这几兄弟折腾的傻傻分不清的日子&#xff0c;今天特地在此对它们进行一个梳理。 珠玉在前&a…

LDUOJ spj 修改

特判使用教程 感谢涛巨 记录一下&#xff0c;省的以后忘记了。 /* Utility functions for writing output validators for the Kattis* problem format.** The primary functions and variables available are the following.* In many cases, the only functions needed are …

noip 2022 第二题 喵了个喵 meow 在 Lemon LemonLime 中 SPJ Special Judge 测评 配置 设置

noip 2022 第二题 喵了个喵 meow 在 Lemon LemonLime 中 SPJ Special Judge 测评配置设置 比赛目录如下&#xff1a; 用户程序(meow.cpp)如下&#xff1a; #include <bits/stdc.h> using namespace std;template<typename T> inline void read(T &x) {x 0; …

数据库例题(创建数据库SPJ包含S、P、J和SPJ表)

目录 运行说明 例题 例题解答 运行说明 1、运行环境&#xff1a;win10 2、所需步骤&#xff1a; &#xff08;1&#xff09; 通过PowerDesigner软件创建逻辑数据模型(CDM)&#xff0c;再将其转换为物理数据模型(PDM)&#xff0c;再导出为SQL语句。 &#xff08;2&#xff…

Lemon LemonLime 中 SPJ Special Judge 使用 实践 入门 a

精度需要SPJ 入门&#xff1a; 题目&#xff0c;以整数形式给定圆的半径&#xff0c;输出该圆的周长&#xff0c;该圆的面积。 比赛目录如下&#xff1a; 标准输入输出数据如下&#xff1a; circle1.in 1 circle1.ans 6.283185 3.141593 circle2.in 2 circle2.ans 12.566370 12…

数据库---[复习2]---数据查询---设有一个SPJ数据库,包括S、P、J及SPJ4个关系模式··· ···

文章目录 问题重述数据表S表&#xff1a;P表&#xff1a;J表&#xff1a;SPJ表&#xff1a; 问题解析1. 找出所有供应商的姓名和所在城市2. 找出所有零件的名称&#xff0c;颜色&#xff0c;重量3. 找出使用供应商S1所供应零件的工程号码4. 找出工程项目J2使用的各种零件的名称…

Lemon LemonLime 中 SPJ Special Judge 使用 实践 入门 c

多解需要SPJ 入门&#xff1a; 题目&#xff1a;输出 Hello, World!&#xff0c;大小写不限。 比赛目录如下&#xff1a; 标准输入输出数据如下&#xff1a; string1.in(空文件&#xff0c;里面没有任何内容) string1.ans Hello, World! 用户程序(string.cpp)如下&#xff1a; …

Lemon LemonLime 中 SPJ Special Judge 使用 实践 入门 b

多解需要SPJ 入门&#xff1a; 题目&#xff1a;给出一个不小于12的正整数n&#xff0c;请你输出两个合数&#xff0c;使他们的和等于n,注意&#xff0c;每个测试&#xff0c;有多组测试数据. 比赛目录如下&#xff1a; 标准输入输出数据如下&#xff1a; sum1.in 2 12 13 sum1…

如何配置luogu,codeforces的spj(special judge)

洛谷的spj配置很资瓷啊&#xff0c;以下部分引用来自luogu官方链接 codeforces同理 https://www.luogu.org/wiki/show?name%E5%B8%AE%E5%8A%A9%EF%BC%9Aspecial%20judge 搞了一上午1020导弹拦截的spj step1 先从链接中下载那个testlib-master文件解压后&#xff0c;在那个…

SPJ数据库例题(数据库实验)

题目内容&#xff1a; 设有一个SPJ数据库&#xff0c;包括S&#xff0c;P&#xff0c;J&#xff0c;SPJ四个关系模式&#xff1a; S&#xff08;SNO&#xff0c;SNAME&#xff0c;STATUS&#xff0c;CITY&#xff09;&#xff1b; P&#xff08;PNO&#xff0c;PNAME&#xff0…

mysql建立spj_数据库概论——SQL练习一(SPJ零件问题)

系统: MySQL 8.0.19 题目: 三张表: S(SNO, SNAME, STATUS, CITY) P(PNO, PNAME, COLOR, WEIGHT, CITY) J(JNO, JNAME,CITY) SPJ(SNO, PNO, JNO, PRICE, QTY) S表示供应商,各属性依次为供应商号,供应商名,供应商状态值,供应商所在城市; P表示零件,各属性依次为零件号,…

SPJ数据库例题

1道论述题&#xff1a; 书本P71页习题6&#xff1a; 设有一个SPJ数据库&#xff0c;包括S&#xff0c;P&#xff0c;J&#xff0c;SPJ四个关系模式&#xff1a; S&#xff08;SNO&#xff0c;SNAME&#xff0c;STATUS&#xff0c;CITY&#xff09;&#xff1b; P&#xff08;P…

sql spj

一 select sno,snamevar from student; select sno,snamevar,sdeptvar from student; select * from student; select snamevar,2014-age from student; select snamevar,‘year of birth’,2014-age,lower(sdeptvar) from student; select snamevar from student where …

浅谈online judge平台 spj [special judge] 使用 | 修改问题

浅谈oj平台 spj 使用 | 修改问题 首先&#xff1a;参数对应返回值代码提交几种spj第一种&#xff1a;简单的一类特判第二种&#xff1a;多组输入的特判第三种&#xff1a;需要判断特殊情况[impossible]第四种&#xff1a;带有[testlib.h]的spj第五种&#xff1a;GCPC [German C…

HUSTOJ SPJ 示例

什么是 SPJ SPJ 是 Special Judge 的意思。 什么时候使用 SPJ 当题目答案不止一个的时候&#xff0c;我们就必须使用 SPJ。 如何使用 SPJ 题目中打开 SPJ 首先&#xff0c;我们需要在出题的时候&#xff0c;增加 SPJ 选项&#xff0c;如下图所示。 题目保存后&#xff0…

《数据库原理与运用》上机实验之SPJ

《数据库原理与运用》上机实验之SPJ 前言一、关系模式二、使用SQL语句创建、修改基本表1.对基本表字段名的增加2.对基本表字段名的增加3.索引 二、使用SQL语句对数据库表的单表查询1.对指定列的查询2.对表达式计算和改变表达方式的查询3.消除重复行的查询4.WHERE条件查询5.分组…