菲涅尔衍射(Python实现)

目录

1.原理 

1.1傅里叶变换中的分辨率问题

1.2角谱算法和冲击响应积分的适用条件

2.参考代码

3.结果

4.结论

5.参考


1.原理 

        经过几天的折磨,终于是把目前遇到的问题全部解决了。下面我主要讲一下我觉得比较关键的两个点。一个是采样的问题一个是适用条件的问题。其实参考文献中都已经讲的比较清楚,只是本人没有认真阅读【汗颜】。话不多说把调试好的代码奉上,开始

       总的算法可以分成是上面两类,冲击响应和角谱(这里的单次傅里叶算法不知道能不能算作角谱)。具体算法的由来和分类可以看参考文献1,2。两位大佬讲的是非常好【👏】。

1.1傅里叶变换中的分辨率问题

        首先看看对二维图像做傅里叶变换后的图像的分辨率和范围到底是怎么确定的,关于这个问题我们首先给出一个一维的离散坐标系。表示离散的坐标轴,这个坐标轴是有实际的物理尺寸的。如下,这里取x方向分析,y方向是一样的。

        在这么一个坐标轴下,你能找到的最小周期Tmin = 2*dx,这里dx是空间频率的分辨率。那么这时候更具频率和周期的关系,以及假定频率采样点和空间采样点一致。可以得到空间频率的范围和采样率。

