
简介HoloLib_MATLAB 是一套面向计算全息CGH学习与实验的 MATLAB 函数库适合光学、光电信息及相关专业的学生与研究人员使用用于简化计算全息编程流程、快速搭建相位图生成与传播仿真实验。压缩包共 128 个文件约 17.05MB以 36 个 .m 源码函数为主体辅以 png、bmp 等示例图像与说明文档源码集中在 source 目录涵盖路径初始化、图像边界扩充与矩阵扩展、轴锥透镜与闪耀光栅及菲涅尔透镜相位生成、迭代傅里叶与迭代菲涅尔算法、两次与三次傅里叶变换的菲涅尔传播、DOE 元件传播、计算重构、图像拼接、相位保存与 LCOS 显示等模块函数职责清晰、便于按需调用与二次开发。已有 1285 人学习下载可作为计算全息入门练习与算法验证的参考工具库。1. 拿到一份 CGH 函数库先别急着跑 demo做光学仿真的人大概都有过这种经历想验证一个相位恢复算法翻遍手头资料重建脚本、传播核、误差评价各写一遍跑出来的重建图却和文献对不上。问题往往不在算法本身而在传播距离的单位、采样间隔的定义、相位包裹的处理这些底层细节上。HoloLib_MATLAB 就是冲着这个痛点来的——一套面向计算机生成全息图CGH的 MATLAB 函数库把球面波、平面波、菲涅尔与角谱传播、GS 与 Gerchberg-Saxton 类迭代、相位编码这些常用环节封装成可调用函数。它适合做光学、显示、衍射器件方向的研究生和工程师也适合需要快速搭一个 CGH 验证环境的人。系统开源意味着你能直接看到每个函数的实现而不是对着黑匣子猜参数。2. 函数库的骨架传播核与迭代引擎怎么分工拿到一个 CGH 库第一件事不是跑示例而是搞清楚它把哪些物理环节拆成了独立函数。HoloLib_MATLAB 的组织逻辑基本遵循「输入场 → 传播 → 目标面约束 → 反传 → 更新」这条闭环每个环节对应一组函数。理解这个分工后面调参才知道该动哪一层。2.1 三类传播函数的选择依据CGH 里最核心的运算是光场传播不同传播距离和采样条件对应不同近似。这个库通常提供三类菲涅尔衍射近场到中场、角谱传播任意距离、采样严格、球面波卷积适合大尺寸快速计算。选错传播核是新手最常见的翻车点——用菲涅尔近似去算毫米级近场或者用角谱却在频域采样不足导致混叠。判断依据可以记成一条经验线传播距离 z 远大于孔径尺寸平方除以波长时菲涅尔近似够用z 与孔径尺寸可比时老老实实上角谱。角谱的代价是必须做补零否则循环卷积会污染结果。库里的角谱函数一般会暴露padFactor或类似的补零参数这个参数不是摆设后面避坑章节会专门说。2.2 迭代引擎的输入输出约定GS 类迭代是 CGH 生成的主力。库里的迭代函数通常接受初始相位、目标振幅、传播算子、迭代次数作为输入返回相位分布和误差曲线。关键在于它约定的是「目标面振幅约束」还是「目标面强度约束」——两者在误差评价上差一个平方根混用会让收敛曲线看起来很好但重建图发灰。我一般会先跑一个最小闭环确认约定% 最小闭环确认迭代函数的输入输出约定 lambda 532e-9; % 波长单位米 pitch 8e-6; % 像素间距单位米 N 512; % 采样点数 z 0.3; % 传播距离单位米 % 构造目标振幅简单矩形孔径便于肉眼判断 target zeros(N); target(N/4:3*N/4, N/4:3*N/4) 1; % 初始相位随机相位能打破对称性避免迭代卡在局部极小 phase0 2*pi*rand(N); % 调用库内迭代函数函数名以实际库为准 [phaseOut, errCurve] gs_iterate(target, phase0, lambda, pitch, z, 50); % 检查误差曲线是否单调下降不降说明约定或参数有问题 figure; plot(errCurve); xlabel(迭代次数); ylabel(误差);这段代码的重点不在跑通而在验证三件事误差曲线是否在前几次迭代明显下降、phaseOut的取值范围是[-pi, pi]还是[0, 2*pi]、传播距离单位是米还是毫米。这三个约定任何一个对不上后面所有结果都是错的。参数上pitch和lambda必须同单位N取 2 的幂是为了 FFT 效率z的选择要让目标面落在传播核的有效区内。2.3 相位编码与重建评价迭代出来的相位是连续分布真正上器件或上 SLM 前要做相位编码——把连续相位量化到有限级数或者转成振幅全息的编码图案。库里的编码函数一般支持二值、多阶和误差扩散几种模式。量化级数越低重建噪声越大但器件实现越简单这是典型的工程折中。重建评价环节容易被忽略。库里通常提供 RMSE、衍射效率、信噪比几个指标但它们的计算前提不同RMSE 要在归一化振幅上算衍射效率要区分「目标区能量」和「总能量」。我见过不少人直接拿原始强度算 RMSE数值看着漂亮实际重建图对比度一塌糊涂。3. 从目标图到相位图一次完整复现的四个步骤这一章走一遍完整流程从读入目标图到输出可用的相位全息图。步骤按实际动手顺序排每步给出可抄的代码和参数说明。假设你已经把库加入 MATLAB 路径函数名以库内实际命名为准逻辑不变。3.1 目标图预处理与采样对齐目标图的像素尺寸必须和传播网格对齐否则传播核的采样间隔和目标图对不上重建会出现缩放错位。常见做法是把目标图缩放到N×N并确认物理尺寸N*pitch与你的器件孔径一致。% 目标图预处理灰度化、归一化、尺寸对齐 img imread(target.png); if size(img,3) 3 img rgb2gray(img); % 转灰度CGH 一般只用振幅信息 end img im2double(img); img imresize(img, [N N]); % 对齐到传播网格尺寸 target img / max(img(:)); % 归一化到 [0,1]避免能量尺度混乱这里imresize的顺序有讲究先缩放到N×N再归一化而不是反过来因为插值会改变极值。归一化用max(img(:))而不是固定 255是为了兼容不同位深的输入图。如果目标图本身带相位信息比如复振幅目标这一步要改成分别处理振幅和相位通道。3.2 传播核参数配置传播核的参数决定了整个仿真的物理可信度。以角谱为例关键参数是补零倍数和频域坐标构造方式。补零不足会导致循环卷积混叠补零过度则浪费算力且可能引入数值噪声。% 角谱传播核配置 padFactor 2; % 补零倍数2 倍是常用起点 Npad N * padFactor; dx pitch; % 空域采样间隔 fx (-Npad/2:Npad/2-1) / (Npad*dx); % 频域坐标单位 1/m [FX, FY] meshgrid(fx, fx); % 角谱传递函数注意 evanescent 波要截断否则出现虚数 arg 1 - (lambda*FX).^2 - (lambda*FY).^2; H exp(1i*2*pi*z/lambda*sqrt(max(arg,0))); % 传播函数补零 → FFT → 乘传递函数 → IFFT → 裁剪 propagate (U) crop(ifft2(fft2(padarray(U,[N*(padFactor-1)/2 ... N*(padFactor-1)/2]) .* H), N);max(arg,0)这一步是血泪经验角谱传递函数在arg0时对应倏逝波物理上快速衰减数值上会变成虚数导致结果发散。截断为 0 是标准处理。padFactor2对多数目标够用如果重建边缘出现周期性伪影加到 3 或 4 再试。crop是库内或自写的裁剪函数把补零后的结果裁回N×N。3.3 迭代生成与收敛监控迭代环节要监控的不只是误差曲线还有相位分布的直方图。相位过度集中意味着迭代陷入局部极小重建图会出现明显伪影。% 迭代生成相位带收敛监控 maxIter 100; errCurve zeros(maxIter,1); phase 2*pi*rand(N); % 随机初相位 for k 1:maxIter U0 target .* exp(1i*phase); % 目标面复振幅 Uz propagate(U0); % 正向传播 Uz target .* exp(1i*angle(Uz)); % 目标面振幅约束 Uback propagate(conj(Uz)); % 反向传播共轭技巧 phase angle(Uback); % 更新相位 errCurve(k) norm(abs(Uz(:)) - target(:)) / norm(target(:)); end反向传播用conj加正向传播实现是 GS 的经典技巧避免单独写反传核。误差用归一化 L2 范数数值在 0.05 以下通常认为收敛可接受。如果 100 次迭代后误差还在 0.2 以上先别加迭代次数回头检查传播核的补零和单位。3.4 相位量化与结果导出连续相位要量化到器件支持的级数。量化方式直接影响重建质量误差扩散比直接取整好但计算量略大。% 相位量化到 8 级并导出 levels 8; phaseQ round((phase pi) / (2*pi) * (levels-1)) / (levels-1) * 2*pi - pi; % 重建验证 Ufinal propagate(target .* exp(1i*phaseQ)); recon abs(Ufinal); recon recon / max(recon(:)); % 导出为 PNG注意归一化到 0-255 imwrite(uint8(255 * (phaseQ pi) / (2*pi)), phase_hologram.png);量化级数levels按你的 SLM 或加工能力定8 级是常见起点。导出前把相位映射到[0,255]灰度是因为多数器件驱动按灰度读相位。重建验证这一步不能省量化后的重建图要和量化前对比差异过大说明级数不够或目标图对比度太高。4. 避坑与排查五个让重建图对不上的原因这一章按「现象 → 原因 → 解决」列五条实际踩过的坑。每条都对应前面章节的某个参数或约定出问题时按顺序排查能省不少时间。4.1 重建图整体缩放错位现象重建出的图案形状对但尺寸比目标大一圈或小一圈。原因传播距离z的单位和目标图物理尺寸不匹配或者pitch用了像素间距却按毫米填。解决统一所有长度单位为米用N*pitch反算物理孔径和器件参数核对一遍。菲涅尔传播对z敏感角谱对pitch敏感先确认用的是哪个核。4.2 边缘出现周期性条纹现象重建图四周有规律性亮纹或暗纹。原因角谱传播补零不足循环卷积把对侧能量卷了回来。解决把padFactor从 2 提到 3 或 4观察条纹是否消失。如果目标图本身在边界有强跳变先做边缘渐变再传播能进一步压住高频泄漏。4.3 误差曲线不降反升现象迭代前几次误差下降之后震荡或上升。原因目标面约束用错了量纲——把强度当振幅约束或者相位更新时符号反了。解决确认约束是target .* exp(1i*angle(Uz))而不是sqrt(target)反传用conj而不是直接ifft。另外检查初相位是否全零全零初相位在对称目标上容易卡死换随机相位。4.4 量化后重建噪声骤增现象连续相位重建正常量化到 4 级或 8 级后噪声明显。原因目标图动态范围太大低阶量化无法表达细节。解决先对目标图做伽马校正压缩动态范围或者改用误差扩散量化。级数实在上不去就在迭代时直接把量化步骤嵌进去让算法自己适应量化误差。4.5 不同机器结果不一致现象同一份代码换台机器跑重建图有细微差异。原因随机初相位没固定种子或者 FFT 实现差异导致浮点误差累积。解决迭代前rng(0)固定种子误差评价用相对范数而不是绝对范数。跨平台对比时把中间相位分布存成.mat逐层比对定位是哪一步开始分叉。5. 进阶技巧把迭代嵌进量化少走一轮返工前面流程是「先迭代出连续相位再量化」这个顺序在级数低的时候会浪费迭代成果。更稳的做法是把量化算子直接嵌进迭代循环让算法在每一步都「知道」最终要量化收敛到的相位天然适配器件级数。代价是每次迭代多一次量化运算但省掉了量化后重建不达标再返工的时间。具体改法是在目标面约束之后、反传之前插入量化% 量化感知迭代在循环内嵌量化 levels 8; for k 1:maxIter U0 target .* exp(1i*phase); Uz propagate(U0); Uz target .* exp(1i*angle(Uz)); % 关键改动反传前把相位量化模拟器件行为 phaseQ round((angle(Uz)pi)/(2*pi)*(levels-1))/(levels-1)*2*pi - pi; Uz abs(Uz) .* exp(1i*phaseQ); Uback propagate(conj(Uz)); phase angle(Uback); errCurve(k) norm(abs(Uz(:)) - target(:)) / norm(target(:)); end这个改动的逻辑是量化误差在迭代中被反复「看到」并补偿最终相位分布对量化更鲁棒。实测在 4 级量化下量化感知迭代的 RMSE 通常比「先迭代后量化」低一截重建图对比度也更均匀。参数上levels要和实际器件一致别用 8 级迭代却上 4 级器件那等于白做。验证方法也简单同一目标图跑两条路径一条先迭代后量化一条量化感知迭代把两条重建图的 RMSE 和衍射效率列成表对比。如果量化感知那条没有优势多半是levels填错或者量化公式的相位范围没对齐。对比项先迭代后量化量化感知迭代4 级量化 RMSE偏高通常低 20% 左右迭代耗时短多约 15%适用场景级数高、算力紧级数低、质量优先还有一个容易忽略的点量化感知迭代的误差曲线不会像连续迭代那样单调平滑会有小幅台阶这是量化算子引入的离散跳变属于正常现象别看到曲线抖就以为发散。判断收敛看整体趋势和最终重建图不看单点数值。从那以后我每次搭 CGH 流程都强制先跑一遍最小闭环确认单位、约定和补零再上目标图。这套习惯帮我省掉的返工时间比任何加速技巧都值。希望帮到你。本文还有配套的精品资源点击获取