将精确的波形保存在内存中
Keeping exact wave form in memory
假设我有一个程序计算时间 t
的正弦波值。正弦波的形式为 sin(f*t + phi)
。振幅为 1
.
如果我只有一个 sin
学期,一切都很好。我可以随时轻松计算出价值 t
.
但是,在运行时,波形在与其他波形结合时会发生变化。 sin(f1 * t + phi1) + sin(f2 * t + phi2) + sin(f3 * t + phi3) + ...
最简单的解决方案是让 table 包含 phi
和 f
的列,遍历所有行,然后对结果求和。但是对我来说,一旦达到数千行,计算就会变慢。
有没有其他方法可以做到这一点?就像将所有正弦组合成一个 statement/formula?
有不同的基础(复数基础)可以有利于(即紧凑)表示不同的波形。最常见和最著名的是你提到的,通常称为傅立叶基础。例如,Daubechies 小波是一个相对较新的补充,它比傅里叶基更好地处理更多的不连续波形。但这确实是一个数学主题,如果您 post 在 Math Overflow 上,您可能会得到更好的答案。
如果你有一个傅里叶级数(即 f_i
= i f
对于某些 f)你可以使用 Clenshaw recurrence relation 这比计算所有正弦要快得多(但它可能稍微不太准确)。
在你的情况下,你可以考虑顺序:
f_k = exp( i ( k f t + phi_k) ) , where i is the imaginary unit.
注意 Im(f_k)
= sin( k f t + phi_k )
,这是你的序列。
还有
f_k = exp( i ( k f t + phi_k) ) = exp( i k f t ) exp( i phi_k )
因此你有 a_k = exp(i phi_k)
。您可以预先计算这些值并将它们存储在一个数组中。为简单起见,从现在起假设 a_0 = 0
。
现在,exp( i (k + 1) f t) = exp(i k f t) * exp(i f t)
,所以 alpha_k = exp(i f t)
和 beta_k = 0
。
您现在可以应用递归公式,在 C++ 中您可以这样做:
complex<double> clenshaw_fourier(double f, double t, const vector< complex<double> > & a )
{
const complex<double> alpha = exp(f * t * i);
complex<double> b = 0;
for (int k = a.size() - 1; k >0; -- k )
b = a[k] + alpha * b;
return a[0] + alpha * b;
}
假设 a[k] == exp( i phi_k )
。
答案的实部是cos(k f t + phi_k)
的总和,而虚部是sin(k f t + phi_k)
的总和。
如您所见,这仅使用加法和乘法,除了仅计算一次的 exp(f * t * i)
。
假设我有一个程序计算时间 t
的正弦波值。正弦波的形式为 sin(f*t + phi)
。振幅为 1
.
如果我只有一个 sin
学期,一切都很好。我可以随时轻松计算出价值 t
.
但是,在运行时,波形在与其他波形结合时会发生变化。 sin(f1 * t + phi1) + sin(f2 * t + phi2) + sin(f3 * t + phi3) + ...
最简单的解决方案是让 table 包含 phi
和 f
的列,遍历所有行,然后对结果求和。但是对我来说,一旦达到数千行,计算就会变慢。
有没有其他方法可以做到这一点?就像将所有正弦组合成一个 statement/formula?
有不同的基础(复数基础)可以有利于(即紧凑)表示不同的波形。最常见和最著名的是你提到的,通常称为傅立叶基础。例如,Daubechies 小波是一个相对较新的补充,它比傅里叶基更好地处理更多的不连续波形。但这确实是一个数学主题,如果您 post 在 Math Overflow 上,您可能会得到更好的答案。
如果你有一个傅里叶级数(即 f_i
= i f
对于某些 f)你可以使用 Clenshaw recurrence relation 这比计算所有正弦要快得多(但它可能稍微不太准确)。
在你的情况下,你可以考虑顺序:
f_k = exp( i ( k f t + phi_k) ) , where i is the imaginary unit.
注意 Im(f_k)
= sin( k f t + phi_k )
,这是你的序列。
还有
f_k = exp( i ( k f t + phi_k) ) = exp( i k f t ) exp( i phi_k )
因此你有 a_k = exp(i phi_k)
。您可以预先计算这些值并将它们存储在一个数组中。为简单起见,从现在起假设 a_0 = 0
。
现在,exp( i (k + 1) f t) = exp(i k f t) * exp(i f t)
,所以 alpha_k = exp(i f t)
和 beta_k = 0
。
您现在可以应用递归公式,在 C++ 中您可以这样做:
complex<double> clenshaw_fourier(double f, double t, const vector< complex<double> > & a )
{
const complex<double> alpha = exp(f * t * i);
complex<double> b = 0;
for (int k = a.size() - 1; k >0; -- k )
b = a[k] + alpha * b;
return a[0] + alpha * b;
}
假设 a[k] == exp( i phi_k )
。
答案的实部是cos(k f t + phi_k)
的总和,而虚部是sin(k f t + phi_k)
的总和。
如您所见,这仅使用加法和乘法,除了仅计算一次的 exp(f * t * i)
。