2016-10-17 20 views
1

我发现了一个类似的问题,但没有找到合适的答案。如何计算正弦波的最小周期在缓冲区中有整数N个周期?

我想有正弦波缓冲剂,做音频合成,和想要计算最佳尺寸为缓冲器,以避免伪像其中样品中测得的正弦波的周期是一个非整数。

例如,正弦在A4,440.0赫兹,具有44100的采样率,重复每四百四十零分之一* 44100的样品,或每100.22727272727272样品。如果您只是创建100(或101)个采样的循环缓冲区以包含正弦的单个循环,则播放对于不相交会产生明显的伪影。

基于该响应到以前的海报的版本,所提出的解决方案是表达期间作为一个整体分数,并找到最大公约数找到所需的周期和样本数量。然而,在实践中,我一直在寻找最大公约数计算为1的比率,这在我看来是不太可能的。

使用上面的例子,在Python:

freq = 440.0 
rate = 44100 
period = 1.0/freq * rate 
ratio = period.as_integer_ratio() 
from fractions import gcd 
divisor = gcd(*ratio) 

除数等于1,显然这意味着不存在公约数,这意味着它需要的频率的无限循环到曾经发现样品的整数倍,以完美存储正弦。

我做错了吗?还有其他解决方案吗?

在实践中注意到,我发现将缓冲区大小设置在1000x左右,正弦的实际周期消除了裸耳的伪像,但是我想降低我的内存使用量,所以想在数学上确定较小的基于任意频率的容许缓冲区大小。

+0

你只是想避免昂贵的电话'罪'?在这种情况下,你可能会考虑错误的方法。您可以存储一个正弦值表格,以适当的频率进行采样,然后通过内插表格中的相邻值为任意值生成“sin”近似值。 – paddy

+0

paddy缓冲区*是*查找表。即时通过在每帧中添加许多正弦波来创建泛音系列,然后在合成器中演奏的每个音符进行合成。复制缓冲区的速度比在每次传递时计算每个样本要快得多 –

+0

当然,复制速度很快,但不容易产生任意频率。你是否建议你为每一个你想添加的谐波都有不同的缓冲区?这听起来像是你正在以样本域映射到时域的形式思考这个问题,而不是相反。保持“播放头”确切地告诉你当前样本在波浪周期中的位置并不昂贵,然后在表格中查找幅度值。 – paddy

回答

0

返回1的gcd(*ratio)告诉您,您用period.as_integer_ratio()获得的分数已经被简化了,而不是“它需要频率的无限循环才能找到整数个样本来完美存储正弦”。

但是计算period = 1.0/freq * rate时简化可能不会那么大给舍入误差。您会使用会更好:

divisor = fractions.gcd(rate, freq) 
ratio = (rate/divisor, freq/divisor) 

在这一点上,因为ratio是一个简化的级分(在特定情况下(2205, 22)),ratio[1]周期将适合于样品的整数倍(更具体地说ratio[0]*ratio[1]或在特定情况下48510样品)。

+0

啊,你是对的。当我发布时,我太累了。然而,它告诉我,对于许多感兴趣的频率,需要具有整数N个周期的样本数量已经比我仅使用1000个周期左右的默认情况下大得多。 我正在寻找替代方法的蛮力检查每N个周期如何接近整数n个样本是必需的,如果小数部分低于一个阈值,使用它。还不确定,如果这消除了可听见的文物。 –

+0

但是,由于as_integer_ratio()返回的比率不是很好简化。例如。打印(440.0/44100).as_integer_ratio()显示(2875767925323201,288230376151711744),显然不像(440/44100)那么简单。并且gcd()返回1的事实证明gcd()有缺陷,或者获得的比率由于浮点错误而关闭。使用gmpy.mpq()我有更好的运气。 –