Source code for pyuff_ustb.objects.wave
from typing import TYPE_CHECKING
import numpy as np
from pyuff_ustb.objects.uff import (
Uff,
compulsory_property,
dependent_property,
optional_property,
)
from pyuff_ustb.readers import read_scalar, util
if TYPE_CHECKING:
from pyuff_ustb.objects.apodization import Apodization
from pyuff_ustb.objects.point import Point
from pyuff_ustb.objects.probes.probe import Probe
from pyuff_ustb.objects.wavefront import Wavefront
# Make sure properties are treated as properties when type checking
compulsory_property = property
optional_property = property
dependent_property = property
[docs]
class Wave(Uff):
""":class:`Uff` class that describes a transmitted wave.
:class:`Wave` contains information to describe a wave: ``planar``, ``spherical``, or ``photoacoustic``, and the apodization used to produce it.
:attr:`wavefront` defines the type of wave produced: :attr:`Wavefront.plane`, :attr:`Wavefront.spherical`, or :attr:`Wavefront.photoacoustic`.
:attr:`source` defines the wave attitude. If :attr:`wavefront` is :attr:`Wavefront.spherical` then :attr:`source` defines the point in space from which the wave originated. If :attr:`source` is behind the plane ``z=0`` then the spherical wave will be diverging. If :attr:`source` is in front of the plane ``z=0`` the the spherical wave will be converging. If the :attr:`wavefront` is :attr:`Wavefront.plane` then :attr:`source` defines the orientation through the azimuth and elevation angles, i.e. :attr:`source.distance` becomes meaningless. If the :attr:`wavefront` is :attr:`Wavefront.photoacoustic` then :attr:`source` is ignored.
:attr:`Apodization` is a :class:`~pyuff_ustb.objects.apodization.Apodization` class used to compute the apodization values that generate the :class:`Wave`.
:attr:`delay` defines the time interval between the reference time ``t0`` and the start of acquisition for this particular wave. We refer to reference time, or time zero, as the moment the wave passes through the origin of coordinates ``(0, 0, 0)``.
See also:
:class:`~pyuff_ustb.objects.wavefront.Wavefront`
:class:`~pyuff_ustb.objects.apodization.Apodization`
Original authors:
* Alfonso Rodriguez-Molares <alfonso.r.molares@ntnu.no>
* Ole Marius Hoel Rindal <olemarius@olemarius.net>
* Anders E. Vrålstad <anders.e.vralstad@ntnu.no>
"""
# Compulsory properties
@compulsory_property
def wavefront(self) -> "Wavefront":
"WAVEFRONT enumeration class"
from pyuff_ustb.objects.wavefront import Wavefront
if "wavefront" in self._reader:
return util.read_enum(self._reader["wavefront"], Wavefront)
return Wavefront.spherical
@compulsory_property
def source(self) -> "Point":
"POINT class"
from pyuff_ustb.objects.point import Point
return Point(self._reader["source"])
@compulsory_property
def origin(self) -> "Point":
"POINT class"
from pyuff_ustb.objects.point import Point
if "origin" in self._reader:
return Point(self._reader["origin"])
return Point(
distance=0.0,
azimuth=0.0,
elevation=0.0,
)
@compulsory_property
def apodization(self) -> "Apodization":
"APODIZATION class"
from pyuff_ustb.objects.apodization import Apodization
return Apodization(self._reader["apodization"])
# Optional properties
@optional_property
def probe(self) -> "Probe":
"PROBE class."
return util.read_probe(self._reader["probe"])
@optional_property
def event(self) -> int:
"Index of the transmit/receive event this wave refers to"
return int(read_scalar(self._reader["event"]))
@optional_property
def delay(self) -> float:
"Time interval between t0 and acquistion start [s]"
if "delay" in self._reader:
return read_scalar(self._reader["delay"])
return 0.0
@optional_property
def sound_speed(self) -> float:
"Reference speed of sound [m/s]"
if "sound_speed" in self._reader:
return read_scalar(self._reader["sound_speed"])
return 1540.0
# Dependent properties
@dependent_property
def N_elements(self) -> int:
"Number of elements"
return self.probe.N_elements
@dependent_property
def delay_values(self) -> np.ndarray:
"Delay [s]"
if self.probe is None:
raise ValueError("Probe must be defined to compute delay values")
if self.sound_speed is None:
raise ValueError("Sound speed must be defined to compute delay values")
source_origin_dist = np.sqrt(np.sum(self.source.xyz**2))
if np.isinf(source_origin_dist):
dst = np.sqrt(
(self.probe.x - self.source.x) ** 2
+ (self.probe.y - self.source.y) ** 2
+ (self.probe.z - self.source.z) ** 2
)
if self.source.z < 0:
return dst / self.sound_speed - np.abs(
source_origin_dist / self.sound_speed
)
else:
return source_origin_dist / self.sound_speed - dst / self.sound_speed
else:
return (self.probe.x - self.origin.x) * np.sin(
self.source.azimuth
) / self.sound_speed + (self.probe.y - self.origin.y) * np.sin(
self.source.elevation
) / self.sound_speed
return value
@dependent_property
def apodization_values(self) -> np.ndarray:
"Apodization [unitless]"
raise NotImplementedError(
"Apodization computation is outside the scope of pyuff_ustb"
)