[旧日谈] 再考 IIR 与 FIR 滤波器对相位影响的定量分析

IIR 与 FIR 濾波器对音频相位的影响 先前我有写过一个简单的文章分析过两种滤波器对音频相位的影响,但是我只是知其然不知其所以然。对于音频,我虽然知道相位是一个很重要的概念,但是我始终不知道相位对实际音频的印象是什么水平的。这个问题在这些年的开发过程中始终萦绕在心头。虽然不做音频了,但是我仍然对这个问题保持好奇,综上,这也是为什么有了这个文章。 一、从一个问题开始 假设我们有一个 1kHz 的正弦信号,经过一个低通滤波器之后,输出还是 1kHz 的正弦信号,幅度变小了——这很好理解,滤波器嘛,该衰减的衰减。 但仔细看输出波形,会发现它相对于输入信号产生了一个时间上的延迟。这个延迟不是简单的"整体往后挪了 N 个采样点",而是不同频率的信号延迟不一样。 1kHz 的信号延迟了 0.5ms,500Hz 的信号延迟了 0.8ms,2kHz 的信号延迟了 0.3ms——每个频率成分的延迟都不一样。 这就是相位失真。 对于音频处理来说,这个问题比听起来严重得多。人耳对相位差的感知不如幅度那么直接,但当不同频率成分的延迟差异大到一定程度时,会导致: 瞬态信号(比如鼓点、齿音)的波形被"模糊化" 立体声声像偏移 某些频段的"堆叠"或"空洞" 所以,理解滤波器的相位特性,是做音频处理的基本功。 先说结论,IIR 的相位响应受幅度响应约束(最小相位特性),无法独立控制;FIR 可以独立控制幅度和相位,因此能实现线性相位或任意指定相位。 但是至于为什么音频行业常用IIR滤波器,这个问题我将在补充后说明。 二、先回顾一下:FIR 和 IIR 是什么 FIR(有限脉冲响应) FIR 滤波器的差分方程: $$ y[n] = \sum_{k=0}^{M} b_k \, x[n-k] $$输出只依赖于当前和过去的输入,没有反馈。脉冲响应是有限长的(长度 M+1)。 IIR(无限脉冲响应) IIR 滤波器的差分方程: $$ y[n] = \sum_{k=0}^{M} b_k \, x[n-k] - \sum_{k=1}^{N} a_k \, y[n-k] $$输出同时依赖于输入和过去的输出(反馈)。脉冲响应理论上是无限长的。 两者的核心区别在于有没有反馈。这个结构上的差异,直接决定了它们的相位特性。 三、相位响应的推导 从频率响应说起 一个 LTI(线性时不变)系统的频率响应可以写成: ...

June 18, 2026 · 17 min · Leventure

GTCRN 演进路径:v4 → v5 → 落地

