
1. 项目概述用Matlab重现光的衍射之美在光学实验和理论教学中衍射图样是理解光波动性的直观窗口。无论是大学物理实验课上的单缝衍射还是光学仪器设计中的光栅光谱分析亦或是评估光学系统分辨率的圆孔衍射艾里斑这些经典的衍射现象都离不开一张清晰的衍射光强分布图。然而实验受限于环境、设备精度和稳定性理论公式又过于抽象。这时Matlab作为一款强大的数值计算与可视化工具就成为了连接理论与视觉的绝佳桥梁。这个项目的核心就是利用Matlab编程精确模拟并绘制四种基础且重要的衍射图样单缝衍射、光栅衍射、圆孔衍射和矩孔衍射。这不仅仅是简单的公式绘图它涉及到从物理模型到离散数值计算的转换、二维光强分布的可视化技巧以及如何通过代码参数灵活地“调节”实验条件观察衍射图样的变化。对于物理、光学工程、电子信息等相关专业的学生和工程师而言掌握这套方法意味着你可以在电脑上搭建一个“虚拟光学实验室”无需昂贵设备就能深入探究衍射现象的每一个细节。接下来我将以一个从业多年的视角拆解实现这一过程的完整思路、关键技术细节和那些容易踩坑的实操要点。2. 核心物理模型与数值化思路在动手写代码之前我们必须把连续的物理世界“翻译”成Matlab能处理的离散数学模型。衍射的核心理论是惠更斯-菲涅尔原理但在夫琅禾费衍射远场衍射的近似下我们可以利用傅里叶光学的一个美妙结论观察屏上的复振幅分布恰好是衍射孔径函数的傅里叶变换。这是我们实现所有模拟的基石。2.1 单缝衍射的数学模型单缝衍射是最简单的模型。设单缝宽度为a入射光波长为lambda观察屏距离为L满足夫琅禾费条件L a^2/lambda。沿垂直于缝长方向的坐标x上的光强I(x)分布公式为I(x) I0 * [sin(β) / β]^2其中β (π * a * x) / (lambda * L)I0是中心光强。在数值计算时我们并不直接使用这个一维公式绘图。为了与后续二维衍射统一并为绘制二维衍射图样即考虑缝长方向也有一定扩展做准备我们将其构建为一个二维矩阵。思路是创建一个二维矩阵来表示“单缝”缝宽方向比如x方向的透过率函数为矩形函数rect缝长方向y方向的透过率函数在理想无限长情况下可视为常数1。那么孔径函数P(x, y) rect(x/a)。其二维傅里叶变换的模平方就是衍射光强分布。在Matlab中我们可以通过构建一个二维矩阵大部分为0中间一列为1来近似这个单缝然后计算其二维离散傅里叶变换DFT。注意这里存在一个关键技巧。直接用矩阵的一列非零元素模拟无限长单缝其傅里叶变换在y方向会引入 sinc 函数导致图样在y方向也有变化。若只想展示经典的一维单缝衍射条纹需确保矩阵在y方向的尺寸足够大并在最后观察时只取中心一行或一列的数据。更严谨的做法是直接使用一维傅里叶变换但为了代码框架的统一性我们通常采用二维方法然后通过调整可视化范围来聚焦核心现象。2.2 光栅衍射的数学模型光栅是多个等宽等间距单缝的集合。设缝宽为a光栅常数为dd a bb为不透光部分宽度缝数为N。其夫琅禾费衍射光强公式为I(θ) I0 * [sin(β)/β]^2 * [sin(Nγ)/sin(γ)]^2。 其中β (π * a * sinθ) / lambdaγ (π * d * sinθ) / lambda。第一部分是单缝衍射因子决定了包络线形状第二部分是多光束干涉因子决定了尖锐的主极大条纹。数值模拟时我们同样构建二维孔径函数。一个包含N条缝的光栅其透过率函数是N个矩形函数的叠加位置间隔为d。在Matlab中我们可以通过循环或向量化操作在一个零矩阵的特定行或列上以d为间隔设置长度为a的线段为1。然后计算这个二维矩阵的二维离散傅里叶变换的模平方。这种方法能同时自然地呈现出单缝衍射包络和多光束干涉细纹效果非常直观。2.3 圆孔衍射的数学模型圆孔衍射艾里斑是分析光学系统分辨率的基础。半径为R的圆孔其夫琅禾费衍射的光强分布为I(r) I0 * [2 * J1(ρ) / ρ]^2。 其中J1是一阶贝塞尔函数ρ (2π * R * r) / (lambda * L)r是观察屏上的径向坐标。数值模拟的关键在于生成一个圆形的孔径函数。我们需要创建一个二维网格坐标[X, Y]计算每个点到中心的距离r_matrix sqrt(X.^2 Y.^2)。然后令孔径矩阵P (r_matrix R)。这个逻辑判断会生成一个1圆内和0圆外的二值矩阵。接着计算P的二维傅里叶变换并取模平方。由于贝塞尔函数是圆对称的模拟结果应该呈现出一系列明暗相间的同心圆环中心是最亮的艾里斑。2.4 矩孔衍射的数学模型矩孔是更一般化的形状其衍射是单缝衍射在两个垂直方向上的直接推广。设矩孔边长分别为a_x和a_y。其夫琅禾费衍射光强分布为I(x, y) I0 * [sin(β_x)/β_x]^2 * [sin(β_y)/β_y]^2。 其中β_x (π * a_x * x) / (lambda * L)β_y (π * a_y * y) / (lambda * L)。数值模拟最为直接生成一个二维矩形区域在|x| a_x/2且|y| a_y/2的范围内置1其余置0。这个矩阵本身就是一个矩形。计算其二维傅里叶变换模平方结果将呈现十字形的衍射条纹两个方向的条纹宽度分别由a_x和a_y决定。实操心得上述所有模型的数值实现都统一到了“构建孔径函数矩阵 - 计算二维DFTFFT- 取模平方得到光强 - 可视化”这个流程上。这不仅是代码复用的基础更深刻反映了傅里叶光学“孔径函数与衍射场是傅里叶变换对”这一核心思想。理解这一点你就掌握了用计算模拟几乎所有夫琅禾费衍射现象的钥匙。3. Matlab实现的核心步骤与代码解析有了理论模型我们进入具体的Matlab实现环节。我将分步骤详细解析代码并解释每一个参数和操作背后的意图。3.1 环境准备与参数定义首先我们需要定义一系列物理和计算参数。这些参数直接影响模拟的准确性和图像的质量。% 1. 物理参数定义 lambda 632.8e-9; % 氦氖激光波长单位米 L 1; % 观察屏到孔径的距离单位米需满足夫琅禾费条件 % 单缝参数 a_slit 0.1e-3; % 单缝宽度单位米 % 光栅参数 a_grating 0.1e-3; % 光栅单缝宽度 d_grating 0.3e-3; % 光栅常数 (ab) N_slits 5; % 光栅缝数 % 圆孔参数 R_aperture 0.5e-3; % 圆孔半径单位米 % 矩孔参数 a_rect_x 0.2e-3; % 矩孔x方向边长 a_rect_y 0.4e-3; % 矩孔y方向边长 % 2. 计算参数定义关键 N 1024; % 采样点数矩阵尺寸推荐2的幂次以提高FFT效率 % 孔径平面的尺寸模拟范围需要大于实际孔径尺寸 sim_width 5e-3; % 孔径平面模拟区域的物理宽度单位米 dx sim_width / N; % 孔径平面的采样间隔 % 根据傅里叶变换关系衍射面观察屏的坐标范围与孔径面采样间隔dx成反比 % 衍射面的角空间频率坐标 fx (-N/2 : N/2-1) / (N * dx); % 空间频率单位1/米 % 将空间频率转换为观察屏上的实际位置坐标小角度近似下sinθ ≈ θ ≈ x/L x_screen lambda * L * fx; % 观察屏x方向坐标单位米 y_screen x_screen; % 假设y方向与x方向相同参数选择详解N1024采样点数决定了模拟的精度和计算量。点数太少模拟的衍射条纹会失真出现锯齿或混叠现象点数太多计算速度会变慢。1024是一个在精度和效率之间很好的平衡点并且是2的幂次能最大化FFT算法的效率。sim_width这是模拟的“画布”大小必须完全覆盖你的孔径单缝、光栅等并且周围留有足够的零区域。如果sim_width只比孔径大一点点那么在做FFT时会由于“截断效应”导致模拟结果出现不必要的波纹。通常设置为孔径最大尺寸的3-5倍。dx与x_screen的关系这是整个模拟最易出错的地方。dx是孔径平面的采样间隔。根据离散傅里叶变换DFT的性质变换后的域这里是衍射面的坐标范围由1/dx决定采样间隔由1/(N*dx)决定。代码中通过fx构建了正确的映射关系最终得到观察屏上的物理坐标x_screen。理解这个关系才能正确解释输出图像的横纵坐标标度。3.2 构建孔径函数矩阵这是模拟的核心不同的衍射类型对应不同的矩阵生成方法。% 生成坐标网格 x (-N/2 : N/2-1) * dx; % 孔径平面x坐标 y x; % 孔径平面y坐标转置以生成网格 [X, Y] meshgrid(x, y); % 生成二维网格坐标 % 初始化孔径函数矩阵 P zeros(N, N); % --- 选择要模拟的衍射类型 --- diffraction_type circular; % 可选single_slit, grating, circular, rectangular switch diffraction_type case single_slit % 单缝在x方向中心创建一个狭缝 slit_half_width a_slit / 2; % 创建一个宽度为a_slit的狭缝。注意这里在y方向没有限制模拟无限长单缝。 P(abs(X) slit_half_width) 1; % 注意更精确的模拟可以限制Y范围但为了展示典型二维图样这里用全Y范围。 case grating % 光栅创建N条等间距狭缝 slit_half_width a_grating / 2; center_positions (-floor((N_slits-1)/2) : floor((N_slits-1)/2)) * d_grating; for xc center_positions % 对于每条缝在x方向特定位置设置透过率为1 idx (X (xc - slit_half_width)) (X (xc slit_half_width)); P(idx) 1; end case circular % 圆孔创建一个圆形孔径 R R_aperture; P(sqrt(X.^2 Y.^2) R) 1; case rectangular % 矩孔创建一个矩形孔径 rect_half_width_x a_rect_x / 2; rect_half_width_y a_rect_y / 2; P((abs(X) rect_half_width_x) (abs(Y) rect_half_width_y)) 1; end构建技巧与避坑指南坐标原点通过(-N/2 : N/2-1) * dx生成对称于零点的坐标是为了让孔径如圆、矩形能居中显示。如果从0开始生成坐标孔径会位于矩阵一角导致傅里叶变换后的相位中心偏移衍射图样不在图像中心。光栅缝数N_slits在代码中center_positions计算了每条缝中心的x坐标。确保这些坐标都落在模拟区域sim_width内否则缝会被截断。floor函数的使用确保了无论缝数是奇数还是偶数光栅都能关于中心对称。逻辑索引P(abs(X) slit_half_width) 1;这种使用逻辑矩阵进行索引赋值的方式是Matlab向量化编程的精华比用for循环遍历每个元素快得多。矩阵二值化孔径矩阵P的值通常是0不透光和1透光。这对应于振幅透过率。如果考虑更复杂的孔径如相位光栅P可以是复数。3.3 计算衍射图样与FFT技巧得到孔径函数P后我们需要计算其夫琅禾费衍射图样。% 计算衍射场的复振幅夫琅禾费衍射近似下为孔径函数的傅里叶变换 % 使用fft2进行二维快速傅里叶变换 U fft2(P); % 关键步骤使用fftshift将零频分量移动到频谱中心 U_shifted fftshift(U); % 计算光强分布正比于复振幅模的平方 I abs(U_shifted).^2; % 可选为了显示美观常对光强进行对数缩放或归一化 I_display I / max(I(:)); % 归一化到[0, 1] % 或者使用对数标度来增强弱条纹的可见性I_display_log log(1 I);FFT操作的核心要点fft2vsfftshiftfft2计算的结果其零频分量对应衍射图样的中心亮斑位于矩阵的左上角(1,1)。为了符合我们的观察习惯中心亮斑在图像中间必须使用fftshift将零频分量移到矩阵中心。忘记fftshift是新手最常见的错误之一会导致衍射图样在四个角上完全不对。abs().^2探测器如眼睛、CCD测量的是光强即光波复振幅的模平方。所以一定要先取模abs()再平方。如果直接对U_shifted取实部或平方会得到错误结果。归一化与显示原始计算出的I值可能动态范围很大中心极亮周围极暗。直接imagesc(I)可能只能看到中心一个白点。归一化到最大值I/max(I(:))是标准做法。如果想同时看清中心主极大和周围微弱的高级次条纹采用对数缩放log(1I)是更佳选择它能压缩动态范围。3.4 结果可视化与专业出图将计算得到的光强矩阵以图像形式呈现并添加必要的标注。% 创建图形窗口 figure(Position, [100, 100, 800, 600], Color, w); % 设置图形位置和背景色 % 子图1孔径函数即“光阑”形状 subplot(1, 2, 1); imagesc(x*1e3, y*1e3, P); % 坐标转换为毫米显示 axis image; % 保持纵横比相等 colormap(gray); % 使用灰度图0为黑1为白 title(孔径函数 (Aperture Function), FontSize, 12, FontWeight, bold); xlabel(x (mm)); ylabel(y (mm)); colorbar; % 子图2衍射光强分布图 subplot(1, 2, 2); % 使用imagesc显示坐标映射到观察屏的实际尺寸 imagesc(x_screen*1e3, y_screen*1e3, I_display); axis image; colormap(jet); % 使用jet色图表示光强强弱 title(夫琅禾费衍射光强分布, FontSize, 12, FontWeight, bold); xlabel(观察屏 x (mm)); ylabel(观察屏 y (mm)); colorbar; % 可选叠加等高线以更清晰显示条纹 hold on; contour(x_screen*1e3, y_screen*1e3, I_display, 10, LineColor, k, LineWidth, 0.5); hold off; % 为整个图添加一个总标题 sgtitle([衍射类型: , strrep(diffraction_type, _, ), ... | 波长: , num2str(lambda*1e9), nm], FontSize, 14, FontWeight, bold);可视化进阶技巧axis image这个命令至关重要。它确保x轴和y轴的刻度单位等长即图像不会被拉伸或压缩。对于圆孔衍射如果没有axis image你看到的可能是一个椭圆形的“艾里斑”这是错误的。坐标轴标签使用x_screen*1e3将坐标从米转换为毫米进行显示使得坐标轴读数更直观。务必在标签中注明单位。色图选择gray色图适合二值的孔径函数。jet,hot,parula等色图适合表示光强其中parula是Matlab新版默认的感知均匀色图对色盲友好是学术出版推荐。添加等高线contour函数可以在光强图上叠加等高线能非常清晰地勾勒出暗纹的位置对于分析条纹间距特别有帮助。图形窗口管理figure(Position, [100, 100, 800, 600])预设了图形大小和位置避免弹出窗口大小不合适。sgtitle可以为包含多个子图的整个图形窗口添加总标题。4. 四种衍射图样的模拟结果分析与参数探究运行上述代码切换diffraction_type变量我们可以得到四种经典的衍射图样。但看图不是终点理解参数如何影响图样才是关键。4.1 单缝衍射图样分析将diffraction_type设为single_slit。你会看到右侧衍射图是一系列平行于y轴的明暗条纹。中心亮纹最宽最亮两侧对称分布着强度迅速衰减的次级亮纹。改变缝宽a_slit将a_slit从0.1e-3改为0.2e-3变宽。重新运行你会发现衍射条纹整体变“瘦”了即条纹间距相邻暗纹的间隔变小。这与理论公式一致条纹角宽度与缝宽a成反比。缝越宽衍射效应越不明显条纹越集中缝越窄衍射效应越显著条纹铺展得越开。观察一维分布为了与教科书上的曲线对比可以提取衍射图样中心行的数据绘图figure; plot(x_screen*1e3, I_display(N/21, :), b-, LineWidth, 2); xlabel(观察屏 x (mm)); ylabel(归一化光强); title(单缝衍射光强一维分布中心线); grid on;这条曲线应该是一个完美的sinc函数的平方。4.2 光栅衍射图样分析将diffraction_type设为grating。图样会变得非常有趣你能看到一组非常细锐的亮条纹主极大但这些亮条纹的包络轮廓呈现出单缝衍射的sinc^2形状。改变光栅常数d_grating增大d_grating缝间距变大。主极大条纹之间的角距离会变小即条纹在屏幕上变得更密集。因为sinθ mλ/dd越大θ越小。改变缝数N_slits将N_slits从5增加到10。你会发现主极大条纹变得更加尖锐而次级极大主极大之间的小峰的数量变多但强度降低。干涉因子[sin(Nγ)/sin(γ)]^2在N增大时主极大更锐利这正是光栅高色散本领和高分辨本领的来源。改变缝宽a_grating减小a_grating。单缝衍射包络会变宽可能使得更高级次的主极大被“包络”压制而消失不见。这就是光栅衍射中的“缺级”现象。你可以尝试调整a_grating和d_grating的比例观察特定级次的主极大是否消失。4.3 圆孔衍射图样分析将diffraction_type设为circular。你会看到著名的艾里斑一个明亮的中心圆斑周围环绕着明暗相间的同心圆环。中心亮斑集中了约84%的光能量。改变圆孔半径R_aperture增大半径。艾里斑的尺寸第一个暗环的半径会变小。根据公式艾里斑角半径θ ≈ 1.22 λ / DD为直径。孔径越大衍射斑越小成像系统分辨率理论上越高。这是光学仪器分辨率极限瑞利判据的直观体现。采样点数N的影响尝试将N降到256。你会发现艾里斑的圆环变得不光滑有锯齿感。这是因为采样率太低无法很好地描述圆形边界。对于圆孔这类具有曲线边界的孔径需要较高的采样点数N来保证模拟精度。4.4 矩孔衍射图样分析将diffraction_type设为rectangular。衍射图样是十字形的明暗条纹x方向和y方向的条纹宽度不同。改变边长比例将a_rect_x和a_rect_y设为不等的值例如0.1e-3和0.3e-3。观察衍射图样你会发现沿着边长较短的方向a_rect_x小衍射条纹间距大衍射显著沿着边长较长的方向a_rect_y大衍射条纹间距小衍射不明显。这完美体现了衍射效应与孔径尺寸的反比关系。过渡到单缝如果令a_rect_y远大于a_rect_x例如a_rect_y 10e-3同时保持模拟区域sim_width大于a_rect_y那么y方向的衍射效应将变得极不明显图样将近似退化为一系列平行于y轴的条纹即单缝衍射图样。这展示了模型的一致性。实操心得参数探究是模拟的灵魂。不要满足于生成一张静态图片。编写一个循环或使用Matlab的交互式控件如滑块实时观察某个参数如缝宽、波长连续变化时衍射图样的动态响应。这个过程能极大地加深你对物理规律的理解。例如你可以清晰地看到当单缝宽度趋近于光波长时衍射条纹变得极其宽泛而当缝宽远大于波长时衍射图样收缩成一个亮点接近几何光学的结果。5. 常见问题、调试技巧与高级扩展即使按照步骤操作你也可能会遇到一些问题。这里汇总一些典型问题和解决方法。5.1 图样不在屏幕中心或发生畸变问题衍射图样的最亮部分不在图像中心或者圆孔衍射的艾里斑不是圆形而是椭圆形。排查检查fftshift确保在计算光强I之前已经对fft2的结果U进行了fftshift操作。检查axis image在imagesc绘图后务必加上axis image命令确保纵横比正确。检查坐标生成确认生成x和y坐标时使用的是对称于零的区间(-N/2 : N/2-1) * dx而不是(0 : N-1) * dx。检查孔径位置确保你的孔径函数P是在以(X, Y)坐标原点为中心构建的。例如圆孔的条件是sqrt(X.^2 Y.^2) R。5.2 衍射条纹模糊或细节丢失问题光栅衍射的主极大条纹不够尖锐或者高次条纹看不清。排查与解决增加采样点数N这是提高模拟分辨率最直接的方法。尝试将N从1024增加到2048或4096。注意计算时间会大致按N^2增长。增大模拟区域sim_width如果sim_width设置得太大而N固定会导致采样间隔dx变大从而降低孔径平面的采样精度。但更大的sim_width能提供更“干净”的频谱。需要权衡。一个经验法则是sim_width至少是孔径最大尺寸的3倍N足够大使得dx远小于孔径特征尺寸如缝宽。使用零填充Zero-padding这是一种高级技巧。在计算FFT前将孔径矩阵P放置在一个更大的零矩阵中心。例如创建一个2048x2048的零矩阵P_large然后将1024x1024的P放在P_large的中心。再对P_large做fft2。这相当于在频域衍射面进行了插值能获得更光滑的衍射图样而无需增加对孔径本身的采样精度。命令如下N_large 2048; P_large zeros(N_large); start_idx (N_large - N)/2 1; end_idx start_idx N - 1; P_large(start_idx:end_idx, start_idx:end_idx) P; U fft2(P_large); % ... 后续步骤需相应调整坐标5.3 出现奇怪的波纹或对称性不佳问题衍射图样背景上有不规则的波纹或者本应对称的图样出现轻微不对称。原因与解决混叠Aliasing如果孔径包含非常精细的结构例如光栅常数d非常小而采样间隔dx不够小即sim_width/N不够小就会发生频谱混叠。表现为高频信息折叠到低频产生虚假条纹。解决方法减小dx即增大N或减小sim_width在保证覆盖孔径的前提下。数值误差虽然双精度浮点数精度很高但对于极端参数仍可能引入微小不对称。这通常影响很小。确保所有运算都是矩阵化操作避免循环引入的不对称。孔径截断如果sim_width设置得仅比孔径大一点点孔径边缘被突然截断相当于给孔径函数乘了一个矩形窗其傅里叶变换会引入 sinc 函数卷积产生波纹。解决方法适当增大sim_width让孔径周围有足够的零区域。5.4 高级扩展方向掌握了基础模拟后你可以尝试以下扩展让项目更具深度和应用价值模拟非理想孔径尝试模拟相位型孔径如透镜、随机相位板模拟散射、或者带有缺陷的光栅如缝宽不均匀。只需改变孔径矩阵P的值从二值0/1变为复数值如exp(1i*phase)。菲涅尔衍射模拟夫琅禾费衍射是远场近似。要模拟近场菲涅尔衍射需要用到卷积运算或角谱传播方法。核心公式是衍射积分可以用FFT加速计算。这能模拟出衍射图样从孔径附近到远场的演化过程。彩色光衍射将波长lambda设为数组例如可见光范围[400e-9, 550e-9, 700e-9]对应蓝、绿、红。分别计算每个波长下的光强I_red, I_green, I_blue然后使用cat(3, I_red, I_green, I_blue)合成一个RGB图像就能模拟白光照射下的彩色衍射条纹特别是光栅的光谱。交互式GUI使用Matlab的App Designer或GUIDE创建一个图形用户界面集成滑块来控制缝宽、波长、缝数等参数并实时更新衍射图样。这对于教学演示来说效果极佳。定量测量从模拟结果中提取数据例如测量艾里斑的直径、单缝衍射暗纹间距并与理论公式计算结果对比验证模拟的准确性。通过这个项目你不仅学会了用Matlab绘制几种衍射图样更重要的是掌握了一套基于傅里叶光学进行波动现象数值模拟的通用方法。这套方法可以迁移到声波衍射、天线辐射场分析等众多领域。记住调试过程中遇到问题多从物理模型和离散数值计算的基本原理如采样定理、FFT性质出发去思考大部分问题都能迎刃而解。