能说实际上吗?
原子光谱都有一定的线宽。----说人话就是,原子的光谱都有一个分布范围,比如说波长600纳米,意思是光谱中心波长是600纳米,大概是一个高斯型分布有一定的宽度。这个宽度可能非常小(0.000几个纳米),主要还是因为原子不是处于绝对零度的状态。
实际上,我们认为的物理常数准确的描述是:现在的认知范围内,在多少精度以内我们认为是不变的。科学家也不停的在做实验,来检测这些常数是不是真的恒定不变的,这个学科叫精密测量物理。看下这个报导,测量万有引力常数G的,是2018年的科学进展。
回到这个问题,原子光谱本来就是实验的东西,实际上肯定不会是一个绝对精确的数值。当然可以相像一下理想情况:原子光谱宽度可以无限窄.......但仅限于真空中的球型鸡!
听个故事吧。
农场的鸡病了。农场主请来生物学家、化学家和物理学家。生物学家对鸡做了一番检查说不知道鸡得的什么病;化学家作了一番试验也没查出什么毛病。物理学家站在那儿,对着鸡看了一会,拿出笔记本开始写了起来,经过一番可怕的计算,物理学家说:“搞定了,可是,只适用于真空中的球型鸡。”
强烈建议从事光谱学研究的朋友们、学物理或者化学的朋友们收藏该回答,尤其是最后的matlab代码。
我来用数学物理的语言重新描述一下这个问题:
原子光谱,在一定的条件下可以是一个 函数吗?如果不能的话,将会是什么特征的分布呢?是什么原因导致的不能呢?
所谓 函数,或者叫做狄拉克 函数,可看作是无限高、无限细,但是总面积为1的一个尖峰。在物理上常用来代表理想化的质点或点电荷的密度。
答案是,比如不会是 函数,总会有些不可避免的因素导致谱线展宽。
那么,会有哪些因素导致实际的光谱分布偏离 函数呢?
导致谱线变宽的有两种不同的方式,分别被称作homogeneous broadening和inhomogeneous broadening。这两种方式区别的简单理解就是,homogeneous broadening是对于所有的原子或者分子是等同的,而inhomogeneous broadening则是对于不同的原子或者分子其效果不尽相同。下面让我来举几个简单的例子。
比如由于不确定性关系,导致谱线展宽,这就是homogeneous broadening,因为所有的原子都是一模一样的公式 ,都是等价的;
在比如,在水中水分子会形成氢键,有的水分子形成了两个氢键,有的形成了三个氢键,有的形成了四个氢键——这样导致的展宽就是inhomogeneous broadening。
对于原子光谱,重要的homogeneous broadening的因素:
1、不确定关系
由于,并且激发态的lifetime肯定不可能是无限长的,所以必定会导致有展宽。有人认为谱线肯定是高斯型分布的,这是非常错误的想法。实际上,对于所有的homogeneous broadening,谱线展宽都是洛伦兹分布的(Lorentzian)——本质原因是,自由感应衰减(Free induction decay,FID)或者指数衰减的傅立叶变换就是Lorentzian。
另外,不确定关系导致的展宽是无法避免的。这也是为什么哪怕你将温度降低至接近绝对0度,谱线依然会有宽度。
2、Pressure broadening (因为分子碰撞导致的)
由于分子/原子之间的碰撞,导致激发态的lifetime 减小,从而由于不确定关系导致 增加,所以谱线展宽。由于压强越高,分子/原子间的碰撞越多,所以它也被称作Pressure broadening。通过降温可以减少该因素的影响。
重要的inhomogeneous broadening因素有:
1、多普勒展宽(Doppler broadening)
由于分子/原子会一直在运动,并且相对于观察者,有的向观察者运动,有的背离观察者运动,还有的垂直方向运动。很多人都知道声波的多普勒效应:当火车从远方急驶而来时,其鸣笛声变得尖细(即频率变高,波长变短);而当火车离我们而去时,其鸣笛声变得低沉(即频率变低,波长变长)——就是多普勒效应的现象。实际上,对于光波也会有多普勒效应——并且这也是激光冷却的重要原理——具体可以见下面我的这个回答。
那么正是由于分子/原子在运动,那么就会有些波长红移,有些蓝移,从而导致了展宽。由于速度的分布满足玻尔兹曼分布,是个高斯函数,所以多普勒展宽导致的是谱线展宽是高斯分布的。通过降温也可以减少该因素的影响。
2、不同的化学环境(主要是凝聚态)
比如在水中,有的水分子形成了更多的氢键,从而导致红移的程度不同;比如在固体中,一些原子所处的化学环境不太相同。在气相中,基本不存在该因素;在液相中,非极性溶剂中该因素的影响较小,而极性溶剂中该因素影响较大。
在一个具体的体系中,既会有homogeneous broadening,也会有inhomogeneous broadening。其中前者是洛伦兹分布,后者是高斯分布,那么在具体的体系中会是什么样的谱线分布呢?
实际上,实际谱线的分布,是叫做Voigt profile,是洛伦兹函数和高斯函数的卷积。你可以看作是很多个洛伦兹函数叠加在一起形成了Voigt profile,并且这些洛伦兹函数的强度满足高斯分布。
在我们的实际科研中,经常需要对谱图进行拟合。高斯拟合和洛伦兹拟合都很简单,那么如何进行Voigt profile拟合呢?下面我就将我的matlab代码提供给各位,希望能帮助到一些从事光谱学研究的同行们。如果真的帮助到了各位,欢迎在致谢部分感谢我一下~如果想要引用文献的话,可以引用以下两个:
J. Phys. Chem. B 2019, 123, 29, 6212–6221
Proceedings of the National Academy of Sciences, Sep 2020,117(38)23385-23392;DOI:10.1073/pnas.2001861117
事先声明该代码是在 Penn State University 的 Paul Cremer教授提供的代码基础上修改的结果,他们组的 Dr. Xin Chen 最初写的该代码。但是他们并没有发表,并且也没有在正式发表的论文中使用。主要原因是,Voigt profile fitting需要信噪比(signal-to-noise ratio, SNR)很高,而SFG(Sum Frequency Generation,和频光谱)是非线性光学过程,一般信噪比都不太好。我的实验,SNR 非常好,所以可以用Voigt profile来拟合图谱。这也是为何我不能将code总结成Arxiv发表(毕竟部分是他人提供的代码),但是我很乐意与各位同行共享,正如同当初 Paul Cremer教授所做的那样。
该代码分在好几个部分,需要生成一共4个matlab文件。由于我是做SFG的,所以名字中都是带有SFG的,实际上对于其他的光谱学也都适用。它们分别为Spectral_Fitting, SFG_signal_sum, SFG_Lorentzian_Gaussian, SFG_Lorentzian. 其中这四个是四层,前面的调用后面的。
SFG_Lorentzian是生成最初的洛伦兹函数,SFG_Lorentzian_Gaussian是将洛伦兹函数和高斯函数卷积在一起生成一个峰的Voigt profile,SFG_signal_sum是将所有峰的结果求和起来,Spectral_Fitting就是你实际需要操作的code,用来输入初始值和边界值。
SFG_Lorentzian
function ki = SFG_Lorentzian (A,wr,w,Tau) ki=A*ones(size(w))./(w-wr+i*Tau);
SFG_Lorentzian_Gaussian
function ki = SFG_Lorentzian_Gaussian (A,wr,w,Tau,sigma) ki=zeros(size(w)); num_per_sigma=30; %number of point evaluated for each sigma max_sigma=3; %max sigma evaluated step=1; if Tau<5 step=0.1; end norm=0; for n= -num_per_sigma*max_sigma:step:num_per_sigma*max_sigma weight= exp(-1*n*n/(num_per_sigma*num_per_sigma)); % weight according to gaussion distribution. ki=ki+SFG_Lorentzian(A,wr-n/num_per_sigma*sigma,w,Tau)*weight; norm=norm + weight; end ki=ki/norm;
SFG_signal_sum
function y = SFG_signal_sum (parameters, frequency) ki=zeros(size(frequency)); y=zeros(size(frequency)); num_peaks = (length(parameters)-2)/4; for i = 1:num_peaks index = (i-1)*4 + 2 ; ki=ki+SFG_Lorentzian_Gaussian(parameters(index+1),parameters(index+2),frequency,parameters(index+3),parameters(index+4)); end ki= ki+ parameters(2); % non-resonant SFG signal y = abs(ki).^2; y= y+ parameters(1); % Background noise from green light scattering
Spectral_Fitting,其中p和Boundary是你的input,Boundary是p的上限和下限。第一个数值是背景散射,第二个数值是non-resonant signal(对于SFG适用,可能对于其他光谱不适用),后面的数值每四个就是一个峰分别的强度、中心频率、homogeneous broadening导致的展宽和inhomogeneous broadening导致的展宽。
x=wavenumber; y=intensity; %If more peaks are needed, please follow the rule below p=[0 %background scattering 0.0001 %non-resonant signal 220 %A1 2483 %wr1 5 %Tau1 45 %sigma1 240 %A2 2524 %wr2 5 %tau2 23 %sigma2 90 %A3 2349 %wr3 5 %tau3 49 %sigma3 ]; num_peaks = (length(p)-2)/4; % num of peaks n=5; %set optimization cycles Boundary=[ 0 8 -2 2 10 280 %A1 2380 2510 %wr1 5 5%Tau1 20 90 %sigma1 120 300 %A2 2510 2535%wr2 5 5%tau2 0 50 %sigma2 0 150 2310 2390 5 5 0 150 % 0 480 % 2380 2480 % 5 5 % 0 90 ]; p_LB= Boundary(:,1); p_UB= Boundary(:,2); %[p_LB,p_UB]=Xin_Set_Parameter_Boundary(p); pall=zeros(length(p),3); pall(:,1)=p_LB; pall(:,2)=p; pall(:,3)=p_UB; %Display the initial error %y_predicted = SFG_signal_sum(p, x); %[relative_residual,residual]=relative_residual(y_predicted,y); %disp(strcat('Initial error = ',num2str(relative_residual))); % optimization options=optimset('Maxiter',500000,'TolFun',1.0*10^-8); %set iterative cycles for index=1:n disp(strcat('********Starting optimization cycle # ',num2str(index),'********')); [p,residual_norm,residual]=lsqcurvefit('SFG_signal_sum',p,x,y,p_LB,p_UB,options); relative_residual = sqrt(residual_norm / sum (y.^2)); disp(strcat('relative error = ',num2str(relative_residual))); end % print final error for individual points and sum error if n>=0 peaks=zeros(length(y),10); for index =1:num_peaks temp=SFG_Lorentzian_Gaussian(p(index*4-1),p(index*4),x,p(index*4+1),p(index*4+2)); peaks(:,index)=abs(temp).^2; end y_predicted = SFG_signal_sum(p, x); %plot(x,y_predicted,'b-',x,peaks(:,1),'r--',x,peaks(:,2),'g--',x,peaks(:,3),'c--',x,peaks(:,4),'r--',x,peaks(:,5),'g--',x,peaks(:,6)); % plot y against x % Print final variables disp(p); end % Print results ys=zeros(10,length(y)); ys(1,:)=rot90(x); ys(2,:)=rot90(y); ys(3,:)=rot90(y_predicted); for index =1:num_peaks temp=SFG_Lorentzian_Gaussian(p(index*4-1),p(index*4),x,p(index*4+1),p(index*4+2)); ys(index+3,:)=rot90(abs(temp).^2); end fid=fopen('data.txt','w'); fprintf(fid,'%6.6f %6.6f %6.6f %6.6f %6.6f %6.6f %6.6f %6.6f %6.6f %6.6f
',ys); fclose(fid); figure;plot(x,y);hold on;plot(x,y_predicted)