梳理一下各大平台使用的sample rate convert算法

梳理一下各大平台使用的sample rate convert算法梳理一下各大平台使用的resample算法

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

前言

转采样属于数字信号重建的范畴,整数倍的升降采样可以通过插值抽取+带限滤波的方法【1】,并且通过级联来实现任意比值的采样率转换。这里需要对奈奎斯特采样定理,以及数字信号时频关系有比较清晰的理解。还有一种方法是插值,插值的方法比较多,在参考里有一阶保持FOH零阶保持ZOH三次样条函数splinesinc函数,引用的博文中有比较直观的分析和事例。那么在各大平台,最后都是用什么实现的resample重建呢?

Smarc对Interpolation和Decimation的执著

来自法国的Smarc的内核是经典的数字信号差值抽取方法,能够支持任意采样率,众所周知,48k到44.1k的互相转采样是个挑战,在SMARC method详细的讲述的算法的特点,通过因式分解和多相、多阶实现降低了FIR的阶数,提高了算法效率。简单的翻译一些文中的思想如下:
经典的香农插值抽取法虽然便于理解,但碍于为了实现非整数(有理数)比的转采样,滤波器级数可能长的无法用于实现,文中举了一个例子,可以这样理解 44100 48000 = 147 160 \frac{44100}{48000}=\frac{147}{160} 4800044100=160147那么两个频率的最小公倍数为: 44100 ∗ 160 = 48000 ∗ 147 = 7056000 = 7.056 M 44100*160=48000*147=7056000=7.056M 44100160=48000147=7056000=7.056M
为了满足48000->44100的变换,满足截止频率22.05k的设计要求,需要FIR的阶数38560,这个抽头和延时是无法接受,这个计算是利用smarc内置的remez方法。smarc则采样了多级滤波器的设计思想,规避了长延时的问题,每一级采用很小的系数比,同时结合多相滤波的实现,进一步优化算法。对于降采样抽取:

1

1

1/M

x(n)

h(n)

w(n)

M decimation

y(n)

经过低通滤波消除混叠频率后就可以抽取除想要的新采样。

CCRMA & speex

搜了一下外文网站,能够完整讲述插值重建的就是斯坦福大学的这篇Digital Audio Resampling Home Page,文中讲述了带限插值的原理。简单的翻译一下,根据奈奎斯特和傅里叶变换的知识,时域信号可以被重建:
x ( t ) ^ ≜ ∑ n = − ∞ ∞ x ( n T s ) h s ( t − n T s ) ≡ = x ( t ) \hat{x(t)} \triangleq\sum_{n=-\infty}^{\infty}x(nT_s)h_s(t-nT_s)\equiv=x(t) x(t)^n=x(nTs)hs(tnTs)=x(t)
这里的 h s ( t ) ≜ s i n c ( F s t ) ≜ s i n ( π F s t ) π F s t h_s(t)\triangleq sinc(F_st)\triangleq \frac{sin(\pi F_st)}{\pi F_st} hs(t)sinc(Fst)πFstsin(πFst)
s i n c sinc sinc函数的神奇就不赘述,但这个公式这么干是不行滴,因为正负无穷谁也受不了,所以还得加个窗,减小纹波和过冲。文中利用凯撒窗来评估对截取5个过零点的sinc函数卷积的频响比较,截取拼接了一下,效果变化很明显。
在这里插入图片描述如果要利用这个公式进行新采样率 F s ′ F_s^\prime Fs的抽取,可以改写: x ( n T s ′ ) = ∑ n = − ∞ ∞ x ( n T s ) h s ( n T s ′ − n T s ) = ∑ n = − ∞ ∞ x ( n T s ) h s ( n ( T s ′ − T s ) ) \begin{aligned} x(nT_s^\prime)&=\sum_{n=-\infty}^{\infty}x(nT_s)h_s(nT_s^\prime-nT_s)\\ &=\sum_{n=-\infty}^{\infty}x(nT_s)h_s(n(T_s^\prime-T_s)) \end{aligned} x(nTs)=n=x(nTs)hs(nTsnTs)=n=x(nTs)hs(n(TsTs))据此,首先准备sinc函数的样点,找了一张图:
在这里插入图片描述
如果能对准备好的 h s ( t ) h_s(t) hs(t)样点进行插值,那么就可以根据公式求出累加后的新采样点 x ( n T s ′ ) x(nT_s^\prime) x(nTs),这里假设 ρ = F s ′ F s \rho=\frac{F_s^\prime}{F_s} ρ=FsFs ρ \rho ρ小于1意味着降采样, ρ \rho ρ大于1则是升采样。这相当于设计一个低通滤波器,那么这个滤波器实际上只需要存储半边的系数。那么剩下来的问题就是这个插值如何计算了。原文写的很节略,刚开始看的云山雾绕,不如先回归公式,假设就使用一个矩形窗,截断无限长的冲激响应。 x ′ ( n ) ≜ ∑ n = − N N x ( n ) h s ( n T s ′ − n T s ) ≜ ∑ n = − N N x ( n ) h s ( n ( T s ′ − T s ) ) ≜ ∑ n = − N N x ( n ) h s ( n + ( T s ′ − T s ) T s ) \begin{aligned} x^\prime(n)&\triangleq\sum_{n=-N}^{N}x(n)h_s(nT_s^\prime-nT_s)\\ &\triangleq\sum_{n=-N}^{N}x(n)h_s(n(T_s^\prime-T_s))\\ &\triangleq\sum_{n=-N}^{N}x(n)h_s(n+\frac{(T_s^\prime-T_s)}{T_s}) \end{aligned} x(n)n=NNx(n)hs(nTsnTs)n=NNx(n)hs(n(TsTs))n=NNx(n)hs(n+Ts(TsTs))
上面这个卷积不是因果系统,这点跟插值抽取一样的特性。只要输入 2 N + 1 2N+1 2N+1个输入序列,同时能求得偏离 h s ( n ) h_s(n) hs(n)的插值,即可以算出来转采样之后的点。具体实现细节不追了。

