簡體   English   中英

在 VBA Excel 中實現 Rosseta Code FFT

[英]Implementing Rosseta Code FFT into VBA Excel

我試圖將FFT Rosetta 代碼實現到 VBA excel 中。 我無法完全按照 Rosetta Code 中所寫的方式重建相同的輸出數據。 起初我以為是類型轉換不匹配,但是將輸入值縮放 1.1 也會將輸出值縮放 1.1。 我認為我的代碼唯一可能有問題的方面是我如何在代碼中實現引用的數組,而不是 Rosetta 編寫的內容。 我發現 Rosetta 通過在其奇數遞歸調用中寫出 + step 和 buf + step 來移動數組的地址。 我不知道 VBA 中有類似的結構,所以我只是傳遞了一個額外的遞歸參數移位,它會在地址傳遞到下一個遞歸調用時跟蹤地址的移位。

我的班次實施有什么問題還是別的什么?

Rosetta 聲稱其 FFT 是內存到位,但是他們制作了一份額外的數據副本並將其存儲到 out[] 中。 我很感激解釋為什么會這樣。

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);
}

我在 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

輸出比較

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)

您已將 c1 聲明為Long

 "Dim c1(1 To 2) As Long"

將其更改為Double並且它可以工作:

 "Dim c1(1 To 2) As Double"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM