数字信号处理基础回顾:DFT、卷积定理与线性/循环卷积

各位同学,咱们今天聊点基础,但基础往往最要命。我记得刚入行那会儿,总觉得DFT和卷积就是数学公式,跟硬件设计没啥关系。直到第一次在FPGA上做实时滤波,发现时序怎么都跑不满,才意识到——嗯,这些理论是真正能卡住你项目的硬骨头。

这一节,我带你快速过一遍DFT原理、卷积定理,以及线性卷积和循环卷积的区别。别小看这些,后面做FFT卷积一体化设计,全得靠它们撑腰。

离散傅里叶变换(DFT)原理

说白了,DFT就是把时域信号掰开,看看它由哪些频率成分组成。你想想看,一个连续的正弦波,采样成离散点后,我们怎么知道它的频率?DFT就是干这个的。

公式长这样:

X[k] = Σ_{n=0}^{N-1} x[n] · e^{-j(2π/N)kn}

其中:

  • x[n]:时域采样序列,长度N
  • X[k]:频域结果,k=0,1,...,N-1
  • e^{-j(2π/N)kn}:旋转因子,本质是个复数旋转

我个人的习惯是,把DFT理解成「相关性检测」。每个X[k]其实就是输入信号x[n]与一个特定频率的复指数信号做内积。如果信号里真有这个频率,内积结果就大;没有,结果就接近零。

小技巧: 在FPGA里实现DFT时,千万别直接套公式做N²次复数乘法。N稍微大一点(比如1024点),乘法器资源就炸了。这就是为什么我们要用FFT——它把复杂度从O(N²)降到O(N log₂N)。

卷积定理:时域卷积 = 频域相乘

这个定理,是我做数字信号处理时用得最多的工具。没有之一。

公式极其简洁:

x[n] * h[n]  ↔  X[k] · H[k]

左边是时域卷积,右边是频域点乘。也就是说,你想在时域做卷积滤波,完全可以把信号和滤波器系数都变换到频域,乘一下,再变换回来。

为什么这很重要?因为时域卷积的计算量是O(N²),而频域相乘加两次FFT的计算量只有O(N log₂N)。N越大,优势越明显。

我在项目中遇到过这样一个场景:做一个256阶的FIR滤波器,输入数据流速率很高。如果直接在时域做卷积,每个输出点要算256次乘累加,FPGA的DSP单元根本扛不住。后来改用FFT+频域相乘,资源占用直接降了一个数量级。

核心结论: 卷积定理是FFT卷积一体化设计的理论基石。你后面会看到,我们就是把长序列切成块,用FFT加速每一块的卷积计算。

线性卷积 vs 循环卷积

这里有个坑,我当年踩过。你想想看,DFT本身隐含了周期性——它假设时域信号是无限重复的。所以两个序列做DFT后相乘再IDFT,得到的是循环卷积,不是我们通常想要的线性卷积

区别在哪?

特性 线性卷积 循环卷积
输出长度 N + M - 1 max(N, M)
是否混叠 无混叠 尾部折叠到头部,产生混叠
计算方式 直接乘累加 DFT → 相乘 → IDFT
实际用途 滤波、卷积神经网络等 频谱分析、OFDM等

举个例子:x[n]长度4,h[n]长度3。线性卷积结果长度是4+3-1=6。但如果你直接做4点DFT相乘再IDFT,结果只有4个点——第5、第6个点被折叠到了前4个点里,这就是混叠。

避坑指南: 我曾经在做一个实时音频均衡器时,直接用FFT做卷积,结果低频段出现奇怪的失真。查了两天才发现——没有做补零处理,循环卷积的混叠把低频能量折叠到了高频段。从那以后,我每次做FFT卷积前,第一件事就是检查序列长度是否满足 N ≥ L + M - 1。

如何用FFT实现线性卷积?

方法很简单,就三步:

  1. 补零:把两个序列都补零到长度 N ≥ L + M - 1
  2. FFT → 相乘 → IFFT:在频域完成乘法
  3. 截取有效部分:取前 L+M-1 个点作为结果

补零的本质,就是给循环卷积「腾出空间」,让混叠的部分落在补零区域,不影响有效数据。你想想看,这就像在操场上画圈跑步,如果跑道足够长,折叠回来的部分就不会撞到前面的人。

在FPGA实现时,我建议用重叠保留法(Overlap-Save)重叠相加法(Overlap-Add)来处理长序列。这两种方法的核心思想都是:把长序列切成块,每块用FFT做循环卷积,然后通过重叠拼接消除混叠影响。

个人经验: 重叠保留法在FPGA上更容易实现,因为它不需要额外的加法器做重叠相加。我做的几个项目都用的重叠保留法,资源占用更可控。

小结

这一节的内容,说白了就三句话:

  • DFT把时域信号变到频域,FFT是它的快速实现
  • 卷积定理告诉我们,时域卷积等价于频域相乘
  • 直接做DFT相乘得到的是循环卷积,要做线性卷积必须补零

这些概念,后面每一章都会用到。尤其是做FFT卷积一体化设计时,补零长度怎么选、块大小怎么定、混叠怎么处理——全得靠今天这些基础来撑。别急,咱们一步步来。