Skip to content

Commit e1e740b

Browse files
Add Modelling Sensor Directivity In 2D Example (#500)
* Add Modelling Sensor Directivity In 2D Example * Fix Readme files & record notebook outputs --------- Co-authored-by: Walter Simson <waltersimson@stanford.edu>
1 parent d4b8e3c commit e1e740b

File tree

4 files changed

+390
-11
lines changed

4 files changed

+390
-11
lines changed

examples/README.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ Every example has a short readme.md file which briefly describes the purpose of
99
- [Array as a sensor](at_array_as_sensor/) ([original example](http://www.k-wave.org/documentation/example_at_array_as_sensor.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/at_array_as_sensor/at_array_as_sensor.ipynb))
1010
- [Array as a source](at_array_as_source/) ([original example](http://www.k-wave.org/documentation/example_at_array_as_source.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/at_array_as_source/at_array_as_source.ipynb))
1111
- [Linear array transducer](at_linear_array_transducer/)
12-
([original example](http://www.k-wave.org/documentation/example_at_linear_array_transducer.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/at_linear_array_transducer/at_linear_array_transducer.ipynb))
12+
([original example](http://www.k-wave.org/documentation/example_at_linear_array_transducer.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/at_linear_array_transducer/at_linear_array_transducer.ipynb))
1313
- [Photoacoustic Waveforms](ivp_photoacoustic_waveforms/) ([original example](http://www.k-wave.org/documentation/example_ivp_photoacoustic_waveforms.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/ivp_photoacoustic_waveforms/ivp_photoacoustic_waveforms.ipynb))
1414
- [Controlling the PML](na_controlling_the_pml/)
15-
([original example](http://www.k-wave.org/documentation/example_na_controlling_the_pml.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/na_controlling_the_pml/na_controlling_the_pml.ipynb))
15+
([original example](http://www.k-wave.org/documentation/example_na_controlling_the_pml.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/na_controlling_the_pml/na_controlling_the_pml.ipynb))
1616
- [Defining An Ultrasound Transducer Example](us_defining_transducer) ([original example](http://www.k-wave.org/documentation/example_us_defining_transducer.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/us_defining_transducer/us_defining_transducer.ipynb))
1717
- [Simulating Ultrasound Beam Patterns](us_beam_patterns/)([original example](http://www.k-wave.org/documentation/example_us_beam_patterns), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/us_beam_patterns/us_beam_patterns.ipynb))
1818
- [Linear transducer B-mode](us_bmode_linear_transducer/) ([original example](http://www.k-wave.org/documentation/example_us_bmode_linear_transducer.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/us_bmode_linear_transducer/us_bmode_linear_transducer.ipynb))
1919
- [Phased array B-mode](us_bmode_phased_array/)
20-
([original example](http://www.k-wave.org/documentation/example_us_bmode_phased_array.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/us_bmode_phased_array/us_bmode_phased_array.ipynb))
20+
([original example](http://www.k-wave.org/documentation/example_us_bmode_phased_array.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/us_bmode_phased_array/us_bmode_phased_array.ipynb))
2121
- [Circular piston transducer](at_circular_piston_3D/) ([original example](http://www.k-wave.org/documentation/example_at_piston_and_bowl_transducers.php#heading3), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/at_circular_piston_3D/at_circular_piston_3D.ipynb))
2222

2323
- [Circular piston transducer (axisymmetric)](at_circular_piston_AS/) ([original example](http://www.k-wave.org/documentation/example_at_piston_and_bowl_transducers.php#heading4), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/at_circular_piston_AS/at_circular_piston_AS.ipynb))
@@ -32,20 +32,21 @@ Every example has a short readme.md file which briefly describes the purpose of
3232

3333
- [Focussed Detector In 3D Example](sd_focussed_detector_3D/) ([original example](http://www.k-wave.org/documentation/example_sd_focussed_detector_3D.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/sd_focussed_detector_3D/sd_focussed_detector_3D.ipynb))
3434

35+
- [Modelling Sensor Directivity In 2D Example](sd_directivity_modelling_2D/) ([original example](http://www.k-wave.org/documentation/example_sd_directivity_modelling_2D.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/sd_directivity_modelling_2D/sd_directivity_modelling_2D.ipynb))
3536

3637
## Contributing new examples
3738

3839
When adding a new example notebook, follow these steps:
3940

4041
1. Search the [list of examples](https://docs.google.com/spreadsheets/d/1-x13iIez84AEyjjHMOe2GoC8FSyzUFHoy9R7VKttTlo/edit?usp=sharing) to find an open example.
4142
1. Claim your example by opening an "Example" issue on GitHub.
42-
3. Fork and clone the repository and create a branch for your new example.
43-
2. Create an example sub-directory using the name from the hyperlink of the original k-wave example if it exists (e.g. for http://www.k-wave.org/documentation/example_ivp_loading_external_image.php name the directory "ivp_loading_external_image).
44-
3. Add your example notebook to your example directory.
45-
4. Create a Python script that mirrors your example notebook in the same directory. Using `nbconvert` is an easy way to convert to a Python script using ` jupyter nbconvert --to python --RegexRemovePreprocessor.patterns="^%" <notebook_path>`
46-
5. Add a README.md file to your example directory briefly describing the concept or principle the example is meant to display and linking to the origonal k-wave example page if it exists.
47-
6. Include a link in the `README.md` in the examples directory to a colab notebook for your example.
48-
7. Add a your example to the list on this `README.md` and add a colab badge [using html](https://openincolab.com/) OR copy the pure markdown version above.
49-
8. Open a pull request that [closes the open issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) from your forked example branch and name pull request "[Example] \<name of your example\>".
43+
1. Fork and clone the repository and create a branch for your new example.
44+
1. Create an example sub-directory using the name from the hyperlink of the original k-wave example if it exists (e.g. for http://www.k-wave.org/documentation/example_ivp_loading_external_image.php name the directory "ivp_loading_external_image).
45+
1. Add your example notebook to your example directory.
46+
1. Create a Python script that mirrors your example notebook in the same directory. Using `nbconvert` is an easy way to convert to a Python script using ` jupyter nbconvert --to python --RegexRemovePreprocessor.patterns="^%" <notebook_path>`
47+
1. Add a README.md file to your example directory briefly describing the concept or principle the example is meant to display and linking to the origonal k-wave example page if it exists.
48+
1. Include a link in the `README.md` in the examples directory to a colab notebook for your example.
49+
1. Add a your example to the list on this `README.md` and add a colab badge [using html](https://openincolab.com/) OR copy the pure markdown version above.
50+
1. Open a pull request that [closes the open issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) from your forked example branch and name pull request "[Example] \<name of your example\>".
5051

5152
Thanks for contributing to k-wave-python!
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Modelling Sensor Directivity In 2D Example
2+
3+
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/sd_directivity_modelling_2D/sd_directivity_modelling_2D.ipynb)
4+
5+
This example demonstrates how the sensitivity of a large single element detector varies with the angular position of a point-like source.
6+
7+
To read more, visit the [original example page](http://www.k-wave.org/documentation/example_sd_directivity_modelling_2D.php).
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"%pip install git+https://github.com/waltsims/k-wave-python "
10+
]
11+
},
12+
{
13+
"cell_type": "markdown",
14+
"metadata": {},
15+
"source": [
16+
"# Modelling Sensor Directivity In 2D Example\n",
17+
"\n",
18+
"This example demonstrates how the sensitivity of a large single element detector varies with the angular position of a point-like source."
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": null,
24+
"metadata": {},
25+
"outputs": [],
26+
"source": [
27+
"%matplotlib inline\n",
28+
"\n",
29+
"import os\n",
30+
"from copy import deepcopy\n",
31+
"from tempfile import gettempdir\n",
32+
"\n",
33+
"import numpy as np\n",
34+
"import matplotlib.pyplot as plt\n",
35+
"\n",
36+
"from kwave.data import Vector\n",
37+
"from kwave.kgrid import kWaveGrid\n",
38+
"from kwave.kmedium import kWaveMedium\n",
39+
"from kwave.ksensor import kSensor\n",
40+
"from kwave.ksource import kSource\n",
41+
"from kwave.kspaceFirstOrder2D import kspaceFirstOrder2DC\n",
42+
"from kwave.options.simulation_execution_options import SimulationExecutionOptions\n",
43+
"from kwave.options.simulation_options import SimulationOptions\n",
44+
"from kwave.utils.conversion import cart2grid\n",
45+
"from kwave.utils.filters import filter_time_series\n",
46+
"from kwave.utils.mapgen import make_cart_circle\n",
47+
"from kwave.utils.matlab import ind2sub, matlab_find, unflatten_matlab_mask\n",
48+
"from kwave.utils.colormap import get_color_map\n",
49+
"from kwave.utils.data import scale_SI"
50+
]
51+
},
52+
{
53+
"cell_type": "markdown",
54+
"metadata": {},
55+
"source": [
56+
"## Create the computational grid and medium"
57+
]
58+
},
59+
{
60+
"cell_type": "code",
61+
"execution_count": null,
62+
"metadata": {},
63+
"outputs": [],
64+
"source": [
65+
"grid_size_points = Vector([128, 128]) # [grid points]\n",
66+
"grid_size_meters = Vector([50e-3, 50e-3]) # [m]\n",
67+
"grid_spacing_meters = grid_size_meters / grid_size_points # [m]\n",
68+
"kgrid = kWaveGrid(grid_size_points, grid_spacing_meters)\n",
69+
"\n",
70+
"# define the properties of the propagation medium\n",
71+
"medium = kWaveMedium(sound_speed=1500)\n",
72+
"\n",
73+
"# define the array of time points [s]\n",
74+
"Nt = 350\n",
75+
"dt = 7e-8 # [s]\n",
76+
"kgrid.setTime(Nt, dt)"
77+
]
78+
},
79+
{
80+
"cell_type": "markdown",
81+
"metadata": {},
82+
"source": [
83+
"## Define a large area detector"
84+
]
85+
},
86+
{
87+
"cell_type": "code",
88+
"execution_count": null,
89+
"metadata": {},
90+
"outputs": [],
91+
"source": [
92+
"sz = 20 # [grid points]\n",
93+
"sensor_mask = np.zeros(grid_size_points)\n",
94+
"sensor_mask[grid_size_points.x // 2, (grid_size_points.y // 2 - sz // 2) : (grid_size_points.y // 2 + sz // 2) + 1] = 1\n",
95+
"sensor = kSensor(sensor_mask)"
96+
]
97+
},
98+
{
99+
"cell_type": "markdown",
100+
"metadata": {},
101+
"source": [
102+
"## Define a time varying sinusoidal source"
103+
]
104+
},
105+
{
106+
"cell_type": "code",
107+
"execution_count": null,
108+
"metadata": {},
109+
"outputs": [],
110+
"source": [
111+
"# define equally spaced point sources lying on a circle centred at the\n",
112+
"# centre of the detector face\n",
113+
"radius = 30 # [grid points]\n",
114+
"points = 11\n",
115+
"circle = make_cart_circle(radius * grid_spacing_meters.x, points, Vector([0, 0]), np.pi)\n",
116+
"\n",
117+
"# find the binary sensor mask most closely corresponding to the Cartesian\n",
118+
"# coordinates from makeCartCircle\n",
119+
"circle, _, _ = cart2grid(kgrid, circle)\n",
120+
"\n",
121+
"# find the indices of the sources in the binary source mask\n",
122+
"source_positions = matlab_find(circle, val=1, mode=\"eq\")\n",
123+
"\n",
124+
"source = kSource()\n",
125+
"source_freq = 0.25e6 # [Hz]\n",
126+
"source_mag = 1 # [Pa]\n",
127+
"source.p = source_mag * np.sin(2 * np.pi * source_freq * kgrid.t_array)\n",
128+
"\n",
129+
"# filter the source to remove high frequencies not supported by the grid\n",
130+
"source.p = filter_time_series(kgrid, medium, source.p)"
131+
]
132+
},
133+
{
134+
"cell_type": "markdown",
135+
"metadata": {},
136+
"source": [
137+
"## Define simulation parameters and run simulations"
138+
]
139+
},
140+
{
141+
"cell_type": "code",
142+
"execution_count": null,
143+
"metadata": {},
144+
"outputs": [],
145+
"source": [
146+
"# pre-allocate array for storing the output time series\n",
147+
"single_element_data = np.zeros((Nt, points)) # noqa: F841\n",
148+
"\n",
149+
"# run a simulation for each of these sources to see the effect that the\n",
150+
"# angle from the detector has on the measured signal\n",
151+
"for source_loop in range(points):\n",
152+
" # select a point source\n",
153+
" source.p_mask = np.zeros(grid_size_points)\n",
154+
" source.p_mask[unflatten_matlab_mask(source.p_mask, source_positions[source_loop] - 1)] = 1\n",
155+
"\n",
156+
" # run the simulation\n",
157+
"\n",
158+
" input_filename = f\"example_input_{source_loop + 1}_input.h5\"\n",
159+
" pathname = gettempdir()\n",
160+
" input_file_full_path = os.path.join(pathname, input_filename)\n",
161+
" simulation_options = SimulationOptions(save_to_disk=True, input_filename=input_filename, data_path=pathname)\n",
162+
" # run the simulation\n",
163+
" sensor_data = kspaceFirstOrder2DC(\n",
164+
" medium=medium,\n",
165+
" kgrid=kgrid,\n",
166+
" source=deepcopy(source),\n",
167+
" sensor=deepcopy(sensor),\n",
168+
" simulation_options=simulation_options,\n",
169+
" execution_options=SimulationExecutionOptions(),\n",
170+
" )\n",
171+
" single_element_data[:, source_loop] = sensor_data['p'].sum(axis=1)"
172+
]
173+
},
174+
{
175+
"cell_type": "markdown",
176+
"metadata": {},
177+
"source": [
178+
"## Visualize recorded data"
179+
]
180+
},
181+
{
182+
"cell_type": "code",
183+
"execution_count": null,
184+
"metadata": {},
185+
"outputs": [],
186+
"source": [
187+
"plt.figure()\n",
188+
"plt.imshow(circle + sensor.mask, \n",
189+
" extent=[\n",
190+
" kgrid.y_vec.min() * 1e3, kgrid.y_vec.max() * 1e3, \n",
191+
" kgrid.x_vec.max() * 1e3, kgrid.x_vec.min() * 1e3], vmin=-1, vmax=1, cmap=get_color_map())\n",
192+
"plt.ylabel('x-position [mm]')\n",
193+
"plt.xlabel('y-position [mm]')\n",
194+
"plt.axis('image')\n",
195+
"\n",
196+
"_, t_scale, t_prefix, _ = scale_SI(kgrid.t_array[-1])\n",
197+
"\n",
198+
"# Plot the time series recorded for each of the sources\n",
199+
"plt.figure()\n",
200+
"# Loop through each source and plot individually\n",
201+
"for i in range(single_element_data.shape[1]):\n",
202+
" plt.plot((kgrid.t_array * t_scale).squeeze(), single_element_data[:, i], label=f'Source {i+1}')\n",
203+
"\n",
204+
"plt.xlabel(f'Time [{t_prefix}s]')\n",
205+
"plt.ylabel('Pressure [au]')\n",
206+
"plt.title('Time Series For Each Source Direction')\n",
207+
"\n",
208+
"\n",
209+
"# Calculate angle between source and center of detector face\n",
210+
"angles = []\n",
211+
"for source_position in source_positions:\n",
212+
" x, y = ind2sub(kgrid.y.shape, source_position)\n",
213+
" angles.append(np.arctan(kgrid.y[x, y] / kgrid.x[x, y]))\n",
214+
"\n",
215+
"# Plot the maximum amplitudes for each of the sources\n",
216+
"plt.figure()\n",
217+
"plt.plot(angles, np.max(single_element_data[200:350, :], axis=0), 'o', mfc='none')\n",
218+
"plt.xlabel('Angle Between Source and Centre of Detector Face [rad]')\n",
219+
"plt.ylabel('Maximum Detected Pressure [au]')\n",
220+
"plt.show()"
221+
]
222+
}
223+
],
224+
"metadata": {
225+
"kernelspec": {
226+
"display_name": "env_kwave",
227+
"language": "python",
228+
"name": "python3"
229+
},
230+
"language_info": {
231+
"codemirror_mode": {
232+
"name": "ipython",
233+
"version": 3
234+
},
235+
"file_extension": ".py",
236+
"mimetype": "text/x-python",
237+
"name": "python",
238+
"nbconvert_exporter": "python",
239+
"pygments_lexer": "ipython3"
240+
}
241+
},
242+
"nbformat": 4,
243+
"nbformat_minor": 2
244+
}

0 commit comments

Comments
 (0)