简介基于达曼光栅原理生成点阵图像的MATLAB程序面向光学工程、激光物理等方向的学生和研究人员也适合希望通过代码理解衍射光学与傅里叶变换的MATLAB用户。压缩包内含1个.m源码文件整体仅约719B代码精简覆盖了光栅参数设定、相位分布计算、fft2变换、点阵提取与图像显示等核心步骤。目前已有2324人学习使用验证了其参考价值。通过运行该程序读者可以直观看到入射光经达曼光栅后形成的点阵强度分布并据此理解相位延迟如何影响干涉图案掌握用数值模拟还原光学实验的基本方法为后续设计更复杂的光栅结构或开展相关科研打下基础。1. 达曼光栅与点阵生成这份Matlab资源到底能做什么做激光加工或者结构光投影的人迟早会撞到达曼光栅这个名字。它的作用很直接一束光进去出来变成规则排列的二维点阵而且每个点的能量几乎一样。这份Matlab程序就是把达曼光栅从“光学元件”变成“一段可运行的代码”——输入目标点阵数量输出相位分布再模拟出远场光强分布。我拆过不少衍射光学的仿真代码这套程序的价值在于它不是黑匣子相位跳变点、周期、波长、采样间隔全部暴露在参数区改一个数就能看到点阵形态的变化。适合正在做激光分束、结构光编码或者光学实验仿真的人拿来当设计工具和教学样板都很顺手。2. 从相位跳变到傅里叶点阵达曼光栅设计原理与程序架构2.1 达曼光栅为什么能“凭空”变出点阵先理解最核心的一件事达曼光栅本身是一块纯相位元件表面没有振幅遮挡只有台阶状的相位分布。当平行光通过它波前被调制再经过透镜聚焦焦平面上的光场就是相位分布的傅里叶变换。这个结论我在第一次跑通时专门验证过——把相位板放进去做角谱传播出来的光强分布和直接对相位函数做傅里叶变换得到的结果完全一致。一维达曼光栅的相位分布是二值的通常是0和π在周期内出现若干次跳变。这些跳变点的位置决定了各级衍射光的能量分配。经典的达曼设计目标是让目标阶次的衍射效率相等能量损失最小。程序里的优化部分本质上就是在搜索一组最佳跳变点坐标。二维达曼光栅的构造有一个很有用的性质可分离性。即二维相位分布可以直接写成两个一维达曼光栅相位分布的笛卡尔积phase_2D repmat(phase_1D_x, N, 1) repmat(phase_1D_y., 1, N);逻辑说明把一维跳变相位沿x方向铺开再沿y方向铺开两者相加就是对相位调制。因为傅里叶变换的可分离性二维频谱就是两个一维频谱的外积于是点阵自然呈现矩形排列。参数说明phase_1D_x和phase_1D_y可以相同也可以不同。相同的时候点阵是正方形对称分布不同的时候可以生成矩形点阵比如3×5。这个写法比直接做二维优化简单太多也是程序里最妙的一步。2.2 程序文件结构从跳变点搜索到光强输出整套程序拆开来看核心模块有四个每个模块解决一个独立问题。模块文件虚构职责一维相位优化optimize_1D.m搜索指定阶数下的最佳跳变点位置相位生成gen_phase.m根据跳变点生成一维/二维相位分布傅里叶模拟fft_focus.m用FFT模拟透镜聚焦后的光强分布结果评估evaluate_points.m计算点阵坐标、均匀性误差和衍射效率跑通程序的顺序建议是先跑evaluate_points.m用内置的预置相位数据看一遍点阵长什么样再跑gen_phase.m生成自己的相位最后才动optimize_1D.m去搜索新参数。很多人上手就跳到最后一步结果优化半天不知道好坏因为评估模块还没看明白。跳变点搜索这个模块程序用的是模拟退火算法。目标函数很直白让目标阶次的衍射光强尽量相等同时让非目标阶次的能量尽量低。搜索变量是若干个跳变点的位置每个点的取值范围在光栅周期内。模拟退火的好处是不容易陷在局部最优里坏处是跑得慢。2.3 为什么用傅里叶变换而不是角谱传播程序中模拟聚焦光场用的是FFT不是角谱法。两者在数学上等价但使用场景有差别。FFT默认输入是周期延拓的这正是达曼光栅的理想化假设——无限大周期结构角谱法在Matlab里需要手动处理孔径边缘的衍射效应做起来繁琐且对初学者不友好。但要说清楚局限FFT模拟出来的点阵是“理想周期”下的结果没有边缘效应。真实实验中光栅尺寸有限边缘会带来散射噪声点阵周围会出现微弱的杂散光。如果你要做实验前的定量预测FFT的结果需要再叠加上孔径函数再做一次角谱传播这一步程序里没有需要自己补。模拟退火的迭代过程也被设计成可视化输出每500次迭代画一次当前跳变点对应的衍射光强分布。这个设计在调试时帮了我大忙——你能直观看到光强从一团糟慢慢收敛成等高的山峰远比盯着数值强。3. 程序运行与核心函数拆解三步生成可用的点阵光场3.1 环境准备与最小复现路径程序对Matlab版本要求不高R2018以后的版本都能跑不依赖额外工具箱。核心代码只用到了基础函数fft2、repmat、mod和自带的优化算法。我自己在R2021a上跑通没有报错。最小复现路径三步设置目标点阵数、生成相位、跑傅里叶模拟。直接在命令窗口按顺序执行% 第一步设定目标点阵数比如想要5x5的方形点阵 orders 5; % 一维衍射级次 0, ±1, ±2 wavelength 532e-9; % 波长单位米对应绿光 period 200e-6; % 光栅周期单位米 focal_length 0.1; % 透镜焦距单位米 pixel_size 3.45e-6; % 采样像素尺寸等同探测器像元 % 第二步调用相位生成函数 [phase, jump_points] gen_phase(orders, period, pixel_size); % 第三步傅里叶模拟焦平面光强 [I_focus, coords] fft_focus(phase, wavelength, focal_length, pixel_size);逻辑说明gen_phase输入的是你想要的一维衍射级次输出的是二维相位分布和跳变点坐标。fft_focus把相位做傅里叶变换取模平方再换算成焦平面坐标。参数说明wavelength、focal_length、pixel_size这三个参数直接决定了点阵的物理间距。点阵间距近似等于wavelength * focal_length / period这个公式记牢调参数时会经常用到。3.2 一维跳变点优化改一个数改变整个点阵均匀性这是整套程序里最有技术含量的部分。目标阶数从3改成9跳变点数量、搜索策略复杂度完全不同。程序里优化函数的核心逻辑如下function [best_jumps, best_score] optimize_1D(target_orders, num_jumps, max_iter) % target_orders: 需要均匀分配能量的衍射级次 % num_jumps: 跳变点数量一般等于目标级次数量 % max_iter: 最大迭代次数 current rand(1, num_jumps) * 0.5; % 初始随机跳变点范围在半个周期内 temperature 1.0; % 模拟退火初始温度 for iter 1:max_iter candidate current randn(1, num_jumps) * 0.02; candidate mod(candidate, 0.5); % 跳变点只在半个周期内搜索利用对称性 score_cur evaluate_uniformity(current, target_orders); score_new evaluate_uniformity(candidate, target_orders); % Metropolis准则新解更差时以一定概率接受避免局部最优 if score_new score_cur || rand exp((score_cur - score_new) / temperature) current candidate; end temperature temperature * 0.995; % 降温 end best_jumps sort(current); end逻辑说明evaluate_uniformity计算的是目标级次间的强度差异。先把相位分布做傅里叶变换取目标阶次处的幅值再计算这些幅值的标准差与平均值的比值。这个比值越小均匀性越好。参数说明这里的0.02是扰动的标准差太小收敛慢太大容易跳过最优解。0.995是降温速率决定了搜索的“鲁莽程度”。如果你想要更均匀的结果把max_iter从默认的5000改成10000但运行时间会多出一倍多。3.3 二维相位生成从一维到二维的坑与技巧二维相位生成看起来只是两个一维相位的叠加实际执行时有个细节必须注意一维相位向二维扩展时必须确保两个方向的周期像素数一致否则点阵会变形。function phase_2D gen_phase(orders, period, pixel_size) % 计算一个周期内的像素数 N round(period / pixel_size); % 先生成一维跳变相位 phase_1D zeros(1, N); jump_idx round(jump_points * N); for i 1:length(jump_idx) phase_1D(jump_idx(i):end) phase_1D(jump_idx(i):end) pi; end % 二维扩展分别沿x和y方向复制后相加 phase_2D repmat(phase_1D, N, 1) repmat(phase_1D., 1, N); phase_2D mod(phase_2D, 2*pi); end逻辑说明repmat(phase_1D, N, 1)把一维相位按行复制N次生成沿x方向周期变化的二维矩阵repmat(phase_1D., 1, N)按列复制。两者相加后取模2π因为相位周期性叠加会导致部分区域超过2π取模后恢复为有效相位值。参数说明N是周期内的像素采样数在傅里叶模拟中它同时决定了点阵的“分辨率”。N太小跳变点位置量化误差大点阵均匀性严重变差。程序里默认period / pixel_size要大于256。如果你的实验系统像元尺寸偏大导致N不到256建议在模拟阶段先把pixel_size虚设为一个更小的值得到相位后在实际制造时再换算回坐标。这一步我在第一次跑的时候踩过坑直接把两个一维相位相加完事忘了mod(phase, 2*pi)出来的点阵强度分布完全不对。原因是相位叠加超过2π的部分等价于跳变点位置发生了偏移等效光栅变了。4. 参数调节与均匀性优化点阵数、波长与采样间隔怎么配4.1 目标点阵数为什么“更多点”不等于“更好”你可能会直觉地觉得目标点阵数越大越牛。实际工程里点阵数增加带来的代价非常具体第一衍射效率下降。能量被分配到更多级次上每个点的能量自然变低。5×5点阵的每点效率大约在80%上下9×9点阵直接掉到50%左右。第二跳变点数量增多优化难度指数上升均匀性更难保证。程序里模拟退火给出的均匀性指标5×5能到1%以内9×9通常只能到3%左右。第三制造容差变严。相位跳变点的位置误差对均匀性的影响在高端点数情况下会被放大。摩尔的加工误差原本可以容忍0.5微米做9×9时可能需要压到0.2微米。选择建议能少不要多。你的实验只需要4个点就不要去生成5×5的点阵因为多出来的外围点能量会稀释核心点的强度现阶段做光学实验单点能量密度往往比点阵数量更重要。4.2 波长、周期与焦距的三角关系这三个参数是纠缠在一起的。核心公式前面已经提过点阵间距 λ · f / d其中λ是波长f是焦距d是光栅周期。从公式能直接推出三个结论。第一波长越长间距越大所以你换了光源后点阵间距会变化这不是程序问题。第二想要更密的点阵加大光栅周期d是最直接的但周期增大会让跳变点更密制造难度增加。第三焦距越短点阵越密但焦深变短对对准精度要求更高。程序中这三个参数全部集中在参数配置区我在实际调参时会用一个简单的对照表来确定合理值参数典型值范围对点阵的影响波长 λ405nm / 532nm / 1064nm间距随λ线性增大同时衍射角增大周期 d50μm ~ 500μm间距随d增大而减小焦距 f50mm ~ 200mm间距随f增大而增大焦深也随之变化4.3 采样间隔的约束别让傅里叶模拟骗了你程序用FFT做模拟采样间隔直接决定模拟结果的真实性。这里有两个硬性条件必须同时满足。第一个条件是奈奎斯特采样约束。相位函数本身是高频跳变的结构如果每个跳变沿只采到一两个点傅里叶变换给出的高频衍射级完全是混叠噪声点阵看起来一团糊。我一般要求每个周期内至少256个采样点低于这个值点阵均匀性指标会失真。第二个条件是焦平面采样。FFT的输出网格间距是像素尺寸如果这个尺寸大于点阵间距的一半两个相邻点会混淆在一起看不出分离。程序中的pixel_size同时被用来生成相位和模拟输出实际使用中如果探测器的像元尺寸真的很大需要把模拟像素设小再在结果中做下采样。% 检查采样是否足够 N_period round(period / pixel_size); if N_period 256 warning(周期内采样点少于256跳变点量化误差显著建议缩小pixel_size); end这段检查代码值得放在运行开头。静默跑完得到不靠谱的结果这种坑我在调试中遇到太多次一个warning能省半天时间去排查结果为什么“看起来不对劲”。4.4 均匀性指标的衡量方式程序自带的evaluate_points.m会输出两个关键指标均匀性误差和衍射效率。均匀性误差的定义是“所有目标点强度的标准差除以平均值”衍射效率是“目标点总能量除以入射总能量”。真实实验中最常见的情况是均匀性误差比仿真高出一截。仿真里1%的均匀性实验里做到3%就不错了。原因包括相位台阶蚀刻深度误差、光栅表面灰尘、入射光不是理想平面波等因素。因此仿真阶段建议把目标定在1%以内给实验留出余量。另一个容易被忽略的指标是“零级抑制比”。理想达曼光栅的中心零级光和其他级次强度相等但实际制造中因为跳变点位置误差零级经常会亮于其他级次。程序里evaluate_points.m会单独输出零级强度如果这个值超过其他点的1.5倍基本可以断定跳变点量化出了问题。5. 高频踩坑排查从全零矩阵到“不存在的第5级衍射”5.1 现象跑出全零矩阵相位图全黑那是第一次跑gen_phase时遇到的。相位图输出是全黑的检查代码发现phase_1D(jump_idx:end) phase_1D(jump_idx:end) pi这一步中jump_idx被算成了浮点数Matlab自动取整后直接超出数组索引范围赋值被静默忽略。原因round(jump_points * N)里如果jump_points某些值乘以N超过了数组长度索引越界Matlab不会报错只是不执行赋值。解决在乘完之后加一句jump_idx mod(jump_idx, N) 1强制落在有效索引区间。从那以后我每次写这种索引计算都会强制检查边界。5.2 现象点阵数量是目标的两倍生成3×3点阵结果出现了5×5的规则点阵。看着很惊喜实际上是错误。原因一维相位在半个周期内搜索跳变点时程序自动利用了对称性但二维扩展时相位矩阵的周期设置出了问题——repmat复制后的矩阵周期是原来的两倍傅里叶变换后的频谱间隔减半点阵数量就翻倍了。解决检查gen_phase里的N round(period / pixel_size)是否和优化时使用的周期一致。优化时输入的是半个周期长度生成相位时却用了整个周期这个量纲不匹配在程序注释里写得很清楚我偷懒没细看就踩了。5.3 现象模拟出“不存在的第5级衍射”目标设置是4×4点阵模拟结果在两侧出现了微弱的第5级衍射峰。光强大约是正常点的2%初看不影响但做实验时周围杂散光会明显。原因跳变点搜索的边界约束不够严个别跳变点位置挨得太近等效产生了更细的光栅结构在更高级次上产生了弱衍射。解决在optimize_1D.m的目标函数中加入一个惩罚项当任意两个跳变点间距小于周期像素数的2%时直接把分数设为无穷大。这样做之后第5级衍射峰消失了均匀性微有提升因为优化器不再浪费时间搜索那些不可制造的位置。5.4 现象相同代码两周后跑出不同结果同一份代码同一台机器结果却和之前不一样。查了一圈原因出在模拟退火的随机数种子没有固定。原因rand和randn每次调用都会改变全局随机数流导致每次搜索到的跳变点位置不同点阵微有差异。解决在optimize_1D.m开头加rng(42)这一行固定随机数种子。加完之后同一个输入永远得到同一个输出这不仅是科研可复现性的基本要求也是你自己排查问题的必要条件。没有固定种子你根本分不清结果变化是参数改变导致的还是随机波动导致的。5.5 现象FFT结果中心出现巨大亮斑跑模拟时中心点特别亮其他点都黯淡和点阵均匀性的预期严重不符。原因相位矩阵里有大量零值区域——二维叠加时由于repmat的策略四个角区域产生了相位相消等效于中心区域有一个纯透射窗口能量集中到零级。解决检查phase_2D mod(phase_2D, 2*pi)是否执行这行代码必不可少。相位叠加后在0~2π范围内重新映射让整个光栅面内都有有效相位调制不再出现局部“空白区”。6. 角谱法复核怎么确认你生成的点阵真的能打出来FFT模拟很理想实验前我一般会额外做一次角谱法复核两者结果对比能暴露很多问题。角谱法的核心语句是% 假设已有输入光场 E_in(二维复数矩阵) % 传播距离 d 后计算输出光场 [kx, ky] meshgrid((-Nx/2:Nx/2-1)/(Nx*pixel_size), ... (-Ny/2:Ny/2-1)/(Ny*pixel_size)); H exp(1i * 2 * pi * d * sqrt(1 - (wavelength*kx).^2 - (wavelength*ky).^2)); E_out ifft2(fft2(E_in) .* H);逻辑说明角谱法的核心是传递函数H。它描述了每个空间频率分量在自由空间中传播距离d后的相位变化。E_in乘上H后再做逆傅里叶变换就得到了距离d处的光场。参数说明d是传播距离透射式达曼光栅后面放置透镜时d取透镜焦距。Nx, Ny是空间采样点数pixel_size是空间采样间隔。注意这里pixel_size是“物理空间”的采样尺寸和焦平面模拟时的像素含义不同。FFT模拟和角谱法结果一致基本可以放心做实验。如果两者偏差超过5%优先检查采样是否满足奈奎斯特定理其次检查相位分布里是否有异常跳变点。把角谱法结果和实验光斑图对比时还有一个判断小技巧看点阵外围的杂散光分布形态。FFT模拟没有孔径边缘效应角谱法带入了孔径截断两者杂散光分布形态不一样和实验吻合的往往是角谱法结果。从那以后我每次做达曼光栅实验前都强制走一遍“FFT 角谱法”双模复核流程省掉了好几次试错成本。希望帮到你。本文还有配套的精品资源点击获取