brandondube / prysm

physical optics: integrated modeling, phase retrieval, segmented systems, polynomials and fitting, sequential raytracing...
https://prysm.readthedocs.io/en/stable/
MIT License
268 stars 46 forks source link

Mismatch in iczt2 and ifft2 #104

Closed u-yuta closed 1 year ago

u-yuta commented 1 year ago

Hello, thanks for this useful library! I think I've come across a potential bug. Could you check into it?

I believe that iczt2(czt2(input)) should be equal to input, but it's equal to the complex conjugate of input. Similarly, iczt2(input) should be equal to fftshiftt(ifft2(ifftshift(input))), but iczt2(input) seems to be equal to the complex conjugate of fftshiftt(ifft2(ifftshift(input))).

import numpy as np
from numpy import fft
from prysm.fttools import czt

arr_in = np.random.rand(4, 4) + 1.0j * np.random.rand(4, 4)

# iczt2(czt2(input, Q=1)) does not match input 
arr_in_ft = czt.czt2(arr_in, Q=1, samples=4)
print(np.allclose(arr_in, czt.iczt2(arr_in_ft, Q=1, samples=4)))  # False
# conj(iczt2(czt2(input))) matches input
print(np.allclose(arr_in, np.conj(czt.iczt2(arr_in_ft, Q=1, samples=4))))  # True

# ifft2(input) does not match conj(iczt2(input, Q=1))
arr_in_ft_ifft = fft.fftshift(fft.ifft2(fft.ifftshift(arr_in), norm="ortho"))
arr_in_ft_iczt = czt.iczt2(arr_in, Q=1)
print(np.allclose(arr_in_ft_ifft, arr_in_ft_iczt))  # False
# ifft2(input) matches conj(iczt2(input, Q=1))
print(np.allclose(arr_in_ft_ifft, np.conj(arr_in_ft_iczt)))  # True

I think it might be necessary to modify iczt2 to return the complex conjugate of its current output.

brandondube commented 1 year ago

Since this fix seems simple, would you mind creating a pull request with the fix, and a new unit test to make sure it doesn't get un-fixed?