# SPDX-FileCopyrightText: 2021 Division of Intelligent Medical Systems, DKFZ
# SPDX-FileCopyrightText: 2021 Janek Groehl
# SPDX-License-Identifier: MIT
import numpy as np
from simpa.core.device_digital_twins import DetectionGeometryBase
from simpa.utils import Settings, Tags
[docs]class PlanarArrayDetectionGeometry(DetectionGeometryBase):
"""
This class represents a digital twin of a ultrasound detection device
with a linear detection geometry. The origin for this device is the center of the planar array.
"""
def __init__(self, pitch_mm=0.5,
number_detector_elements_x=100,
number_detector_elements_y=100,
detector_element_width_mm=0.24,
detector_element_length_mm=0.5,
center_frequency_hz=3.96e6,
bandwidth_percent=55,
sampling_frequency_mhz=40,
device_position_mm: np.ndarray = None,
field_of_view_extent_mm: np.ndarray = None):
"""
:param pitch_mm:
:param number_detector_elements_x:
:param number_detector_elements_y:
:param detector_element_width_mm:
:param detector_element_length_mm:
:param center_frequency_hz:
:param bandwidth_percent:
:param sampling_frequency_mhz:
:param device_position_mm: Center of the planar array.
"""
if field_of_view_extent_mm is None:
field_of_view_extent_mm = np.asarray([-number_detector_elements_x * pitch_mm / 2,
number_detector_elements_x * pitch_mm / 2,
-number_detector_elements_y * pitch_mm / 2,
number_detector_elements_y * pitch_mm / 2,
0, 100])
super(PlanarArrayDetectionGeometry, self).__init__(
number_detector_elements=number_detector_elements_x * number_detector_elements_y,
detector_element_width_mm=detector_element_width_mm,
detector_element_length_mm=detector_element_length_mm,
center_frequency_hz=center_frequency_hz,
bandwidth_percent=bandwidth_percent,
sampling_frequency_mhz=sampling_frequency_mhz,
device_position_mm=device_position_mm,
field_of_view_extent_mm=field_of_view_extent_mm)
self.pitch_mm = pitch_mm
self.number_detector_elements_x = number_detector_elements_x
self.number_detector_elements_y = number_detector_elements_y
self.probe_depth_mm = number_detector_elements_y * pitch_mm
self.probe_width_mm = number_detector_elements_x * pitch_mm
[docs] def get_field_of_view_extent_mm(self) -> np.ndarray:
return np.asarray([-self.number_detector_elements_x*self.pitch_mm/2,
self.number_detector_elements_x*self.pitch_mm/2,
-self.number_detector_elements_y * self.pitch_mm / 2,
self.number_detector_elements_y * self.pitch_mm / 2,
0, 100])
[docs] def check_settings_prerequisites(self, global_settings: Settings) -> bool:
if global_settings[Tags.DIM_VOLUME_X_MM] < self.probe_width_mm + global_settings[Tags.SPACING_MM]:
self.logger.error(f"Volume x dimension is too small to encompass RSOM device in simulation!"
f"Must be at least {self.probe_width_mm + global_settings[Tags.SPACING_MM]} mm but "
f"was {global_settings[Tags.DIM_VOLUME_X_MM]} mm")
return False
if global_settings[Tags.DIM_VOLUME_Y_MM] < self.probe_depth_mm + global_settings[Tags.SPACING_MM]:
self.logger.error(f"Volume y dimension is too small to encompass RSOM device in simulation!"
f"Must be at least {self.probe_depth_mm + global_settings[Tags.SPACING_MM]} mm but "
f"was {global_settings[Tags.DIM_VOLUME_X_MM]} mm")
return False
return True
[docs] def update_settings_for_use_of_model_based_volume_creator(self, global_settings):
pass
[docs] def get_detector_element_positions_base_mm(self) -> np.ndarray:
detector_element_positions_mm = np.zeros((self.number_detector_elements, 3))
for x in range(self.number_detector_elements_x):
for y in range(self.number_detector_elements_y):
detector_element_positions_mm[x + y*self.number_detector_elements_x] = \
[(x - self.number_detector_elements_x/2 + 0.5) * self.pitch_mm,
(y - self.number_detector_elements_y/2 + 0.5) * self.pitch_mm,
0]
return detector_element_positions_mm
[docs] def get_detector_element_orientations(self) -> np.ndarray:
detector_element_orientations = np.zeros((self.number_detector_elements, 3))
detector_element_orientations[:, 2] = 1
return detector_element_orientations
[docs] def serialize(self) -> dict:
serialized_device = self.__dict__
return {"PlanarArrayDetectionGeometry": serialized_device}
[docs] @staticmethod
def deserialize(dictionary_to_deserialize):
deserialized_device = PlanarArrayDetectionGeometry()
for key, value in dictionary_to_deserialize.items():
deserialized_device.__dict__[key] = value
return deserialized_device