那么通过上面的这两个公式,就可以得到以下两个结论:

        1.对原图像补零,L增大->detaf减小,可以得到更高的空间分辨率

        2.对信号上采样,采样点数增加但是空间的尺寸不变,也就是空间分辨率dx减小。fmax增大也就是得到了更大的频率范围

        读到这里,读者可以思考一下为什么冲击响应的方式可以只计算局部而角谱却必须计算整个和光源平面一样的范围(作者认为:角谱上的每一个频率分量都是光源平面上每一个点的映射

1.2角谱算法和冲击响应积分的适用条件

这里参考2给了详细的推导,我这里直接剽窃结论

冲击响应条件
冲击响应条件
角谱条件

代码里面可以使用,两个条件的交集对应的传播距离,这样可以兼顾两种类型的方法。

d = np.sqrt((deta*L0/lambda_)**2-0.25*(L0**2))                          # 传输距离,单位米
f = d

2.参考代码

        下面是完整的代码,读者可以自己跑一下。

import numpy as np
import time
import matplotlib.pyplot as plt
from fanc import *

# 参数设置
lambda_ = 1.064e-6              # 波长,单位转换为米
k = 2 * np.pi / lambda_         # 波矢大小
N0 = 1024                       # 入射面采样点数
N = 512                         # 出射面采样点数
L0 = 60*1e-3                    # 入射面尺寸,单位转换为米
L = 60*1e-3                    # 出射面尺寸,单位转换为米
w = 1*1e-3
n = 6
ll = 5*1e-3
deta = L0/N0
d = np.sqrt((deta*L0/lambda_)**2-0.25*(L0**2))                          # 传输距离,单位米
f = d

# 离散化入射平面和出射面
x0 = np.linspace(-L0/2, L0/2, N0)
y0 = np.linspace(-L0/2, L0/2, N0)
X0, Y0 = np.meshgrid(x0, y0)
x = np.linspace(-L/2, L/2, N)
y = np.linspace(-L/2, L/2, N)
X, Y = np.meshgrid(x, y)
dx0, dy0 = np.gradient(x0)[0], np.gradient(y0)[0]
T = {}

# 生成光源
centers = [(ll*1/2, ll*np.sqrt(3)/2), (-ll*1/2, ll*np.sqrt(3)/2), (ll*1/2, -ll*np.sqrt(3)/2), (-ll*1/2, -ll*np.sqrt(3)/2), (ll,0), (-ll,0)]
U_total = generate_gaussian_sources(X0, Y0, centers, w)
U_total2 = generate_gaussian_sources(X0, Y0, centers, w)
# 透镜调制
U_after_lens = apply_lens_phase_factor(U_total, X0, Y0, f, lambda_)

# 利用矩阵乘法计算出射面光场复振幅
start_time = time.time()
u1 = matrix_method(U_after_lens, k, d, x, y, x0, y0)
checkpoint_time = time.time()
T['matrix_method'] = checkpoint_time-start_time
I1 = np.abs(u1)**2
I1 = I1 / I1.max()
# 绘制
plt.figure()
plt.imshow(I1)
plt.title('matrix_method')
plt.colorbar()


# 利用积分法计算出射面光场复振幅
#u2 = integrate_method(U_after_lens, d, lambda_, X0, Y0, X, Y)
#I2 = np.abs(u2)**2
#I2 = I2 / I2.max()
# 绘制
#plt.figure()
#plt.imshow(I2)
#plt.title('integrate_method')
#plt.colorbar()


# 两次傅里叶方法
start_time = time.time()
u5 = d_fft_method(U_after_lens, d, lambda_, dx0, dy0)
checkpoint_time = time.time()
T['d_fft_method'] = checkpoint_time-start_time
I5 = np.abs(u5)**2
I5 = I5 / I5.max()
# 绘制
plt.figure()
plt.imshow(I5)
plt.title('d_fft_method')
plt.colorbar()

# 三次傅里叶方法
start_time = time.time()
u3 = t_fft_method(U_after_lens, d, lambda_, dx0, dy0, L0)
checkpoint_time = time.time()
T['t_fft_method'] = checkpoint_time-start_time
I3 = np.abs(u3)**2
I3 = I3 / I3.max()
# 绘制
plt.figure()
plt.imshow(I3)
plt.title('t_fft_method')
plt.colorbar()

# 单次傅里叶
start_time = time.time()
u4 = s_fft_method(U_after_lens, d, lambda_, X0, Y0)
checkpoint_time = time.time()
T['s_fft_method'] = checkpoint_time-start_time
I4 = np.abs(u4)**2
I4 = I4 / I4.max()
# 绘制
plt.figure()
plt.imshow(I4)
plt.title('s_fft_method')
plt.colorbar()


# 光源绘制
plt.figure()
plt.title('origin_img')
plt.imshow(np.abs(U_total))
plt.colorbar()


plt.show()

print(T)

代码中调用的方法 

import numpy as np

from tqdm import tqdm

from scipy.fftpack import *


def generate_gaussian_sources(xx, yy, centers, sigma_x=1, sigma_y=None):
    if sigma_y is None:
        sigma_y = sigma_x

    # 初始化叠加后的高斯光源矩阵
    gaussian_sources = np.zeros(xx.shape)

    # 计算每个高斯分布并叠加
    for center in centers:
        center_x, center_y = center

        # 高斯分布
        exponent = - ((xx - center_x) ** 2 / sigma_x ** 2 + (yy - center_y) ** 2 / sigma_y ** 2)
        gaussian_source = np.exp(exponent)

        # 叠加到总光源矩阵
        gaussian_sources += gaussian_source

    return gaussian_sources

def apply_lens_phase_factor(U, X, Y, f, lambda_):
    k = 2 * np.pi / lambda_
    phase_factor = np.exp(-1j * k * (X**2 + Y**2) / (2 * f))
    return U * phase_factor

def matrix_method(U, k, d, x, y, x0, y0):

    X0, Y0 = np.meshgrid(x0, y0)
    # 构建矩阵Mx, My和M
    Mx = np.exp(-1j * k / d * np.outer(x, x0))
    My = np.exp(-1j * k / d * np.outer(y0, y))
    M = U * np.exp(1j * k * (X0 ** 2 + Y0 ** 2) / (2 * d))

    # 利用矩阵乘法计算出射面光场复振幅
    return Mx @ M @ My

def d_fft_method(U, d, lambda_, dx, dy):

    k = 2 * np.pi / lambda_

    # 轴向传播在频率域的传递函数
    fx = np.linspace(-1/(2*dx), 1/(2*dx), U.shape[0])
    fy = np.linspace(-1/(2*dy), 1/(2*dy), U.shape[1])[::-1]
    FX, FY = np.meshgrid(fx, fy)
    t = 1j*k*d
    uxs = np.sqrt(1 - (lambda_*FX)**2 - (lambda_*FY)**2)
    H = np.exp(t * uxs)

    # 将光场变换到频率空间
    U1=fftshift(fft2(U))
    U2=H*U1
    u2=ifft2(ifftshift(U2))

    return u2

def t_fft_method(U, d, lambda_, dx, dy, L):

    k = 2 * np.pi / lambda_

    # 轴向传播在频率域的传递函数
    x = np.linspace(-L / 2, L / 2, U.shape[0])
    y = np.linspace(-L / 2, L / 2, U.shape[1])
    X, Y = np.meshgrid(x, y)
    H = np.exp(1j * k / (2*d) * (X ** 2 + Y ** 2))

    # 将光场变换到频率空间
    H_freq = fft2(H)
    U_freq = fft2(U)

    # 应用传递函数
    U_freq_after_TTF = U_freq * H_freq

    # 将光场变换回实空间
    U_z = np.exp(1j*k*d)/1j/lambda_/d * fftshift(ifft2(U_freq_after_TTF))

    return U_z

def s_fft_method(U, d, lambda_, X, Y):

    k = 2 * np.pi / lambda_

    Lx = X.shape[0] * lambda_ * d / (X[-1,-1]-X[-0, -0])
    Ly = Y.shape[0] * lambda_ * d / (Y[-1,-1]-Y[-0, -0])
    x1 = np.linspace(-Lx / 2, Lx / 2, X.shape[0])
    y1 = np.linspace(-Ly / 2, Ly / 2, Y.shape[0])
    X1, Y1 = np.meshgrid(x1, y1)

    F0 = np.exp(1j * k * d) / (1j * lambda_ * d) * np.exp(1j * k / 2 / d * (X1 ** 2 + Y1 ** 2))
    F = np.exp(1j * k / 2 / d * (X ** 2 + Y ** 2))
    F = fftshift(fft2(U*F))
    return F0 * F

    return U

def integrate_method(U, d, lambda_, Xin, Yin, Xout, Yout):

    dx = Xin[1] - Xin[0]
    dy = dx

    # 计算波矢
    k = 2 * np.pi / lambda_
    phase_shift = k / (2 * d)

    # 初始化传播后的场分布
    u_propagated = np.zeros((Xout.shape[1], Yout.shape[0]), dtype=np.complex128)

    # 对整个空间进行积分以计算传播后的场分布
    for i in tqdm(range(Xout.shape[1]), desc="Outer Loop"):
        for j in range(Xout.shape[0]):
            -1j / lambda_ / d * np.exp(1j * k * d) * sum(sum(U * np.exp(1j * k / 2 / d * ((Xout[i, j] - Xin) ** 2 + (Yout[i, j] - Yin) ** 2))))

    return u_propagated

3.结果

放出结果

        这里读者如果理解了上面的思考问题,就可以理解这里的矩阵方法是可以通过调整计算范围来调整准确度的。

4.结论

方法matrix_methodt_fft_methods_fft_methodd_fft_method
t/s0.1066970.1016770.0697670.123922

5.参考

人类能看懂的衍射光学(含基尔霍夫衍射,瑞利--索末菲衍射,夫琅禾费衍射,角谱衍射,菲涅尔衍射积分,菲涅尔衍射的S-FFT算法,T-FFT算法,D-FFT算法)_瑞利索末菲衍射积分公式-CSDN博客

标量衍射计算指南(python 实现) - 楚千羽 - 博客园

一种快速实现光场传输的算法研究_龚海龙

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值