[离散时间信号处理学习笔记] 13. 重采样
重采样常用于音频处理。在用麦克风对音频进行采集的时候,常见的采样率有8k(电话)、44.1k(CD)、48k(视频音轨)、96k/192k(Hi-Res),而某些系统会有默认固定的输出采样率(如Android的默认输出采样率为44.1k),此时就需要对输入音频数据进行重采样。
重采样的源样本序列为x[n]
x[n]=xc(nT)
重采样的目标序列为x′[n]
x′[n]=xc(nT′)
如何通过x[n]得到x′[n]就是本文的讨论内容。
本文假设以采样周期为T对xc(t)进行采样满足奈奎斯特采样定律。
减采样(downsampling)
减小采样率的过程被称为减采样,这一小节讨论的是按整数倍减小采样率。
按照我们一般的思维来说,按整数倍(倍数为M)减少采样率应该是直接对源样本序列每隔M个样本提取一个值
xd[n]=x[nM]=xc(nMT)
这种提取方法被称为采样率压缩器,简称压缩器(compressor)。可以看到所得的新序列是原始连续信号的一部分,并且新序列的采样周期为Td=MT。对于该新序列,我们可以分为两种情况进行讨论:
- Td符合奈奎斯特采样定理,即新序列能通过一个低通滤波器还原为原始的连续信号
- Td不符合奈奎斯特采样定理,即新序列发生混叠,无法还原为原始的连续信号
如下图假设信号在M=2时恰好满足奈奎斯特采样定理,那么在M=3时则会发生混叠
如果在采用了压缩率为M的压缩器后,序列仍然符合奈奎斯特采样定理,我们可以直接进行使用xd[n]=x[Mn]来得到减采样序列。而发生混叠的情况则稍微复杂一点。观察混叠的频谱,可以发现只有低频部分保持了与原始信号频谱的一致性,而相当多的高频由于混叠而失去了原始频谱。
频谱丢失得越多说明信号的失真越大,因此为了减少失真,需要尽可能保留更多的原始信号频谱。我们可以先对元素信号进行低通滤波,然后再对滤波后的信号进行周期为MT的采样即可得到失真更少的序列。按照这种思想,采样周期固定为MT,如果一个被采样信号的采样周期为MT,那么采样后不会混叠的条件就是该信号的截至频率为πMT,因此低通滤波的截至频率为πMT。
很明显,先低通滤波后采样的这种方法能最大限度地减低频谱的丢失,从而降低信号失真。
˜Xd(jΩ)=Xc(jΩ)HM(jΩ)
其中˜Xd(jΩ)就是对原始信号进行低通滤波后的信号˜xd(t)的傅里叶变换,低通滤波器的傅里叶变换为HM(jΩ)。不过我们手中的并不是原始信号xc(t),而是序列x[n],为了进入上述流程,我们需要先用x[n]重构出xc(t),才能进行低通滤波以及后续采集
˜xd(t)=F−1˜Xd(jΩ)=F−1{Xc(jΩ)HM(jΩ)}=F−1{X(ejΩT)Hr(jΩ)HM(jΩ)}=F−1{X(ejΩT)THM(jΩ)}{Hr(jΩ)={T,|Ω|<π/T0,elseHM(jΩ)={1,|Ω|<π/MT0,else=F−1{Xs(jΩ)THM(jΩ)}=xs(t)∗[MT⋅hm(t)]/Mfourier convolution theorem={∞∑n=−∞x[n]δ(t−nT)}∗{sin(πt/MT)πt/MT}/M=∞∑n=−∞x[n]sin[π(t−nT)/MT]π(t−nT)/MT/M
然后从˜xd(t)中以MT为周期采集得到˜xd[n]
˜xd[n]=˜xd(nMT)=∞∑k=−∞x[k]sin[π(t−kT)/MT]π(t−kT)/MT/M|t=nMT=∞∑k=−∞x[k]sin[π(nMT−kT)/MT]π(nMT−kT)/MT/M=∞∑k=−∞x[k]sin[π(nM−k)/M]π(nM−k)/M/M
如果要从连续时间系统来理解的话,我们可以发现重建的连续信号˜xd(t)是由无数个x[k]分别对相应位置的截至频率为π/MT的sinc函数进行加权后叠加,然后对叠加得到的信号的幅度除以M得到的。
如果要从离散时间系统来理解˜xd[n]的构造公式的话,可以发现上面公式中的sinc函数有如下规律(下二)
H(ejω)={M,|ω|<π/M0,else⇔h[n]=sin[πn/M]πn/MH(ejω)={1,|ω|<π/M0,else⇔h[n]=sin[πn/M]πn/M/M
可以发现该sinc函数是一个增益为1、截至频率为π/M的低通滤波器,该滤波器后接因子为M的压缩器。那么,前面的公式可以理解为:用该滤波器对x[k]进行滤波后再用因子为M的压缩器即可得到˜xd[n]。这一过程又被称为抽取(decimation)。
增采样(upsampling)
增加采样率的过程被称为增采样,这一小节讨论的是按整数倍增加采样率。
假设增加采样率的倍数为L,那么增加采样率后的采样周期为Ti=LT,有
xi[n]=xc(nTi)=xc(nLT)
不过实际上我们只有采样周期为T的序列x[n],因此需要先进行xc(t)的重建,然后对xc(t)进行周期为Ti的采样
xi[n]=xc(nT/L)=∞∑k=−∞x[k]sin[π(t−kT)/T]π(t−kT)/T|t=nT/L=∞∑k=−∞x[k]sin[π(nT/L−kT)/T]π(nT/L−kT)/T=∞∑k=−∞x[k]sin[π(n−kL)/L]π(n−kL)/L
下面我们从频域来展开讨论
增采样即采样频率提高了,因此不会出现混叠的情况,即不会改变原始的连续时间信号。现假设用采样周期T对xc(t)进行采样恰好满足奈奎斯特采样定理,即有
增采样后采样周期为Ti=T/L,那么频谱将有如下变化
观察两张图右下角的X(ejω)以及Xi(ejω),它们的时域表示分别就是我们的源序列x[n]与目标序列xi[n]。从X(ejω)变为Xi(ejω)只需进行执行两个步骤:
- 对X(ejω)的变量ω进行倍数为L的扩展,得到Xe(ejω)=X(ejωL)
- 对所得的新频谱进行低通滤波,滤波器的增益为L,截至频率为πL
对第一步有如下分析:
X(ejω)=∞∑n=−∞x[n]e−jωn⇒X(ejωL)=∞∑k=−∞x[k]e−jωLk=∞∑n/L=−∞x[n/L]e−jωnn=Lk⇒xe[n]={x[n/L],n=0,±L,±2L⋅⋅⋅0,else
如下图所示,对序列x[n]进行步长为L的扩展,即可得到xe[n],这种转换称为扩展器(expander)
第二步的低通滤波器的增益为L、截至频率为π/L,即其脉冲响应为(从前面的增采样公式同样也能得出该结论)
hi[n]=sin(πn/L)πn/L
因此增采样系统分解如下图,这一过程又被称为内插(interpolation)。
简单的内插滤波采样
在对序列进行内插时,某些情况下,我们并不用追求很准确的信号还原,此时用一些简单的滤波器即可达到不错的效果,如常见的线性内插、三次样条内插等。
hlin[n]={1−|n|/L,|n|⩽
- 线性内插只用到内插的位置两旁的两个样本,在图上表示的话,就是把两个样本用直线连接后,该直线在对应内插位置上的的值就是所求的内插值。
- 三次样条内插会用到内插位置两旁的四个样本,即左右各两个,曲线类似于对低通滤波器进行截取后的曲线(下面取L=5, a=-0.5)。
观察上面两个脉冲响应,我们能发现这些简单内插器脉冲响应的一些规律:
- 零点的左右两边对称,\tilde{h}[n] = \tilde{h}[-n]
- 长度为2KL-1,K=1,2,\cdot\cdot\cdot,也就是说左右两边距离零点超过KL时的值为0,即\tilde{h}[n] = 0,|n|\geqslant KL·
- 零点处的值为1,h[0] = 1
- KL处的值为0,h[KL] = 0
既然有这些简单但不够准确的内插器,那么就应该有相应的方法来判断这些内插器的内插效果。内插效果可以通过观察这些内插器的频谱来进行分析。
对比增采样所需要的低通滤波器跟简单的线性内插器频谱,可以发现在频谱的\omega<\frac{\pi}{L}处本应做大小固定为L的增益,但是线性内插在这部分有衰减,另外在\omega>\frac{\pi}{L}处本应该是对原始序列频谱进行截断,但是由于线性内插器的频谱在\omega>\frac{\pi}{L}仍然有较大的能量(幅度较高),因此可见线性内插可能不会获得很令人满意的内插效果。不过如果原本的采样频率就远大于原始信号的截至频率,则表明采样所得的序列的频谱较为集中,此时采用线性内插则会得到较好的效果。
对比线性内插以及三次样条内插,可以发现在\omega<\frac{\pi}{L}处,三次样条的旁瓣较宽,而在\omega>\frac{\pi}{L}处,三次样条的能量更小(幅度更低),即三次样条更接近于低通滤波器,因此三次样条内插会比线性内插的效果更好。
图中蓝色实线为线性内插频谱,红色虚线为三次样条内插频谱。为了更突出两者的频谱差异,右图对频谱的幅度进行了对数运算。
非整数因子重采样
我们前面讨论了减采样以及增采样,它们的系统分别被称为抽取器与内插器。对于非整数因子,我们可以通过先接一个内插器,后接一个抽取器这种级联的方式来得到该重采样系统。例如,若L=100,M=101,则重采样的周期为1.01T
由于中间两个都是低通滤波器,因此可以合并成一个低通滤波器,取其中的最小值min(\pi/L, \pi/M)作为截至频率,增益为L。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律