sox & deadbeef

从它github主页上的描述

 for real-time resampling, libsoxr may have a higher latency
than non-FFT based resamplers.  For example, when using the `High Quality'
configuration to resample between 44100Hz and 48000Hz, the latency is
around 1000 output samples, i.e. roughly 20ms (though passband and FFT-
size configuration parameters may be used to reduce this figure).

推测这是个频域的转采样算法,据说是被deadbeef采用的,但实时性一般,

WebRTC

webRtc也有sinc带限转采样方法,对于整数的也有抽取和插值的方法。稍微多说的是早期的webrtc是不支持多媒体44.1族的采样率。在AOSP的webrtc代码里能找到sinc框架。

ffmpeg

早期用的是libavcodec,后来改用libswresampleGitHub有源码可供分析

Secret Rabbit Code

这个平台借用一个客户的评价“完胜大部分主流”,那这个平台里的用到的就是插值方法:

  1. ZOH插值
  2. 线性插值
  3. sinc插值

其中前两种是简单的,但声音质量一般,后一种是“完美”插值重建,而且还分为fast/medium/quality三种滤波器插值系数可选,满足用户不同的需求,是一个比较成熟的实现平台。

参考

1.采样率变换和多速率filter
2.【 MATLAB 】MATLAB 实现模拟信号采样后的重建(三)一阶保持(FOH)内插
3.【 MATLAB 】MATLAB 实现模拟信号采样后的重建(三)应用三次样条函数spline实现内插
4.【 MATLAB 】MATLAB 实现模拟信号采样后的重建(二)零阶保持(ZOH)
5.【 MATLAB 】MATLAB 实现模拟信号采样后的重建(一)
【信号与系统学习笔记】—— 采样与恢复(内插重建方法解析)
数字信号处理之内插
零阶保持器(ZOH)
Resampling Audio Algorithms
Secret Rabbit Code
Resampling from hydrogenaudio
Resampling from dspguru
Digital Audio Resampling Home Page
FFmpeg/libswresample/
Planet CCRMA at home
CCRMA:libresample
shibatch SSRC
chirlu /soxr
重采样Resample 的一些研究记录
What is DeaDBeeF?
speex
Speex编码器中回声消除算法的分析与评估
[WebRTC架构分析]采样率转换

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/181211.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 局域网,园区网,广域网的区别是什么_局域网和互联网的区别与联系

    局域网,园区网,广域网的区别是什么_局域网和互联网的区别与联系局域网局域网LAN(LocalAreaNetwork):一般不大于10公里,而且通常只使用一种传输介质;地域上看局域网通常是用在一座建筑物或一个工厂内,使用上通常是某一单位或某一部门使用,规模上一般不超过几百个用户。(局域网也是相对而言,一栋楼可以看作一个局域网,一个国家性对于世界来说也可以看作一个局域网。多个楼栋,组成的局域网就可以看作一个园区网。)城域网MAN(MetropolitanAreaNetwork):城域网是一种比局域网更大的网,通常覆盖一个城市,从几十公里到100公里不等,可能

    2022年8月31日
    2
  • Python不使用int()函数把字符串转换为数字「建议收藏」

    Python不使用int()函数把字符串转换为数字「建议收藏」Python不使用int()函数把字符串转换为数字2018年05月21日14:18:45边缘ob边缘ob阅读数:1035https://blog.csdn.net/qq_33192555/a

    2022年7月6日
    26
  • cmpp发送短信[通俗易懂]

    cmpp发送短信[通俗易懂]思路:把各种操作解耦,创建各种线程异步进行1.创建一个阻塞队列用来存储任务2.创建一个任务线程,从待发表里取数据(待发表里有专门标明是否被处理过的字段),注入任务队列3.创建n个接收线程,向接收表中塞入数据4.创建n个发送进程,从任务队列里取数据,发送一共有待发表,接收表,已发表,发送错误表,回执状态表5张基础表具体基础代码参考cmpp2.0文档,或者自己搜索…

    2025年7月5日
    2
  • ms17010批量扫描备忘

    ms17010批量扫描备忘安装一些依赖:dpkg–add-architecturei386&&apt-getupdate&&apt-getinstallwine32rm-r~/.winewinecmd.exeexit漏洞扫描一:useauxiliary/scanner/smb…

    2022年6月9日
    46
  • kernel logo到开机动画之间闪现黑屏(android 5.X)

    kernel logo到开机动画之间闪现黑屏(android 5.X)

    2022年2月6日
    56
  • python定时执行函数_python定时执行详解「建议收藏」

    python定时执行函数_python定时执行详解「建议收藏」知识点1.sched模块,准确的说,它是一个调度(延时处理机制),每次想要定时执行某任务都必须写入一个调度。(1)生成调度器:s=sched.scheduler(time.time,time.sleep)第一个参数是一个可以返回时间戳的函数,第二个参数可以在定时未到达之前阻塞。可以说sched模块设计者是“在下很大的一盘棋”,比如第一个函数可以是自定义的一个函数,不一定是时间戳,第二个也可以…

    2025年11月9日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号