Wolfram Research

Function Repository Resource:

NPseudoVoigt

Source Notebook

Fast numerical approximation to the PDF of the Voigt distribution with around 1.2% of maximum deviation

Contributed by: Julien Kluge
Quantum Optical Metrology; Joint Lab Integrated Quantum Sensors
Department of Physics
Humboldt-Universität zu Berlin
(julien@physik.hu-berlin.de)

ResourceFunction["NPseudoVoigt"][x,b,σ]

calculates the approximation at postions x of a Voigt distribution with CauchyDistribution parameter b and NormalDistribution parameter σ.

Details and Options

ResourceFunction["NPseudoVoigt"] automatically threads over lists.
ResourceFunction["NPseudoVoigt"] is approximately normed to 1 for all parameters b and σ above 0.

Examples

Basic Examples

NPseudoVoigt always returns numerical results, even for exact inputs:

In[1]:=
ResourceFunction["NPseudoVoigt"][0, 1, 1]
Out[1]=

NPseudoVoigt compared to the analytic solution:

In[2]:=
Plot[{ResourceFunction["NPseudoVoigt"][x, 1, 1], PDF[VoigtDistribution[1, 1], x]}, {x, -5, 5}]
Out[2]=

Scope

NPseudoVoigt automatically threads over lists:

In[3]:=
ResourceFunction["NPseudoVoigt"][{-1, 0, 1}, 2, {1, 2, 3}]
Out[3]=

NPseudoVoigt is approximately normed to 1 for b and σ greater than 0:

In[4]:=
NIntegrate[
 ResourceFunction["NPseudoVoigt"][x, 10, 20], {x, -Infinity, Infinity}]
Out[4]=

NPseudoVoigt's norm has four additional terms that cancel out for non-extreme values of b and σ:

In[5]:=
Integrate[
  ResourceFunction["NPseudoVoigt"][x, b, \[Sigma]], {x, -Infinity, Infinity}, Assumptions -> b > 0 && \[Sigma] > 0] /. {num_?NumericQ :> Round[num, 10^-15]}
Out[5]=

NPseudoVoigt's deviation to the analytic solution in the maximum is usually less than ±1% for every parameter combination b and σ:

In[6]:=
PercentForm /@ MinMax[Table[(PDF[VoigtDistribution[b, \[Sigma]], 0] - ResourceFunction["NPseudoVoigt"][0, b, \[Sigma]])/
    PDF[VoigtDistribution[b, \[Sigma]], 0], {b, 1/10, 3, 1/10}, {\[Sigma], 1/10, 3, 1/10}]]
Out[6]=

NPseudoVoigt's relative deviation increases if b and σ approach one another:

In[7]:=
Plot3D[(PDF[VoigtDistribution[b, \[Sigma]], 0] - ResourceFunction["NPseudoVoigt"][0, b, \[Sigma]])/
  PDF[VoigtDistribution[b, \[Sigma]], 0], {b, 0.1, 3}, {\[Sigma], 0.1,
   3}, PlotRange -> All]
Out[7]=

NPseudoVoigt is also stable against σ being 0:

In[8]:=
PDF[VoigtDistribution[1, 10^-20], 0.0] == ResourceFunction["NPseudoVoigt"][0, 1, 0]
Out[8]=

Applications

NPseudoVoigt can be compiled to obtain faster execution times:

In[9]:=
data = Range[-5, 5, 0.0005];

Total[PDF[VoigtDistribution[1, 1], data]] // Timing (*analytical solution*)
Out[3]=
In[10]:=
Total[ResourceFunction["NPseudoVoigt"][data, 1, 1]] // Timing (*uncompiled [\[FilledSmallSquare]]	NPseudoVoigt solution*)
Out[10]=
In[11]:=
NPseudoVoigtC = Compile[{x, b, \[Sigma]}, Evaluate@
    ResourceFunction["NPseudoVoigt"][x, b, \[Sigma]]]; (*compile*)

Total[NPseudoVoigtC[#, 1, 1] & /@ data] // Timing (*compiled [\
\[FilledSmallSquare]]	NPseudoVoigt*)
Out[11]=

Possible Issues

Negative b parameters can produce imaginary values:

In[12]:=
ResourceFunction["NPseudoVoigt"][0, -1, 1]
Out[12]=

Negative σ parameters do not yield symmetric values:

In[13]:=
ResourceFunction["NPseudoVoigt"][0, 1, -1] == ResourceFunction["NPseudoVoigt"][0, 1, 1]
Out[13]=

Neat Examples

NPseudoVoigt can be used to approximate an atomic absorption spectrum efficiently:

In[14]:=
data = Table[{f, RandomVariate[NormalDistribution[0, 0.003]] + 0.5*PDF[VoigtDistribution[0.5, 2], f] + PDF[VoigtDistribution[0.5, 2], f - 5] + 0.7*PDF[VoigtDistribution[0.5, 2], f + 7]}, {f, -15, 15, 0.05}];
fit = NonlinearModelFit[data, A1*ResourceFunction["NPseudoVoigt"][x + x1, b, \[Sigma]] + A2*ResourceFunction["NPseudoVoigt"][x + x2, b, \[Sigma]] + A3*ResourceFunction["NPseudoVoigt"][x + x3, b, \[Sigma]], {{x1, -4}, {x2, 0}, {x3, 5}, A1, A2, A3, b, \[Sigma]}, x];
Show[{ListPlot[data], Plot[fit[f], {f, -15, 15}]}]

Quiet[fit["ParameterTable"]]
Out[15]=
Out[16]=

NPseudoVoigt can be used to show that σ is negligible or even 0, whereas the VoigtDistribution could throw errors:

In[17]:=
data = Table[{f, RandomVariate[NormalDistribution[0, 0.003]] + 0.5*PDF[CauchyDistribution[0, 2], f] + PDF[CauchyDistribution[5, 2], f] + 0.7*PDF[CauchyDistribution[-7, 2], f]}, {f, -15, 15, 0.05}];
fit = NonlinearModelFit[data, A1*ResourceFunction["NPseudoVoigt"][x + x1, b, \[Sigma]] + A2*ResourceFunction["NPseudoVoigt"][x + x2, b, \[Sigma]] + A3*ResourceFunction["NPseudoVoigt"][x + x3, b, \[Sigma]], {{x1, -4}, {x2, 0}, {x3, 5}, A1, A2, A3, b, \[Sigma]}, x];
Quiet[fit["ParameterTable"]]
Out[19]=

Resource History

Source Metadata

License Information