执行FFT计划后FFTW输出向量大小错误
FFTW output vector size is wrong after executing the FFT plan
我在使用 fftw
库执行 FFT 计划时遇到问题。我正在声明大小为 2048 的 fftIn
和 fftOut
向量,并用它们定义一个 fftwf_plan_dft_1d
。
但是当我执行计划时,fftOut
向量突然全错了。在我的代码中,调试时我可以看到它的大小从 2048 变为 0。当我编写下面的小型可执行示例时,我得到的大小不正确,例如 17293858104588369909。
当然,当我尝试访问向量的第一项时,会发生 SIGSEGV
。
我的代码:
#include <complex>
#include <iostream>
#include <fftw3.h>
#include <vector>
using namespace std;
typedef std::vector<std::complex<float>> fft_vector;
int main() {
const unsigned int VECTOR_SIZE = 2048;
fft_vector* fftIn = new fft_vector(VECTOR_SIZE);
fft_vector* fftOut = new fft_vector(VECTOR_SIZE);
fftwf_plan fftPlan = fftwf_plan_dft_1d(VECTOR_SIZE, reinterpret_cast<fftwf_complex*>(fftIn), reinterpret_cast<fftwf_complex*>(fftOut), FFTW_FORWARD, FFTW_ESTIMATE);
fftwf_execute(fftPlan);
std::cout << fftOut->size() << std::endl;
std::cout << fftOut->at(0).real() << fftOut->at(0).imag() << std::endl;
return 0;
}
当然,我知道 fftIn
vector 在这个例子中是空的,但是当它不是空的时候输出就坏了。在这种情况下,SIGSEGV 发生在第二个 cout 中,如前所述。
我的完整代码有线程(但 FFT 全部发生在同一个线程中,因此竞争条件不适用),这是在这个小示例中尝试隔离代码的原因之一,以防万一,不过好像还是有问题。
有什么想法吗?
你不能 reinterpret_cast
指向复杂元素指针的向量:你正在访问向量内部变量(如大小),不一定是向量原始数据,这可能解释了为什么对象被丢弃在输出中,以及接下来发生的所有坏事。
另一方面,强制转换向量数据的地址是可行的。
只需做(不需要 new
向量,使用标准声明):
fft_vector fftIn(VECTOR_SIZE);
fft_vector fftOut(VECTOR_SIZE);
// load your data in fftIn
fftwf_plan_dft_1d(VECTOR_SIZE, static_cast<const fftwf_complex*>(&fftIn[0]), static_cast<fftwf_complex*>(&fftOut[0]), FFTW_FORWARD, FFTW_ESTIMATE);
主要问题是您将一个矢量传递给它,这是行不通的;您需要传递矢量内容: &((*fftIn)[0]) 和 &((*fftOut)[0]) 或类似的内容。实际上,您是在告诉 fftw 踩踏矢量对象的元数据(包括长度,这解释了为什么它有时为 0 有时是乱码)。它实际上是写到向量结构的开头,因为那是指针指向的地方。它还使用 fftIn 的元数据作为 fft 输入的一部分,这也不是您想要的。
您可以考虑改用 fftw_complex 和 fftw_malloc,这将确保您的数据按照 fftw 需要的方式存储:http://www.fftw.org/doc/SIMD-alignment-and-fftw_005fmalloc.html
如果你真的需要它,你可以在之后将 fftOut 放在一个向量中。这将确保您获得 SIMD(如果可用)的优势,并避免任何具有复杂类型和内存分配的特定于编译器或平台的行为。使用 fftw 的类型和分配器意味着您的代码将始终如您所愿地以最佳方式工作,无论您 运行 它在哪个平台上以及您使用哪个编译器。
这是您从 fftw 的文档 (http://www.fftw.org/doc/Complex-One_002dDimensional-DFTs.html) 进行转换的示例:
#include <fftw3.h>
...
{
fftw_complex *in, *out;
fftw_plan p;
...
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
...
fftw_execute(p); /* repeat as needed */
...
fftw_destroy_plan(p);
fftw_free(in); fftw_free(out);
}
尝试匹配此示例,您的代码应该会达到您的预期。
编辑:
如果你必须使用 C++ 复数和向量,这应该有效:
const unsigned int VECTOR_SIZE = 2048;
fft_vector* fftIn = new fft_vector(VECTOR_SIZE);
fft_vector* fftOut = new fft_vector(VECTOR_SIZE);
fftwf_plan fftPlan = fftwf_plan_dft_1d(VECTOR_SIZE,
reinterpret_cast<fftwf_complex*>(&(*fftIn)[0]),
reinterpret_cast<fftwf_complex*>(&(*fftOut)[0]),
FFTW_FORWARD, FFTW_ESTIMATE);
fftwf_execute(fftPlan);
std::cout << fftOut->size() << std::endl;
std::cout << fftOut->at(0).real() << fftOut->at(0).imag() << std::endl;
请注意,您必须取消引用向量指针才能让 [] 运算符工作;获取索引 0 为您提供实际矢量数据的第一个元素,因此该元素的地址是您需要提供给 fftw_plan.
的地址(指针)
我在使用 fftw
库执行 FFT 计划时遇到问题。我正在声明大小为 2048 的 fftIn
和 fftOut
向量,并用它们定义一个 fftwf_plan_dft_1d
。
但是当我执行计划时,fftOut
向量突然全错了。在我的代码中,调试时我可以看到它的大小从 2048 变为 0。当我编写下面的小型可执行示例时,我得到的大小不正确,例如 17293858104588369909。
当然,当我尝试访问向量的第一项时,会发生 SIGSEGV
。
我的代码:
#include <complex>
#include <iostream>
#include <fftw3.h>
#include <vector>
using namespace std;
typedef std::vector<std::complex<float>> fft_vector;
int main() {
const unsigned int VECTOR_SIZE = 2048;
fft_vector* fftIn = new fft_vector(VECTOR_SIZE);
fft_vector* fftOut = new fft_vector(VECTOR_SIZE);
fftwf_plan fftPlan = fftwf_plan_dft_1d(VECTOR_SIZE, reinterpret_cast<fftwf_complex*>(fftIn), reinterpret_cast<fftwf_complex*>(fftOut), FFTW_FORWARD, FFTW_ESTIMATE);
fftwf_execute(fftPlan);
std::cout << fftOut->size() << std::endl;
std::cout << fftOut->at(0).real() << fftOut->at(0).imag() << std::endl;
return 0;
}
当然,我知道 fftIn
vector 在这个例子中是空的,但是当它不是空的时候输出就坏了。在这种情况下,SIGSEGV 发生在第二个 cout 中,如前所述。
我的完整代码有线程(但 FFT 全部发生在同一个线程中,因此竞争条件不适用),这是在这个小示例中尝试隔离代码的原因之一,以防万一,不过好像还是有问题。
有什么想法吗?
你不能 reinterpret_cast
指向复杂元素指针的向量:你正在访问向量内部变量(如大小),不一定是向量原始数据,这可能解释了为什么对象被丢弃在输出中,以及接下来发生的所有坏事。
另一方面,强制转换向量数据的地址是可行的。
只需做(不需要 new
向量,使用标准声明):
fft_vector fftIn(VECTOR_SIZE);
fft_vector fftOut(VECTOR_SIZE);
// load your data in fftIn
fftwf_plan_dft_1d(VECTOR_SIZE, static_cast<const fftwf_complex*>(&fftIn[0]), static_cast<fftwf_complex*>(&fftOut[0]), FFTW_FORWARD, FFTW_ESTIMATE);
主要问题是您将一个矢量传递给它,这是行不通的;您需要传递矢量内容: &((*fftIn)[0]) 和 &((*fftOut)[0]) 或类似的内容。实际上,您是在告诉 fftw 踩踏矢量对象的元数据(包括长度,这解释了为什么它有时为 0 有时是乱码)。它实际上是写到向量结构的开头,因为那是指针指向的地方。它还使用 fftIn 的元数据作为 fft 输入的一部分,这也不是您想要的。
您可以考虑改用 fftw_complex 和 fftw_malloc,这将确保您的数据按照 fftw 需要的方式存储:http://www.fftw.org/doc/SIMD-alignment-and-fftw_005fmalloc.html 如果你真的需要它,你可以在之后将 fftOut 放在一个向量中。这将确保您获得 SIMD(如果可用)的优势,并避免任何具有复杂类型和内存分配的特定于编译器或平台的行为。使用 fftw 的类型和分配器意味着您的代码将始终如您所愿地以最佳方式工作,无论您 运行 它在哪个平台上以及您使用哪个编译器。
这是您从 fftw 的文档 (http://www.fftw.org/doc/Complex-One_002dDimensional-DFTs.html) 进行转换的示例:
#include <fftw3.h>
...
{
fftw_complex *in, *out;
fftw_plan p;
...
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
...
fftw_execute(p); /* repeat as needed */
...
fftw_destroy_plan(p);
fftw_free(in); fftw_free(out);
}
尝试匹配此示例,您的代码应该会达到您的预期。
编辑: 如果你必须使用 C++ 复数和向量,这应该有效:
const unsigned int VECTOR_SIZE = 2048;
fft_vector* fftIn = new fft_vector(VECTOR_SIZE);
fft_vector* fftOut = new fft_vector(VECTOR_SIZE);
fftwf_plan fftPlan = fftwf_plan_dft_1d(VECTOR_SIZE,
reinterpret_cast<fftwf_complex*>(&(*fftIn)[0]),
reinterpret_cast<fftwf_complex*>(&(*fftOut)[0]),
FFTW_FORWARD, FFTW_ESTIMATE);
fftwf_execute(fftPlan);
std::cout << fftOut->size() << std::endl;
std::cout << fftOut->at(0).real() << fftOut->at(0).imag() << std::endl;
请注意,您必须取消引用向量指针才能让 [] 运算符工作;获取索引 0 为您提供实际矢量数据的第一个元素,因此该元素的地址是您需要提供给 fftw_plan.
的地址(指针)