简体   繁体   English

C:数值接收(FFT)

[英]C: Numerical Recipies (FFT)

This question is directed at any fans of Numerical Recipes or anyone that understands FFT well. 这个问题针对的是Numerical Recipes的任何粉丝或任何了解FFT的人。

Can anyone explain why the real component is calculated by -2*(sin(theta/2))^2 ? 任何人都可以解释为什么真实分量是由-2 *(sin(theta / 2))^ 2计算的? I can't seem to wrap my head around it. 我似乎无法绕过它。 I've seen other examples such as http://www.dspdimension.com/admin/dft-a-pied/ tutorial which simply takes cos(theta) as real and -sin(theta) as imaginary. 我已经看过其他的例子,例如http://www.dspdimension.com/admin/dft-a-pied/ tutorial,它简单地将cos(theta)视为真实,将-sin(theta)视为虚构。 I've also seen here in basic http://www.dspguide.com/ch12/3.htm which lists it as cos(theta) as real and -sin(theta) as imaginary. 我在这里也看到了基本的http://www.dspguide.com/ch12/3.htm ,它将cos(theta)列为real,-sin(theta)列为imaginary。 I can think of a few more resources that simply take the cos and -sin as real and imaginary. 我可以想到一些简单地将cos和-sin视为真实和想象的资源。

cos(theta) = 1-2*(sin(theta/2))^2

if the above trig identity is true, then why does this not folllow? 如果上面的trig标识是真的那么为什么不这样呢?

theta=isign*(6.28318530717959/mmax);
wtemp=sin(0.5*theta);
wpr = -2.0*wtemp*wtemp;
wpi=sin(theta);

I am assuming Numerical Recipe must be using some trig identity? 我假设Numerical Recipe必须使用一些trig身份? I can't seem to figure it out and the book doesn't explain at all. 我似乎无法弄明白,这本书根本没有解释。

Code found here: http://ronispc.chem.mcgill.ca/ronis/chem593/sinfft.c.html 代码见: http//ronispc.chem.mcgill.ca/ronis/chem593/sinfft.c.html

#define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr

void four1(double *data,unsigned long nn,int isign)
{
        unsigned long n,mmax,m,j,istep,i;
        double wtemp,wr,wpr,wpi,wi,theta;
        double tempr,tempi;

        n=nn << 1;
        j=1;
        for (i=1;i<n;i+=2) {
                if (j > i) {
                        SWAP(data[j],data[i]);
                        SWAP(data[j+1],data[i+1]);
                }
                m=n >> 1;
                while (m >= 2 && j > m) {
                        j -= m;
                        m >>= 1;
                }
                j += m;
        }
        mmax=2;
        while (n > mmax) {
                istep=mmax << 1;
                theta=isign*(6.28318530717959/mmax);
                wtemp=sin(0.5*theta);
                wpr = -2.0*wtemp*wtemp;
                wpi=sin(theta);
                wr=1.0;
                wi=0.0;
                for (m=1;m<mmax;m+=2) {
                        for (i=m;i<=n;i+=istep) {
                                j=i+mmax;
                                tempr=wr*data[j]-wi*data[j+1];
                                tempi=wr*data[j+1]+wi*data[j];
                                data[j]=data[i]-tempr;
                                data[j+1]=data[i+1]-tempi;
                                data[i] += tempr;
                                data[i+1] += tempi;
                        }
                        wr=(wtemp=wr)*wpr-wi*wpi+wr;
                        wi=wi*wpr+wtemp*wpi+wi;
                }
                mmax=istep;
        }
}
#undef SWAP

Start from: 从...开始:

  • cos(A+B) = cos(A) cos(B) - sin(A) sin(B) cos(A + B)= cos(A)cos(B) - sin(A)sin(B)
  • sin(A+B) = sin(A) cos(B) + cos(A) sin(B) sin(A + B)= sin(A)cos(B)+ cos(A)sin(B)
  • cos(2A) = 1 - 2 sin 2 (A) cos(2A)= 1 - 2 sin 2 (A)
  • e i θ = cos(θ) + i sin(θ) eiθ = cos(θ)+ i sin(θ)

So: 所以:

e i (φ+δ) e i(φ+δ)

= cos(φ + δ) + i sin(φ + δ) = cos(φ+δ)+ i sin(φ+δ)

= cos(φ) cos(δ) - sin(φ) sin(δ) + i [sin(φ) cos(δ) + cos(φ) sin(δ)] = cos(φ)cos(δ) - sin(φ)sin(δ)+ i [sin(φ)cos(δ)+ cos(φ)sin(δ)]

= cos(φ) [ 1 - 2 sin 2 (δ/2) ] + i sin(φ) [ 1 - 2 sin 2 (δ/2) ] + i sin(δ) [ i * sin(φ) + cos(φ) ] = cos(φ)[1 - 2 sin 2 (δ/ 2)] + i sin(φ)[1 - 2 sin 2 (δ/ 2)] + i sin(δ)[i * sin(φ)+ cos (φ)]

= [ cos(φ) + i sin(φ) ] [ 1 - 2 sin 2 (δ/2) ] + [ cos(φ) + i sin(φ) ] i sin(δ) = [cos(φ)+ i sin(φ)] [1 - 2 sin 2 (δ/ 2)] + [cos(φ)+ i sin(φ)] i sin(δ)

= e i φ + e i φ [ - 2 sin 2 (δ/2) + i sin(δ)] = eiφ + eiφ [ - 2 sin 2 (δ/ 2)+ i sin(δ)]

