C:数值计算 (FFT)
这个问题是针对任何 Numeric Recipes 的粉丝或任何熟悉 FFT 的人。
谁能解释为什么实部是通过 -2*(sin(theta/2))^2 计算的? 我似乎无法理解它。我看过其他示例,例如 http://www.dspdimension.com/admin /dft-a-pied/ 教程简单地将 cos(theta) 视为实数,将 -sin(theta) 视为虚数。我也在这里看到了基本的http://www.dspguide.com/ch12/3。 htm 将其列为实数 cos(theta) 和虚数 -sin(theta)。我可以想到更多一些简单地将余弦和-sin 视为实数和虚数的资源。
cos(theta) = 1-2*(sin(theta/2))^2
如果上面的三角恒等式为真,那么为什么这不成立呢?
theta=isign*(6.28318530717959/mmax);
wtemp=sin(0.5*theta);
wpr = -2.0*wtemp*wtemp;
wpi=sin(theta);
我假设数值配方必须使用一些三角恒等式?我似乎无法弄清楚,书上根本没有解释。
代码在这里找到: 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
This question is directed at any fans of Numerical Recipes or anyone that understands FFT well.
Can anyone explain why the real component is calculated by -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. 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. I can think of a few more resources that simply take the cos and -sin as real and imaginary.
cos(theta) = 1-2*(sin(theta/2))^2
if the above trig identity is true, then why does this not folllow?
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? 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
#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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
起始:
所以:
ei ( Φ+δ)
= cos(Φ + δ) + i sin(Φ + δ)
= cos(Φ) cos(δ) - sin(Φ) sin(δ) + i [sin(Φ) cos( δ) + cos(φ) sin(δ)]
= cos(φ) [ 1 - 2 sin2(δ/2) ] + i sin(φ) [ 1 - 2 sin 2(δ/2) ] + i sin(δ) [ i * sin(φ) + cos(φ) ]
= [ cos(φ) + i sin(φ) ] [ 1 - 2 sin2(δ/2) ] + [ cos(φ) + i sin(φ) ] i sin(δ)
= ei φ + ei φ [ - 2 sin2(δ/2) + i sin(δ)]
编辑:对我而言,这是很多无用的格式。实际上更简单:
对于任何
y
,y(a+b) = ya × yb。因此:ei (φ+δ)
= ei φ ei δ
= ei φ [ cos (δ) + i sin(δ) ]
= ei φ [ 1 - 2 sin2(δ/2) + i sin(δ) ]
Start from:
So:
ei (φ+δ)
= cos(φ + δ) + i sin(φ + δ)
= cos(φ) cos(δ) - sin(φ) sin(δ) + i [sin(φ) cos(δ) + cos(φ) sin(δ)]
= cos(φ) [ 1 - 2 sin2(δ/2) ] + i sin(φ) [ 1 - 2 sin2(δ/2) ] + i sin(δ) [ i * sin(φ) + cos(φ) ]
= [ cos(φ) + i sin(φ) ] [ 1 - 2 sin2(δ/2) ] + [ cos(φ) + i sin(φ) ] i sin(δ)
= ei φ + ei φ [ - 2 sin2(δ/2) + i sin(δ)]
Edit: That was a lot of useless formatting on my part. It's actually way simpler:
y(a+b) = ya × yb for any
y
. So:ei (φ+δ)
= ei φ ei δ
= ei φ [ cos(δ) + i sin(δ) ]
= ei φ [ 1 - 2 sin2(δ/2) + i sin(δ) ]
余弦半角恒等式的一种形式是:
不确定这是否回答了您的问题。
One form of the half angle identity for cosines is:
Not sure if that answers your question.
原因是为了数值精度。如果您仔细检查以下代码:
并且
它们旨在协同工作以产生正确的预期结果。一个朴素的方法将实现如下:
和
和 具有无限精度将在功能上等效。
然而,当
theta
接近零时(即大量样本点或较大的nn
),cos(theta)
就会出现问题,因为对于小角度cos(theta)
接近 1,斜率接近 0。并且在某个角度cos(theta) == 1
。我的实验表明,对于 floatcos(2*PI/N) == 1
来说,对于 float (即 32 位精度)来说,N >= 25736
正是如此。 25,736 点的 FFT 是可以想象的。因此,为了避免这个问题,wpr
使用三角学的半角公式计算为cos(theta)-1
。它是用sin
计算的,对于小角度来说非常精确,因此对于小角度,wpr
和wpi
都小而精确。然后,通过在复数乘法之后重新添加 1,可以在更新代码中撤消此操作。用数学表达,我们得到:更新规则为:
The reason is for numerical accuracy. If you closely examine the following code:
and
they are designed to work together to yield the correct expected result. A naive approach would be implemented as follows:
and
and with infinite precision would be functionally equivalent.
However when
theta
is close to zero (i.e. a lot of sample points or largenn
),cos(theta)
becomes problematic, because for small anglescos(theta)
approaches 1 and has a slope approaching 0. And at some anglecos(theta) == 1
. My experimentation shows that for floatcos(2*PI/N) == 1
exactly forN >= 25736
for float (i.e. 32-bit precision). A 25,736 point FFT is conceivable. So to avoid this problemwpr
is computed ascos(theta)-1
using the half angle formula from trigonometry. It is computed withsin
which is very precise for small angles, thus for small angles bothwpr
andwpi
are small and precise. This is then undone in the update code by adding the 1 back back on after the complex multiply. Expressed mathematically, we get:and the update rule is:
我不太了解FFT,我做过一个,但已经很长时间了。
所以我在 http://www.sosmath.com/trig 查找了三角恒等式/Trig5/trig5/trig5.html
并根据 sin(u)*sin(v) 的第一个“乘积求和”恒等式,我们有
sin^2(theta/2) = (1/2) [cos(零) - cos(theta)] = 0.5 - 0.5 cos(theta)
这有帮助吗?
I don't know FFT well I've done one but its been a long time.
So I looked up trig identities at http://www.sosmath.com/trig/Trig5/trig5/trig5.html
and from the first "Product-To-Sum" identity for sin(u)*sin(v) we have
sin^2(theta/2) = (1/2) [cos(zero) - cos(theta)] = 0.5 - 0.5 cos(theta)
Does this help?
令人困惑的是,NR 使用数学/物理版本的 FFT,它以与 EE 定义 FFT 相反的方式旋转旋转因子。所以 NR 正向是 EE 逆向,反之亦然。请注意,在 NR 中,前向指数具有正指数,而不是 EE 负指数。 EE 方法将时间转换为频率,其中数学和物理版本使用角动量。
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. So the NR forward is the EE inverse and visa versa. Notice that in NR the forward has a positive exponent instead of the EE negative exponent. The EE method transforms time to frequency where the Math and Physics version plays with angular momentum.
他们使用三角恒等式来最小化需要计算的循环函数的数量。许多快速实现只是查找这些函数。如果你真的想知道,你需要通过展开上面的循环并进行适当的变量替换来计算出细节......是的,很乏味。
顺便说一句,众所周知,NR 的实现速度非常慢。
保罗
They are using trig identities to minimize the number of circular functions they need to compute. 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.
Paul
好的,这是三角恒等式。它不是半 cos(theta) 三角恒等式的原因是因为依赖欧拉和虚数。数学仍然超出我的能力......
(来源:librow.com)
Ok so here is the trig identity. The reason its not the half cos(theta) trig identity is because of the reliance on euler and imaginary numbers. The math is still beyond me...
(source: librow.com)