In [21]:
import numpy as np
from scipy.special import erf, gamma
import matplotlib.pyplot as plt
Error function¶
$$ \mathrm{erf}(x) = \frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2} dt $$
In [13]:
x = 0.7
t = np.linspace(0,x,100000)
dt = np.diff(t)[0]
# approximation at x=3
erf_approx = 2/np.sqrt(np.pi) * np.sum(np.exp(-t**2)*dt)
print(erf_approx, erf(x))
0.6778075626862514 0.6778011938374184
Plot: integrand
In [14]:
plt.axvline(x)
t = np.linspace(0,4,1000)
plt.plot(t, np.exp(-t**2))
Out[14]:
[<matplotlib.lines.Line2D at 0x11df63a40>]
Plot: error function itself
In [17]:
t = np.linspace(-5,5,1000)
plt.plot(t,erf(t))
Out[17]:
[<matplotlib.lines.Line2D at 0x11df76cf0>]
Approximation with a series
$$ \mathrm{erf}(x) = \frac{2}{\sqrt{\pi}} \sum_{n=0}^\infty \frac{(-1)^n x^{2n + 1}}{n! (2n-1)} $$
In [42]:
big = 10
n = np.arange(0,big,1,dtype=int)
x = 0.7
nfactorial = gamma(n+1)
In [46]:
erf_series = 2/np.sqrt(np.pi)*np.sum( ((-1)**n * x**(2*n+1) )/(nfactorial*(2*n+1)) )
In [47]:
erf_series, erf(x)
Out[47]:
(np.float64(0.6778011938294721), np.float64(0.6778011938374184))
Complex error function¶
In [48]:
x = np.linspace(-10,10,1000)
y = np.linspace(-10,10,1000)
x, y = np.meshgrid(x,y,indexing="ij")
z = x + 1j*y
erf_eval = erf(z)
In [49]:
plt.pcolormesh(np.real(z),np.imag(z),np.real(erf_eval),vmin=-10,vmax=10,cmap="seismic_r")
plt.colorbar()
plt.grid()
In [50]:
plt.pcolormesh(np.real(z),np.imag(z),np.imag(erf_eval),vmin=-10,vmax=10,cmap="seismic_r")
plt.colorbar()
plt.grid()
From the definition of erf(x), one can see that for a complex argument $z$
$$ \mathrm{erf}(z) = \frac{2}{\sqrt{\pi}}\int_0^z e^{-t^2} dt $$
and a change of variables inside of the integral such that the integration limit becomes real but then the integrand must become complex, there is a relationship between the error function and integrals involving $\cos u^2$ and $\sin u^2$ for real $u$ (after the change of variable, the exponential becomes complex). Those are the Fresnel integrals
In [ ]: