|
9 | 9 | "Illustrates the usage of the SFS toolbox for the simulation of different 2.5D WFS referencing schemes for contours within the listening area that exhibit amplitude correct synthesis, cf. Ch. 4.1.3 in <cite data-cite=\"Firtha2019\">[Firtha19]</cite> and <cite data-cite=\"Firtha2017\">(FFSS17)</cite>."
|
10 | 10 | ]
|
11 | 11 | },
|
| 12 | + { |
| 13 | + "cell_type": "code", |
| 14 | + "execution_count": null, |
| 15 | + "metadata": {}, |
| 16 | + "outputs": [], |
| 17 | + "source": [ |
| 18 | + "import matplotlib.pyplot as plt\n", |
| 19 | + "import numpy as np\n", |
| 20 | + "import sfs" |
| 21 | + ] |
| 22 | + }, |
12 | 23 | {
|
13 | 24 | "cell_type": "markdown",
|
14 | 25 | "metadata": {},
|
|
22 | 33 | "metadata": {},
|
23 | 34 | "outputs": [],
|
24 | 35 | "source": [
|
25 |
| - "import matplotlib.pyplot as plt\n", |
26 |
| - "import numpy as np\n", |
27 |
| - "import sfs\n", |
28 |
| - "\n", |
29 |
| - "R = 1.5 # Radius of circular loudspeaker array\n", |
30 |
| - "array = sfs.array.circular(N=64, R=R)\n", |
| 36 | + "R = 1.5 # Radius of circular loudspeaker array, in m\n", |
| 37 | + "array = sfs.array.circular(N=64, R=R) # with N loudspeakers\n", |
31 | 38 | "grid = sfs.util.xyz_grid([-2, 2], [-2, 2], 0, spacing=0.02)\n",
|
32 | 39 | "\n",
|
33 |
| - "xs = sfs.util.asarray_of_rows((-4, 0, 0)) # point source on negative x-axis\n", |
34 |
| - "normalize_gain = 4 * np.pi * np.linalg.norm(xs)\n", |
35 |
| - "wavelength = 1 / 4 # m\n", |
36 |
| - "f = sfs.default.c / wavelength # Hz\n", |
37 |
| - "omega = 2 * np.pi * f # rad/s" |
| 40 | + "xs = -4, 0, 0 # point source on negative x-axis\n", |
| 41 | + "wavelength = 1 / 4 # m" |
38 | 42 | ]
|
39 | 43 | },
|
40 | 44 | {
|
|
43 | 47 | "metadata": {},
|
44 | 48 | "outputs": [],
|
45 | 49 | "source": [
|
46 |
| - "def sound_field(d, xref, selection,\n", |
47 |
| - " secondary_source, array, grid, tapering=True):\n", |
48 |
| - " if tapering:\n", |
49 |
| - " tapering_window = sfs.tapering.kaiser(selection, beta=1)\n", |
50 |
| - " else:\n", |
51 |
| - " tapering_window = sfs.tapering.none(selection)\n", |
| 50 | + "def sound_field(\n", |
| 51 | + " d, xref, selection, secondary_source, array, grid):\n", |
52 | 52 | "\n",
|
53 |
| - " p = sfs.fd.synthesize(d, tapering_window,\n", |
54 |
| - " array, secondary_source, grid=grid)\n", |
| 53 | + " p = sfs.fd.synthesize(\n", |
| 54 | + " d, selection, array, secondary_source, grid=grid)\n", |
55 | 55 | "\n",
|
56 |
| - " fig, axs = plt.subplots(1, 2, figsize=(10, 8))\n", |
57 |
| - " sfs.plot2d.amplitude(p, grid, vmax=2, vmin=-2, ax=axs[0])\n", |
58 |
| - " sfs.plot2d.level(p, grid, vmax=6, vmin=-6, ax=axs[1],\n", |
59 |
| - " cmap='seismic', colorbar_kwargs={'label': 'dB'})\n", |
60 |
| - " for i in range(axs.shape[0]):\n", |
61 |
| - " sfs.plot2d.loudspeakers(array.x, array.n,\n", |
62 |
| - " tapering_window,\n", |
63 |
| - " size=0.125, ax=axs[i])\n", |
64 |
| - " axs[i].plot(xref[:, 0][selection],\n", |
65 |
| - " xref[:, 1][selection],\n", |
66 |
| - " marker='o', linestyle='', color='dimgray', ms=4)\n", |
67 |
| - " axs[i].grid(True)\n", |
| 56 | + " fig, [ax_amp, ax_lvl] = plt.subplots(2, 1, sharex=True)\n", |
| 57 | + " fig.set_figheight(fig.get_figwidth() * 3/2)\n", |
| 58 | + " sfs.plot2d.amplitude(p, grid, vmax=2, vmin=-2, ax=ax_amp)\n", |
| 59 | + " sfs.plot2d.level(\n", |
| 60 | + " p, grid, vmax=6, vmin=-6, ax=ax_lvl, cmap='seismic',\n", |
| 61 | + " colorbar_kwargs={'label': 'dB'})\n", |
| 62 | + " for ax in ax_amp, ax_lvl:\n", |
| 63 | + " sfs.plot2d.loudspeakers(\n", |
| 64 | + " array.x, array.n, selection, size=0.125, ax=ax)\n", |
| 65 | + " ax.scatter(*xref[selection, :2].T, s=20, c='dimgray',\n", |
| 66 | + " zorder=3)\n", |
| 67 | + " ax.grid(True)\n", |
68 | 68 | " plt.tight_layout()\n",
|
69 | 69 | " return p\n"
|
70 | 70 | ]
|
71 | 71 | },
|
| 72 | + { |
| 73 | + "cell_type": "code", |
| 74 | + "execution_count": null, |
| 75 | + "metadata": {}, |
| 76 | + "outputs": [], |
| 77 | + "source": [ |
| 78 | + "xs = sfs.util.asarray_of_rows((-4, 0, 0))\n", |
| 79 | + "f = sfs.default.c / wavelength # Hz\n", |
| 80 | + "omega = 2 * np.pi * f # rad/s\n", |
| 81 | + "normalize_gain = 4 * np.pi * np.linalg.norm(xs)" |
| 82 | + ] |
| 83 | + }, |
72 | 84 | {
|
73 | 85 | "cell_type": "markdown",
|
74 | 86 | "metadata": {},
|
|
89 | 101 | "# calc reference contour xref(x0), cf. [FFSS17, eq. (24), (31), (52)]\n",
|
90 | 102 | "# this code assumes virtual point source on x-axis\n",
|
91 | 103 | "cosbeta = (array.n @ [1, 0, 0]).reshape(-1, 1)\n",
|
92 |
| - "xref = array.x + (xs - array.x) * \\\n", |
93 |
| - " (xref_line + R * cosbeta) / (xs[0, 0] + R * cosbeta)\n", |
| 104 | + "xref = array.x + \\\n", |
| 105 | + " (xs - array.x) * (xref_line + R * cosbeta) / (xs[0, 0] + R * cosbeta)\n", |
94 | 106 | "\n",
|
95 | 107 | "d, selection, secondary_source = sfs.fd.wfs.point_25d(\n",
|
96 | 108 | " omega, array.x, array.n, xs, xref=xref)\n",
|
97 |
| - "p_line = sound_field(d * normalize_gain, xref, selection,\n", |
98 |
| - " secondary_source, array, grid, tapering=False)" |
| 109 | + "p_line = sound_field(\n", |
| 110 | + " d * normalize_gain, xref, selection,\n", |
| 111 | + " secondary_source, array, grid)" |
99 | 112 | ]
|
100 | 113 | },
|
101 | 114 | {
|
|
123 | 136 | "\n",
|
124 | 137 | "d, selection, secondary_source = sfs.fd.wfs.point_25d(\n",
|
125 | 138 | " omega, array.x, array.n, xs, xref=xref)\n",
|
126 |
| - "p_circ = sound_field(d * normalize_gain, xref, selection,\n", |
127 |
| - " secondary_source, array, grid, tapering=False)" |
| 139 | + "p_circ = sound_field(\n", |
| 140 | + " d * normalize_gain, xref, selection,\n", |
| 141 | + " secondary_source, array, grid)" |
128 | 142 | ]
|
129 | 143 | },
|
130 | 144 | {
|
|
134 | 148 | "outputs": [],
|
135 | 149 | "source": [
|
136 | 150 | "# (complex-valued) ratio between the two soundfields tells\n",
|
137 |
| - "# us about the difference of both approaches\n", |
138 |
| - "sfs.plot2d.level(p_line / p_circ, grid, vmax=1, vmin=-1,\n", |
139 |
| - " cmap='seismic', colorbar_kwargs={'label': 'dB'})\n", |
140 |
| - "sfs.plot2d.loudspeakers(array.x, array.n, size=0.125)\n", |
| 151 | + "# us about the difference of both approaches in terms of dB\n", |
| 152 | + "sfs.plot2d.level(\n", |
| 153 | + " p_line / p_circ, grid, vmax=1, vmin=-1, cmap='seismic',\n", |
| 154 | + " colorbar_kwargs={'label': 'dB'})\n", |
| 155 | + "sfs.plot2d.loudspeakers(array.x, array.n, selection, size=0.125)\n", |
| 156 | + "plt.grid(True)\n", |
| 157 | + "plt.tight_layout()" |
| 158 | + ] |
| 159 | + }, |
| 160 | + { |
| 161 | + "cell_type": "code", |
| 162 | + "execution_count": null, |
| 163 | + "metadata": {}, |
| 164 | + "outputs": [], |
| 165 | + "source": [ |
| 166 | + "# (complex-valued) difference between the two soundfields tells\n", |
| 167 | + "# us about the difference of both approaches in terms of magnitude\n", |
| 168 | + "sfs.plot2d.amplitude(\n", |
| 169 | + " p_line - p_circ, grid, vmax=1e-1, vmin=-1e-1)\n", |
| 170 | + "sfs.plot2d.loudspeakers(array.x, array.n, selection, size=0.125)\n", |
141 | 171 | "plt.grid(True)\n",
|
142 | 172 | "plt.tight_layout()"
|
143 | 173 | ]
|
|
0 commit comments