Разложение 2D FFT (и обратного fft) с fftw в fortran77

[edit 1] Добавлены рисунки, чтобы показать исходные данные и полученные данные

[править 2] Я нашел свои ошибки, я использовал fftw_measure вместо fftw_estimate в вызове dfftw_plan_many_dft

[edit 3] исправлена ​​опечатка в коде (замените u на u2d в dfftw_execute_dft_r2c)

Я пытаюсь выполнить 2D fft массива, используя несколько 1D fft вместо использования функции 2D fft, уже существующей в библиотеке fftw. И впоследствии мне нужно выполнить обратное 2D БПФ. Причина этого в том, что (в будущем) мой массив будет слишком большим, чтобы его можно было загрузить за один раз для выполнения 2D fft.

1-й черновик моего кода на данный момент выглядит примерно так:

  double precision u2d(nx,ny),u2d2(nx,ny)
  double complex qhat2d(nx/2+1,ny),qhat2d2(nx/2+1,ny)
  integer N(1)
  integer howmany, idist, odist, istride, ostride
  integer inembed(2), onembed(2)
  integer rank

  ! some function to read the data into u2d

  ! perform x-fft
  N(1) = NX
  howmany = NY
  inembed(1) = NX
  inembed(2) = NY
  istride = 1
  idist = NX
  ostride = 1
  odist = (NX/2+1)
  onembed(1) = (NX/2+1)
  onembed(2) = NY
  rank = 1
  write(*,*) 'u', u2d(1,1)
  CALL dfftw_plan_many_dft_r2c(PLAN,rank,N(1),howmany,
&                              u2d,inembed,
&                              istride,idist,
&                              qhat2d,onembed,
&                              ostride,odist,FFTW_ESTIMATE) ! 
  CALL dfftw_execute_dft_r2c(PLAN,u2d,qhat2d) ! x-fft
  CALL dfftw_destroy_plan(PLAN)


  ! perform y-fft
  N(1) = NY
  howmany = (NX/2+1)
  inembed(1) = (NX/2+1)
  inembed(2) = NY
  istride = (NX/2+1)
  idist = 1
  ostride = (NX/2+1)
  odist = 1
  onembed(1) = (NX/2+1)
  onembed(2) = NY
  rank = 1
  CALL dfftw_plan_many_dft(PLAN,rank,N(1),howmany,
&                              qhat2d,inembed,
&                              istride,idist,
&                              qhat2d2,onembed,
&                              ostride,odist,FFTW_FORWARD,
&                              FFTW_MEASURE) ! 
  CALL dfftw_execute_dft(PLAN,qhat2d,qhat2d2) ! y-fft
  CALL dfftw_destroy_plan(PLAN)

  ! normally here, perform some filtering operation
  ! but at the moment, I do nothing

  ! perform inv-y-fft
  N(1) = NY
  howmany = (NX/2+1)
  inembed(1) = (NX/2+1)
  inembed(2) = NY
  istride = (NX/2+1)
  idist = 1
  ostride = (NX/2+1)
  odist = 1
  onembed(1) = (NX/2+1)
  onembed(2) = NY
  rank = 1
  CALL dfftw_plan_many_dft(PLAN,rank,N(1),howmany,
 &                             qhat2d2,inembed,
 &                              istride,idist,
 &                              qhat2d,onembed,
 &                              ostride,odist,FFTW_BACKWARD,
 &                              FFTW_MEASURE) ! 
  CALL dfftw_execute_dft(PLAN,qhat2d2,qhat2d) ! inv-y-fft
  CALL dfftw_destroy_plan(PLAN)

  ! perform inv-x-fft
  N(1) = NX ! I'm not too sure about this value here
  howmany = NY
  inembed(1) = (NX/2+1)
  inembed(2) = NY
  istride = 1
  idist = (NX/2+1)
  ostride = 1
  odist = NX
  onembed(1) = NX
  onembed(2) = NY
  rank = 1
  CALL dfftw_plan_many_dft_c2r(PLAN,rank,N(1),howmany,
&                              qhat2d,inembed,
&                              istride,idist,
&                              u2d2,onembed,
&                              ostride,odist,FFTW_ESTIMATE) ! 
  CALL dfftw_execute_dft_c2r(PLAN,qhat2d,u2d2) ! x-fft
  CALL dfftw_destroy_plan(PLAN)
  write(*,*) 'u2d2', u2d2(1,1)

  do i=1,nx
   do j=1,ny
    u2d2(i,j) = u2d2(i,j) / (nx*ny)
   enddo
  enddo
  write(*,*) 'u2d2', u2d2(1,1) ! here the values u2d2(1,1) is different from u2d(1,1)

  ! some action to write u2d2 to file
  end

