Концепция fftshift
и ifftshift
довольно прямо вперед , Вот фигура, я вытащил из MathWorks (создатели MATLAB):
![](https://www.mathworks.com/help/matlab/ref/math_f38.gif)
Source: MathWorks doc page on fftshift
Представьте, что ваш вход 2D матрица разбивается на квадранты. Квадрант № 1 находится в верхнем левом углу, квадрант № 2 находится в верхнем правом углу, четверть 3 - внизу справа, а четверть 4 - внизу слева. Для 2D-матриц fftshift
по умолчанию меняет первый и третий квадранты, второй и четвертый квадранты. Вы можете переопределить это поведение, когда вы можете просто выполнить fftshift
по одному измерению отдельно. Если вы это сделаете, вы обмениваете то, что называется полупространством. Если вы указали для свопинга вдоль строк (т. Е. Размер 1), то верхняя половина матрицы будет заменена нижней половиной. Если вы указали, чтобы поменять местами вдоль столбцов (т.е. размер 2), то правая половина становится местами с левой половины:
![](https://www.mathworks.com/help/matlab/ref/math_f37.gif)
Source: MathWorks doc page on fftshift
Использование fftshift
по умолчанию цепочки в обменивать размеров 1 и размеры 2 в последовательности. Если у вас есть матрица четного размера, где строки и столбцы четные, то очень однозначно разрезать матрицу на четыре части и выполнить обмен. Однако, если размер матрицы нечетный, это зависит от того, на каком языке вы смотрите. Например, в MATLAB и Python , где выполнение переключения определяется как (r,c) = ceil(rows/2), ceil(cols/2)
, где rows
и cols
являются строками и столбцами матрицы. r
и c
- это строка и столбец, где происходит обмен.
Для ifftshift
вы просто обратный действия, совершенные на fftshift
. Поэтому действие по умолчанию состоит в том, чтобы поменять размеры 2, а затем размеры 1. Однако вам нужно переопределить, где центр переключения используется для матриц нечетных размеров. Вместо ceil
вы должны использовать floor
, потому что это точно определяет, где полупространства были после того, как было выполненоfftshift
, и теперь вы уничтожаете то, что было сделано на исходной матрице. Поэтому новый центр коммутации - (r,c) = floor(rows/2), floor(cols/2)
. Кроме того, логика для обмена между одним измерением - это то же самое - только что центр переключения теперь изменился.
Таким образом, вот что я придумал. Эти функции принимают матрицу, определенную в R, а также второй необязательный аргумент, чтобы определить, какой размер вы хотите поменять.Опуская это выполняет квадранта по умолчанию переставляем Я просто говорил о:
fftshift <- function(input_matrix, dim = -1) {
rows <- dim(input_matrix)[1]
cols <- dim(input_matrix)[2]
swap_up_down <- function(input_matrix) {
rows_half <- ceiling(rows/2)
return(rbind(input_matrix[((rows_half+1):rows), (1:cols)], input_matrix[(1:rows_half), (1:cols)]))
}
swap_left_right <- function(input_matrix) {
cols_half <- ceiling(cols/2)
return(cbind(input_matrix[1:rows, ((cols_half+1):cols)], input_matrix[1:rows, 1:cols_half]))
}
if (dim == -1) {
input_matrix <- swap_up_down(input_matrix)
return(swap_left_right(input_matrix))
}
else if (dim == 1) {
return(swap_up_down(input_matrix))
}
else if (dim == 2) {
return(swap_left_right(input_matrix))
}
else {
stop("Invalid dimension parameter")
}
}
ifftshift <- function(input_matrix, dim = -1) {
rows <- dim(input_matrix)[1]
cols <- dim(input_matrix)[2]
swap_up_down <- function(input_matrix) {
rows_half <- floor(rows/2)
return(rbind(input_matrix[((rows_half+1):rows), (1:cols)], input_matrix[(1:rows_half), (1:cols)]))
}
swap_left_right <- function(input_matrix) {
cols_half <- floor(cols/2)
return(cbind(input_matrix[1:rows, ((cols_half+1):cols)], input_matrix[1:rows, 1:cols_half]))
}
if (dim == -1) {
input_matrix <- swap_left_right(input_matrix)
return(swap_up_down(input_matrix))
}
else if (dim == 1) {
return(swap_up_down(input_matrix))
}
else if (dim == 2) {
return(swap_left_right(input_matrix))
}
else {
stop("Invalid dimension parameter")
}
}
В каждой функции, я определить функции, поменять местами левую и правую половины, а также верхнюю и нижнюю половины. Чтобы поменять местами левую и правую половинки, просто определите, какой столбец вы используете для выполнения обмена и используйте индексирование, чтобы создать новую матрицу, объединив эти две половины вместе, где первая половина - правая половина, а вторая половина - левая половина , Вы бы сделали то же самое при замене верхней и нижней половин, но найти правильную строку для выполнения свопа.
Второй параметр dim
может быть установлен в 1 или 2 для замены соответствующего измерения. Обратите внимание, что единственная разница между fftshift
и ifftshift
- это центр обмена, который определяется так же, как и порядок операций, когда вы по умолчанию меняете оба измерения. Остальная часть кода такая же.
В качестве средства демонстрации, предположим, я объявлен 5 х 5 числовой матрицы следующим образом:
> O <- matrix(1:25, 5, 5)
> O
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 3 8 13 18 23
[4,] 4 9 14 19 24
[5,] 5 10 15 20 25
Обратите внимание, что размер матрицы нечетно в обоих измерениях. Выполнение fftshift
дает нам:
> P <- fftshift(O)
> P
[,1] [,2] [,3] [,4] [,5]
[1,] 19 24 4 9 14
[2,] 20 25 5 10 15
[3,] 16 21 1 6 11
[4,] 17 22 2 7 12
[5,] 18 23 3 8 13
Вы можете видеть, что соответствующие размеры были заменены. Реверсивный это с ifftshift
должно дать нам первоначальную матрицу обратно, и это делает:
> Q <- ifftshift(P)
> Q
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 3 8 13 18 23
[4,] 4 9 14 19 24
[5,] 5 10 15 20 25
Конечно, вы можете переопределить и указать, какие размерности вы хотите поменять местами, так что давайте скажем, вы хотите поменять только строки:
> fftshift(O, 1)
[,1] [,2] [,3] [,4] [,5]
[1,] 4 9 14 19 24
[2,] 5 10 15 20 25
[3,] 1 6 11 16 21
[4,] 2 7 12 17 22
[5,] 3 8 13 18 23
> ifftshift(fftshift(O, 1), 1)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 3 8 13 18 23
[4,] 4 9 14 19 24
[5,] 5 10 15 20 25
Позаботьтесь, что при выполнении ifftshift
на матрицу, которая была выгружена в одном измерении, вы должны использовать один и тот же размер, который был использован для замены, когда вы использовали fftshift
, чтобы убедиться, что вы получите оригинальную матрицу обратно.
Мы также можем сделать то же самое для второго измерения:
> ifftshift(O, 2)
[,1] [,2] [,3] [,4] [,5]
[1,] 11 16 21 1 6
[2,] 12 17 22 2 7
[3,] 13 18 23 3 8
[4,] 14 19 24 4 9
[5,] 15 20 25 5 10
> ifftshift(fftshift(O, 2), 2)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 3 8 13 18 23
[4,] 4 9 14 19 24
[5,] 5 10 15 20 25
Как интересное примечание, мы можем убедиться, что numpy
делает то же самое, что мы обсуждали выше. Вот сессия IPython:
In [16]: import numpy as np
In [17]: from numpy.fft import fftshift, ifftshift
In [18]: O = np.reshape(np.arange(1,26), (5,5)).T
In [19]: O
Out[19]:
array([[ 1, 6, 11, 16, 21],
[ 2, 7, 12, 17, 22],
[ 3, 8, 13, 18, 23],
[ 4, 9, 14, 19, 24],
[ 5, 10, 15, 20, 25]])
In [20]: fftshift(O)
Out[20]:
array([[19, 24, 4, 9, 14],
[20, 25, 5, 10, 15],
[16, 21, 1, 6, 11],
[17, 22, 2, 7, 12],
[18, 23, 3, 8, 13]])
In [21]: ifftshift(fftshift(O))
Out[21]:
array([[ 1, 6, 11, 16, 21],
[ 2, 7, 12, 17, 22],
[ 3, 8, 13, 18, 23],
[ 4, 9, 14, 19, 24],
[ 5, 10, 15, 20, 25]])
numpy
, а также fftshift
и ifftshift
из numpy.fft
пакета импортированы в и 2D матрица создается, что это то же самое, что вы видели в примере, определенной в R. Затем мы называем fftshift
, затем fftshift
и ifftshift
, и мы видим, что мы получаем те же результаты, что и в коде R.
Спасибо за ваш комментарий. Функция в SynchWave предназначена только для векторов. И я постараюсь переписать с документом matlab. –
Хорошо, вы хотите это для 2D-матриц? Я могу что-то написать для вас. – rayryeng
Да! Спасибо, это очень мило с вашей стороны! –