Skip to content

Commit 7d4f267

Browse files
committed
updates due to mgeier's review and comments
- we temporarily hard code normalize_rows from PR194 to see if it improves the code (IMO it does) - sound_field and sfs.fd.synthesize arguments consistent - some code comments are better as markdown text - completely removed the p_line - p_circ difference plots, they don't add to the story, story now is more compelling: line, circ, point referencing - improve default case for point referencing -> indeed use default function call - some minor text changes to avoid misconceptions or make things more clear - spa_uni_path plotting taken from mgeier proposal via mail
1 parent 5408606 commit 7d4f267

File tree

1 file changed

+48
-72
lines changed

1 file changed

+48
-72
lines changed

doc/examples/wfs-referencing.ipynb

Lines changed: 48 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@
2525
"import sfs"
2626
]
2727
},
28+
{
29+
"cell_type": "code",
30+
"execution_count": null,
31+
"metadata": {},
32+
"outputs": [],
33+
"source": [
34+
"# we test the usage of\n",
35+
"# https://github.com/sfstoolbox/sfs-python/pull/194\n",
36+
"def normalize_rows(x):\n",
37+
" \"\"\"Normalize a list of vectors.\"\"\"\n",
38+
" x = sfs.util.asarray_of_rows(x)\n",
39+
" return x / np.linalg.norm(x, axis=1, keepdims=True)\n",
40+
"# to be removed once this is merged"
41+
]
42+
},
2843
{
2944
"cell_type": "markdown",
3045
"metadata": {},
@@ -52,10 +67,8 @@
5267
"metadata": {},
5368
"outputs": [],
5469
"source": [
55-
"def sound_field(d, xref, selection, secondary_source, array, grid):\n",
56-
"\n",
70+
"def sound_field(d, selection, array, secondary_source, grid, xref):\n",
5771
" p = sfs.fd.synthesize(d, selection, array, secondary_source, grid=grid)\n",
58-
"\n",
5972
" fig, [ax_amp, ax_lvl] = plt.subplots(2, 1, sharex=True)\n",
6073
" fig.set_figheight(fig.get_figwidth() * 3/2)\n",
6174
" sfs.plot2d.amplitude(p, grid, vmax=2, vmin=-2, ax=ax_amp)\n",
@@ -88,7 +101,9 @@
88101
"source": [
89102
"### Line as reference contour\n",
90103
"\n",
91-
"The reference contour is calculated according to <cite data-cite=\"Firtha2017\">(Firtha2017)</cite> for a virtual point source on x-axis."
104+
"The reference contour is calculated according to eqs. (24), (31), (52) in <cite data-cite=\"Firtha2017\">(Firtha2017)</cite>. \n",
105+
"The code assumes a virtual point source on x-axis.\n",
106+
"The reference contour is a straight line on y-axis."
92107
]
93108
},
94109
{
@@ -97,18 +112,15 @@
97112
"metadata": {},
98113
"outputs": [],
99114
"source": [
100-
"# reference contour is a straight line on y-axis\n",
101115
"xref_line = 0\n",
102-
"# calc reference contour xref(x0), cf. [Firtha2017, eq. (24), (31), (52)]\n",
103-
"# this code assumes virtual point source on x-axis\n",
104116
"cosbeta = (array.n @ [1, 0, 0]).reshape(-1, 1)\n",
105117
"xref = array.x + \\\n",
106118
" (xs - array.x) * (xref_line + R * cosbeta) / (xs[0, 0] + R * cosbeta)\n",
107119
"\n",
108120
"d, selection, secondary_source = sfs.fd.wfs.point_25d(\n",
109121
" omega, array.x, array.n, xs, xref=xref)\n",
110-
"p_line = sound_field(d * normalize_gain, xref, selection, secondary_source,\n",
111-
" array, grid)"
122+
"p_line = sound_field(\n",
123+
" d * normalize_gain, selection, array, secondary_source, grid, xref)"
112124
]
113125
},
114126
{
@@ -139,53 +151,11 @@
139151
"# reference contour is a circle with origin xs and radius |xs|\n",
140152
"xref_dist = np.linalg.norm(xs)\n",
141153
"# calc reference contour xref(x0), cf. [Firtha19, eq. (24), (31)]\n",
142-
"x0xs = array.x - xs\n",
143-
"x0xs_length = np.linalg.norm(x0xs, axis=1, keepdims=True)\n",
144-
"x0xs_unit = x0xs / x0xs_length # unit vec\n",
145-
"xref = xs + xref_dist * x0xs_unit\n",
146-
"\n",
154+
"xref = xs + xref_dist * normalize_rows(array.x - xs)\n",
147155
"d, selection, secondary_source = sfs.fd.wfs.point_25d(\n",
148-
" omega, array.x, array.n, xs, xref=xref)\n",
149-
"p_circ = sound_field(d * normalize_gain, xref, selection, secondary_source,\n",
150-
" array, grid)"
151-
]
152-
},
153-
{
154-
"cell_type": "markdown",
155-
"metadata": {},
156-
"source": [
157-
"The (complex-valued) difference between the two sound fields (linear vs. circular reference contour) tells us about the difference of both approaches in terms of amplitude."
158-
]
159-
},
160-
{
161-
"cell_type": "code",
162-
"execution_count": null,
163-
"metadata": {},
164-
"outputs": [],
165-
"source": [
166-
"sfs.plot2d.amplitude(p_line - p_circ, grid, vmax=1e-1, vmin=-1e-1)\n",
167-
"sfs.plot2d.loudspeakers(array.x, array.n, selection, size=0.125)\n",
168-
"plt.tight_layout()"
169-
]
170-
},
171-
{
172-
"cell_type": "markdown",
173-
"metadata": {},
174-
"source": [
175-
"The (complex-valued) ratio between the two sound fields (linear vs. circular reference contour) tells us about the difference of both approaches in terms of dB. Note, that again a white 0 dB isobar curve is overlaid as contour plot."
176-
]
177-
},
178-
{
179-
"cell_type": "code",
180-
"execution_count": null,
181-
"metadata": {},
182-
"outputs": [],
183-
"source": [
184-
"sfs.plot2d.level(p_line / p_circ, grid, vmax=1, vmin=-1,\n",
185-
" colorbar_kwargs={'label': 'dB'})\n",
186-
"sfs.plot2d.level_contour(p_line / p_circ, grid, levels=[0], colors='w')\n",
187-
"sfs.plot2d.loudspeakers(array.x, array.n, selection, size=0.125)\n",
188-
"plt.tight_layout()"
156+
" omega, array.x, array.n, xs, xref=xref)\n",
157+
"p_circ = sound_field(\n",
158+
" d * normalize_gain, selection, array, secondary_source, grid, xref)"
189159
]
190160
},
191161
{
@@ -203,9 +173,11 @@
203173
"`point_25d(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None)`\n",
204174
"uses just a reference point xref, and more specifically this default point is the origin of the coordinate system.\n",
205175
"This single point xref, the virtual source position xs and the loudspeaker array geometry together determine the reference contour without further user access to it.\n",
206-
"This handling is chosen due to convenience and practical relevance using circular loudspeaker arrays.\n",
176+
"This handling is chosen due to convenience and practical relevance when working with circular loudspeaker arrays.\n",
177+
"\n",
207178
"The example below shows the resulting reference contour for the default case.\n",
208-
"In the example it looks similar to the line reference contour, but is in general not exactly the same."
179+
"In the example it looks similar to the line reference contour, but is in general not exactly the same.\n",
180+
"For example, please try a virtual point source that is far away from the array."
209181
]
210182
},
211183
{
@@ -214,24 +186,24 @@
214186
"metadata": {},
215187
"outputs": [],
216188
"source": [
217-
"xref = [0, 0, 0]\n",
218-
"normalize_gain = 4 * np.pi * np.linalg.norm(xs - np.array(xref))\n",
219189
"d, selection, secondary_source = sfs.fd.wfs.point_25d(\n",
220-
" omega, array.x, array.n, xs, xref=xref)\n",
221-
"p_point = sound_field(d * normalize_gain, np.array([xref]*array.x.shape[0]),\n",
222-
" selection, secondary_source, array, grid)"
190+
" omega, array.x, array.n, xs)\n",
191+
"p_point = sound_field(\n",
192+
" d * normalize_gain, selection, array, secondary_source,\n",
193+
" grid, np.array([[0, 0, 0]]*array.x.shape[0]))"
223194
]
224195
},
225196
{
226197
"cell_type": "markdown",
227198
"metadata": {},
228199
"source": [
229200
"From an academic viewpoint, the reference point handling in most cases will fail, as it is rather unlikely to set up the loudspeaker array and the virtual source and the reference point, such that the latter exactly fulfills the stationary phase requirement with one of the active loudspeakers.\n",
230-
"In the example above this worked, but only because it was intentionally chosen to do so.\n",
201+
"In the example above this worked, but because it was intentionally chosen to do so.\n",
202+
"\n",
203+
"The example below shows a point xref that does not meet any ray (the gray lines in the level plot) alongside the stationary phase holds with its corresponding loudspeaker.\n",
231204
"\n",
232-
"The example below shows a point xref that does not meet any ray (gray lines) alongside the stationary phase holds with its corresponding loudspeaker.\n",
233205
"The obtained level at the xref point however closely matches the desired reference level, because the white 0 dB isobar curve is very close to it.\n",
234-
"So, in practice this single point reference scheme will likely work with sufficient precision once the position of xref is appropriately chosen (i.e. not too close, not too far, not to off-center etc.)."
206+
"Hence, in practice this single point reference scheme will likely work with sufficient precision once the position of xref is appropriately chosen (i.e. not too close, not too far, not to off-center from the active loudspeakers etc.)."
235207
]
236208
},
237209
{
@@ -246,15 +218,19 @@
246218
"normalize_gain = 4 * np.pi * np.linalg.norm(xs - np.array(xref))\n",
247219
"d, selection, secondary_source = sfs.fd.wfs.point_25d(\n",
248220
" omega, array.x, array.n, xs, xref=xref)\n",
249-
"p_point = sound_field(d * normalize_gain, np.array([xref]*array.x.shape[0]),\n",
250-
" selection, secondary_source, array, grid)\n",
221+
"p_point = sound_field(\n",
222+
" d * normalize_gain, selection, array, secondary_source,\n",
223+
" grid, np.array([xref]*array.x.shape[0]))\n",
251224
"\n",
252225
"spa_unit_path = array.x - xs # path along which the stationary phase holds\n",
253-
"spa_unit_path /= np.linalg.norm(spa_unit_path, axis=1, keepdims=1)\n",
254-
"spa = array.x + R * spa_unit_path\n",
255-
"for spa1, spa2 in zip(array.x[selection, :2], spa[selection, :2]):\n",
256-
" plt.plot([spa1[0], spa2[0]],\n",
257-
" [spa1[1], spa2[1]], 'dimgray')"
226+
"spa_unit_path = normalize_rows(spa_unit_path)\n",
227+
"spa = array.x + R * spa_unit_path # length of all pathes is R\n",
228+
"# such that the horizontal path exactly meets the origin\n",
229+
"# of the coordinate system, this is very close to xref\n",
230+
"plt.plot(\n",
231+
" np.vstack((array.x[selection, 0], spa[selection, 0])),\n",
232+
" np.vstack((array.x[selection, 1], spa[selection, 1])),\n",
233+
" color='dimgray');"
258234
]
259235
},
260236
{

0 commit comments

Comments
 (0)