การสลายตัวของ 2D FFT (และ inverse fft) ด้วย fftw ใน fortran77

[แก้ไข 1] เพิ่มตัวเลขเพื่อแสดงข้อมูลต้นฉบับและข้อมูลที่ได้รับ

[แก้ไข 2] ฉันพบข้อผิดพลาด ฉันใช้ fftw_measure แทน fftw_estimate ในการเรียก dfftw_plan_many_dft

[แก้ไข 3] แก้ไขการพิมพ์ผิดในรหัส (แทนที่ u ด้วย u2d ใน dfftw_execute_dft_r2c )

ฉันกำลังลองทำ 2D fft ของอาร์เรย์โดยใช้ 1D fft หลายอัน แทนที่จะใช้ฟังก์ชัน 2D fft ที่มีอยู่แล้วในไลบรารี fftw และต่อมา ฉันต้องทำ fft 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
เหตุใดคุณจึงทำ DFT มูลค่าจริง (_r2c) กับข้อมูลที่ซับซ้อน   -  person Alexander Vogt    schedule 23.05.2016
comment
นอกจากความคิดเห็นอื่นๆ ฉันเน้นย้ำว่าคุณต้องแสดงให้เห็นว่ามีอะไรผิดปกติ คุณต้องแสดงว่าคุณได้รับค่าใดและทำไมคุณถึงเชื่อว่าค่าเหล่านั้นผิด   -  person Vladimir F    schedule 24.05.2016
comment
@AlexanderVogt ข้อมูลดั้งเดิมของฉัน u2d เป็นจริงดังนั้นฉันคิดว่าการใช้ r2c เป็นวิธีที่ถูกต้องในการทำ fft แรก นอกจากนี้ในตอนท้าย ฉันทำให้ข้อมูลของฉันเป็นปกติอีกครั้งโดยหารผลลัพธ์ของ 2 inverse 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) BTW มีบางกรณีที่ 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 คำถาม/คำตอบที่เชื่อมโยง ฉันจำได้ว่าฉันได้รับผลลัพธ์ที่ผิดหากฉันใช้สิ่ง c2r)] - person roygvib; 25.05.2016