c – 快速等效于STK中引用的DSP的sin()
我正在使用Perry Cook的Synthesis Toolkit(STK)来生成锯齿和方波. STK包括这个基于BLIT的锯齿振荡器:
inline STKFloat BlitSaw::tick( void ) { StkFloat tmp,denominator = sin( phase_ ); if ( fabs(denominator) <= std::numeric_limits<StkFloat>::epsilon() ) tmp = a_; else { tmp = sin( m_ * phase_ ); tmp /= p_ * denominator; } tmp += state_ - C2_; state_ = tmp * 0.995; phase_ += rate_; if ( phase_ >= PI ) phase_ -= PI; lastFrame_[0] = tmp; return lastFrame_[0]; } 方波振荡器大致相似.在顶部,有这样的评论: // A fully optimized version of this code would replace the two sin // calls with a pair of fast sin oscillators,for which stable fast // two-multiply algorithms are well known. 我不知道从哪里开始寻找这些“快速双倍算法”,我很欣赏一些指针.我可以使用查找表,但我很想知道这些’快速振荡器’是什么.我也可以使用缩写的泰勒系列,但这可能超过两倍.搜索没有发现任何太多,虽然我确实发现了这个近似值: #define AD_SIN(n) (n*(2.f- fabs(n))) 绘制出来表明它不是-1到1范围之外的近似值,所以当phase_在-pi到pi的范围内时,我认为我不能使用它: 这里,正弦是蓝线,紫线是近似值. 分析我的代码表明,对sin()的调用是最耗时的调用,所以我真的想优化这一部分. 谢谢 编辑感谢您详细而多样的答案.我将在周末探索这些并接受一个. 编辑2请匿名关闭选民请在评论中解释他们的投票吗?谢谢. 解决方法
本质上,正弦振荡器是一个(或多个)变量,随着每个DSP步骤而变化,而不是从头开始重新计算.
最简单的是基于以下三角形身份:(其中d是常数,因此cos(d)和sin(d)也是如此) sin(x+d) = sin(x) cos(d) + cos(x) sin(d) cos(x+d) = cos(x) cos(d) - sin(x) sin(d) 然而,这需要两个变量(一个用于sin,一个用于cos)和4个乘法来更新.然而,这仍然比在每一步计算完整正弦要快得多. Oli Charlesworth的解决方案基于这个通用方程的解决方案 A_{n+1} = a A_{n} + A_{n-1} 在寻找形式A_n = k e ^(iθ)的解的情况下给出θ的等式. e^(i theta (n+1) ) = a e^(i theta n ) + b e^(i theta (n-1) ) 这简化为 e^(i theta) - e^(-i theta ) = a 2 cos(theta) = a 给予 A_{n+1} = 2 cos(theta) A_{n} + A_{n-1} 无论您使用哪种方法,您都需要为每个频率使用一个或两个这些振荡器,或者使用另一个触发标识来获得更高或更低的频率. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |