Note
Click here to download the full example code
Time-reverse simulation for phased array
The skull adds aberrations to the beam propagation; phased arrays can compensate for those by having different delays for each element, but estimating these delays can be challenging. One method to estimate the delays is a "time reverse" simulation as described in this Article. This notebook demonstrates the "time reverse" method to estimate the delays. The notebook sets up a scenario with a phased array source and a target and then runs a simulation with the source and target reversed to calculate the delays. Finally, it uses the calculated delays to perform a forward-time simulation.
Note
In this notebook, we refer to the "true" target as the eventual brain region we would like to stimulate, and the "true" source as the placement of the ultrasound probes. We refer to the "reversed" or "simulated" target and point-source as the values defined in our simulation, which are reversed from the physical setup to help calculate values.
import matplotlib.pyplot as plt
import numpy as np
import neurotechdevkit as ndk
# Parameters
NUM_ELEMENTS = 20
ELEMENT_WIDTH = 1.2e-3
Helper function to make the scenario with a PhasedArraySource
def make_scenario(element_delays=None):
true_scenario = ndk.scenarios.built_in.Scenario2_2D()
# define a phased-array source
default_source = true_scenario.sources[0]
true_source = ndk.sources.PhasedArraySource2D(
element_delays=element_delays,
position=default_source.position,
direction=default_source.unit_direction,
num_elements=NUM_ELEMENTS,
pitch=default_source.aperture / NUM_ELEMENTS,
element_width=ELEMENT_WIDTH,
num_points=1000,
)
true_scenario.sources = [true_source]
return true_scenario
Set up and visualize the forward scenario
true_scenario = make_scenario()
true_scenario.make_grid()
true_scenario.compile_problem()
true_scenario.render_layout()
Simulate the time-reverse scenario
Place a point source at the true target, and simulate a pulse. The point source is visualized as a gray dot.
# Reinitialize the scenario
reversed_scenario = ndk.scenarios.built_in.Scenario2_2D()
# and reverse the source
point_source = ndk.sources.PointSource2D(
position=true_scenario.target.center,
)
reversed_scenario.sources.append(point_source)
reversed_scenario.make_grid()
reversed_scenario.compile_problem()
reversed_scenario.render_layout()
result = reversed_scenario.simulate_pulse()
assert isinstance(result, ndk.results.PulsedResult2D)
result.render_pulsed_simulation_animation()
Out:
Estimated time to complete simulation: 2 minutes. Memory required is 9.898794145189598 GB (available 73.624408064 GB). These values are approximated.
/home/circleci/.cache/pypoetry/virtualenvs/neurotechdevkit-3aSsmiER-py3.10/lib/python3.10/site-packages/devito/finite_differences/differentiable.py:224: DeprecationWarning: NotImplemented should not be used in a boolean context
return super(Differentiable, self).__eq__(other) and\
/home/circleci/.cache/pypoetry/virtualenvs/neurotechdevkit-3aSsmiER-py3.10/lib/python3.10/site-packages/devito/finite_differences/differentiable.py:224: DeprecationWarning: NotImplemented should not be used in a boolean context
return super(Differentiable, self).__eq__(other) and\
gcc -O3 -g -fPIC -Wall -std=c99 -march=native -Wno-unused-result -Wno-unused-variable -Wno-unused-but-set-variable -ffast-math -shared -fopenmp /tmp/devito-jitcache-uid1001/bc8fb1f60cd9db4d35f8beda3d6ca87c83ea57bd.c -lm -o /tmp/devito-jitcache-uid1001/bc8fb1f60cd9db4d35f8beda3d6ca87c83ea57bd.so
/home/circleci/project/src/neurotechdevkit/rendering/_animations.py:118: UserWarning: You passed in an explicit save_count=563 which is being ignored in favor of frames=563.
anim = FuncAnimation(