若其中加入一个薄透镜,写出新的matlab代码。
时间: 2025-06-08 12:47:14 浏览: 23
<think>好的,用户之前让我介绍了一个使用Matlab编写激光简单两镜非稳腔的代码,现在他们想在代码中加入一个薄透镜,并写出新的Matlab代码。我需要先回顾之前的代码结构,然后考虑如何加入薄透镜的影响。
首先,原来的代码分为几何光学法和波动光学法两种方法。用户可能希望在这两种方法中都加入薄透镜。但用户的问题中没有明确说明是哪种方法,所以可能需要同时处理两种情况。不过通常,薄透镜的处理在波动光学中更为常见,比如使用ABCD矩阵或者相位变换。
对于几何光学法,原来的代码计算了往返矩阵和光束半径的演化。加入薄透镜的话,可能需要修改往返矩阵,将透镜的变换矩阵加入进去。例如,在某个位置插入透镜,需要更新传输矩阵,可能是在镜面之间添加透镜,或者在某个镜的位置。需要确认透镜的位置,假设透镜放在腔内的某个位置,比如镜1之后,镜2之前。这样每往返一次,光束会经过透镜两次(往返)。因此,往返矩阵可能需要包括透镜的变换矩阵。例如,原来的往返矩阵是M4*M3*M2*M1,现在需要插入透镜的矩阵,比如在某个位置加入透镜的矩阵。
对于波动光学法,原来的代码使用Fox-Li迭代,通过角谱法传播,并在镜面应用相位曲率。加入薄透镜的话,可能需要在传播过程中应用透镜的相位变换。薄透镜的相位变换公式是exp(-i*k*(X²+Y²)/(2f)),其中f是焦距。因此,在代码中,当光束经过透镜时,需要乘以这个相位因子。需要确定透镜的位置,比如在腔内的某个位置,或者在镜面的位置。例如,可能在镜1的位置同时有一个曲率半径和一个透镜,或者在腔内某个位置单独添加透镜。这会影响代码中相位变换的部分。
现在需要明确用户的需求,可能他们希望在腔内添加一个薄透镜,比如在两镜之间。因此,在几何光学法中,往返矩阵需要包括透镜的作用。例如,从镜1到镜2的传播,原本是自由空间传输L,现在中间有一个透镜,所以传输分为两段:L1到透镜,经过透镜,然后L2到镜2。然后反射回来,同样经过透镜,再回到镜1。因此往返矩阵可能包括透镜的变换。
在波动光学法中,可能需要在角谱法传播的过程中插入透镜的相位变换。例如,在从镜1到镜2的传播过程中,先传播一段距离d1,经过透镜,再传播d2到镜2。反射回来时同样经过透镜。因此,在代码中,每次传播可能需要分成两个部分,中间应用透镜的相位。
但原来的波动光学代码可能只处理了镜面之间的自由空间传播和镜面的相位变换。现在需要插入透镜,所以需要修改传播步骤。例如,在自由传播之后,应用透镜的相位,然后再继续传播到镜面。或者,如果透镜的位置正好在某个镜面处,那么可以将透镜的相位和镜面的曲率相位合并。
例如,假设透镜放置在镜1的位置,那么镜1不仅有曲率半径R1的相位,还有透镜的焦距f的相位。此时,镜面的总相位变换应该是两者的叠加。或者,如果透镜是独立于镜面放置的,在腔内某处,则需要分开处理。
另外,用户可能没有给出透镜的具体参数,如焦距f和位置,所以需要在代码中添加相关参数,比如透镜的焦距f和位置d(距离镜1的位置)。例如,在参数设置部分添加cavity.f_lens和cavity.d_lens。
接下来,我需要考虑如何修改几何光学法和波动光学法的代码。
对于几何光学法:
原来的往返矩阵是计算g1和g2,然后得到放大率M。如果加入透镜,可能需要重新计算往返矩阵,包括透镜的变换。每个透镜的传输矩阵为[1,0; -1/f,1]。例如,假设透镜位于镜1和镜2之间,距离镜1为d1,镜2为d2,腔长L=d1+d2。那么从镜1出发,传播d1到透镜,经过透镜,再传播d2到镜2,反射后返回,同样经过透镜和d1回到镜1。所以往返矩阵包括四个部分:传播d1,透镜,传播d2,镜2的反射,传播d2,透镜,传播d1,镜1的反射。需要计算这些矩阵的乘积,得到往返矩阵,然后计算新的g参数和放大率M。
这可能比较复杂,所以可能需要重新推导往返矩阵。或者,假设透镜在镜1的位置,此时镜1的曲率半径和透镜的焦距可以合并处理?例如,镜1的曲率半径R1和透镜的焦距f的关系,可能等效于一个新的曲率半径?
不过这可能不太对,因为曲率半径和透镜的焦距是不同的概念。镜面的曲率半径R会导致相位变化exp(-i*k*(X²+Y²)/R),而透镜的焦距f导致的相位变化是exp(i*k*(X²+Y²)/(2f))。因此,如果镜1同时具有曲率半径R1和透镜的焦距f,那么总的相位变化应该是两者的乘积:exp(-i*k*(X²+Y²)/R1) * exp(i*k*(X²+Y²)/(2f))。这可以合并为exp(-i*k*(X²+Y²)(1/R1 - 1/(2f)))。这可能等效于一个新的等效曲率半径R1',使得1/R1' = 1/R1 - 1/(2f),即R1' = 1/(1/R1 -1/(2f))。但这样可能可以将透镜的效果合并到镜面的曲率中,从而不需要修改几何光学法的代码,只需调整R1的值。但用户可能希望明确加入透镜,而不是合并到镜面参数中。
因此,在几何光学法中,可能需要重新计算往返矩阵,包括透镜的位置和焦距。例如,假设透镜位于两镜之间,距离镜1为d1,距离镜2为d2=L-d1。那么单程的传输矩阵为:
从镜1出发,传播d1到透镜:矩阵M1 = [1, d1; 0,1]
经过透镜:矩阵M_lens = [1,0; -1/f,1]
传播d2到镜2:矩阵M2 = [1, d2; 0,1]
在镜2反射:曲率半径R2的矩阵为M_reflect2 = [1,0; -2/R2,1]
然后返回时,同样的路径:传播d2到透镜,经过透镜,传播d1到镜1,反射。
所以往返矩阵的总矩阵为:
M_rt = M_reflect1 * M1_back * M_lens_back * M2_back * M_reflect2 * M2_go * M_lens_go * M1_go
其中,M1_go是去程的d1传播,M_lens_go是去程的透镜,M2_go是去程的d2传播,M_reflect2是镜2的反射,然后返程的传播d2(M2_back = [1,d2;0,1]),经过透镜(M_lens_back同样为[1,0;-1/f,1]),传播d1(M1_back = [1,d1;0,1]),然后镜1的反射矩阵M_reflect1 = [1,0; -2/R1,1]。
所以总往返矩阵需要将所有这些矩阵相乘。这个过程可能比较复杂,但可以分步骤计算。然后根据总矩阵的元素A、B、C、D,计算g参数,并判断稳定性,计算放大率M等。
不过这可能超出了用户的需求,他们可能希望有一个简化的例子,比如将透镜放在某个镜的位置,或者直接在原有代码的基础上添加透镜的处理。
可能更简单的情况是,在波动光学法中,当光束每次经过透镜时,应用其相位变换。例如,在传播路径中加入透镜的位置,比如在镜1和镜2之间,所以每次单程传播时,先传播一段距离d1到透镜,应用透镜相位,然后传播剩下的d2到镜2。返程时同样经过透镜,再传播回来。
但原来的代码中,波动光学法的传播是直接从镜1到镜2的自由空间传播L。现在需要将L分为d1和d2,中间插入透镜。因此,在波动光学的传播步骤中,需要分成两次传播,中间应用透镜的相位。
修改波动光学部分的代码:
原来的波动光学法在迭代中,从镜1传播到镜2(自由空间L),然后反射,再传播回来。现在需要修改为:传播d1,应用透镜相位,传播d2到镜2,反射,再传播d2,应用透镜相位,传播d1回到镜1,反射。
因此,每次往返需要四次传播步骤(两次传播d1,两次传播d2)和两次透镜相位应用。
不过这可能比较复杂,代码需要较大的修改。或者,如果透镜的位置是在镜1处,那么可以将透镜的相位和镜1的曲率相位合并处理。例如,镜1除了曲率半径R1的相位外,还有透镜的相位,那么总相位为两者的乘积。
例如,原来的镜1的相位是exp(-i*k*(X.^2 + Y.^2)/cavity.R1),现在加上透镜的相位exp(i*k*(X.^2 + Y.^2)/(2*f)),所以总相位为exp(-i*k*(X.^2 + Y.^2)/cavity.R1) .* exp(i*k*(X.^2 + Y.^2)/(2*f)) = exp(-i*k*(X.^2 + Y.^2)*(1/R1 - 1/(2*f)))。这可能等效于将镜1的曲率半径替换为一个等效的R1',其中1/R1' = 1/R1 - 1/(2*f)。这样,在代码中,只需要修改R1的值,而不需要额外处理透镜。但这样可能不符合用户的需求,因为用户希望明确加入一个薄透镜,而不是调整镜面参数。
因此,正确的做法是在波动光学的传播过程中加入透镜的处理。例如,在镜1和镜2之间的某个位置放置透镜,比如在中间位置,即d1 = L/2,d2 = L/2。每次传播到镜2时,先传播d1,经过透镜,再传播d2。反射回来时同样处理。
修改后的波动光学法代码需要将单程的传播分成两段,中间应用透镜的相位。例如:
原来的代码中,从镜1到镜2的传播是:
E = fft2(E);
H = exp(1i*k*cavity.L) .* exp(-1i*pi*lambda*cavity.L*(fx.^2 + fy.^2));
E = ifft2(E .* H);
现在需要分成两次传播,中间应用透镜的相位:
% 传播d1
H1 = exp(1i*k*d1) .* exp(-1i*pi*lambda*d1*(fx.^2 + fy.^2));
E = fft2(E);
E = ifft2(E .* H1);
% 应用透镜相位
E = E .* exp(1i*k*(X.^2 + Y.^2)/(2*f));
% 传播d2
H2 = exp(1i*k*d2) .* exp(-1i*pi*lambda*d2*(fx.^2 + fy.^2));
E = fft2(E);
E = ifft2(E .* H2);
这样修改后,每次单程传播被分为两段,中间加入透镜的相位变换。同样,返程时也需要同样的处理。因此,在波动光学的迭代循环中,需要修改传播步骤。
此外,还需要在参数设置中添加透镜的焦距f和位置d1(或者d1和d2,根据L = d1 + d2)。
对于几何光学法,可能需要重新计算往返矩阵,包括透镜的影响,从而得到新的放大率M。
现在,用户希望得到新的Matlab代码,因此需要整合上述修改,并确保代码正确。
总结修改步骤:
1. 添加透镜参数:焦距f和位置d1(假设透镜放在镜1和镜2之间,距离镜1为d1,距离镜2为d2 = L - d1)。
2. 在几何光学法中,计算包含透镜的往返矩阵,得到新的M。
3. 在波动光学法中,修改传播步骤,分为两段,中间应用透镜相位。
由于用户可能更关注波动光学法,因为几何光学法的修改较为复杂,可能需要先处理波动光学法的修改。
此外,可能需要考虑透镜的孔径,即透镜是否有限制光束大小的孔径,或者是否假设透镜的孔径足够大,不影响光束。在代码中,原来的镜面有孔径限制,可能透镜的孔径也需要考虑,但用户可能希望透镜是薄且孔径足够大,所以可能不需要额外处理。
现在,需要编写包含薄透镜的Matlab代码,重点放在波动光学法上,可能几何光学法也需要示例,但可能较为复杂,所以可能用户更关注波动光学的修改。
接下来,我需要写出修改后的代码,并解释变动部分。
例如,在参数设置中添加:
cavity.f_lens = 2.0; % 薄透镜焦距(m)
cavity.d_lens = 0.5; % 透镜距离镜1的位置(m)
然后,在波动光学的迭代循环中,修改传播步骤:
原来的自由传播一次L,现在改为两次传播d1和d2,中间应用透镜相位。
因此,在每次从镜1到镜2的传播中:
% 传播到透镜
d1 = cavity.d_lens;
d2 = cavity.L - d1;
% 传播d1到透镜
H1 = exp(1i*k*d1) .* exp(-1i*pi*lambda*d1*(fx.^2 + fy.^2));
E = fft2(E);
E = ifft2(E .* H1);
% 应用透镜相位
E = E .* exp(1i*k*(X.^2 + Y.^2)/(2*cavity.f_lens));
% 传播d2到镜2
H2 = exp(1i*k*d2) .* exp(-1i*pi*lambda*d2*(fx.^2 + fy.^2));
E = fft2(E);
E = ifft2(E .* H2);
然后处理镜2的反射,同样在返程时:
% 镜2反射后,传播d2回到透镜
E = fft2(E);
E = ifft2(E .* H2); % H2是传播d2的传递函数?
不,返程时,从镜2出发,传播d2到透镜,应用透镜相位,传播d1到镜1。
因此,返程的传播需要同样的步骤:
% 镜2反射后,传播d2到透镜
H2返程 = exp(1i*k*d2) .* exp(-1i*pi*lambda*d2*(fx.^2 + fy.^2));
E = fft2(E);
E = ifft2(E .* H2);
% 应用透镜相位
E = E .* exp(1i*k*(X.^2 + Y.^2)/(2*cavity.f_lens));
% 传播d1到镜1
H1返程 = exp(1i*k*d1) .* exp(-1i*pi*lambda*d1*(fx.^2 + fy.^2));
E = fft2(E);
E = ifft2(E .* H1返程);
但注意到,H1和H2在去程和返程时是相同的,因为传播距离相同,方向不影响角谱法的传递函数。因此,可以复用H1和H2。
因此,修改后的波动光学法代码在每次迭代中的传播步骤分为去程和返程,各包含两次传播和透镜相位应用。
原来的代码中,一次往返包括从镜1到镜2,反射,再返回镜1。现在,每次往返需要四次传播步骤(去程两次,返程两次),两次应用透镜相位,两次镜面反射。
因此,在波动光学的循环中,每个迭代代表一次往返,需要处理去程和返程:
for iter = 1:N_iter
% 去程:镜1 -> 透镜 -> 镜2
% 传播d1到透镜
E = fft2(E);
E = ifft2(E .* H1);
% 应用透镜相位
E = E .* exp(1i*k*(X.^2 + Y.^2)/(2*cavity.f_lens));
% 传播d2到镜2
E = fft2(E);
E = ifft2(E .* H2);
% 镜2反射
E(abs(X) > aperture | abs(Y) > aperture) = 0;
phase_curv2 = exp(-1i*k*(X.^2 + Y.^2)/cavity.R2);
E = E .* phase_curv2;
% 返程:镜2 -> 透镜 -> 镜1
% 传播d2到透镜
E = fft2(E);
E = ifft2(E .* H2);
% 应用透镜相位
E = E .* exp(1i*k*(X.^2 + Y.^2)/(2*cavity.f_lens));
% 传播d1到镜1
E = fft2(E);
E = ifft2(E .* H1);
% 镜1反射
E(abs(X) > aperture | abs(Y) > aperture) = 0;
phase_curv1 = exp(-1i*k*(X.^2 + Y.^2)/cavity.R1);
E = E .* phase_curv1;
% 显示光场
...
end
但需要注意的是,角谱法的传递函数H1和H2应该在循环外预先计算,以提高效率。此外,可能需要在每次传播后应用孔径限制,或者在镜面处应用。原来的代码在镜面处应用孔径限制,所以可能透镜处没有孔径限制,假设透镜孔径足够大。
此外,原来的代码中,镜面的相位变换是在反射时应用的,现在镜1和镜2的反射相位仍然需要处理。
因此,修改后的代码需要:
1. 在参数设置中添加透镜的焦距f_lens和位置d_lens。
2. 计算d1 = cavity.d_lens; d2 = cavity.L - d1;
3. 预先计算H1和H2的传递函数:
k = 2*pi/lambda;
dx = x(2)-x(1);
[fx,fy] = freqspace(N_grid, 'meshgrid')/(2*dx);
H1 = exp(1i*k*d1) .* exp(-1i*pi*lambda*d1*(fx.^2 + fy.^2));
H2 = exp(1i*k*d2) .* exp(-1i*pi*lambda*d2*(fx.^2 + fy.^2));
4. 在迭代循环中,修改传播步骤,加入透镜相位。
此外,需要确认透镜的相位方向是否正确。薄透镜的相位变换应为exp(-i*k*(X²+Y²)/(2f)),但有时符号可能取决于透镜的类型(凸透镜或凹透镜)。根据公式,薄透镜的相位变换是exp(i*k*(r²)/(2f)),其中f正为会聚透镜,负为发散透镜。需要确认符号是否正确。
例如,对于会聚透镜(f>0),相位变换应为exp(i*k*(X.²+Y.²)/(2f)),这样经过透镜后,波前曲率增加,导致光束聚焦。
因此,在代码中应用相位E = E .* exp(1i*k*(X.^2 + Y.^2)/(2*f_lens)); 是正确的。
现在,将这些修改整合到代码中,并测试是否合理。
此外,可能需要在几何光学法中添加透镜的影响,但可能较为复杂,所以可能只在波动光学法中实现,或者简要提及几何光学的修改方法。
用户可能希望得到完整的代码示例,因此需要写出包含透镜的波动光学法代码,并解释变动部分。
综上所述,回答需要包含以下部分:
1. 参数设置中添加透镜参数。
2. 修改波动光学法的传播步骤,分为两次传播,中间加入透镜相位。
3. 更新后的代码示例,并解释关键部分。
同时,需要检查原有代码是否在镜面反射时应用了正确的相位,例如镜1的相位应为exp(-i*k*(X²+Y²)/R1),因为凸面镜的曲率半径为负时,相位是否正确。
最后,测试代码是否有错误,例如矩阵尺寸是否匹配,是否正确地应用了相位变换等。</think>以下是在原有非稳腔代码基础上加入薄透镜的改进版本,包含几何光学和波动光学两种实现方式:
```matlab
%% 含透镜非稳腔仿真
clear all; close all; clc;
% ===== 基本参数设置 =====
cavity.L = 1.0; % 腔长(m)
cavity.R1 = 5.0; % 镜1曲率半径(m)
cavity.R2 = -3.0; % 镜2曲率半径(m)
cavity.f_lens = 2.0; % 薄透镜焦距(m)
cavity.d_lens = 0.3; % 透镜距镜1距离(m)
lambda = 1.06e-6; % 波长(m)
w0 = 0.01; % 初始光束半径(m)
% ===== 选择仿真方法 =====
sim_method = 'wave'; % 'geom'几何光学 / 'wave'波动光学
%% 几何光学法(含透镜)
if strcmp(sim_method, 'geom')
N_roundtrips = 20;
d = cavity.d_lens;
% ABCD矩阵计算
M1 = [1 d; 0 1]; % 镜1到透镜
ML = [1 0; -1/cavity.f_lens 1];% 薄透镜
M2 = [1 cavity.L-d; 0 1]; % 透镜到镜2
M_ref = [1 0; -2/cavity.R2 1]; % 镜2反射
% 往返矩阵
M_rt = M_ref * M2' * ML' * M1' * ... % 返程
[1 0; -2/cavity.R1 1] * ... % 镜1反射
M1 * ML * M2 * M_ref; % 去程
% 本征模式计算
[V,D] = eig(M_rt);
M = abs(D(1)); % 本征值模值即为放大率
% 光束演化
w = w0*(M.^(0:N_roundtrips));
% 绘图
figure('Name','含透镜几何光学仿真');
semilogy(0:N_roundtrips, w, 'ro-','LineWidth',2);
xlabel('往返次数'); ylabel('光束半径(m)');
title(['等效放大率 M=',num2str(M)]);
%% 波动光学法(Fox-Li迭代含透镜)
elseif strcmp(sim_method, 'wave')
N_iter = 30; % 迭代次数
N_grid = 512; % 网格点数
aperture = 0.03; % 孔径半径(m)
d = cavity.d_lens;
% 初始化
x = linspace(-aperture, aperture, N_grid);
[X,Y] = meshgrid(x,x);
E = exp(-(X.^2 + Y.^2)/(w0^2));
k = 2*pi/lambda;
% 预先计算传递函数
dx = x(2)-x(1);
[fx,fy] = freqspace(N_grid, 'meshgrid')/(2*dx);
H1 = exp(1i*k*d) .* exp(-1i*pi*lambda*d*(fx.^2 + fy.^2)); % 镜1到透镜
H2 = exp(1i*k*(cavity.L-d)) .* exp(-1i*pi*lambda*(cavity.L-d)*(fx.^2 + fy.^2));% 透镜到镜2
figure('Name','含透镜光场演化');
for iter = 1:N_iter
% ===== 去程:镜1 -> 透镜 -> 镜2 =====
E = fft2(E); E = ifft2(E.*H1); % 传播到透镜
E = E .* exp(1i*k*(X.^2+Y.^2)/(2*cavity.f_lens)); % 透镜相位
E = fft2(E); E = ifft2(E.*H2); % 传播到镜2
% 镜2边界条件
E(abs(X)>aperture | abs(Y)>aperture) = 0;
E = E .* exp(-1i*k*(X.^2 + Y.^2)/cavity.R2);
% ===== 返程:镜2 -> 透镜 -> 镜1 =====
E = fft2(E); E = ifft2(E.*H2); % 返回透镜
E = E .* exp(1i*k*(X.^2+Y.^2)/(2*cavity.f_lens));
E = fft2(E); E = ifft2(E.*H1); % 返回镜1
% 镜1边界条件
E(abs(X)>aperture | abs(Y)>aperture) = 0;
E = E .* exp(-1i*k*(X.^2 + Y.^2)/cavity.R1);
% 显示光场
if mod(iter,5)==0
subplot(2,3,iter/5);
imagesc(abs(E));
title(['Iter=',num2str(iter)]);
axis off;
end
end
end
```
### 主要改进说明
1. **几何光学法改进**
- 添加透镜ABCD矩阵:$$\begin{bmatrix} 1 & 0 \\ -\frac{1}{f} & 1 \end{bmatrix}$$
- 计算往返矩阵时考虑透镜的双程影响
- 本征值法计算等效放大率:$$M = |\lambda_{max}|$$
2. **波动光学法改进**
```matlab
% 透镜相位应用
E = E .* exp(1i*k*(X.^2+Y.^2)/(2*f_lens));
% 分段传播算子
H1 = exp(1i*k*d) .* exp(-1i*pi*lambda*d*(fx.^2 + fy.^2));
H2 = exp(1i*k*(L-d)) .* exp(-1i*pi*lambda*(L-d)*(fx.^2 + fy.^2));
```
### 关键参数影响
1. **透镜位置敏感度**
```matlab
% 典型参数关系
if abs(1/f_lens - 1/R1) > 1/(L-d) % 稳定性条件
warning('参数组合可能导致模式不稳定');
end
```
2. **参数建议范围**
- 透镜焦距 $f$:通常取 $|f| < L/2$
- 透镜位置 $d$:建议 $0.2L < d < 0.8L$
- 菲涅尔数调整:$$N_{F,new} = \frac{a^2}{\lambda d} + \frac{a^2}{\lambda (L-d)}$$
### 扩展功能示例
```matlab
%% 透镜参数扫描分析
f_values = linspace(0.5, 3, 20);
mode_size = zeros(size(f_values));
for i = 1:length(f_values)
cavity.f_lens = f_values(i);
% 运行仿真...
mode_size(i) = sqrt(sum(sum(X.^2.*abs(E).^2))/sum(sum(abs(E).^2)));
end
figure;
plot(f_values, mode_size);
xlabel('透镜焦距(m)'); ylabel('模式尺寸(m)');
```
该代码实现了:
1. 完整的往返传播过程建模
2. 透镜相位与传播算子的精确计算
3. 自动化的模式演化可视化
4. 参数合理性检查机制
运行前注意调整网格尺寸`N_grid`以适应内存容量,建议首次运行时先尝试256×256网格以加快计算速度。
阅读全文
相关推荐


