Edit : That was a lot of useless formatting on my part. 编辑 :这对我来说是很多无用的格式。 It's actually way simpler: 它实际上更简单:

y (a+b) = y a × y b for any y . 对于任何y y (a + b) = y a ×y b So: 所以:

e i (φ+δ) e i(φ+δ)

= e i φ e i δ = E IφE

= e i φ [ cos(δ) + i sin(δ) ] = eiφ [cos(δ)+ i sin(δ)]

= e i φ [ 1 - 2 sin 2 (δ/2) + i sin(δ) ] = eiφ [1 - 2 sin 2 (δ/ 2)+ i sin(δ)]

One form of the half angle identity for cosines is: 余弦的半角恒等式的一种形式是:

cos(theta) = 1 - 2*(sin(theta/2)^2)

Not sure if that answers your question. 不确定是否能回答你的问题。

The reason is for numerical accuracy. 原因在于数值精度。 If you closely examine the following code: 如果仔细检查以下代码:

wtemp=sin(0.5*theta);
wpr = -2.0*wtemp*wtemp;
wpi=sin(theta);

and

wr=(wtemp=wr)*wpr-wi*wpi+wr;
wi=wi*wpr+wtemp*wpi+wi;

they are designed to work together to yield the correct expected result. 它们旨在协同工作以产生正确的预期结果。 A naive approach would be implemented as follows: 一种天真的方法将实施如下:

wpr = cos(theta);
wpi = sin(theta);

and

wtemp = wr;
wr =wr*wpr - wi*wpi;
wi =wi*wpr + wtemp*wpi;

and with infinite precision would be functionally equivalent. 并且具有无限精度将在功能上等效。

However when theta is close to zero (ie a lot of sample points or large nn ), cos(theta) becomes problematic, because for small angles cos(theta) approaches 1 and has a slope approaching 0. And at some angle cos(theta) == 1 . 然而,当theta接近于零(即大量采样点或大nn )时, cos(theta)成为问题,因为对于小角度, cos(theta)接近1并且具有接近0的斜率。并且在某个角度cos(theta) == 1 My experimentation shows that for float cos(2*PI/N) == 1 exactly for N >= 25736 for float (ie 32-bit precision). 我的实验表明浮动cos(2*PI/N) == 1 ,对于浮点数(即32位精度), N >= 25736 A 25,736 point FFT is conceivable. 可以想象25,736点FFT。 So to avoid this problem wpr is computed as cos(theta)-1 using the half angle formula from trigonometry. 因此,为了避免这个问题,使用三角法的半角公式将wpr计算为cos(theta)-1 It is computed with sin which is very precise for small angles, thus for small angles both wpr and wpi are small and precise. 它用sin计算,对于小角度非常精确,因此对于小角度, wprwpi都很小且精确。 This is then undone in the update code by adding the 1 back back on after the complex multiply. 然后在更新代码中通过在复数乘法后重新添加1来撤消。 Expressed mathematically, we get: 用数学表达式,我们得到:

w_p = cos(theta) - 1    + i*sin(theta) 
    = -2*sin^2(theta/2) + i*sin(theta)

and the update rule is: 并且更新规则是:

w = w * (w_p + 1) 
  = w + w*w_p

What is confusing is that NR uses the Math/Physics version of the FFT which rotates the twiddle factors the opposite way that EEs define the FFT. 令人困惑的是,NR使用FFT的数学/物理版本,它旋转旋转因子的方式与EE定义FFT的方式相反。 So the NR forward is the EE inverse and visa versa. 所以NR前锋是EE逆,反之亦然。 Notice that in NR the forward has a positive exponent instead of the EE negative exponent. 请注意,在NR中,forward具有正指数而不是EE负指数。 The EE method transforms time to frequency where the Math and Physics version plays with angular momentum. EE方法将时间转换为数学和物理版本以角动量播放的频率。

I don't know FFT well I've done one but its been a long time. 我不知道FFT我已经完成了一次,但已经很长时间了。

So I looked up trig identities at http://www.sosmath.com/trig/Trig5/trig5/trig5.html 所以我在http://www.sosmath.com/trig/Trig5/trig5/trig5.html查看了trig身份

and from the first "Product-To-Sum" identity for sin(u)*sin(v) we have 从我们所拥有的罪(你)*罪(v)的第一个“产品 - 总和”身份

sin^2(theta/2) = (1/2) [cos(zero) - cos(theta)] = 0.5 - 0.5 cos(theta) sin ^ 2(theta / 2)=(1/2)[cos(零) - cos(theta)] = 0.5 - 0.5 cos(theta)

Does this help? 这有帮助吗?

They are using trig identities to minimize the number of circular functions they need to compute. 他们使用trig标识来最小化他们需要计算的循环函数的数量。 Many fast implementations just look up these functions. 许多快速实现只是查找这些功能。 If you really want to know you need to just work out the details by unrolling the loop above and making the appropriate variable substitutions....tedious yes. 如果你真的想知道你需要通过展开上面的循环并进行适当的变量替换来计算细节....单调是的。

BTW, the NR implementation is known to be very slow. 顺便说一句,已知NR实现非常慢。

Paul 保罗

Ok so here is the trig identity. 好的,这里是trig标识。 The reason its not the half cos(theta) trig identity is because of the reliance on euler and imaginary numbers. 它不是半cos(theta)trig标识的原因是因为依赖于欧拉和虚数。 The math is still beyond me... 数学仍然超出我的意义......

链接文字
(source: librow.com ) (来源: librow.com

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM