c++ - 快速等效于 STK 中引用的 DSP 的 sin()

标签 c++ algorithm math signal-processing

我正在使用 Perry Cook 的综合工具包 (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 范围内时我不能使用它:

Plot of Sine vs. approximation

这里,正弦是蓝线,紫线是近似值。

分析我的代码表明对 sin() 的调用无疑是最耗时的调用,因此我真的很想优化这一部分。

谢谢

编辑 感谢您提供详细而多样的答案。我将探索这些并在周末接受一个。

EDIT 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 theta n) 形式的解时,给出了 theta 的方程。

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}

无论您使用哪种方法,您都需要为每个频率使用一个或两个这些振荡器,或者使用另一个三角恒等式来导出更高或更低的频率。

关于c++ - 快速等效于 STK 中引用的 DSP 的 sin(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9285983/

相关文章:

c++ - 防止子进程进行系统调用

c++ - boost::asio::async_write 没有完成它的任务

c - 如何在C中读取csv的特定列

c# - 数学函数消除负号

math - 如何使物体沿弧线运动?

c++ - 如何区分/分隔模板功能的两个连续可变参数模板参数包?

c++ - 如何在类构造函数中设置STL队列的大小

algorithm - Kotlin - 按类别和子类别排序的列表

c++ - 晶格缩减

c - 四元数 "lookAt"函数