Coverage for kwave/reconstruction/converter.py: 0%

53 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-10-24 11:52 -0700

1import scipy 

2import uff 

3import numpy as np 

4from kwave import NotATransducer 

5from uff.linear_array import LinearArray 

6import time 

7 

8 

9def build_channel_data(sensor_data: np.ndarray, 

10 kgrid, 

11 not_transducer: NotATransducer, 

12 sampling_frequency, 

13 prf, 

14 focal_depth): 

15 number_scan_lines = sensor_data.shape[1] 

16 input_signal = not_transducer.input_signal 

17 transducer = not_transducer.transducer 

18 

19 x0 = np.arange(0, 96) * transducer.element_width * kgrid.dy 

20 x0 = x0 - (x0.max() / 2) 

21 

22 unique_excitations = uff.excitation.Excitation( 

23 waveform=input_signal, 

24 sampling_frequency=sampling_frequency, 

25 pulse_shape='Gaussian' 

26 ) 

27 

28 probe = LinearArray( 

29 number_elements=transducer.number_elements * 4, 

30 pitch=transducer.element_width * kgrid.dy + transducer.element_spacing * kgrid.dx, 

31 element_width=transducer.element_width * kgrid.dy, 

32 element_height=transducer.element_length * kgrid.dx, 

33 transform=uff.transform.Transform(uff.transform.Translation(0, 0, 0), uff.transform.Rotation(0, 0, 0)) 

34 ) 

35 

36 ####### Move to LinearArray.update 

37 

38 if probe.pitch and probe.number_elements: 

39 

40 # for all lines in this block, probe.element_geometry[0] is hard coded as 0. Should be dynamic! 

41 

42 # update perimeter 

43 if probe.element_width and probe.element_height: 

44 

45 if not probe.element_geometry: 

46 probe.element_geometry = [uff.element_geometry.ElementGeometry( 

47 uff.perimeter.Perimeter([ 

48 uff.Position(0, 0, 0), 

49 uff.Position(0, 0, 0), 

50 uff.Position(0, 0, 0), 

51 uff.Position(0, 0, 0), 

52 ]) 

53 )] 

54 

55 if not probe.element_geometry[0].perimeter: 

56 probe.element_geometry.perimeter = uff.perimeter.Perimeter([ 

57 uff.Position(0, 0, 0), 

58 uff.Position(0, 0, 0), 

59 uff.Position(0, 0, 0), 

60 uff.Position(0, 0, 0), 

61 ]) 

62 

63 probe.element_geometry[0].perimeter.position[0] = uff.Position(x=-probe.element_width / 2, 

64 y=-probe.element_height / 2, z=0) 

65 probe.element_geometry[0].perimeter.position[1] = uff.Position(x=probe.element_width / 2, 

66 y=-probe.element_height / 2, z=0) 

67 probe.element_geometry[0].perimeter.position[2] = uff.Position(x=probe.element_width / 2, 

68 y=probe.element_height / 2, z=0) 

69 probe.element_geometry[0].perimeter.position[3] = uff.Position(x=-probe.element_width / 2, 

70 y=probe.element_height / 2, z=0) 

71 

72 # compute element position in the x-axis 

73 x0_local = np.arange(1, probe.number_elements + 1) * probe.pitch 

74 x0_local = x0_local - x0_local.mean() 

75 x0_local = x0_local.astype(np.float32) 

76 

77 # create array of elements 

78 probe.element = [] 

79 for n in range(probe.number_elements): 

80 element = uff.Element( 

81 transform=uff.Transform( 

82 translation=uff.Translation(x=x0_local[n], y=0, z=0), 

83 rotation=uff.Rotation(x=0, y=0, z=0) 

84 ), 

85 # linear array can only have a single perimenter impulse_response 

86 # impulse_response=[], # probe.element_impulse_response, 

87 element_geometry=probe.element_geometry[0] 

88 ) 

89 

90 probe.element.append(element) 

91 

92 ####### Move end 

93 

94 unique_waves = [] 

95 for n in range(number_scan_lines): 

96 wave = uff.Wave( 

97 wave_type=uff.WaveType.CONVERGING, 

98 origin=uff.SphericalWaveOrigin( 

99 position=uff.Position(x=x0[n], z=focal_depth) 

100 ), 

101 aperture=uff.Aperture( 

102 origin=uff.Position(x=x0[n]), 

103 fixed_size=transducer.element_length*kgrid.dx, # wrong, correct one is in below 

104 # fixed_size=[active_aperture*el_pitch, el_height], 

105 window='rectangular' 

106 ) 

107 ) 

108 unique_waves.append(wave) 

109 

110 unique_events = [] 

111 lag = 1.370851370851371e-06 # (length(input_signal) / 2 + 1) * dt 

112 downsample_factor = 1 

113 first_sample_time = 650e-9 * np.ones((number_scan_lines, 1)) # CHANGE 

114 

115 for n in range(number_scan_lines): 

116 # we select a time zero reference point: in this case the location of the first element fired 

117 arg_min = np.argmax(np.sqrt((x0[n] - x0) ** 2 + focal_depth ** 2)) 

118 time_zero_reference_point = x0[arg_min] 

119 

120 transmit_wave = uff.TransmitWave( 

121 wave=n, 

122 time_zero_reference_point=uff.TimeZeroReferencePoint(x=time_zero_reference_point, y=0, z=0), 

123 time_offset=lag, 

124 weight=1 

125 ) 

126 

127 # transmit and receive channel 

128 # channel_mapping = np.arange(n, number_elements + n).tolist() 

129 channel_mapping = np.arange(n, transducer.number_elements + n)[None, :].T # shape: [number_elements x 1] 

130 transmit_setup = uff.TransmitSetup( 

131 probe=1, # different from Matlab 

132 channel_mapping=channel_mapping, 

133 transmit_waves=[transmit_wave] # should be list! 

134 ) 

135 

136 # active_elment_positions = channel_data.probes{1}.get_elements_centre(); 

137 

138 receive_setup = uff.ReceiveSetup( 

139 probe=1, # different from Matlab 

140 time_offset=first_sample_time[n], 

141 channel_mapping=channel_mapping, 

142 sampling_frequency=sampling_frequency / downsample_factor 

143 ) 

144 

145 unique_event = uff.Event( 

146 transmit_setup=transmit_setup, 

147 receive_setup=receive_setup 

148 ) 

149 

150 unique_events.append(unique_event) 

151 

152 sequence = [] 

153 for n in range(len(unique_events)): 

154 sequence.append(uff.TimedEvent( 

155 event=n, 

156 time_offset=(n - 1) / prf 

157 )) 

158 

159 channel_data = uff.channel_data.ChannelData( 

160 data=sensor_data, 

161 probes=[probe], 

162 unique_excitations=[unique_excitations], 

163 unique_waves=unique_waves, 

164 unique_events=unique_events, 

165 description='US B-Mode Linear Transducer Scan, kWave.', 

166 authors='kWave.py', 

167 sound_speed=not_transducer.sound_speed, 

168 system='kWave.py', 

169 country_code='DE', 

170 local_time=time.strftime('%Y-%m-%dTHH:MM:SS+00'), # fix 

171 repetition_rate=prf / len(unique_events), 

172 sequence=sequence 

173 ) 

174 return channel_data