递归 IFFT 实现中的缩放不正确

问题描述 投票:0回答:1

我正在用 C++ 开发一个简单的递归 FFT/IFFT 实现。代码如下:

#include <complex>
#include <numbers>
#include <ranges>
#include <valarray>
#include <vector>

#include "assert.hpp"

template<typename T = float>
std::valarray<std::complex<T>> fft(std::valarray<std::complex<T>> const& data)
{
    const auto N = data.size();
    ASSERT(!(N & (N - 1)), "FFT length has to be power of two");

    if (N == 1)
        return data;

    auto even = fft(data[std::slice(0, N / 2, 2)]);
    auto odd = fft(data[std::slice(1, N / 2, 2)]);

    auto result = std::valarray<std::complex<T>>(N);
    for (size_t k = 0; k < N / 2; ++k)
    {
        auto t = std::exp(std::complex<T>(0, -2 * std::numbers::pi * T(k) / N));
        result[k] = even[k] + odd[k] * t;
        result[k + N / 2] = even[k] - odd[k] * t;
    }

    return result;
}

template<typename T = float>
std::valarray<std::complex<T>> ifft(std::valarray<std::complex<T>> const& data)
{
    const auto N = data.size();
    ASSERT(!(N & (N - 1)), "FFT length has to be a power of two");

    if (N == 1)
        return data;

    auto even = ifft(data[std::slice(0, N / 2, 2)]);
    auto odd = ifft(data[std::slice(1, N / 2, 2)]);

    auto result = std::valarray<std::complex<T>>(N);
    for (size_t k = 0; k < N / 2; ++k)
    {
        auto t = std::exp(std::complex<T>(0, 2 * std::numbers::pi * T(k) / N));
        result[k] = (even[k] + odd[k] * t) / T(N);
        result[k + N / 2] = (even[k] - odd[k] * t) / T(N);
    }

    return result;
}

虽然正向 FFT 工作正常,但反向 FFT 会错误地缩放其输出(对于大小为 8 的 FFT,缩放比例为 1/8)。 我正在使用此代码来测试我的实现:

std::valarray<std::complex<float>> data = { 3, 5, 8, 9, 1, 4, 7, 2 };

std::cout << "Data: ";
for (auto const& e : data)
    std::cout << e << " ";
std::cout << "\n";

auto spectrum = fft(data);

std::cout << "Forward FFT: ";
for (auto const& e : spectrum)
    std::cout << e << " ";
std::cout << "\n";

std::cout << "Inverse FFT: ";
auto inverse = ifft(spectrum);
for (auto const& e : inverse)
    std::cout << e << " ";
std::cout << "\n";

产生以下输出:

Data: (3,0) (5,0) (8,0) (9,0) (1,0) (4,0) (7,0) (2,0) 
Forward FFT: (39,0) (-2.24264,-6.65685) (-11,2) (6.24264,-4.65685) (-1,0) (6.24264,4.65685) (-11,-2) (-2.24264,6.65685) 
Inverse FFT: (0.375,0) (0.625,6.58126e-09) (1,2.73196e-09) (1.125,-1.21692e-08) (0.125,0) (0.5,-1.20452e-08) (0.875,-2.73196e-09) (0.25,1.76331e-08)

根据numpy,前向FFT是正确的,而逆向FFT当然应该是原始数据,但事实并非如此。

是什么原因导致这种行为?我该如何解决它?

c++ recursion fft
1个回答
0
投票

我发现我做错了什么:

1/N
的缩放系数不正确。使用
1/sqrt(N)
时效果非常好。

IFFT 函数必须更改为:

template<typename T = float>
std::valarray<std::complex<T>> ifft(std::valarray<std::complex<T>> const& data)
{
    const auto N = data.size();
    ASSERT(!(N & (N - 1)), "FFT length has to be a power of two");

    if (N == 1)
        return data;

    auto even = ifft(data[std::slice(0, N / 2, 2)]);
    auto odd = ifft(data[std::slice(1, N / 2, 2)]);

    auto result = std::valarray<std::complex<T>>(N);
    for (size_t k = 0; k < N / 2; ++k)
    {
        auto t = std::exp(std::complex<T>(0, 2 * std::numbers::pi * T(k) / N));
        result[k] = (even[k] + odd[k] * t) / T(sqrt(N));
        result[k + N / 2] = (even[k] - odd[k] * t) / T(sqrt(N));
    }

    return result;
}
© www.soinside.com 2019 - 2024. All rights reserved.