Дифракция Френеля в два этапа
Я написал короткий файл сценария matlab, который, как предполагается, должен выполнять распространение (дифракцию) Френеля, чтобы при заданном поле ввода U0 оно сообщало вам, как выглядит поле после расстояния z0. Я сравнил результат с результатами учебника, и похоже, что моя программа работает нормально. Проблема в том, что если я попытаюсь сделать два шага распространения вместо одного. т.е. вместо одной итерации программы для распространения на расстояние z0, я беру две итерации программы для распространения на расстояние z0/2 каждая. Тогда я получаю полную чушь и не могу понять, в чем проблема. Любой совет будет принят с большой благодарностью. Вот код:
function U = fresnel_advance (U0, dx, dy, z, lambda)
% The function receives a field U0 at wavelength lambda
% and returns the field U after distance z, using the Fresnel
% approximation. dx, dy, are spatial resolution.
k=2*pi/lambda;
[ny, nx] = size(U0);
Lx = dx * nx;
Ly = dy * ny;
dfx = 1./Lx;
dfy = 1./Ly;
u = ones(nx,1)*((1:nx)-nx/2)*dfx;
v = ((1:ny)-ny/2)'*ones(1,ny)*dfy;
O = fftshift(fft2(U0));
H = exp(1i*k*z).*exp(-1i*pi*lambda*z*(u.^2+v.^2));
U = ifft2(O.*H);
3 ответа
После звонка fft2
звоните также fftshift
иметь частоту постоянного тока в середине.
Но когда вы звоните ifft2
, функция предполагает, что у вас все еще есть частота постоянного тока в (1,1). Таким образом, вы должны вернуться к этому формату, прежде чем делать обратное БПФ.
Таким образом, изменение последней строки U = ifft2(fftshift(O.*H))
может решить проблему.
РЕДАКТИРОВАТЬ
Я только что видел, что Matlab советует использовать ifftshift
после fftshift
в два раза ifftshift
(не могу найти версию, в которой он представлен). Согласно документации, последовательность звонков ifftshift(fftshift(X))
а также ifftshift(fftshift(X))
не эквивалентны в случае нечетных размеров.
Поэтому я думаю, что лучше сделать: U = ifft2(ifftshift(O.*H))
на последнем шаге вашего кода.
На самом деле проблема заключается в том, как вы запускаете свой fft. Это хорошо объясняется в Fourier Optics and Computational Imaging Khedar Kare, Wiley 2015:
Подходящая последовательность для 2D БПФ на большинстве программных платформ для того, чтобы результат был значимым с физической точки зрения (например, при описании таких явлений, как дифракция), таким образом, задается следующим образом: fftshift(fft2(ifftshift(...))).
В вашем коде вы должны:O = fftshift(fft2(ifftshift(U0)));
Если вас интересует программное обеспечение, разработанное на Python, существует быстро развивающийся набор инструментов Python для оптики, включая дифракцию: PyOptica. В PyOptica волновой фронт можно распространять с помощью:
import astropy.units as u
import numpy as np
import pyoptica as po
wavelength = 500 * u.nm
pixel_scale = 22 * u.um
npix = 1024
w = 6 * u.mm
h = 3 * u.mm
axis_unit = u.mm
wf = po.Wavefront(wavelength, pixel_scale, npix)
ap = po.RectangularAperture(w, h)
wf = wf * ap
fig_1 = po.plotting.plot_wavefront(wf, 'intensity', axis_unit=axis_unit)
Второй шаг - размножить:
f = 50 * u.cm
fs_f = po.FreeSpace(f)
wf_forward = wf * fs_f
fig_2 = po.plotting.plot_wavefront(wf_forward, 'intensity', axis_unit=axis_unit)
Важно помнить условия выборки для распространения Френеля, а именно:(z <= N (dx) ^ 2 / lambda), где:
- N - количество пикселей (в одну сторону);
- dx - размер пикселя;
- лямбда - длина волны.
Это условие основано на " Computational Fourier Optics: A MATLAB Tutorial by David Voelz, SPIE 2011".
Вы должны реализовать это условие в своем коде. В PyOptica это всегда проверяется перед распространением; если запрошенное расстояние нарушает условие, расстояние распространения разбивается на подшаги.
Было бы полезно, если бы вы могли опубликовать некоторые примеры входных данных в вашей программе, чтобы продемонстрировать проблему.
Я подозреваю, что проблема может быть связана с тем, что вы не звоните в FFTSHIFT достаточное количество раз. Обычно считается, что центр матрицы оптического поля находится в "начале координат", а FFT2 рассматривает "левый нижний" угол. Поэтому вы должны FFTSHIFT до FFT2, а также после.
Вы должны сделать то же самое для части IFFT2.
РЕДАКТИРОВАТЬ Обоснование добавления двух вызовов в FFTSHIFT: сравните эти два:
N = 512; [x,y] = meshgrid(-1:1/N:(N-1)/N);
mask = (x.*x + y.*y) < 0.001;
figure(1)
imagesc(angle(fftshift(fft2(fftshift(mask)))))
figure(2)
imagesc(angle(fftshift(fft2(mask)))
Я думаю, что есть ошибка фазового члена. "H = exp (1ik z).Exp (-1i pilambda z * (u. ^ 2 + v. ^ 2));"
должно быть "H = exp (1ik z).exp (-1i pi / lambda / z * (u. ^ 2 + v. ^ 2));"