Coverage for kwave/ksensor.py: 62%

1 from dataclasses import dataclass

2 import numpy as np

3

4 from kwave.utils import expand_matrix

5

6

7 class kSensor(object):

8

9 def __init__(self, mask=None, record=None):

10 self._mask = mask

11 self.record = record #: cell array of the acoustic parameters to record in the form Recorder

12 # record the time series from the beginning by default

13 self._record_start_index = 1 #: time index at which the sensor should start recording the data specified by sensor.record

14

15 #: Directivity of the individiual sensor points

16 self.directivity = None

17

18 self.time_reversal_boundary_data = None #: time varying pressure enforced as a Dirichlet boundary condition over sensor.mask

19 self.frequency_response = None #: two element array specifying the center frequency and percentage bandwidth of a frequency domain Gaussian filter applied to the sensor_data

20

21 @property

22 def mask(self):

23 """

24 Binary matrix or a set of Cartesian points where the pressure is recorded at each time-step

25 """

26 return self._mask

27

28 @mask.setter

29 def mask(self, val):

30 self._mask = val

31

32 def expand_grid(self, expand_size) -> None:

33 """

34 Enlarge the sensor mask (for Cartesian sensor masks and cuboid corners,

35 this has already been converted to a binary mask for display in inputChecking)

36

37 Args:

38 expand_size: the number of elements to add in each dimension

39

40 Returns:

41 None

42 """

43 self.mask = expand_matrix(self.mask, expand_size, 0)

44

45 @property

46 def record_start_index(self):

47 """

48 Time index to start recording if transducer is used as a sensor

49 """

50 return self._record_start_index

51

52 @record_start_index.setter

53 def record_start_index(self, val):

54 # force the user index to be an integer

55 self._record_start_index = int(round(val))

56

57

58@dataclass

59 class kSensorDirectivity(object):

60 #: matrix of directivity angles (direction of maximum

61 #: response) for each sensor element defined in

62 #: sensor.mask. The angles are in radians where 0 = max

63 #: sensitivity in x direction (up/down) and pi/2 or -pi/2

64 #: = max sensitivity in y direction (left/right)

65 angle : np.ndarray = None

66

67 #: string defining the directivity pattern, valid inputs

68 #: are 'pressure' (spatial averaging over the sensor

69 #: surface equivalent to a sinc function) and 'gradient'

70 pattern : str = 'pressure'

71

72 #: equivalent element size (the larger the element size the more directional the response)

73 size : float = None

74

75 #: list of the unique directivity angles

76 unique_angles : np.ndarray = None

77

78 #: It is precomputed to allow data casting, as kgrid.kx (etc) are computed on the fly.

79 wavenumbers : np.ndarray = None

80

81 def set_default_size(self, kgrid) -> None:

82 """

83 Set the element size based on the kGrid

84

85 Args:

86 kgrid: Instance of `~kwave.kgrid.kWaveGrid` class

87

88 Returns:

89 None

90 """

91 DEFAULT_SIZE = 10

92 self.size = DEFAULT_SIZE * max(kgrid.dx, kgrid.dy)

93

94 def set_unique_angles(self, sensor_mask) -> None:

95 """

96 Assign unique_angles from sensor_mask

97

98 Args:

99 sensor_mask:

100

101 Returns:

102 None

103 """

104 self.unique_angles = np.unique(self.angle[sensor_mask == 1])

105

106 def set_wavenumbers(self, kgrid) -> None:

107 """

108 Assign the wavenumber vectors

109

110 Args:

111 kgrid: Instance of `~kwave.kgrid.kWaveGrid` class

112

113 Returns:

114 None

115 """

116 self.wavenumbers = np.vstack([kgrid.ky.T, kgrid.kx.T])