简介:这份资源面向非线性光纤光学与数值仿真方向的学习者,提供用分步傅里叶法求解非线性薛定谔方程(NLS)的完整源代码,帮助理解光脉冲在光纤中传输时色散与非线性共同作用的数值实现思路。压缩包共1个文件,为docx文档,约13KB,内含带注释的Matlab代码及配套解析,涵盖输入参数与模拟参数设置、sech与超高斯脉冲生成、色散相移因子与非线性相移因子的构造,以及1/2N→D→1/2N对称分步的主循环实现,并给出输入与输出脉冲时域、频域的可视化绘图。已有1377人学习下载,适合具备一定Matlab基础、希望从公式推导过渡到可运行程序的读者,可据此复现孤子演化、调整步长与FFT点数观察数值稳定性,并作为光纤通信仿真的入门参考。
1. 一份能跑的分步傅里叶 NLS 源码,省掉你两周推导
做非线性光纤光学仿真的人,迟早会撞上非线性薛定谔方程(NLS)。理论课上推一遍、论文里看一遍,都不如亲手把一段光脉冲在光纤里“跑”出去一次来得实在。这份 MATLAB 源码干的就是这件事:用分步傅里叶法(Split-Step Fourier Method,SSFM)把 NLS 方程从 z=0 积分到 z=10,输入一个 sech 孤子或超高斯脉冲,输出时域波形和频谱。它不依赖任何工具箱,纯基础 MATLAB 语法,一百来行,参数全暴露在文件头部,改一个数就能换一套物理场景。适合两类人:一是刚进非线性光纤方向、需要快速建立数值直觉的研究生;二是做光通信链路预算、想验证色散与非线性相互作用的老手。下面按“方程怎么落到代码里 → 参数怎么调 → 哪里会翻车”的顺序拆。
2. 从 NLS 到 SSFM:方程怎么变成可执行的循环
2.1 方程形式与符号约定先对齐
源码注释里写的方程是:
i du/dz - sgn(beta2)/2 * d^2u/d(tau)^2 + N^2*|u|^2*u = 0这里有几个符号约定必须先钉死,否则后面所有参数都会对不上号。u是归一化复包络,z是传输距离,tau是随脉冲一起移动的本地时间(retarded time),beta2是群速度色散系数,N是非线性参数。注意源码里色散项前面带的是- sgn(beta2)/2,而很多教材写成+ (beta2/2) d^2u/dtau^2,两者差一个符号约定。源码把beta2 = -1直接代入,等价于反常色散区(beta2 < 0),此时 sech 脉冲可以形成孤子。如果你从别的文献抄来一个beta2 = +20 ps^2/km的正色散值,直接填进去,色散项符号会反,脉冲会正常展宽而不是压缩,这是第一个容易翻车的地方。
N的定义是N^2 = gamma * P0 * L_D,其中L_D = T0^2/|beta2|。源码里N = 1对应基阶孤子,N = 2对应二阶孤子,物理上表现为脉冲在传输中周期性压缩-展宽。这个参数不是随便填的,它直接决定步长:源码里step_num = round(20*distance*N^2),N 越大,非线性相位变化越快,需要的 z 步数越多。
2.2 对称分步:为什么是 1/2N → D → 1/2N
SSFM 的核心思想是把一个 z 步内的演化拆成“纯非线性”和“纯色散”两段,各自有解析解。但直接拆会引入 O(h) 的分裂误差,源码用的是对称形式(Strang splitting):
半步非线性 → 整步色散 → 半步非线性对应代码里的三段:
% 半步非线性(进入循环前) temp = uu.*exp(abs(uu).^2.*hhz/2); for n=1:step_num % 整步色散:先 ifft 到时域乘色散相位,再 fft 回频域 f_temp = ifft(temp).*dispersion; uu = fft(f_temp); % 整步非线性 temp = uu.*exp(abs(uu).^2.*hhz); end % 收尾半步非线性 uu = temp.*exp(-abs(uu).^2.*hhz/2);这里有个容易看懵的细节:temp在循环里存的其实是“非线性作用后的场”,而uu是“色散作用后的场”。循环体里先对temp做ifft乘dispersion再fft,得到uu;然后uu乘非线性相位因子存回temp。首尾两个半步非线性合起来是一个整步,所以总步数守恒。这种写法比“每步内先非线性后色散”精度高一阶,代价是多存一个中间变量。
dispersion和hhz在循环外预计算,这是性能关键:
dispersion = exp(i*0.5*beta2*omega.^2*deltaz); % 频域色散相位 hhz = i*N^2*deltaz; % 非线性相位系数dispersion是频域上的相位斜坡,omega.^2决定色散随频率二次增长;hhz是复数步长因子,abs(uu).^2是瞬时功率,两者相乘就是非线性相移。预计算避免在 1024 点循环里反复算exp,这是 MATLAB 向量化思维的基本操作。
2.3 频域网格的排列:fftshift 与负频率
源码里频率轴的定义是:
omega = (pi/Tmax)*[(0:nt/2-1) (-nt/2:-1)];这是 MATLABfft输出的标准排列:前一半是正频率 0 到 (nt/2-1),后一半是负频率 -nt/2 到 -1。注意这里没有用fftshift,因为ifft和fft本身按这个顺序工作。但画图时必须fftshift(omega)才能得到从负到正的连续频率轴。源码里画频谱时用了fftshift(ifft(uu)),这个ifft是把频域场变回时域?不对——uu在循环结束后是时域场,ifft(uu)得到的是频域谱(差一个归一化因子),再fftshift把零频移到中间。这个操作在 MATLAB 里容易绕晕,记住一条:fft和ifft互为逆变换,差1/N因子,源码用*(nt*dtau)/sqrt(2*pi)补了归一化,保证频谱幅值有物理意义。
3. 参数怎么设:从脉冲形状到步长收敛
3.1 时间窗口与 FFT 点数的取舍
nt = 1024、Tmax = 32是一组保守的默认值。dtau = 2*Tmax/nt = 0.0625,时间分辨率够细;频率分辨率pi/Tmax ≈ 0.098,对 sech 脉冲的谱宽(约 1/T0 量级)足够。但这两个参数不是随便定的,它们要满足两个约束:
第一,时间窗口要装得下脉冲展宽后的拖尾。如果N较大或beta2较大,脉冲在 z=10 处可能展宽到几十个时间单位,Tmax=32可能不够,表现为波形在边界处被截断,频谱出现振荡。判断方法是看输出波形两端是否贴近零。
第二,FFT 点数要避免频率混叠。nt翻倍,dtau减半,频率范围pi/dtau翻倍。如果脉冲谱宽接近 Nyquist 频率,高频成分会折叠回来。常见做法是先用nt=1024跑一遍,把nt改成 2048 再跑,如果波形和频谱肉眼无差别,说明 1024 够用;如果差别明显,就得加点数。
3.2 步长收敛性:20 这个系数从哪来
step_num = round(20*distance*N^2)里的 20 是经验系数,不是物理常数。它保证每个色散长度或非线性长度内有足够多的采样步。严格做法是做步长减半测试:
% 把 20 改成 40,重跑,比较输出峰值功率 step_num = round(40*distance*N^2);如果峰值功率变化小于 1%,说明 20 够用;如果变化超过 5%,说明步长太大,非线性相位在单步内变化过剧烈,对称分裂的精度不够。对于N=1、distance=10,step_num=200,deltaz=0.05,这个步长在多数场景下收敛。但如果你把N调到 3 以上,step_num自动变成 1800,计算量上去了,精度才稳得住。
3.3 脉冲形状与 chirp 的物理含义
mshape = 0走 sech 分支:
uu = sech(tau).*exp(-0.5i*chirp0*tau.^2);chirp0 = 0时是变换极限孤子,无初始啁啾。chirp0非零时给脉冲加二次相位,相当于给了一个初始频率啁啾,会破坏孤子条件,脉冲在传输中先压缩后展宽。mshape > 0走超高斯分支:
uu = exp(-0.5*(1+i*chirp0).*tau.^(2*mshape));mshape = 1是高斯,mshape = 2是二阶超高斯,mshape越大边缘越陡。超高斯脉冲的谱宽比 sech 大,容易触发更多非线性效应,适合观察自相位调制(SPM)导致的频谱展宽和振荡。改mshape时记得同步检查Tmax是否够宽,超高斯拖尾比 sech 长。
提示:
chirp0的单位是归一化的,量级在 0 到几之间。填 100 这种值会让相位在窗口内转几十圈,数值上直接崩,不是物理问题,是参数越界。
4. 避坑排查:五个真实会翻车的地方
4.1 现象:输出功率突然爆掉或归零
原因:deltaz太大,非线性相位abs(uu).^2*hhz在单步内转过超过 pi,指数函数出现数值不稳定。或者N填了非整数值但step_num没跟着调,步长与非线性强度不匹配。
解决:先把step_num的系数从 20 提到 50 跑一遍,看是否恢复。如果恢复,说明是步长问题;如果仍爆,检查beta2符号是否与N的物理场景匹配(反常色散配正 N 才是孤子)。
4.2 现象:频谱出现对称的鬼影峰
原因:nt不够,脉冲谱宽超过 Nyquist 频率,高频成分折叠到低频。超高斯脉冲尤其容易触发,因为它的谱边沿陡。
解决:nt翻倍到 2048,Tmax保持不变,dtau自动减半,频率范围翻倍。重跑后鬼影消失即确认是混叠。
4.3 现象:波形在两端被削平
原因:Tmax太小,脉冲展宽后拖尾超出窗口,ifft的周期性边界条件把尾部绕回头部,形成伪干涉。
解决:把Tmax从 32 加到 64,nt同步加到 2048 保持dtau不变。观察波形两端是否自然衰减到零。
4.4 现象:ifft和fft混用后幅值不对
原因:MATLAB 的fft/ifft默认不做1/N归一化,源码里*(nt*dtau)/sqrt(2*pi)是手动补的。如果你改了nt但忘了这个因子跟着变,频谱幅值会差一个比例。
解决:把归一化因子写成nt*dtau/sqrt(2*pi)的表达式,不要硬编码数字,改nt时自动更新。
4.5 现象:循环跑完uu和temp对不上
原因:首尾半步非线性的符号。源码收尾用的是exp(-abs(uu).^2.*hhz/2),负号是因为hhz本身含i,半步非线性在进入和退出时方向相反。如果你手动改循环结构,容易把首尾半步写成同号,导致总非线性相位多算或少算一个整步。
解决:对照temp = uu.*exp(abs(uu).^2.*hhz/2)和收尾的负号,确保首尾各半步、循环内整步,总和非线性步数等于step_num。
5. 进阶验证:用守恒量给仿真结果上保险
跑出波形只是第一步,怎么判断结果可信?NLS 方程有两个守恒量:能量∫|u|^2 dtau和哈密顿量。能量守恒是最便宜的检查,在循环里加一行:
energy = zeros(step_num+1,1); energy(1) = sum(abs(uu).^2)*dtau; for n=1:step_num f_temp = ifft(temp).*dispersion; uu = fft(f_temp); temp = uu.*exp(abs(uu).^2.*hhz); energy(n+1) = sum(abs(temp).^2)*dtau; % 注意用 temp,非线性不改变模 end对称 SSFM 下能量应该守恒到机器精度(相对误差 1e-12 量级)。如果能量漂移超过 1e-6,说明步长太大或归一化因子有误。这个检查比看波形直观得多,波形可能因为色散展宽看起来“正常”,但能量已经在悄悄漏。
另一个验证是孤子周期性。N=1、chirp0=0、beta2=-1时,基阶孤子在传输中形状不变,峰值功率应保持为 1。跑完distance=10后看max(abs(uu).^2),如果偏离 1 超过 2%,要么步长不够,要么Tmax截断了拖尾。我一般会先把step_num翻倍跑一次,确认峰值稳定后再回到默认值出图。
| 检查项 | 合格阈值 | 不达标时先调什么 |
|---|---|---|
| 能量相对漂移 | < 1e-6 | step_num系数 |
| 基阶孤子峰值 | 1 ± 0.02 | Tmax、nt |
| 频谱边界幅值 | 接近 0 | nt翻倍 |
| 波形两端 | 自然衰减 | Tmax加倍 |
最后说个习惯:每次改完参数,先跑nt=512的粗网格看趋势,确认物理行为对(比如反常色散下脉冲先压缩),再上nt=2048出正式图。粗网格跑一次不到一秒,能挡掉大半参数填错的情况。这份源码的价值不在于它多复杂,而在于它把 SSFM 的骨架完整暴露出来,你可以直接在上面加拉曼项、加高阶色散、换多脉冲输入。拿到手先别急着改物理,把第 4 章那五个坑挨个踩一遍,再动参数,心里就有底了。希望帮到你。
本文还有配套的精品资源,点击获取