GTCRN 演进路径:v4 → v5 → 落地 记录噪声抑制模型从架构精简开始,经历质量优化、极限压缩,到最终在嵌入式 C 端落地的全过程。 前言 v4.1 把 464 KB 的推理管线交到了 C 端手里。这个数字已经够小——能在大多数嵌入式芯片上跑起来,RTF 不到 0.04。但我们还想要更多。 不是「把模型再做小一点」这么简单。键盘敲击声和风扇底噪的压制效果已经不错了,如果裁剪的过程中把这两个能力丢掉,小就没有意义。换句话说,压缩是手段,质量是底线。每次下手之前,先问一句:压完之后,瞬态噪声还能不能盖住?听感会不会变差? v5 这条线走了四个月。它从 v4.1 的 464 KB 跑到了最终的 412 KB,中间踩了不少坑。这份文档把踩过的坑、走通的路、放弃的岔路都记下来。 时间线:2026-03(v4.1 交付) → 2026-06(v5.6 C 端落地) 版本总览 版本 改了什么 参数 关键指标 内存 结论 v4.1 INT8 混合精度 C 推理 87K PESQ 2.037 464 KB 基线,已交付 v5.1 架构定型 (4层, CH=20) 55.6K PESQ 2.462 ~466 KB 可靠起点 v5.2 多模块 all-in 73.9K PESQ ~1.20 ~538 KB 失败,复盘后放弃 v5.3 网络优化,单模块消融 61.6K [5,10) PESQ 1.92 ~466 KB n4 被接受 v5.4 宽度裁剪 CH→16 41.2K [5,10) PESQ 1.46 ~400 KB 失败,暂停 v5.5 极限压缩 (INT4/INT8) — PESQ drop < 0.05 ~314-349 KB (投) 过门,主线收敛 v5.6 C 端落地:GTC6/INT4/hidden INT8 60.3K DNSMOS SIG +0.86 412 KB 交付 网络结构 (v5.3-n4 最终) 输入 spec (B, 513, T, 2) │ ▼ ERB_48k.bm(): 513 → 219 │ ▼ in_conv: Conv2d(2→3) │ ▼ ┌─ CausalEncoder ───────────────────────────┐ │ DSConv: 219→110 ← skip1 │ │ DSConv: 110→55 ← skip2 │ │ CausalGTConv×4 (d=1,2,4,2) ← skip3-6│ │ SubbandAttention │ └───────────────────────────────────────────┘ │ ▼ CausalDPGRNN × 2 │ intra: 双向GRU (频率轴) │ inter: 单向GRU (时间轴) │ ▼ ┌─ CausalDecoder ───────────────────────────┐ │ SkipResidualFusion + CausalGTConv×4 │ │ Fuse + DSDeconv: 55→110 │ │ SkipResidualFusion + DSDeconv: 110→219 │ └───────────────────────────────────────────┘ │ ▼ out_conv → ERB_48k.bs() → CRM → 输出 相比 v4,decoder 的 skip 连接从简单的 x + skip 换成了带门控和残差分支的融合模块。 ...

June 18, 2026 · 7 min · Leventure

带噪信号的趋势分析方法

带噪信号的趋势分析方法 前言 手头有两组时域采样数据,每组大约240个采样点。采样周期固定,信号值在两千到四千之间游走。 肉眼扫过去——毛刺很多,高频抖动明显。但拉远了看,似乎底下藏着某种缓慢变化的结构。就像隔着一层磨砂玻璃看一幅画,大色块能辨认,细节却糊成一团。 DSP里降噪去扰的招数不少。卡尔曼、Holt-Winters、高斯平滑、巴特沃斯、Savitzky-Golay,各有各的路子。我想试试——把这套工具搬到这个信号上,看谁能把底下的轮廓挖出来,谁会被噪声带跑偏。 另外再拿两组最简单的滑动平均(SMA和EMA)当参考线,看看"简单粗暴"和"精心设计"之间到底差多少。 信号概览 先看一眼这两组信号的素颜: 特征 Signal A Signal B 值域 2,863 ~ 3,652 3,097 ~ 4,030 振幅(span) 789 933 采样点 242 243 逐点变化率 std 1.17% 1.53% 均值 3,174 3,575 Signal A的振幅比Signal B小,但逐点变化率的峰值很大——有过几次接近 ±5% 的跳变。整体走势像一条被反复折叠的绳子:先往下摔,弹回来,又摔一次,再弹。方向频繁切换。 Signal B的振幅更大,但方向很一致——从头到尾在往上走。中途有几次小幅回撤,但不改大方向。 这两组信号的差异,决定了后面每种方法的命运。 一、卡尔曼滤波——让状态方程替你猜 原理 卡尔曼不直接相信观测值,也不全信预测值。它在两者之间做加权,权重由各自的不确定性决定。 设一个状态向量 $x_k = [p_k, v_k]^T$,装着"当前位置"和"变化速度"。假设信号按匀速模型演化: $$ x_k = F x_{k-1} + w_k, \quad F = \begin{bmatrix}1 & \Delta t \\ 0 & 1\end{bmatrix} $$每来一个新的观测 $z_k$,先预测、再修正: ...

June 18, 2026 · 3 min · Leventure