Я ожидал, что u2d и u2d2 будут одинаковыми, но я получаю относительно разные значения. Я где-то ошибся?

Оригинал и результаты показаны ниже. Форма выглядит похожей, но значения относительно разные (например, минимум и максимум).

Исходное поле

Поле, полученное после fft и i-fft


person Anh Khoa    schedule 23.05.2016    source источник
comment
FFTW не нормализует значения. Следовательно, будет фактор длины массива, если вы будете преобразовывать одни и те же данные вперед и назад.   -  person Alexander Vogt    schedule 23.05.2016
comment
См., например, stackoverflow.com/questions/3721125/   -  person Alexander Vogt    schedule 23.05.2016
comment
или stackoverflow.com/questions/4855958/normalising-fft-data-fftw   -  person Alexander Vogt    schedule 23.05.2016
comment
или stackoverflow.com/questions/30402282/   -  person Alexander Vogt    schedule 23.05.2016
comment
Почему вы выполняете ДПФ с действительным знаком (_r2c) для сложных данных?   -  person Alexander Vogt    schedule 23.05.2016
comment
В дополнение к другим комментариям я подчеркиваю, что вы должны показать, что не так. Вы должны показать, какие значения вы получили и почему вы считаете, что они неверны.   -  person Vladimir F    schedule 24.05.2016
comment
@AlexanderVogt Мои исходные данные u2d реальны, поэтому я подумал, что использование r2c было правильным способом выполнения первого fft. Кроме того, в конце я перенормализую свои данные, разделив результат двух обратных БПФ на (nx*ny).   -  person Anh Khoa    schedule 24.05.2016
comment
@roygvib На самом деле дубликат? stackoverflow.com/questions/36885526/ Однако заголовок абсолютно неверен.   -  person Vladimir F    schedule 24.05.2016
comment
@VladimirF Сначала я так и думал, но если промежуточное преобразование Фурье не используется повторно (даже фильтруется перед входом в обратное преобразование), код, кажется, работает (если предположить, что FFTW_ESTIMATE сохраняет входной массив нетронутым). Итак, хм, я не очень уверен... (однако я уверен в том, что я бы не стал одновременно смешивать создание плана и фактическое преобразование.)   -  person roygvib    schedule 24.05.2016


Ответы (2)


Чтобы устранить путаницу. Что происходит, так это то, что подпрограммы FFTW c2r и r2c не гарантируют сохранение входных массивов. Они могут затереть результат мусором.

Теперь вам может повезти, и вы просто используете FFTW_ESTIMATE вместо FFTW_MEASURE, но это не очень хорошая идея. FFTW_MEASURE пробует множество алгоритмов и, следовательно, вероятно, попробует также тот, который не сохраняет входные данные. FFTW_ESTIMATE не будет пытаться ничего вычислить и не перезапишет ввод.

Проблема в том, что ваш ввод может быть перезаписан при выполнении преобразования (выполнения плана). Вам повезет только тогда, когда FFT_ESTIMATE выберет алгоритм, который сохранит ввод для вас. Это лотерея.

Чтобы убедиться, что ввод сохранен, вы должны использовать FFTW_INPUT_PRESERVE в дополнение к FFT_ESTIMATE или FFTW_MEASURE.

