简体   繁体   English

在 VBA Excel 中实现 Rosseta Code FFT

[英]Implementing Rosseta Code FFT into VBA Excel

I attempted to implement the FFT Rosetta Code into VBA excel.我试图将FFT Rosetta 代码实现到 VBA excel 中。 I was unable to reconstruct the same output data exactly as written in the Rosetta Code.我无法完全按照 Rosetta Code 中所写的方式重建相同的输出数据。 At first I thought it was type conversion mismatch, but scaling the input values by 1.1 scaled the output values by 1.1 as well.起初我以为是类型转换不匹配,但是将输入值缩放 1.1 也会将输出值缩放 1.1。 The only aspect of my code that I think could be in question is how I implemented the referenced arrays in code versus what Rosetta writes.我认为我的代码唯一可能有问题的方面是我如何在代码中实现引用的数组,而不是 Rosetta 编写的内容。 I discovered Rosetta shifts the addresses of the arrays by writing out + step and buf + step in its odd recursion calls.我发现 Rosetta 通过在其奇数递归调用中写出 + step 和 buf + step 来移动数组的地址。 I am unaware of a similar construction in VBA, so I simply passed an additional recursion parameter shift, which keeps track of the shifting of addresses as its passed into the next recursion call.我不知道 VBA 中有类似的结构,所以我只是传递了一个额外的递归参数移位,它会在地址传递到下一个递归调用时跟踪地址的移位。

What is wrong with my shift implementation or is it something else?我的班次实施有什么问题还是别的什么?

Rosetta claims its FFT is memory in place, however they make an extra copy of the data and store it into out[]. Rosetta 声称其 FFT 是内存到位,但是他们制作了一份额外的数据副本并将其存储到 out[] 中。 I would appreciate an explanation of why this is so.我很感激解释为什么会这样。

FFT Rosetta Code in C C中的FFT Rosetta代码

void _fft(cplx buf[], cplx out[], int n, int step)
{
    if (step < n) {
        _fft(out, buf, n, step * 2);
        _fft(out + step, buf + step, n, step * 2);

        for (int i = 0; i < n; i += 2 * step) {
            cplx t = cexp(-I * PI * i / n) * out[i + step];
            buf[i / 2]     = out[i] + t;
            buf[(i + n)/2] = out[i] - t;
        }
    }
}

void fft(cplx buf[], int n)
{
    cplx out[n];
    for (int i = 0; i < n; i++) out[i] = buf[i];

    _fft(buf, out, n, 1);
}

My attempted FFT in VBA我在 VBA 中尝试的 FFT

Private Sub rec_fft(ByRef buf, ByRef out, ByVal n, ByVal step, ByVal shift)
If step < n Then
    Dim ii As Long
    Dim pi As Double
    pi = 3.14159265358979 + 3.23846264338328E-15
    Dim c1(1 To 2) As Long
    Dim c2(1 To 2) As Double
    Call rec_fft(out, buf, n, step * 2, shift)
    Call rec_fft(out, buf, n, step * 2, shift + step)
    For i = 1 To n / (2 * step)
        ii = 2 * step * (i - 1)    
        c1(1) = Cos(-1 * pi * CDbl(ii) / CDbl(n))
        c1(2) = Sin(-1 * pi * CDbl(ii) / CDbl(n))
        c2(1) = c1(1) * out(shift + 1 + ii + step, 1) - c1(2) * out(shift + 1 + ii + step, 2)
        c2(2) = c1(1) * out(shift + 1 + ii + step, 2) + c1(2) * out(shift + 1 + ii + step, 1)
        buf(shift + 1 + ii / 2, 1) = out(shift + 1 + ii, 1) + c2(1)
        buf(shift + 1 + ii / 2, 2) = out(shift + 1 + ii, 2) + c2(2)
        buf(shift + 1 + (ii + n) / 2, 1) = out(shift + 1 + ii, 1) - c2(1)
        buf(shift + 1 + (ii + n) / 2, 2) = out(shift + 1 + ii, 2) - c2(2)
    Next i
End If

End Sub

Private Sub fft(ByRef buf, ByVal n)
    Dim out() As Double
    ReDim out(1 To n, 1 To 2)
    For i = 1 To n
        out(i, 1) = buf(i, 1)
        out(i, 2) = buf(i, 2)
    Next i
    Call rec_fft(buf, out, n, 1, 0)
End Sub

Output Comparison输出比较

Input Data: 1 1 1 1 0 0 0 0 
Rosetta FFT : 4 (1, -2.41421) 0 (1, -0.414214) 0 (1, 0.414214) 0 (1, 2.41421)
My FFt : 4 (1, -3) 0 (1, -1) 0 (1, 1) 0 (1, 3)

You have declared c1 as Long :您已将 c1 声明为Long

 "Dim c1(1 To 2) As Long"

Change it to Double and it works:将其更改为Double并且它可以工作:

 "Dim c1(1 To 2) As Double"

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

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