5.5 Waves in software
Software 5.5.1 (Spherical waves). The residual of the radial wave equation \(u_{tt} = c^2(u_{rr} + \frac {n - 1}ru_r)\) for an outgoing wave in three and in two dimensions:
>>> import sympy as sp
>>> r, t, c = sp.symbols('r t c', positive=True)
>>> F = sp.Function('F')
>>> def radial(u, n): # u_tt - c^2 (u_rr + (n - 1) u_r / r)
... return u.diff(t, 2) - c**2 * (u.diff(r, 2) + (n - 1) / r * u.diff(r))
...
>>> sp.simplify(radial(F(r - c*t) / r, 3)) # spherical wave in 3D
0
>>> sp.simplify(radial(F(r - c*t) / sp.sqrt(r), 2)) # none in 2D
-c**2*F(-c*t + r)/(4*r**(5/2))
Reading the output. \(F(r - ct)/r\) is an exact solution in three dimensions for every profile \(F\). Its two-dimensional analogue \(F(r - ct)/\sqrt r\) leaves a residual of order \(r^{-5/2}\): in two dimensions an outgoing wave cannot keep its shape, and is a travelling profile only far from the source. This is the same fact as the wake.
MATLAB/Octave: with the Symbolic Math Toolbox, the same diff expressions.
Software 5.5.2 (Kirchhoff’s formula). Example 5.3.1 in three dimensions, with \(a = 1\), \(R = 5\): the spherical mean in Kirchhoff’s formula estimated from a million random directions, against the exact pulse:
>>> import numpy as np >>> rng = np.random.default_rng(1) >>> w = rng.normal(size=(10**6, 3)); w /= np.linalg.norm(w, axis=1)[:, None] >>> a, R = 1.0, 5.0 # g = 1 in the unit ball, f = 0, c = 1 >>> x = np.array([R, 0, 0]) >>> def kirchhoff(t): # u = t * (mean of g over |y - x| = t) ... return t * np.mean(np.linalg.norm(x + t * w, axis=1) < a) ... >>> for t in (3.5, 4.5, 5.0, 5.5, 6.5): ... exact = max(a**2 - (R - t)**2, 0) / (4 * R) ... print(t, round(kirchhoff(t), 4), round(exact, 4)) ... 3.5 0.0 0.0 4.5 0.0371 0.0375 5.0 0.0498 0.05 5.5 0.037 0.0375 6.5 0.0 0.0
Reading the output. The solution is \(0\) before \(t = 4\) and after \(t = 6\), and in between follows \((1 - (5 - t)^2)/20\), with peak \(0.05\) at \(t = 5\), to within the Monte Carlo error, which is \(t\sqrt {p(1 - p)/10^6} \approx 0.0005\) near the peak, where \(p = u/t \approx 0.01\) is the fraction of directions that hit the ball.
MATLAB/Octave: w = randn(1e6,3); w = w./vecnorm(w,2,2); and the same mean.
Software 5.5.3 (Poisson’s formula and the wake). Example 5.3.1 in two dimensions. Writing \(\rho = |y - x|\), Poisson’s formula becomes \(u = \frac 1{2\pi }\int \theta (\rho )\rho \,d\rho /\sqrt {t^2 - \rho ^2}\), with \(\theta (\rho )\) the angle of the circle of radius \(\rho \) about \(x\) that lies in the disc; the substitution \(\rho = t\sin \phi \) removes the square-root singularity:
>>> from scipy.integrate import quad >>> def poisson(R, t, a=1.0): # 2D, g = 1 in the unit disc, c = 1 ... def arc(rho): # angle of circle |y - x| = rho in disc ... if R == 0: return 2 * np.pi * (rho < a) ... q = (R**2 + rho**2 - a**2) / (2 * R * rho) ... return 2 * np.arccos(np.clip(q, -1, 1)) ... lo, hi = max(R - a, 0.0), min(R + a, t) ... if hi <= lo: return 0.0 ... f = lambda phi: arc(t * np.sin(phi)) * t * np.sin(phi) # rho=t sin ... lims = np.arcsin(lo / t), np.arcsin(hi / t) ... return quad(f, *lims, limit=200)[0] / (2 * np.pi) ... >>> for t in (0.5, 2.0, 10.0, 100.0): # centre: t - sqrt(t^2 - a^2) ... exact = t - np.sqrt(max(t * t - 1, 0)) ... print(t, round(poisson(0.0, t), 6), round(exact, 6)) ... 0.5 0.5 0.5 2.0 0.267949 0.267949 10.0 0.050126 0.050126 100.0 0.005 0.005 >>> [round(poisson(5.0, t), 4) for t in (3.5, 5.0, 6.5, 10.0, 30.0)] [0.0, 0.1736, 0.1271, 0.058, 0.0169]
Reading the output. At the centre the quadrature reproduces \(t - \sqrt {t^2 - 1}\) to six digits, and the value at \(t = 100\), \(0.005\), is the asymptotic \(1/2t\). At distance \(5\) the solution is still \(0.058\) at \(t = 10\) and \(0.0169\) at \(t = 30\), close to \(1/2t = 0.0167\); in three dimensions it would be exactly \(0\) for all \(t > 6\).
MATLAB/Octave: integral with the same integrand.
Questions on this section
Stuck on something here? Ask below and it stays attached to this topic.