Вы также можете не использовать его и вместо этого сохранить ввод куда-нибудь. Я думаю, что часто это лучше, потому что FFTW_INPUT_PRESERVE может (весьма вероятно) выбрать более медленный алгоритм.

person Vladimir F    schedule 24.05.2016

Я нашел свои ошибки, я использовал fftw_measure вместо fftw_estimate в вызове dfftw_plan_many_dft.

Исправление этого дает мне соответствующее исходное поле.

person Anh Khoa    schedule 24.05.2016
comment
Это вообще не должно иметь значения. Что может иметь значение, так это FFTW_PRESERVE_INPUT, но только если вы не сохраняете ввод где-то еще. - person Vladimir F; 24.05.2016
comment
@VladimirF Проверка страницы руководства fftw.org/doc/Planner-Flags.html на самом деле кажется, что если использовать FFTW_MEASURE, входной массив будет перезаписан при создании плана. Очень запутанный интерфейс... - person roygvib; 24.05.2016
comment
@roygvib Да, вы не должны просто брать входной массив как intent(in), это не так. Даже во время трансформаций. Тогда вы должны использовать `FFTW_PRESERVE_INPUT`. Я настоятельно рекомендую сохранять входные значения в другом месте, если они понадобятся вам позже для каких-либо целей. Недостаточно просто использовать FFTW_ESTIMATE, как пытается предложить ответ. Это может скрыть проблему, но она может проявиться в любой момент, когда оценка выбирает алгоритм, который не сохраняет входные данные. Затем ввод будет перезаписан во время преобразования, а не во время планирования. Поэтому этот ответ неверен. - person Vladimir F; 24.05.2016
comment
Да, и вообще, я предлагаю как-то разделить создание планов и фактические преобразования. В моем случае я создаю модуль, который обрабатывает это внутри пользователя. Но я думаю, что сам ответ правильный, потому что стиль кодирования — это дело вкуса (в некоторой степени). Тем не менее, я думаю, что было бы очень полезно, если бы в качестве альтернативного (более безопасного) стиля был добавлен другой ответ... - person roygvib; 24.05.2016
comment
@roygvib Это неправильно, вы можете использовать FFTW_ESTIMATE и все равно ваш ввод будет перезаписан. Единственная удача в том, что планировщик выбрал алгоритм, который не перезаписывает, но это чистая удача. В следующий раз с тем же кодом на другом компьютере может снова произойти сбой. - person Vladimir F; 24.05.2016
comment
Хотя у него есть CALL dfftw_execute_dft_r2c(PLAN,u,qhat2d), почему бы и нет CALL dfftw_execute_dft_r2c(PLAN,u2d,qhat2d)? Где вообще определяется u? Я подозреваю, что это тип, и мой вывод все еще правильный. - person Vladimir F; 24.05.2016
comment
Ах, вы должны быть опечаткой u2d. Код работал на моем компьютере с этой модификацией (при изменении FFTW_MEASURE на FFTW_ESTIMATE). Кстати, действительно ли есть случай, когда FFTW_ESTIMATE может изменить входной массив? Поскольку я хочу узнать больше об этом, я был бы очень признателен за любую дополнительную информацию... - person roygvib; 24.05.2016
comment
@roygvib не во время планирования, я думаю. Но во время трансформации это могло произойти. Трудно воспроизвести, потому что вы не знаете, что выбирает оценка, но этот парень stackoverflow.com/questions/29322026/ действительно использовал FFTW_ESTIMATE. И на самом деле, ваш ответ здесь stackoverflow.com/questions/36885526/ столкнулся с той же проблемой или нет? - person Vladimir F; 25.05.2016
comment
[@VladimirF Привет, я проверю это позже и вернусь. (RE связанный Q / A, я помню, что получил неправильный результат, если я использовал вещь c2r.)] - person roygvib; 25.05.2016