首页 / 资讯中心 / 文章详情

Simulink音频混响模拟:梳状滤波器原理、参数推导与调优

Simulink音频混响模拟:梳状滤波器原理、参数推导与调优 ★ FEATURED ARTICLE
做音频算法的人大概都经历过这个阶段一开始觉得混响不就是加几个延迟、乘一个衰减系数等真把它塞进 Simulink 跑起来听到的声音却像有人在铁皮桶里敲弹簧——金属味重、尾巴发抖、低频糊成一团。我在给一个语音交互的模拟项目做前端处理时就整整卡在这上面两天。后来才明白问题不在代码写错而在于梳状滤波器Comb Filter这套结构本身有很强的个性你不顺着它的物理规律调它就用最难听的梳齿回敬你。这篇就围绕基于 Simulink 的音频与语音处理滤波器场景把梳状滤波器在音频混响模拟中的那一整套东西摊开讲它是什么、为什么混响要用它、参数怎么算、Simulink 里怎么搭、跑起来之后哪几个坑最要命。无论你是刚接触离散滤波器的新手还是已经能用延迟线拼出简单效果器的老手下面这些参数推导和排查过程应该都能直接用上。1. 先把混响拆开为什么一个延迟加一路反馈就撑起了整个模型1.1 房间脉冲响应的两种读法拿一支气球在空房间里炸一下录下来的那条曲线就是房间脉冲响应。它有两种读法。第一种是时域读法曲线开头几十毫秒内散布着一簇离散的尖峰这些是早期反射来自墙面、地面、天花板的第一次弹射过了大约 50 到 80 毫秒尖峰密到分辨不出来连成一片缓慢下降的噪声状包络这部分叫晚期混响。第二种是频域读法如果把这条脉冲响应做傅里叶变换会看到一条极其密集的、近似随机的幅度谱峰谷之间的间隔非常窄。这两种读法对应两种完全不同的建模思路。频域那套直接拿真实脉冲响应做卷积音质最好但不可调时域这套用延迟线加反馈去生长出那条尾巴参数可调、计算量小梳状滤波器就是这条路线上的第一块积木。我习惯把梳状滤波器理解成一间只有两面平行墙的房间声音在两面墙之间来回弹每次弹回来幅度乘以一个小于 1 的系数弹一次花固定的时间。这个极简模型虽然离真实房间差得远但它抓住了晚期混响最本质的两个特征——离散的重复周期和指数的能量衰减。理解了这一点后面所有参数调整就都有了物理依据。延迟时间决定这间房子有多大反馈增益决定墙面吸音棉贴了多少而不是靠耳朵瞎试。1.2 梳状滤波器在信号链里补的到底是哪块短板有人会问既然卷积混响音质更好为什么还要费劲搭梳状网络答案在实际部署场景里。卷积混响需要一个几秒长的脉冲响应文件做一次卷积就是几千次乘加在资源紧张的嵌入式设备、或者需要实时调混响时间的交互式语音系统里成本压不下来。而梳状网络的核心计算只有取一个延迟样本、乘一个增益、加回输入一路延迟线只占一个长度为 N 的缓冲区N 通常在一千到两千个样本之间。更关键的是可调性。卷积混响的混响时间是录制那一刻就定死的想改就得换一整套脉冲响应、重新加载梳状网络的混响时间由反馈增益一个系数直接决定运行时实时改这个系数尾巴长度立刻跟着变。这在语音交互模拟中特别有用——同一个场景里用户可能从会议室走到走廊再走到大厅混响时间需要平滑过渡梳状网络天然支持这种连续调节。所以梳状滤波器不是卷积混响的廉价替代品它是另一种设计哲学用极少的自由度去逼近混响的统计特征牺牲的是细节真实度换来的是可控性、低延迟和低算力。搞清楚这个定位你就不会拿它去跟卷积混响比像不像真房间而是去比参数响应快不快、听感自不自然。1.3 从回声到混响的临界点在哪里单个梳状滤波器最容易翻车的地方是延迟时间选得不对导致听感从混响滑向回声。人耳有个大约 50 到 80 毫秒的回声感知阈值具体数值跟声音类型有关对 clicks 这类瞬态信号阈值在 10 毫秒左右就能听出分离感对持续性的语音要 50 毫秒以上才明显。这意味着如果单路梳状的延迟设成 100 毫秒你听到的是清清楚楚的喂——喂——喂而不是混响。我一般在混响网络里把单路梳状延迟控制在 25 到 45 毫秒这个区间。短于 20 毫秒梳齿间隔太宽对应 50Hz 以上会在语音的基频附近形成明显染色长于 50 毫秒又开始有可辨识的重复感。这个区间不是死规矩但作为起点很可靠。还有一个必须注意的细节多路梳状的延迟长度不能成整数倍关系否则它们的梳齿会周期性重合重合处能量叠加听起来就是突兀的嗡鸣。业内常用互质素数长度来错开这个做法后面会详细算。2. 前馈梳状与反馈梳状同一个名字两套完全不同的听感2.1 前馈梳状的传递函数与梳齿分布前馈梳状Feedforward Comb的结构是输入信号分成两路一路直通一路延迟 N 个样本后乘以增益 g两路相加。写成差分方程是 y[n] x[n] g·x[n−N]对应的传递函数 H(z) 1 g·z⁻ᴺ。这个式子的幅度响应很有特点。把 z 换成 e^{jω}得到 |H(e^{jω})| |1 g·e^{−jωN}|展开后是 sqrt(1 g² 2g·cos(ωN))。当 ωN 2πk 时 cos 取 1幅度是 1 g这是峰值当 ωN (2k1)π 时 cos 取 −1幅度是 |1 − g|这是谷值。峰谷比是 (1g)/(1−g)。g 0.7 时这个比值是 5.67约 15dB。峰和谷在频率轴上等间隔排列间隔是 fs/N也就是延迟时间的倒数。这就解释了梳状这个名字的由来——频响曲线上一排排的齿。以 fs 48000、N 120025 毫秒为例齿的间隔是 40Hz在 20kHz 带宽内会有一共 500 个齿。齿这么密在音乐上会产生一种金属味的染色。前馈梳状有个绕不开的问题它的冲激响应只有两个脉冲——一个在 0 时刻一个在 N 时刻然后就没了。也就是说它只能造出一下回声造不出尾巴。所以在混响模拟里前馈梳状通常不用来生成混响主体而是用于其他用途比如做单点延迟、做梳状滤波效果、或者跟反馈结构配合做全通。2.2 反馈梳状的极点和指数衰减反馈梳状Feedback Comb的结构是输入先跟延迟输出乘以 g相加再送进延迟线。差分方程 y[n] x[n] g·y[n−N]传递函数 H(z) 1/(1 − g·z⁻ᴺ)。这一改性质完全变了。它的冲激响应是 g⁰、g¹、g²、g³……每隔 N 个样本出现一个幅度按几何级数衰减一直延伸到无穷。这才是有尾巴的结构。关键在于极点位置。分母 1 − g·z⁻ᴺ 0 意味着 zᴺ g也就是 N 个极点在复平面上均匀分布在半径 g^(1/N) 的圆上。注意这个细节极点的模是 g 的 N 次方根不是 g 本身。g 0.85、N 1200 时极点模长是 0.85^(1/1200) ≈ 0.99986非常靠近单位圆。这解释了为什么反馈梳状对增益变化如此敏感——g 从 0.85 涨到 0.9极点模长从 0.99986 涨到 0.99991看着差别极小但对应的时间常数变化很大。关于会不会发散只要 |g| 1所有极点严格落在单位圆内系统就收敛。g 越接近 1衰减越慢尾巴越长。这个界限是硬性的但在实际实现里如果反馈路径里还有别的滤波器后面要讲的阻尼低通、全通它们的增益会跟 g 相乘总环路增益可能超出预期那就真的要炸了。这一点后面单独说。2.3 一张表看清两者的取舍对比维度前馈梳状 1 g·z⁻ᴺ反馈梳状 1/(1 − g·z⁻ᴺ)冲激响应长度2 个脉冲无限长峰谷比(1g)/(1−g)(1g)/(1−g)能否造出混响尾巴不能能对增益的敏感度线性很温和指数极其敏感极点位置无极点只有 N 个零点N 个极点模长 g^(1/N)主要用途单点延迟、梳状染色效果、结构组件混响网络的混响主体这张表是我自己在选型时反复对照的。要造混响主体必然是反馈梳状前馈梳状更多是配角。但有一点容易被忽视两者在频响上的梳齿形状是一样的峰谷比公式完全一致。区别只在于群延迟——前馈结构的相位响应比较平缓反馈结构的相位在极点附近变化剧烈这也是反馈混响听起来比前馈厚重的原因之一。还有一个实用的推论既然峰谷比是 (1g)/(1−g)那 g 大到一定程度某些频率会被严重衰减。g 0.9 时峰谷比是 19约 25.6dB。如果单路梳状单独听会出现明显的某些频段被吃掉了的感觉。这就是为什么单个梳状滤波器永远不够必须靠多路并联把彼此的谷填上——下一节展开。3. 在 Simulink 里把反馈梳状搭起来含完整参数推导3.1 采样时间与信号维度的前置决定搭模型之前必须先定一个事信号是按单个样本传还是按帧传。这个决定看着不起眼实际上是我踩过最大的一个坑。Simulink 里的 Delay 模块延迟长度是按输入信号的样本维度算的。如果信号是一个标量每步一个样本设 1501 就是延迟 1501 个样本但如果信号是一个 1024 维的帧很多音频模块默认输出这种格式Delay 模块设 1501 就变成了延迟 1501 帧也就是 1501 × 1024 1537024 个样本约 32 秒。我第一次搭的时候就是这个结果等了半天只见输出迟迟不来还以为是反馈回路卡住了。排查方法是打开 Signal Attributes 看一眼信号维度。解决办法有两条方案一在信号源后面不接 Buffer直接让每一时刻只有 1 个样本。Sine Wave 模块默认输出标量From Workspace 也可以配成标量。这样做最干净Delay 模块的参数就是你想要的样本数。方案二如果确实要用帧信号为了提升仿真效率就不能用普通 Delay 模块得在自己的 MATLAB Function 块里写环形缓冲区或者用 延迟 缓冲组合 把帧拆开。我一般先用方案一把结构跑通把参数调对了再考虑性能优化。因为方案一的仿真是逐步进行的48kHz 采样率下跑 10 秒就是 48 万步速度确实慢但胜在每步都能看波形、能随时暂停检查内部信号调试阶段这点比速度重要得多。求解器配置也要跟着改。在 Model Settings 里把 Solver 设成 Fixed-stepSolver 选 discrete (no continuous states)Fixed-step size 填 1/48000。用变步长求解器跑离散反馈回路会出现过零检测反复触发的问题仿真速度掉到几乎不可用。3.2 Delay-Sum-Gain 回路的搭建与代数环反馈梳状的 Simulink 拓扑其实非常短输入 → Sum() → Delay(length N) → 输出 ↑ | └──── Gain(g) ←────────┘具体接法一个 Sum 模块配两个输入端口符号设成 或者 - 看你从哪边取反馈。Sum 的输出接 Delay 模块的输入Delay 的输出分两路一路作为整个系统的输出一路经过 Gain 模块回到 Sum 的第二个输入。这里有个经典问题这个结构看起来像代数环因为 Delay 的输出回到了它自己的输入路径上。实际上不是——Delay 模块本身会断开代数环因为它在当前步的输出只取决于历史步的输入不依赖当前步。所以 Simulink 不会报代数环错误。但有两个变种会真的触发代数环报警把 Delay 换成 Gain 或者 Sum也就是纯组合逻辑构成回路那就死循环了。在反馈路径上误加了 Direct Feedthrough 的模块比如某些自定义的 S-Function打破了输出不依赖当前输入这个前提。我遇到过一次更隐蔽的Delay 模块的延迟长度被设成了 0。有些版本的 Delay 模块允许这么设设成 0 之后就退化成直通代数环立刻出现。所以延迟长度至少要是 1实际用的时候都是上千这个坑只会出现在刚开始搭骨架验证结构的时候。3.3 延迟样本数与反馈增益的联动计算这一段是整篇文章最值得抄走的部分。很多人调混响就是试参数其实这两个数之间有精确的换算关系。先推导。反馈梳状每循环一次经过的时间是 N·TsTs 是采样周期幅度乘以 g。经过 k 次循环幅度是 g^k时间经过 k·N·Ts。所谓 RT60就是幅度衰减到初始值的千分之一−60dB所需的时间。令 g^k 10^(−3)两边取对数得 k −3/log₁₀(g)因为 log₁₀(g) 是负数可以写成 k 3/log₁₀(1/g)。代入 RT60 k·N·Ts得到RT60 3·N·Ts / log₁₀(1/g)反过来解 gg 10^(−3·N·Ts/RT60)这个反解公式是实际搭模型时用的那个。给定想要的混响时间和延迟长度直接算出增益不用试。举个具体例子。fs 48000Ts 1/48000 ≈ 20.83 微秒。选四个延迟长度 1501、1627、1753、1879 个样本对应的物理延迟分别是 31.27、33.90、36.52、39.15 毫秒。这四个数都是我特意挑的素数互不成整数倍关系梳齿不会重合。目标是 RT60 1.4 秒。计算过程写成 MATLAB 代码fs 48000; Ts 1/fs; N [1501 1627 1753 1879]; RT60 1.4; g 10.^(-3 * N * Ts / RT60); fprintf(%d 样本 - g %.4f\n, [N; g]);跑出来的结果是 0.8570、0.8461、0.8351、0.8242。注意这个结果里最重要的信息四路梳状的目标混响时间相同但增益各不相同延迟越长增益越小。这是很多人忽略的点。如果四路都用同一个 g那延迟长的支路衰减慢、延迟短的支路衰减快最后整体包络会变成双段衰减听起来头部一阵密、尾部一阵稀很不自然。按公式分别算才能让四条尾巴以同一速率消退。还有一点四个数这么接近0.857 到 0.824说明在实际工程里对增益做微小调整混响时间就能明显变化。g 每变化 0.01RT60 大约变化 10% 到 15%。这也是为什么调参时不能用鼠标拖 Gain 模块的数字框要用代码或变量统一算不然手一抖就过冲了。3.4 反馈支路里的阻尼低通纯反馈梳状有个物理上不真实的毛病所有频率以同样的速率衰减。真实房间里高频被空气吸收、被软性表面吸收衰减得比低频快得多。这个差异正是混响听起来有空间感的关键之一。用纯梳状网络做出来的混响尾巴是白的所有频率一起消失听感偏硬、偏电子。解决办法是在反馈回路里串一个一阶低通。差分方程是 y[n] (1−d)·x[n] d·y[n−1]其中 d 在 0 到 1 之间。d 越大截止频率越低高频衰减越厉害。截止频率的近似换算fc ≈ fs·(1−d)/(2π·d)。d 0.5 时 fc ≈ 7640Hzd 0.7 时 fc ≈ 3270Hzd 0.9 时 fc ≈ 850Hz。做语音场景的室内混响d 取 0.4 到 0.6 之间比较合适做大厅可以到 0.7。但这里有个必须处理的问题这个低通的直流增益是 1/(1−d)不是 1。d 0.6 时直流增益是 2.5。这意味着反馈回路的总增益变成了 g × 2.5原本算好的 0.85 一下子变成 2.1立刻发散。两个修法。一是把低通写成归一化形式 y[n] (1−d)·x[n] d·y[n−1]然后在 Gain 模块里把 g 提前除以 (1−d) 的补偿……等等这样会让直流增益变回 1 但有效反馈增益也变了。更干净的做法是把低通直接写成y[n] a·x[n] (1−a)·y[n−1]其中 a 在 0 到 1 之间这个形式直流增益严格等于 1a 越小截止频率越低。关系是 fc ≈ fs·a/(2π·(1−a))。a 0.5 时 fc ≈ 7640Hza 0.3 时 fc ≈ 3270Hza 0.1 时 fc ≈ 850Hz。跟前面那个 d 表述正好是互补的a 1−d但归一化后的行为完全不同不容易搞混。加入阻尼后实际 RT60 会跟公式算的略有偏差因为低频和高频的衰减速率不一样了。我一般用中频段500Hz 到 2kHz测出来的衰减斜率当作标称 RT60这样跟公式对得上。4. 从单路梳状到完整混响网络并联、串联与全通4.1 为什么单路梳状必然金属味单路反馈梳状最突出的听感问题是金属味metallic ringing。原因不复杂它的冲激响应是一串等间隔、等比衰减的脉冲这在频域上就是一组等间隔的谐波。用信号处理的说法它的频谱是一把梳子用听觉的说法它把任何输入都染上了一个固定音高色彩音高等于 1/(N·Ts)。以 N 1501、fs 48000 算这个重复频率是 31.98Hz。这个频率本身听不见但它的各次谐波覆盖了整个可听频段而且在每个谐波位置都有能量堆积。输入一个宽带噪声输出听起来像是有个 32Hz 的低频在嗡嗡地调制这就是金属味。要打散这个规律性思路有两条一是多路并联让各路梳齿错位、互相填充二是加调制让延迟长度随时间微小变化把固定音高糊掉。前者是基础后者是进阶。判断金属味有没有缓解有个简单的量化指标看脉冲响应的回声密度。理想混响的脉冲响应在两个时间点上回声数量的期望随时间的平方增长因为房间里的反射路径数随时间增加单路梳状的回声数是严格线性增长的每个延迟周期增加一个。并联多路后回声数变成各路线性增长之和密度上来了但因为各路延迟不成整数倍重合点随机化听感就散了。4.2 四并两串的具体参数表经典的组合方式是四路反馈梳状并联后面串两到四个全通滤波器。这是我用的那套参数全是 48kHz 下的样本数环节延迟样本数物理延迟反馈增益RT601.4s备注梳状 1150131.27 ms0.8570素数长度梳状 2162733.90 ms0.8461素数长度梳状 3175336.52 ms0.8351素数长度梳状 4187939.15 ms0.8242素数长度全通 12254.69 ms0.50梳状输出后串联全通 255611.58 ms0.50全通 1 输出后串联并联的四路输出先相加再乘以 0.25 做归一化然后进全通链。归一化这一步不能省四路信号的功率叠加会让电平涨到大约 2 倍相干处更高后面稍微一放大就削波。全通滤波器在这里的结构跟前馈梳状有点像但增益符号反了。它的差分方程是 y[n] −g·x[n] x[n−N] g·y[n−N]传递函数 H(z) (−g z⁻ᴺ)/(1 − g·z⁻ᴺ)。分子分母的模在单位圆上相等所以幅度响应平坦——不管频率多少幅度都是 1。它只改相位不改幅度谱。在 Simulink 里搭这个全通需要两个 Sum 模块、一个 Delay、一个 Gain值是 −g 那个分支和一路直通。具体接法x → Sum1(−, ) → Sum2() → Delay(N) → ×g → Sum2 第二输入 ↑ | └──── x[n] 直通 ───────┘稍微绕。更简单的办法是把全通也看成一组方程直接在 MATLAB Function 块里写环形缓冲区实现。我搭过一次模块化的全通子系统封装好之后当黑盒用省了很多连线的麻烦。全通的作用是增加回声密度而不改变频谱。梳状网络出来的信号回声虽然在时间上散了但每个回声之间还是有明显的空隙感串上两个全通之后每个回声被展开成一小簇密度上去了听感立刻从数字味变成空间感。4.3 为什么全通的增益必须和梳状分开算这里有一个很容易犯的错误把全通的增益也按 RT60 公式算。不行。全通结构的环路增益是 g但因为它分子分母同构幅度响应恒为 1对整个系统的能量衰减贡献不是简单的指数形式。它主要影响的是瞬态密度不是包络斜率。所以全通的 g 取固定值就行0.5 是常用值取到 0.7 会开始有轻微的喷气感因为全通的群延迟在低频处很大取 0.3 以下效果就不明显了。真正决定整体 RT60 的是那四路并联梳状。测出来的 RT60 应该跟设定值吻合如果不吻合先检查是不是某一路的反馈增益算错了或者阻尼低通的归一化有没有做对。5. 实测排查几个把我卡了大半天的现象5.1 帧信号把 Delay 模块的延迟放大了一千多倍这个坑前面提过值得单独展开因为它太容易发生、排查起来又太不直观。现象是这样的模型跑起来输出端只有开头一点点信号后面全是静默或者反过来输入已经停了很久输出还在持续出声音。用 Scope 看延迟模块内部缓冲区里存的是一整块 1024 点的数据而不是单个样本。排查链路我总结成三步第一步看信号维度。在 Delay 模块的输入线上加一个 Display 模块或者打开信号属性看维度是 [1×1] 还是 [1024×1]。这是最直接的验证。第二步看延迟模块的参数含义。Simulink 的 Delay 模块Delay length 这个参数在帮助文档里写得很清楚单位是采样时间而不是样本数。当信号的采样时间不是 1/fs 的时候这两个概念就脱节了。帧信号的采样时间是帧周期一个帧周期里包含 1024 个样本所以延迟 1501 个采样时间就是 1501 × 1024 个样本。第三步确认上游模块。很多音频输入模块包括一些文件读取模块默认输出帧信号因为帧处理对块运算更友好。想让它输出标量得改 Buffer 设置或者中间插一个 Unbuffer 模块信号处理工具箱里有。我的经验是只要是做样本级延迟的算法梳状、全通、延迟线混响都属于这一类一律在信号链最前面把帧拆成标量后面就不需要再操心这个问题了。代价是仿真变慢但正确性优先。5.2 输出削波和直流累积削波的表现很直观输出波形被削平在 ±1 的位置听感上是刺耳的失真而且是那种破碎的失真不是模拟电路过载的柔和饱和。原因是混响是能量累积型处理稳态增益可以远超 1。四路并联梳状虽然每路反馈增益小于 1但四路叠加之后在梳齿重合处的瞬时增益可能达到几倍。处理办法是归一化并联输出除以路数。我在 4.2 的表里写的 0.25 就是这个。更保守一点可以用 0.2留 6dB 的余量。另外在系统输出端串一个限幅器Saturation 模块上下限设 ±0.98作为最后一道防线防止极端输入把后面的设备冲坏。直流累积是另一个隐蔽的问题。反馈回路对直流分量的增益是 g/(1−g)g 0.85 时是 5.67 倍g 0.9 时是 9 倍。只要输入里有一点点直流偏移比如某些信号源开机瞬间的偏置就会在回路里被反复放大最后把整个可用动态范围吃掉表现为输出缓慢漂移到一边。解决办法是在反馈梳状的输入端串一个高通。最简单的一阶高通y[n] a·(y[n−1] x[n] − x[n−1])a 取 0.995 左右截止频率大约几个赫兹对音频内容几乎没有影响但能把直流彻底压住。我一般把这个高通放在整个混响网络的最前面一路就够不用每路都加。5.3 梳齿太尖、尾巴发抖、低频糊成一坨这三个现象是调参阶段最常遇到的对应的原因各不相同。梳齿太尖听感上是明显的音高染色输入什么都有同一个调。原因是并联路数不够或者延迟长度凑得太近。检查方法把四路延迟值列出来看有没有公约数。1501、1627、1753、1879 这四个数都是素数最大公约数是 1安全。如果用了 1500、1600、1700 这种整数它们的最小公倍数是 13600意味着每 13600 个样本283 毫秒就会出现一次四路对齐的强重合这就是听到的重影。改动方案全部换成附近的素数。尾巴发抖听感上是混响尾音有周期性的音量起伏像有人在快速推拉音量旋钮。原因通常是反馈增益太高环路处于临界状态附近数值误差被放大成可听的振荡。检查方法看 RT60 实测值如果比设定值长很多比如设定 1.4 秒、实测 3 秒以上说明有效增益超了。修法是把 g 乘以 0.95 降一点或者检查阻尼低通的归一化有没有做对。低频糊成一坨听感上是低频拖得很长、糊在一切上面中高频却消失得很快。这是阻尼低通设得太重a 太小的典型表现因为低通让高频衰减快、低频衰减慢反差被放大了。检查方法把阻尼旁路掉跑一遍如果低频恢复正常就是阻尼的问题把 a 从 0.4 提到 0.6 试试。另一个可能是输入信号本身低频能量太强可以在输入端加个 100Hz 以下的高通。6. 再往前走一步时变调制与卷积方案的取舍6.1 给延迟做微小的时变调制梳状网络还有一个顽固问题即使四路并联、全通加密长时间听还是能感觉到一个固定的音高感尤其在处理持续音比如长音的人声、弦乐的时候。这是因为整个网络的延迟长度是恒定的梳齿位置固定。解决办法是让延迟长度随时间做极其缓慢、幅度极小的变化。常见做法是用一个 0.5 到 2Hz 的低频正弦幅度在 ±3 到 ±8 个样本之间去调制每一路梳状的延迟长度。幅度必须小大了会变成明显的颤音效果频率必须低高了会觉得声音在抖。在 Simulink 里实现时变延迟不能用普通的 Delay 模块因为它只支持固定长度。三个选择一是用 Variable Integer Delay 模块延迟端口接受一个整数输入。这个模块能直接接正弦调制但要求延迟值在每一步都是非负整数所以调制信号要先经过取整和限幅。取整会引入量化台阶在慢速调制下可能出现阶梯感的噪声。二是分数延迟滤波器用拉格朗日插值或 Thiran 全通来做亚样本精度的延迟。音质最好但计算量大每一路要好几次乘加。Thiran 全通的做法是把一个一阶全通串在延迟后面系数随目标延迟小数部分变化能实现平滑的连续延迟。三是自己写 MATLAB Function 块用环形缓冲区加线性插值。灵活性最高也最容易出错插值系数的边界处理需要格外小心。我自己的偏好是第二条音质和复杂度的平衡最好。给四路梳状各配一个低频调制源相位错开比如 0°、90°、180°、270°这样四路的调制不会同步避免整体音高一起漂。调制会带来一个副作用RT60 的实测值会略微变化因为有效延迟长度在变。变化幅度一般在 5% 以内听感上无感。6.2 什么时候该彻底放弃梳状网络改用卷积我需要说一句实话如果项目对混响的真实度要求高比如做音乐制作工具、影视后期梳状网络再怎么调也追不上卷积。卷积直接拿真实空间的脉冲响应所有早期反射、频率相关的衰减、扩散特性都是现成的梳状网络的参数化模型在物理上就表达不了这些细节。判断该用哪种看三个条件第一个是实时可调性要求。如果用户需要在运行中连续改变混响时间、房间大小、阻尼梳状网络几乎是唯一选择因为卷积方案的参数是烧在脉冲响应里的。当然也有折中方案——预生成多套脉冲响应然后做插值但那个复杂度和内存占用会迅速失控。第二个是算力预算。梳状网络每路延迟线每样本只做一次乘加四路加两个全通总共也就十几次乘加卷积混响做 2 秒的脉冲响应每样本要做十万次乘加。相差四个数量级。嵌入式场景基本没得选。第三个是混响的功能性还是艺术性。如果混响只是为了模拟这个声音是在某个空间里录的或者为了让语音交互系统在不同房间条件下都表现一致那功能性优先梳状网络的可控性更重要。如果混响本身是创作的一部分那真实度优先上卷积。还有一个我很少见人提但很实际的判断依据你的信号是什么。语音信号的能量集中在 300Hz 到 4kHz而且有很强的时变结构梳状网络在这个频段的表现完全可以接受参数化带来的规律性也被语音本身的非平稳性掩盖了。音乐信号宽带、持续梳状网络的固定音高染色就很容易暴露。所以做语音处理的项目用梳状网络搭混响是性价比很高的选择做音乐就得掂量一下。我在那个语音交互项目里最后就是用的梳状方案四并两串加低频调制跑在一块算力有限的板子上实时性毫无压力。后来做过一次对比测试同一段语音分别过梳状网络和卷积混响让几个同事盲听在像不像在房间里说话这个维度上评价差异不大但在长时间听的疲劳感上卷积确实更舒服。所以怎么选还得看你的实际场景更在乎哪个。最后分享一个小技巧调梳状混响的时候别用音乐当测试信号用一段有明显停顿的语音。语音的停顿处会暴露出混响尾巴的所有问题——金属味、抖动、低频堆积在连续音乐里全被掩盖了。我每次改完参数都会用同一段带停顿的语音听三遍比看频谱图管用得多。
阅读完成 · 觉得有帮助?
咨询建站