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

Author Notes

The function, if used for fitting atomic Voigt spectra with several thousand data points and multiples peaks, should be compiled beforehand as shown above to maximize efficiency and evaluation speed.

License Information