数字信号处理基础回顾: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]与一个特定频率的复指数信号做内积。如果信号里真有这个频率,内积结果就大;没有,结果就接近零。
卷积定理:时域卷积 = 频域相乘
这个定理,是我做数字信号处理时用得最多的工具。没有之一。
公式极其简洁:
x[n] * h[n] ↔ X[k] · H[k]
左边是时域卷积,右边是频域点乘。也就是说,你想在时域做卷积滤波,完全可以把信号和滤波器系数都变换到频域,乘一下,再变换回来。
为什么这很重要?因为时域卷积的计算量是O(N²),而频域相乘加两次FFT的计算量只有O(N log₂N)。N越大,优势越明显。
我在项目中遇到过这样一个场景:做一个256阶的FIR滤波器,输入数据流速率很高。如果直接在时域做卷积,每个输出点要算256次乘累加,FPGA的DSP单元根本扛不住。后来改用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实现线性卷积?
方法很简单,就三步:
- 补零:把两个序列都补零到长度 N ≥ L + M - 1
- FFT → 相乘 → IFFT:在频域完成乘法
- 截取有效部分:取前 L+M-1 个点作为结果
补零的本质,就是给循环卷积「腾出空间」,让混叠的部分落在补零区域,不影响有效数据。你想想看,这就像在操场上画圈跑步,如果跑道足够长,折叠回来的部分就不会撞到前面的人。
在FPGA实现时,我建议用重叠保留法(Overlap-Save)或重叠相加法(Overlap-Add)来处理长序列。这两种方法的核心思想都是:把长序列切成块,每块用FFT做循环卷积,然后通过重叠拼接消除混叠影响。
小结
这一节的内容,说白了就三句话:
- DFT把时域信号变到频域,FFT是它的快速实现
- 卷积定理告诉我们,时域卷积等价于频域相乘
- 直接做DFT相乘得到的是循环卷积,要做线性卷积必须补零
这些概念,后面每一章都会用到。尤其是做FFT卷积一体化设计时,补零长度怎么选、块大小怎么定、混叠怎么处理——全得靠今天这些基础来撑。别急,咱们一步步来。