有没有人知道是否有任何免费和开源库以matlab中的方式实现这两个函数?
由于
答案 0 :(得分:15)
FFTHIFT / IFFTSHIFT是一种做CIRCSHIFT的奇特方式。 您可以验证FFTSHIFT是否可以重写为CIRCSHIFT,如下所示。 您可以在C / C ++中定义宏以将FFTSHIFT转换为CIRCSHIFT。
A = rand(m, n);
mm = floor(m / 2);
nn = floor(n / 2);
% All three of the following should provide zeros.
circshift(A,[mm, nn]) - fftshift(A)
circshift(A,[mm, 0]) - fftshift(A, 1)
circshift(A,[ 0, nn]) - fftshift(A, 2)
IFFTSHIFT可以找到类似的等价物。
使用以下代码可以非常简单地实现循环移位(可以使用并行版本的课程进行改进)。
template<class ty>
void circshift(ty *out, const ty *in, int xdim, int ydim, int xshift, int yshift)
{
for (int i = 0; i < xdim; i++) {
int ii = (i + xshift) % xdim;
for (int j = 0; j < ydim; j++) {
int jj = (j + yshift) % ydim;
out[ii * ydim + jj] = in[i * ydim + j];
}
}
}
然后
#define fftshift(out, in, x, y) circshift(out, in, x, y, (x/2), (y/2))
#define ifftshift(out, in, x, y) circshift(out, in, x, y, ((x+1)/2), ((y+1)/2))
这是有点即兴的。如果有任何格式/语法问题,请耐心等待。
答案 1 :(得分:5)
通常,使用v(k)= v(k)*( - 1)** k来完成FFT的居中 时域。在频域中移位是一个糟糕的替代品 数学原因和计算效率。 见第27页: http://show.docjava.com/pub/document/jot/v8n6.pdf
我不确定为什么Matlab文档会像他们那样做, 他们没有提供技术参考。
答案 2 :(得分:5)
可能此代码可能有所帮助。它仅对一个缓冲区内的1D阵列执行fftshift / ifftshift。偶数个元素的前后移位算法完全相同。
void swap(complex *v1, complex *v2)
{
complex tmp = *v1;
*v1 = *v2;
*v2 = tmp;
}
void fftshift(complex *data, int count)
{
int k = 0;
int c = (int) floor((float)count/2);
// For odd and for even numbers of element use different algorithm
if (count % 2 == 0)
{
for (k = 0; k < c; k++)
swap(&data[k], &data[k+c]);
}
else
{
complex tmp = data[0];
for (k = 0; k < c; k++)
{
data[k] = data[c + k + 1];
data[c + k + 1] = data[k + 1];
}
data[c] = tmp;
}
}
void ifftshift(complex *data, int count)
{
int k = 0;
int c = (int) floor((float)count/2);
if (count % 2 == 0)
{
for (k = 0; k < c; k++)
swap(&data[k], &data[k+c]);
}
else
{
complex tmp = data[count - 1];
for (k = c-1; k >= 0; k--)
{
data[c + k + 1] = data[k];
data[k] = data[c + k];
}
data[c] = tmp;
}
}
更新: 也可以在Optolithium(在OptolithiumC / libs / fourier下)找到任意点数的FFT库(包括fftshift操作)
答案 3 :(得分:4)
或者您可以通过键入type fftshift
并在C ++中重新编码来自己完成。 Matlab代码并不复杂。
编辑:我注意到这个答案最近已经被评了几次,并以负面的方式评论。我记得type fftshift
比当前实施更具启发性的时间,但我可能错了。如果我可以删除答案,我认为它似乎不再相关。
Here是一个版本(由Octave提供),无需实现它
circshift
。
答案 4 :(得分:3)
我测试了这里提供的代码并制作了一个示例项目来测试它们。对于1D代码,可以使用std::rotate
template <typename _Real>
static inline
void rotshift(complex<_Real> * complexVector, const size_t count)
{
int center = (int) floor((float)count/2);
if (count % 2 != 0) {
center++;
}
// odd: 012 34 changes to 34 012
std::rotate(complexVector,complexVector + center,complexVector + count);
}
template <typename _Real>
static inline
void irotshift(complex<_Real> * complexVector, const size_t count)
{
int center = (int) floor((float)count/2);
// odd: 01 234 changes to 234 01
std::rotate(complexVector,complexVector +center,complexVector + count);
}
由于其简单性,我更喜欢使用std::rotate
代替来自Alexei的代码。
对于2D来说,它变得更加复杂。对于偶数,它基本上是向左翻转并翻转倒置。对于奇数,它是circshift算法:
// A =
// 1 2 3
// 4 5 6
// 7 8 9
// fftshift2D(A)
// 9 | 7 8
// --------------
// 3 | 1 2
// 6 | 4 5
// ifftshift2D(A)
// 5 6 | 4
// 8 9 | 7
// --------------
// 2 3 | 1
这里我实现了带有接口的circshift代码,只使用一个数组进行输入和输出。对于偶数,只需要一个数组,对于奇数,临时创建第二个数组并将其复制回输入数组。由于复制阵列所需的额外时间,这会导致性能下降。
template<class _Real>
static inline
void fftshift2D(complex<_Real> *data, size_t xdim, size_t ydim)
{
size_t xshift = xdim / 2;
size_t yshift = ydim / 2;
if ((xdim*ydim) % 2 != 0) {
// temp output array
std::vector<complex<_Real> > out;
out.resize(xdim * ydim);
for (size_t x = 0; x < xdim; x++) {
size_t outX = (x + xshift) % xdim;
for (size_t y = 0; y < ydim; y++) {
size_t outY = (y + yshift) % ydim;
// row-major order
out[outX + xdim * outY] = data[x + xdim * y];
}
}
// copy out back to data
copy(out.begin(), out.end(), &data[0]);
}
else {
// in and output array are the same,
// values are exchanged using swap
for (size_t x = 0; x < xdim; x++) {
size_t outX = (x + xshift) % xdim;
for (size_t y = 0; y < yshift; y++) {
size_t outY = (y + yshift) % ydim;
// row-major order
swap(data[outX + xdim * outY], data[x + xdim * y]);
}
}
}
}
template<class _Real>
static inline
void ifftshift2D(complex<_Real> *data, size_t xdim, size_t ydim)
{
size_t xshift = xdim / 2;
if (xdim % 2 != 0) {
xshift++;
}
size_t yshift = ydim / 2;
if (ydim % 2 != 0) {
yshift++;
}
if ((xdim*ydim) % 2 != 0) {
// temp output array
std::vector<complex<_Real> > out;
out.resize(xdim * ydim);
for (size_t x = 0; x < xdim; x++) {
size_t outX = (x + xshift) % xdim;
for (size_t y = 0; y < ydim; y++) {
size_t outY = (y + yshift) % ydim;
// row-major order
out[outX + xdim * outY] = data[x + xdim * y];
}
}
// copy out back to data
copy(out.begin(), out.end(), &data[0]);
}
else {
// in and output array are the same,
// values are exchanged using swap
for (size_t x = 0; x < xdim; x++) {
size_t outX = (x + xshift) % xdim;
for (size_t y = 0; y < yshift; y++) {
size_t outY = (y + yshift) % ydim;
// row-major order
swap(data[outX + xdim * outY], data[x + xdim * y]);
}
}
}
}
答案 5 :(得分:1)
注意:提供了更好的答案,我只是暂时搁置一段时间......我不知道是什么。
试试这个:
template<class T> void ifftShift(T *out, const T* in, size_t nx, size_t ny)
{
const size_t hlen1 = (ny+1)/2;
const size_t hlen2 = ny/2;
const size_t shft1 = ((nx+1)/2)*ny + hlen1;
const size_t shft2 = (nx/2)*ny + hlen2;
const T* src = in;
for(T* tgt = out; tgt < out + shft1 - hlen1; tgt += ny, src += ny) { // (nx+1)/2 times
copy(src, src+hlen1, tgt + shft2); //1->4
copy(src+hlen1, src+ny, tgt+shft2-hlen2); } //2->3
src = in;
for(T* tgt = out; tgt < out + shft2 - hlen2; tgt += ny, src += ny ){ // nx/2 times
copy(src+shft1, src+shft1+hlen2, tgt); //4->1
copy(src+shft1-hlen1, src+shft1, tgt+hlen2); } //3->2
};
对于具有偶数维的矩阵,您可以就地执行此操作,只需将相同的指针传递到输入和输出参数。
另请注意,对于1D数组,fftshift只是std :: rotate。
答案 6 :(得分:1)
您还可以使用arrayfire的shift
函数替换Matlab的circshift
并重新实现其余代码。如果您对AF的任何其他功能感兴趣(例如通过简单地更改链接器标志来移植到GPU),这可能很有用。
但是,如果您的所有代码都要在CPU上运行并且非常复杂,或者您不想使用任何其他数据格式(AF需要af :: arrays),请坚持使用其他选项之一。
我最终改为AF,因为我不得不重新将fftshift作为OpenCL内核重新实现,否则就会回来。
答案 7 :(得分:0)
答案 8 :(得分:0)
它会给matlab中的ifftshift提供相同的结果
ifftshift(vector< vector <double> > Hlow,int RowLineSpace, int ColumnLineSpace)
{
int pivotRow=floor(RowLineSpace/2);
int pivotCol=floor(ColumnLineSpace/2);
for(int i=pivotRow;i<RowLineSpace;i++){
for(int j=0;j<ColumnLineSpace;j++){
double temp=Hlow.at(i).at(j);
second.push_back(temp);
}
ifftShiftRow.push_back(second);
second.clear();
}
for(int i=0;i<pivotRow;i++){
for(int j=0;j<ColumnLineSpace;j++){
double temp=Hlow.at(i).at(j);
first.push_back(temp);
}
ifftShiftRow.push_back(first);
first.clear();
}
double** arr = new double*[RowLineSpace];
for(int i = 0; i < RowLineSpace; ++i)
arr[i] = new double[ColumnLineSpace];
int i1=0,j1=0;
for(int j=pivotCol;j<ColumnLineSpace;j++){
for(int i=0;i<RowLineSpace;i++){
double temp2=ifftShiftRow.at(i).at(j);
arr[i1][j1]=temp2;
i1++;
}
j1++;
i1=0;
}
for(int j=0;j<pivotCol;j++){
for(int i=0;i<RowLineSpace;i++){
double temp1=ifftShiftRow.at(i).at(j);
arr[i1][j1]=temp1;
i1++;
}
j1++;
i1=0;
}
for(int i=0;i<RowLineSpace;i++){
for(int j=0;j<ColumnLineSpace;j++){
double value=arr[i][j];
temp.push_back(value);
}
ifftShiftLow.push_back(temp);
temp.clear();
}
return ifftShiftLow;
}
答案 9 :(得分:-1)
您可以使用kissfft。它速度快,使用极其简单,而且免费。像你想要的那样排列输出只需要:
a)通过(-dim_x / 2,-dim_y / 2,...)移动,具有周期性边界条件
b)FFT或IFFT
c)使用周期性边界条件向后移动(dim_x / 2,dim_y / 2,...)
d)规模? (根据您的需要,IFFT * FFT将按dim_x * dim_y * ...默认扩展功能)