数字信号处理基础:采样定理、FFT与FIR/IIR滤波器原理、定点数与浮点数运算

做DSP IP开发,说白了就是跟数字信号打交道。你想想看,现实世界里的声音、温度、电压,都是连续的模拟信号。但咱们芯片只能处理离散的数字。怎么把模拟信号变成数字信号?这里头第一个坎儿,就是采样定理。

采样定理:别让信号“说谎”

采样定理又叫奈奎斯特-香农定理。它的核心就一句话:采样频率必须大于信号最高频率的两倍。为什么?

我举个例子。你拿手机拍车轮,如果快门速度太慢,拍出来的车轮看起来是倒着转的。这就是混叠效应。采样不够快,高频信号就会伪装成低频信号混进来。

核心公式:

fs > 2 × fmax

其中 fs 是采样频率,fmax 是信号最高频率。

我在项目中遇到过一件事。有个同事做音频处理,采样率设了44.1kHz,觉得够用了。结果发现20kHz以上的高频分量混叠到了低频段,听起来有“嘶嘶”的噪声。后来加了抗混叠滤波器才解决。

避坑指南:

我曾经吃过亏——采样前没加抗混叠滤波器。信号里总有你意想不到的高频噪声。记住:采样前必须用低通滤波器把高于 fs/2 的成分滤掉。这是铁律。

FFT:时域到频域的“翻译官”

FFT(快速傅里叶变换)是数字信号处理里最常用的工具。它把时域信号变成频域信号。说白了,就是告诉你信号里有哪些频率成分。

FFT的原理基于DFT(离散傅里叶变换),但计算量从O(N²)降到了O(N log N)。怎么做到的?

  • 分治思想:把大DFT拆成小DFT
  • 旋转因子对称性:利用WNk的周期性减少计算
  • 蝶形运算:基2FFT的核心结构

我个人习惯用基2时间抽取FFT。它的代码实现很规整,适合硬件实现。

// 基2时间抽取FFT核心代码(伪代码)
void fft(complex* x, int N) {
    // 位反转排序
    for (int i = 0; i < N; i++) {
        int j = bit_reverse(i, log2(N));
        if (i < j) swap(x[i], x[j]);
    }
    
    // 蝶形运算
    for (int len = 2; len <= N; len <<= 1) {
        complex w = exp(-2*PI/len);
        for (int i = 0; i < N; i += len) {
            complex wn = 1;
            for (int j = 0; j < len/2; j++) {
                complex u = x[i+j];
                complex v = x[i+j+len/2] * wn;
                x[i+j] = u + v;
                x[i+j+len/2] = u - v;
                wn *= w;
            }
        }
    }
}

实战经验:

做FFT硬件加速器时,我建议把旋转因子提前算好存到ROM里。运行时实时计算cos/sin太费资源。另外,注意位反转排序——很多新手在这步栽跟头。

FIR与IIR滤波器:两种不同的“筛子”

滤波器就是信号筛子。FIR和IIR是两种最常用的数字滤波器。

FIR滤波器

FIR(有限脉冲响应)滤波器的特点是:没有反馈,只有前馈。它的输出只取决于当前和过去的输入。

公式很简单:

y[n] = b₀x[n] + b₁x[n-1] + ... + bNx[n-N]

  • 优点:线性相位,稳定,容易实现
  • 缺点:要达到陡峭的截止特性,阶数很高,延迟大

我记得有一次做音频均衡器,要求相位不失真。IIR虽然计算量小,但相位非线性,听起来怪怪的。最后用了128阶的FIR,效果很好。

IIR滤波器

IIR(无限脉冲响应)滤波器有反馈。它的输出不仅取决于输入,还取决于过去的输出。

标准形式:

y[n] = b₀x[n] + b₁x[n-1] + ... - a₁y[n-1] - a₂y[n-2] - ...

  • 优点:阶数低,计算量小,频率选择性好
  • 缺点:相位非线性,可能不稳定

避坑指南:

我曾经用IIR做高通滤波器,系数没算好,结果系统自激振荡了。IIR的极点必须在单位圆内。做定点实现时尤其要注意——量化误差可能把极点推到圆外。

定点数与浮点数运算:精度与资源的博弈

DSP芯片里,定点数和浮点数的选择是个老话题。我个人的看法是:没有绝对的好坏,看场景。

定点数

定点数用固定的小数点位置表示数值。比如Q15格式,1位符号位,15位小数位。

格式 位数 范围 精度
Q15 16位 -1 ~ 0.99997 3.05e-5
Q31 32位 -1 ~ 0.9999999995 4.66e-10

定点数的好处是:硬件实现简单,速度快,功耗低。坏处是:动态范围小,容易溢出。

浮点数

浮点数用科学计数法表示。IEEE754标准里,单精度32位,双精度64位。

  • 单精度:1位符号,8位指数,23位尾数
  • 双精度:1位符号,11位指数,52位尾数

浮点数的好处是:动态范围大,不用操心溢出。坏处是:硬件复杂,功耗高,速度慢。

我的建议:

做DSP IP时,我通常这样选:

  • 音频处理:定点Q15或Q31就够了
  • 通信基带:定点Q31或混合精度
  • 雷达/图像:浮点或块浮点
  • 算法原型验证:先用浮点,再转定点

定点转浮点时,有个坑要注意——精度损失。我曾经把一个浮点滤波器系数直接截断成定点,结果滤波器特性完全变了。正确的做法是:先做系数缩放,再做舍入,最后做饱和处理。

实战技巧:

做定点化时,我习惯用MATLAB的fi对象先仿真一遍。看看量化误差对系统性能的影响。如果SNR下降超过3dB,就得考虑增加位宽或者改用浮点。

数字信号处理基础 - 知识体系 DSP基础 采样定理 fs > 2 × fmax 抗混叠滤波器 FFT 蝶形运算 位反转排序 FIR滤波器 IIR滤波器 定点数 vs 浮点数 线性相位 高效率 时域→频域 精度 vs 资源

好了,以上就是数字信号处理基础的核心内容。采样定理是前提,FFT是工具,滤波器是手段,定点浮点是实现选择。做DSP IP开发,这些基础打不牢,后面设计指令集和编译器的时候会处处碰壁。

我个人觉得,理解这些概念最好的方式就是动手。拿MATLAB或者Python,写个FFT,设计个滤波器,再转成定点实现。踩过坑,才能真正理解。

专注资料整理