我正在尝试理解如何利用FFT处理我用软件定义收音机捕获的数据。我发现了C++的fftw3库,并尝试查找一些文档或教程,但发现没有太多可供参考的内容。
然而我找到了这个tutorial。用于执行fft/ifft等操作的代码对我来说编译和工作得很好,但当我尝试实现fftShift函数时,我遇到了以下编译器错误:
In file included from /usr/include/c++/9/algorithm:62,
from CppFFTW.cpp:13:
/usr/include/c++/9/bits/stl_algo.h: In instantiation of ‘_RandomAccessIterator std::_V2::__rotate(_RandomAccessIterator, _RandomAccessIterator, _RandomAccessIterator, std::random_access_iterator_tag) [with _RandomAccessIterator = double (*)[2]]’:
/usr/include/c++/9/bits/stl_algo.h:1449:27: required from ‘_FIter std::_V2::rotate(_FIter, _FIter, _FIter) [with _FIter = double (*)[2]]’
CppFFTW.cpp:76:54: required from here
/usr/include/c++/9/bits/stl_algo.h:1371:16: error: array must be initialized with a brace-enclosed initializer
1371 | _ValueType __t = _GLIBCXX_MOVE(*__p);
| ^~~
/usr/include/c++/9/bits/stl_algo.h:1373:22: error: invalid array assignment
1373 | *(__p + __n - 1) = _GLIBCXX_MOVE(__t);
| ^
/usr/include/c++/9/bits/stl_algo.h:1394:16: error: array must be initialized with a brace-enclosed initializer
1394 | _ValueType __t = _GLIBCXX_MOVE(*(__p + __n - 1));
| ^~~
/usr/include/c++/9/bits/stl_algo.h:1396:10: error: invalid array assignment
1396 | *__p = _GLIBCXX_MOVE(__t);
| ^
这是我用来编译代码的命令行:g++ CppFFTW.cpp -lfftw3 -lm
g++ --version 的输出结果为:
'g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0'
这个错误信息对我来说没有太多意义,但我猜测它的意思是算法的 std::rotate 函数不再与 fftw_complex 数据类型兼容。
这让我有了几个问题:
- 为什么这种方法在教程视频中有效,但对我无效?
- 有哪些方法可以理解这个错误信息的含义?
- 如何实现一个可工作的 fftShift 函数?
- 是否应该使用不同的编译器版本?
fftShift 的作用是将零分量移动到中心位置,就像这个例子一样。
When # elements odd:
{a, b, c, d, e, f, g} -> {e, f, g, a, b, c, d}
When # elements even:
{a, b, c, d, e, f, g, h} -> {e, f, g, h, a, b, c, d}
这里是fftShift的定义: 编辑:原始(损坏的)fftShift
// FFT shift for complex data
void fftShift(fftw_complex *data)
{
// even number of elements
if (N % 2 == 0) {
std::rotate(&data[0], &data[N >> 1], &data[N]);
}
// odd number of elements
else {
std::rotate(&data[0], &data[(N >> 1) + 1], &data[N]);
}
}
这里是代码的剩余部分(与问题无关的函数/调用被省略):编辑:根据Ted的贡献添加#include并修复fftShift函数。
*
Example code for how to utilize the FFTW libs
Adapted from damian-dz C++ Tutorial
https://github.com/damian-dz/CppFFTW/tree/master/CppFFTW
(https://www.youtube.com/watch?v=geYbCA137PU&t=0s)
To compile, run: g++ CppFFTW.cpp -lfftw3 -lm
-lfftw3 -lm links the code to the fftw3 library
*/
#include <fftw3.h>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <complex> // Added post feedback from Ted
// macros for real & imaginary parts
#define REAL 0
#define IMAG 1
// length of the complex arrays
#define N 8
/* Computres the 1-D Fast Fourier Transform. */
void fft(fftw_complex *in, fftw_complex *out)
{
// create a DFT plan
fftw_plan plan = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
// execute the plan
fftw_execute(plan);
// clean up
fftw_destroy_plan(plan);
fftw_cleanup();
}
/* Displays complex numbers in the form a +/- bi */
void displayComplex(fftw_complex *y)
{
for (int idx = 0; idx < N; ++idx) {
if (y[idx][IMAG] < 0) {
std::cout << y[idx][REAL] << " - " << abs(y[idx][IMAG]) << "i" << std::endl;
} else {
std::cout << y[idx][REAL] << " + " << abs(y[idx][IMAG]) << "i" << std::endl;
}
}
}
// Edit: Adjusted fftShift function per Ted's feedback
void fftShift(std::complex<double>* data) {
static_assert(sizeof(fftw_complex) == sizeof(std::complex<double>));
// even number of elements
if(N % 2 == 0) {
std::rotate(&data[0], &data[N >> 1], &data[N]);
}
// odd number of elements
else {
std::rotate(&data[0], &data[(N >> 1) + 1], &data[N]);
}
}
// Edit: Accompanying fftShift to re-cast data
void fftShift(fftw_complex* data) {
fftShift(reinterpret_cast<std::complex<double>*>(data));
}
// Original (broken) FFT shift for complex data
void fftShift(fftw_complex *data)
{
// even number of elements
if (N % 2 == 0) {
std::rotate(&data[0], &data[N >> 1], &data[N]);
}
// odd number of elements
else {
std::rotate(&data[0], &data[(N >> 1) + 1], &data[N]);
}
}
/* Test */
int main()
{
// input array
fftw_complex x[N];
// output array
fftw_complex y[N];
// fill the first array with some numbers
for (int idx = 0; idx < N; ++idx) {
x[idx][REAL] = idx + 1;
x[idx][IMAG] = 0;
}
// compute the FFT of x and store results in y
fft(x, y);
// display the results
std::cout << "FFT =" << std::endl;
displayComplex(y);
// "shifted" results
fftShift(y);
std::cout << "\nFFT shifted =" << std::endl;
displayComplex(y);
return 0;
}
我没有看到任何明显的现有问题适用于我的情况(可能是我错了,因为我还在学习C++),所以我创建了一个帐户,并且这是我在这里的第一个问题。请随意提供反馈,以便我可以使我的问题更容易理解。
void fftShift(double *data)
。它有点偶然地发生了作用。 - alfCfftw_complex*
能正常工作,为什么要改成double *
。编辑:啊,等等...他们还保留了另一个重载...好的,我明白了。double*
重载没有被使用。 :-) - Ted Lyngmo